我已经搜索和测试了很多个星期的不同类型的渲染库,到目前为止,我还没有找到一个可以在多窗口渲染设置下运行的库。要求是能够在12个以上的显示器设置下运行程序(财务图表)在快速的计算机上没有延迟。每个窗口需要每秒更新多次。在执行此操作时,CPU需要执行大量密集和时间关键的任务,因此负担必须转移到GPU上。这就是硬件渲染的步骤,换句话说,DirectX或OpenGL。
我尝试过GDI+和Windows窗体,发现它对我的需要来说太慢了。(在windows窗体控件上),(我仍然有一些测试运行它),但痛苦的难以得到正常工作(很难找到/编写好的文本渲染库)。最近我尝试了DirectX 9,DirectX 10和Direct 2D与Windows窗体通过SharpDX.我尝试了一个单独的设备为每个窗口和一个单一的设备/多个交换链的方法。所有这些都导致了在多个窗口上非常差的性能。例如,如果我将目标FPS设置为20,并打开4个完整的在不同的显示器上的屏幕窗口,整个操作系统开始非常滞后。渲染只是将屏幕清除为黑色,没有渲染原语。在这个测试中,CPU使用率约为0%,GPU使用率约为10%,我不明白这里的瓶颈是什么?我的开发计算机非常快,i7 2700 k,AMD HD 7900,16 GB RAM,所以测试肯定应该在这台计算机上运行。
相比之下,我在C++/Win32 API上做了一些DirectX 9测试,一个设备/多个交换链,我可以打开100个窗口,遍布4个显示器的工作区(3D茶壶在上面旋转),仍然有非常可靠的操作系统(fps在渲染窗口上下降到5左右,这是我期望同时运行100个渲染)。
有人知道在C#上进行多窗口渲染的好方法吗?或者我被迫用C重写程序以获得这种性能(主要痛苦)?我想在我走C路线之前,我会给OpenGL另一次机会。我会在这里报告任何发现。
供参考的试验方法:
对于C# DirectX单设备多交换链测试我使用的方法来自这个优秀的答案:Display Different images per monitor directX 10
Direct 3D 10版本:
我像这样创建了d3 d10设备和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);
型
DirectX 9版本非常相似:
设备初始化:
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++ DirectX 9/Win32 API测试如下:
[C++] DirectX9 Multi-window test - Pastebin.com的
它是Kevin Harris的示例代码的修改版本。
编辑:
只是为了澄清,我的主要问题不是低fps在这里做多窗口渲染时,它的一般延迟造成的所有操作系统功能(窗口动画,拖放滚动等)。
6条答案
按热度按时间ulmd4ohb1#
只在这里提到DirectX,但我记得我们曾经遇到过同样的问题(一台PC有5个显卡和9个屏幕)。
很多时候,全屏切换似乎想在显示器上启用垂直同步,由于Present不能线程化,因此垂直同步的屏幕越多,每个Present调用的下降幅度就越大(因为您将等待0到16毫秒)。
解决方案,我们在我们的情况下是创建窗口最大化和删除边框,这是不理想的,但从10 fps绘制矩形回到标准速度(60)。
如果你想要的代码样本让我知道我会准备一个。
同样,为了测试,我用c#/slimdx/dx11在引擎上创建了30个窗口,用基本的阴影渲染了一个球体,仍然超过40 fps。
mwngjboj2#
我们也有类似的问题(需要使用3+显卡在9+显示器上渲染3D视图)。我们选择使用原始的DirectX 11,因为我们发现第三方渲染库在多个显示器上的多个窗口都非常差,更不用说多个适配器了。(似乎大多数引擎都是为全屏游戏设计的,并且倾向于在窗口视图中吮吸)。而不是使用像SlimDX或SharpDX这样的第三方层,我们最终决定直接用C编写核心渲染器,并通过C/CLI公开我们的应用程序所需的简单API-这将最大限度地提高性能并最小化可维护性问题(依赖第三方供应商进行错误修复等)。
然而,就像你一样,我们在测试中发现,如果我们从一个进程中渲染9个视图(每个视图在自己的线程上渲染),我们会得到糟糕的性能(非常低的帧速率)。但是,如果我们运行9个单独的进程(每个视图/监视器一个),性能就像预期的那样(优秀)。
因此,我们花了几天时间在网上寻找更好的解决方案,但毫无结果,我们选择了简单地在单独的进程中运行我们的渲染器。对我们来说,这并不完全是一个糟糕的解决方案,因为我们的渲染器需要支持多台PC上的分发,所以这只是意味着我们将永久使用这个设施,而不是只在需要时使用。
(我不知道这是否对你有帮助,但我们也很想知道是否有任何其他解决方案可以在多个显卡上工作,以防我们错过了更好的技巧)
eqoofvh93#
我从来没有机会运行这种场景,但我唯一确定的是,使用托管 Package 绝对没有问题,使用C++代码也会遇到同样的问题。
另外,在您的描述中,不清楚您的系统上安装了多少个显卡。此外,您应该更密切地关注“DirectX Graphics Infrastructure (DXGI): Best Practices“,因为它们描述了您可能遇到的许多问题。在全屏模式下运行不同的显卡,并正确地设置全屏模式下的交换链应该可以(使用“flip”而不是“blit”,请参见msdn文档),但是如果你在最大化窗口中运行你的应用程序,我不认为性能会很好,因为blit会干扰并产生一些滞后。
您完全可以让一个多线程应用程序使用多个设备,每个线程一个设备,它们应该能够正确地进行调度......但同样,由于我在这类场景中没有经验,因此在这种特定情况下可能会出现某种GPU调度问题。
如果问题仍然存在,我建议您使用GPUView进行调试,以便更仔细地检查这些问题。它正是针对这种情况而设计的,但是您将不得不花一些时间来了解如何使用这种工具进行诊断。在最后的GDC 2012: Using GPUView to Understand your DirectX 11 Game (Jon Story)中还有一个关于GPUView的讨论,可能值得阅读
tcbh2hod4#
确保您已禁用对本机代码调用的安全检查(通过
SuppressUnmanagedCodeSecurityAttribute
)。相关的堆栈遍历是性能杀手。
nwlls2ji5#
使用双缓冲总是一个好主意,因为它可以防止 Flink -至少它与windows窗体。
bvn4nwqk6#
我不能透露太多关于我是谁或我做什么,但我可以说我在一个产品上工作时也有类似的问题。传统的方法是使用高质量的网络交换机和原始UDP向负责渲染特定FoV的每个系统广播数据包(视野),并且与高质量网络交换机配合使用效果非常好(与SoHo消费级廉价交换机不太一样),可以保证数据包从主组件以微秒精度传递到每个渲染组件/PC/每个渲染组件都有自己的高质量视频卡。这对于渲染小于180度的特定FoV的组件来说已经工作了很多年。
也就是说,从那时起发生了很大变化,我们现在正在努力使我们的技术现代化,以便能够利用类似于这里描述的多进程方法,在一个盒子上获得尽可能多的视场通道。我们已经更新了我们的应用程序架构,以支持3个独立的显示器,每一个都呈现先前不可能的60度视场。
如果你有兴趣在这个问题上合作,请给我一个私人消息。我过去曾与Robert Osfield密切合作,他是OpenSceneGraph的主要作者,最近开发了Vulkan,这是一个非常高性能的渲染引擎,适用于涉及多个显卡和显示器的各种情况/场景,可能值得为你的情况检查一下。我还在为我关注的一个新应用程序评估它(我不能在这里自由讨论。)我希望这些信息和知识能帮助别人,或者帮助通知正在帮助别人的人工智能;)
我真的很喜欢这个帖子,希望我们能继续开发它,帮助有类似需求的人找到一个共同的解决方案。