首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >快速多窗口渲染

快速多窗口渲染
EN

Stack Overflow用户
提问于 2012-11-04 05:25:40
回答 5查看 6.9K关注 0票数 14

几周来,我一直在搜索和测试C# days的不同类型的渲染库。到目前为止,我还没有找到一个在多窗口渲染设置上工作良好的库。要求是能够在快速计算机上无延迟地在12+监视器设置(财务图表)上运行程序。每个窗口每秒需要更新多次。在这样做的时候,CPU需要做很多密集的和时间关键的任务,所以一些负担必须转移到GPU上。这就是硬件渲染的用法,换句话说,就是DirectX或OpenGL。

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

相比之下,我在C++/Win32API上做了一些DirectX9测试,一个设备/多个交换链,我可以打开分布在4个显示器工作区的100个窗口(在它们上旋转3D茶壶),并且仍然有完全负责的操作系统(当然,渲染窗口上的fps下降得相当严重,大约为5,这是我期望同时运行100个渲染的结果)。

有没有人知道在C#上做多窗口渲染的好方法,或者我被迫用C++重写我的程序来获得那样的性能(主要痛苦)?我想在我走C++路线之前我会再给OpenGL一次机会。我会在这里报告任何发现。

供参考的测试方法:

对于C# DirectX单设备多交换链测试,我使用了这个优秀答案中的方法:Display Different images per monitor directX 10

Direct3D10版本:

我像这样创建了d3d10device和DXGIFactory:

代码语言:javascript
复制
D3DDev = new SharpDX.Direct3D10.Device(SharpDX.Direct3D10.DriverType.Hardware,
            SharpDX.Direct3D10.DeviceCreationFlags.None);
DXGIFac = new SharpDX.DXGI.Factory();

然后初始化渲染窗口,如下所示:

代码语言:javascript
复制
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);

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

代码语言:javascript
复制
Parent.D3DDev.ClearRenderTargetView(_rt, new Color4(0, 0, 0, 0));
SC.Present(0, SharpDX.DXGI.PresentFlags.None);

DirectX9版本非常相似:

设备初始化:

代码语言:javascript
复制
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);

渲染窗口初始化:

代码语言:javascript
复制
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);
}

绘制循环的代码:

代码语言:javascript
复制
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/Win32API测试如下:

[C++] DirectX9 Multi-window test - Pastebin.com

它是Kevin Harris的优秀示例代码的修改版本。

编辑:

我的主要问题是,在进行多窗口渲染时,我的主要问题不是fps太低,而是所有操作系统功能(窗口动画、拖放滚动等)的一般延迟。

EN

回答 5

Stack Overflow用户

发布于 2012-11-04 06:18:31

这里只说到DirectX,但我记得我们曾经遇到过类似的问题(一台PC上有5块显卡和9块屏幕)。

很多时候,全屏开关似乎想要在显示器上启用垂直同步,因为Present不能被线程,更多的屏幕与垂直同步,你将有更高的下降(因为你将等待0至16毫秒)为每个当前呼叫。

在我们的例子中,我们的解决方案是创建最大化的窗口并删除边界,这不是理想的,但从10fps绘制一个矩形回到标准速度(60)。

如果你想要代码样本,请让我知道,我会准备一个。

同样为了测试,我使用c#/slimdx/dx11在我的引擎上创建了30个窗口,渲染了一个带有基本着色的球体,仍然超过了40fps。

票数 4
EN

Stack Overflow用户

发布于 2012-11-04 06:58:50

我们也有类似的问题(需要使用3+显卡在9+显示器上渲染3D视图)。我们选择使用原始DirectX11,因为我们发现第三方渲染库在跨多个显示器的多个窗口中都非常差,更不用说使用多个适配器了。(似乎大多数引擎都是为全屏游戏设计的,而且往往在窗口视图上表现不佳)。而不是使用像SlimDX或SharpDX这样的第三方层,我们最终决定直接用C++编写核心渲染器,只需通过C++/CLI公开我们的应用程序所需的简单应用程序接口-这应该会最大化性能并最大限度地减少可维护性问题(依赖第三方供应商来修复错误等)。

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

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

(我不知道这对您是否有帮助,但我们也非常想知道是否有其他解决方案可以在多个显卡上工作,以防我们错过了更好的技巧)

票数 3
EN

Stack Overflow用户

发布于 2012-11-06 20:33:06

我从来没有机会运行过这种情况,但我唯一可以肯定的是,使用托管包装器完全没有问题,使用C++代码也会遇到同样的问题。

此外,在您的描述中,您的系统上安装了多少显卡也是非常不清楚的。此外,您还应该更密切地关注"DirectX Graphics Infrastructure (DXGI): Best Practices“,因为它们描述了您可能遇到的许多问题。在全屏中运行不同的显卡,正确的交换全屏设置应该是可以的(使用"flip“而不是" blit ",请参阅msdn文档),但如果你在最大化窗口中运行应用程序,我不认为性能会很好,因为blit会干扰并产生一些滞后。

你可以完美地拥有一个使用多个设备的多线程应用程序,每个线程一个设备,它们应该能够正确地调度事情……但同样,由于我在这种情况下没有经验,在这种特定情况下可能会有某种类型的GPU调度问题。

如果在仔细进行DXGI设置后问题仍然存在,我建议您使用GPUView调试整个过程,以便更仔细地检查这些问题。它正是为这种情况而设计的,但您必须花一些时间来了解如何使用这种工具进行诊断。最后还有一次关于GPUView的讨论,GDC 2012: Using GPUView to Understand your DirectX 11 Game (Jon Story)可能值得一读。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13213648

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档