使用Direct2D和DXGI(D3D交互)进行多线程编程的最佳实践是什么?

4
理想情况下,我希望有多个工作线程能够渲染到离屏渲染目标,然后将渲染内容“传输”到屏幕目标。对于hwnd渲染目标,这似乎不是问题(MSDN有一个示例)。
但是当屏幕上的渲染目标基于DXGI交换链时,我不太确定该如何实现。据我所知,每个窗口只能有一个交换链。因此,我只能有一个基于交换链的单个渲染目标。这意味着只能通过这个单一的渲染目标进行屏幕渲染。
如果我的上述假设是正确的,那么处理多线程渲染的最佳方法是什么?需要对屏幕目标进行串行访问吗?工作线程是否应共享单个多线程d2d工厂?如果有适当的锁定机制,屏幕目标的BeginDraw / EndDraw / Present是否可以在工作线程上执行(即没有创建屏幕目标的线程)?
非常感谢任何建议。谢谢。
2个回答

4

我现在正在处理同样的问题!根据我在MSDN上的阅读,最好的方法是:

  • 使用多线程工厂 - 这可以让你共享资源(也参见下面引用链接)。
  • 小心一些死锁情况(下面详细说明)。
  • 您可能需要使用ID2D1MultiThread 在使用Direct3D进行绘制时进行锁定。

即使遵循上述建议,我仍然没有得到一个可靠的多线程Direct2D函数集,所以这是我目前知道的所有信息 - 我还不知道其他确定存在的注意事项等等。

一些有用的关键部分:

You can create a multithreaded Direct2D factory instance. You can use and share a multithreaded factory and all it's resources from more than one thread, but accesses to those resources (via Direct2D calls) are serialized by Direct2D, so no access conflicts occur. If your app calls only Direct2D APIs, such protection is automatically done by Direct2D in a granular level with minimum overhead.

ID2D1Factory* m_D2DFactory;

// Create a Direct2D factory.
HRESULT hr = D2D1CreateFactory(
    D2D1_FACTORY_TYPE_MULTI_THREADED,
    &m_D2DFactory
);

还有一个非常重要的警告:

多线程考虑事项

在使用DXGI的应用程序中,如果有多个线程,需要小心避免死锁,即两个不同的线程互相等待。这种情况可能发生在以下两种情况下:

  • 渲染线程不是消息泵线程。
  • 执行DXGI API的线程与创建窗口的线程不同。

注意,在使用全屏交换链时,永远不要让消息泵线程等待渲染线程。例如,从渲染线程调用IDXGISwapChain1::Present1可能会导致渲染线程等待消息泵线程。当模式更改发生时,如果Present1调用::SetWindowPos()或::SetWindowStyle()并且其中任何一种方法调用了::SendMessage(),则此场景是可能发生的。在这种情况下,如果消息泵线程具有关键部分保护或者渲染线程被阻塞,那么两个线程将会死锁。


1
对于离屏渲染目标,您可以创建单独的D2DFactories并将其附加到使用CreateWicBitmapRenderTarget或CreateDxgiSurfaceRenderTarget创建的相应离屏渲染目标上。在将其传输到屏幕目标时,您需要等待所有线程完成,然后逐个将离屏RT传输到屏幕RT。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接