使用DirectX桌面框架的消费者 - 生产者线程

时间:2018-05-14 13:32:28

标签: c++ windows multithreading directx directx-11

我正在用两个线程编写DirectX应用程序:

  • 生产者线程使用DirectX抓取桌面框架(如Desktop Duplication DirectX sample中所述)

    IDXGIResource* DesktopResource = nullptr;
    ID3D11Texture2D *m_AcquiredDesktopImage = nullptr;
    HRESULT hr = m_DeskDupl->AcquireNextFrame(500, &FrameInfo, &DesktopResource);
    hr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&m_AcquiredDesktopImage));
    DesktopResource->Release();
    // The texture pointer I'm interested is m_AcquiredDesktopImage
    
  • 消费者线程在GPU上执行图像处理操作。

为了避免副本,我希望尽可能地将所有内容保存在GPU上。从ReleaseFrame的文档开始,我知道只要我处理完帧后,就应该在桌面复制界面上调用ReleaseFrame

我的问题:我应该将m_AcquiredDesktopImage纹理复制到另一个纹理中,并在复制完成后立即调用ReleaseFrame并将新纹理返回给生产者线程进行处理,或者我可以离开将m_AcquiredDesktopImage纹理指针返回给消费者线程?这是帧缓冲纹理的副本还是帧缓冲纹理,我可能会通过返回来生成数据竞争?

哪一个是处理抓取帧的制作者和GPU纹理消费者的正确方法?

2 个答案:

答案 0 :(得分:1)

ReleaseFrame上的MSDN文档有点令人费解。它具体说明你需要在处理下一帧之前释放当前帧,并且表面状态是&#34;无效&#34;发布后,这表明它不是副本,也不是您的流程拥有的副本(这将产生相同的有效结果)。它还声明您应该将呼叫延迟到ReleaseFrame,直到您出于性能原因致电AcquireNextFrame,这可能会导致一些有趣的时间问题,特别是对于您正在使用的线程模型。 / p>

我认为你最好不要制作副本(所以ReleaseFrame来自上次捕获,AcquireNextFrameCopyResource)。除非您使用围栏,否则您无法保证GPU在生产者线程调用ReleaseFrame之前将消耗资源,这可能会给您带来未定义的结果。如果 使用围栏,并且AcquireNextFrame调用延迟到GPU完成使用前一帧的数据,那么您将引入失速并丢失很多CPU能够在GPU之前运行的好处。

我很好奇为什么当你在GPU上完成工作时,你会使用这个线程模型。我怀疑它让生活变得更复杂一些。虽然制作纹理的副本可以消除很多这些并发症。

答案 1 :(得分:1)

  

...我应该将m_AcquiredDesktopImage纹理复制到另一个纹理中,并在复制完成后立即调用ReleaseFrame,并将该新纹理返回给生产者线程进行处理或...

是的,这就是方法。你得到了你的纹理,你完成它并释放它,因为在发布后数据不再有效。

  

...我可以将m_AcquiredDesktopImage纹理指针返回给消费者线程吗?这是帧缓冲纹理的副本还是帧缓冲纹理,我可能会通过返回来生成数据竞争?

API不断更新此纹理。我们承诺,从AcquireNextFrame成功返回和ReleaseFrame调用之间,API不会触及纹理,您可以自由使用它。如果您无法在上述调用之间完成使用(这是您的情况,毕竟您创建了一个异步运行以捕获的使用者线程),则复制数据和ReleaseFrame。一旦您发布它,API将恢复更新。

尝试在ReleaseFrame之后使用纹理将导致对纹理的同时访问,您和API的进一步更新。