具有 DirectX 桌面框架的消费者-生产者线程
Consumer-Producer threads with DirectX desktop frames
我正在用两个线程编写 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
并将新纹理 return 发送给生产者线程进行处理或者我可以直接 return 将 m_AcquiredDesktopImage
纹理指针指向消费者线程吗?这是帧缓冲区纹理的 副本 还是帧缓冲区纹理,我可能会通过 returning 生成数据竞争?
哪一个是处理抓取帧的生产者和 GPU 纹理的消费者的正确方法?
ReleaseFrame
上的 MSDN 文档有点复杂。它明确指出您需要在处理下一帧之前释放当前帧,并且表面状态在释放后为 "invalid",这表明它不是副本,或者不是您的进程拥有的副本(哪个会产生相同的有效结果)。它还指出,出于性能原因,您应该将对 ReleaseFrame
的调用延迟到调用 AcquireNextFrame
之前,这可能会导致一些有趣的计时问题,尤其是对于您正在使用的线程模型。
我认为你最好复制一份(所以 ReleaseFrame
来自上一次捕获,AcquireNextFrame
,CopyResource
)。除非您使用栅栏,否则您无法保证 GPU 会在您的生产者线程调用 ReleaseFrame
之前消耗资源,这可能会给您未定义的结果。如果您 正在 使用栅栏,并且 AcquireNextFrame
调用被延迟,直到 GPU 完成消耗前一帧的数据,您将引入停顿并失去很多好处CPU 能够 运行 领先于 GPU。
我很好奇,当工作在 GPU 上完成时,您为什么要使用这种线程模型。我怀疑这会让生活变得更加复杂。尽管复制纹理会消除很多复杂情况。
...should I copy the m_AcquiredDesktopImage texture into another one and call ReleaseFrame as soon as the copy is finished and return that new texture to the producer thread for processing or...
是的,就是这样。你得到了你的纹理,你完成了它并释放它,因为数据在释放后不再有效。
...can I just get away with returning the m_AcquiredDesktopImage texture pointer to the consumer thread? Is this a copy of the framebuffer texture or is it the framebuffer texture and I might generate a data race by returning it?
API不断更新这个贴图。我们向您保证,在 AcquireNextFrame
成功 return 和您的 ReleaseFrame
调用之间,API 不会触及纹理,您可以自由使用它。如果您无法在上述调用之间完成您的使用(这是您的情况,毕竟您创建了一个消费者线程以 运行 异步捕获),您复制数据并 ReleaseFrame
。一旦你释放它,API 恢复更新。
在 ReleaseFrame
之后尝试使用纹理将导致并发访问纹理,您和 API 的进一步更新。
我正在用两个线程编写 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
并将新纹理 return 发送给生产者线程进行处理或者我可以直接 return 将 m_AcquiredDesktopImage
纹理指针指向消费者线程吗?这是帧缓冲区纹理的 副本 还是帧缓冲区纹理,我可能会通过 returning 生成数据竞争?
哪一个是处理抓取帧的生产者和 GPU 纹理的消费者的正确方法?
ReleaseFrame
上的 MSDN 文档有点复杂。它明确指出您需要在处理下一帧之前释放当前帧,并且表面状态在释放后为 "invalid",这表明它不是副本,或者不是您的进程拥有的副本(哪个会产生相同的有效结果)。它还指出,出于性能原因,您应该将对 ReleaseFrame
的调用延迟到调用 AcquireNextFrame
之前,这可能会导致一些有趣的计时问题,尤其是对于您正在使用的线程模型。
我认为你最好复制一份(所以 ReleaseFrame
来自上一次捕获,AcquireNextFrame
,CopyResource
)。除非您使用栅栏,否则您无法保证 GPU 会在您的生产者线程调用 ReleaseFrame
之前消耗资源,这可能会给您未定义的结果。如果您 正在 使用栅栏,并且 AcquireNextFrame
调用被延迟,直到 GPU 完成消耗前一帧的数据,您将引入停顿并失去很多好处CPU 能够 运行 领先于 GPU。
我很好奇,当工作在 GPU 上完成时,您为什么要使用这种线程模型。我怀疑这会让生活变得更加复杂。尽管复制纹理会消除很多复杂情况。
...should I copy the m_AcquiredDesktopImage texture into another one and call ReleaseFrame as soon as the copy is finished and return that new texture to the producer thread for processing or...
是的,就是这样。你得到了你的纹理,你完成了它并释放它,因为数据在释放后不再有效。
...can I just get away with returning the m_AcquiredDesktopImage texture pointer to the consumer thread? Is this a copy of the framebuffer texture or is it the framebuffer texture and I might generate a data race by returning it?
API不断更新这个贴图。我们向您保证,在 AcquireNextFrame
成功 return 和您的 ReleaseFrame
调用之间,API 不会触及纹理,您可以自由使用它。如果您无法在上述调用之间完成您的使用(这是您的情况,毕竟您创建了一个消费者线程以 运行 异步捕获),您复制数据并 ReleaseFrame
。一旦你释放它,API 恢复更新。
在 ReleaseFrame
之后尝试使用纹理将导致并发访问纹理,您和 API 的进一步更新。