C#

我一直在为C#日子搜索和测试不同类型的渲染库,现在已经有好几个星期了。 到目前为止,我还没有找到一个适用于多窗口渲染设置的单个库。 要求是能够在高速计算机上在没有延迟的情况下在12个监视器设置(金融图表)上运行该程序。 每个窗口需要每秒更新多次。 虽然做这个CPU需要做很多密集和时间关键的任务,所以一些负担必须转移到GPU上。 这就是硬件渲染的步骤,换句话说就是DirectX或OpenGL。

我尝试过使用Windows窗体的GDI +,并认为它对我的需求来说太慢了。 我已经尝试OpenGL通过OpenTK(在Windows窗体控件上),看起来非常快(我还有一些测试运行在它上),但很难正常工作(很难找到/编程良好的文本渲染库)。 最近我通过SharpDX使用Windows窗体尝试了DirectX9,DirectX10和Direct2D。 我为每个窗口和单个设备/多个交换链方法尝试了一个单独的设备。 所有这些导致在多个窗口中的性能很差。 例如,如果我将目标FPS设置为20,并在不同显示器上打开4个全屏窗口,则整个操作系统开始滞后非常严重。 渲染只是将屏幕清除为黑色,不渲染任何基元。 此测试中的CPU使用率约为0%,GPU使用率约为10%,我不明白这里的瓶颈是什么? 我的开发电脑速度非常快,i7 2700k,AMD HD7900,16GB RAM,所以测试应该在这一个上运行。

相比之下,我在C ++ / Win32 API一个设备/多个交换链上做了一些DirectX9测试,并且我可以在四个显示器的工作区中打开100个窗口(使用3D茶壶在它们上旋转),并且仍然具有完全负责任的操作系统(fps是当然,渲染窗口的渲染速度相当糟糕,大约是5,这是我期望运行100个同时渲染)。

有没有人知道任何好的方法来做C#多窗口渲染或我不得不重新编写我的程序在C + +来获得该性能(主要痛苦)? 我想我在开始C ++路线之前给OpenGL另一个镜头。 我会在这里报告任何发现。

参考测试方法:

对于C#DirectX单设备多交换链测试,我使用了以下优秀答案中的方法:每个显示器显示不同的图像directX 10

Direct3D10版本:

我创建了这样的d3d10device和DXGIFactory:

D3DDev = new SharpDX.Direct3D10.Device(SharpDX.Direct3D10.DriverType.Hardware,
            SharpDX.Direct3D10.DeviceCreationFlags.None);
DXGIFac = new SharpDX.DXGI.Factory();

然后像这样初始化渲染窗口:

var scd = new SwapChainDescription();
scd.BufferCount = 1;
scd.ModeDescription = new ModeDescription(control.Width, control.Height,
      new Rational(60, 1), Format.R8G8B8A8_UNorm);
scd.IsWindowed = true;
scd.OutputHandle = control.Handle;
scd.SampleDescription = new SampleDescription(1, 0);
scd.SwapEffect = SwapEffect.Discard;
scd.Usage = Usage.RenderTargetOutput;

SC = new SwapChain(Parent.DXGIFac, Parent.D3DDev, scd);

var backBuffer = Texture2D.FromSwapChain<Texture2D>(SC, 0);
_rt = new RenderTargetView(Parent.D3DDev, backBuffer);

在每个渲染迭代上执行的绘图命令很简单:

Parent.D3DDev.ClearRenderTargetView(_rt, new Color4(0, 0, 0, 0));
SC.Present(0, SharpDX.DXGI.PresentFlags.None);

DirectX9版本非常相似:

设备初始化:

PresentParameters par = new PresentParameters();
par.PresentationInterval = PresentInterval.Immediate;
par.Windowed = true;
par.SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard;
par.PresentationInterval = PresentInterval.Immediate;
par.AutoDepthStencilFormat = SharpDX.Direct3D9.Format.D16;
par.EnableAutoDepthStencil = true;
par.BackBufferFormat = SharpDX.Direct3D9.Format.X8R8G8B8;

// firsthandle is the handle of first rendering window
D3DDev = new SharpDX.Direct3D9.Device(new Direct3D(), 0, DeviceType.Hardware, firsthandle,
    CreateFlags.SoftwareVertexProcessing, par);

渲染窗口初始化:

if (parent.D3DDev.SwapChainCount == 0)
{
    SC = parent.D3DDev.GetSwapChain(0);
}
else
{
    PresentParameters pp = new PresentParameters();
    pp.Windowed = true;
    pp.SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard;
    pp.BackBufferFormat = SharpDX.Direct3D9.Format.X8R8G8B8;
    pp.EnableAutoDepthStencil = true;
    pp.AutoDepthStencilFormat = SharpDX.Direct3D9.Format.D16;
    pp.PresentationInterval = PresentInterval.Immediate;

    SC = new SharpDX.Direct3D9.SwapChain(parent.D3DDev, pp);
}

绘制循环代码:

SharpDX.Direct3D9.Surface bb = SC.GetBackBuffer(0);
Parent.D3DDev.SetRenderTarget(0, bb);

Parent.D3DDev.Clear(ClearFlags.Target, Color.Black, 1f, 0);
SC.Present(Present.None, new SharpDX.Rectangle(), new SharpDX.Rectangle(), HWND);
bb.Dispose();

具有多个交换链和一个设备代码的C ++ DirectX9 / Win32 API测试在这里:

[C ++] DirectX9多窗口测试 - Pastebin.com

这是来自Kevin Harris很好的示例代码的修改版本。

编辑:

为了说清楚,我的主要问题是在进行多窗口渲染时这里的fps不低,这是所有操作系统功能(窗口动画,拖放滚动等)造成的一般延迟。


说到DirectX只有在这里,但我记得我们曾经有过同样的问题(一台PC有5个图形卡和9个屏幕)。

很多次全屏切换似乎想在显示器上启用垂直同步,并且由于Present不能被线程化,因此垂直同步的屏幕越多,您将拥有的更高的下拉(因为您将在0到16毫秒之间等待)礼物。

在我们的例子中,我们的解决方案是创建最大化的窗口并移除边框,但它不是理想的,而是从10 fps将矩形拉回到标准速度(60)。

如果你想要代码示例让我知道我会准备一个。

也仅仅用于测试,我已经使用c#/ slimdx / dx11在我的引擎上创建了30个窗口,渲染了一个带有基本阴影的球体,仍然超过40 fps。


我们有类似的问题(需要使用3个以上的显卡在9台显示器上渲染3D视图)。 在发现第三方渲染库在多个显示器上的多个窗口中都很差时,我们选择使用原始DirectX11,更不用说多个适配器了。 (似乎大多数引擎都是为全屏游戏而设计的,并且倾向于在窗口视图中吸引)。 我们最终决定直接用C ++编写核心渲染器,而不是使用像SlimDX或SharpDX这样的第三方层,而是直接用C ++编写核心渲染器,并通过C ++ / CLI公开我们的应用程序需要的简单API - 这应该最大限度地提高性能并最大限度地降低可维护性问题(依赖在第三方供应商的bug修复等)。

但是,就像你一样,我们在测试中发现,如果我们从单个进程渲染了9个视图(每个渲染都在它自己的线程中),我们得到了糟糕的性能(非常低的帧速率)。 但是,如果我们运行了9个独立的进程(每个视图/监视器一个进程),则性能与预期的一样(非常好)。

因此,为了更好的解决方案,我们花了数天的时间来无情地拖网,我们选择在单独的流程中简单地运行我们的渲染器。 对于我们来说,这并不是一个糟糕的解决方案,因为我们的渲染器无论如何都需要支持在多台PC上进行分发,所以这意味着我们将永久使用此工具,而不是仅在需要时使用此工具

(我不知道这对你是否有帮助作为答案,但我们也很想知道是否有任何其他解决方案可以在多个显卡上使用,以防我们错过了更好的技巧)


从来没有机会运行这种场景,但唯一可以肯定的是,使用托管包装完全没有问题,您将会遇到与C ++代码完全相同的问题。

另外,在你的描述中,你很难清楚你系统上安装了多少个显卡。 此外,您应该更仔细地关注“DirectX图形基础设施(DXGI):最佳实践”,因为它们描述了许多您可能遇到的问题。 在全屏模式下使用不同的图形卡以正确的swapchain设置全屏运行应该没问题(使用“flip”而不是“blit”,请参阅关于此的msdn文档),但是如果您在最大化窗口中运行应用程序,我不认为那样的表现会很好,因为这个障碍会干扰并产生一些滞后。

你可以完美地使用一个多线程应用程序使用多个设备,每个线程一个设备,他们应该能够正确地安排事情......但是,由于我没有这种场景的经验,可能会有某种GPU调度问题在这个特定的情况下。

如果在仔细观察DXGI设置之后问题仍然存在,我建议您使用GPUView调试整个事情,以便更仔细地检查这些问题。 它专门用于这种场景,但您需要一些时间来了解如何使用这种工具进行诊断。 在去年的GDC 2012上还有一场关于GPUView的讨论:使用GPUView来了解DirectX 11游戏(Jon Story),这可能值得一读。

链接地址: http://www.djcxy.com/p/50347.html

上一篇: c#

下一篇: 2D graph drawing in windows with unmanaged code callable from excel