如何理解CopyResource的异步?
How to understand the asynchrony of CopyResource?
virtual void STDMETHODCALLTYPE CopyResource(
/* [annotation] */
_In_ ID3D11Resource *pDstResource,
/* [annotation] */
_In_ ID3D11Resource *pSrcResource);
我对这个功能有疑问,尤其是pDstResource上马上有读写操作的时候,比如下面的代码,因为是异步的,能不能保证每次pDstResource都是新渲染的图片而不是 black_color?
这个怀疑是因为在使用IDXGIOutputDuplication::AcquireNextFrame获取第一帧调用CopyResource之前,Sleep了很短的时间才可以看到复制了pDstResource(从渲染图来看输出)。
参考performance considerations,这里的原理我还是不清楚,是否是WinB要访问pDstResource_shared的时候,Direct3D内部会同步(也就是,执行 CopyResource 命令)?担心误会。
for(;;)
{
1, WinA_Clear(black_color)
2, WinA_DrawRedTriangleOnTexture(pSrcResource)
3, WinA_CopyResource(pDstResource_shared, pSrcResource)
4, WinB_Clear(white_color)
5, WinB_RenderTexture(pDstResource_shared)
}
Can I ensure that every time pDstResource is a newly rendered image instead of black_color?
与 Direct3D 12 等 lower-level API 不同,在 10 和 11 中,GPU 驱动程序会自动处理。通常做得很好。
如果调用 CopyResource,然后更新源纹理,新的更改将不会在副本中可见。如果您调用 CopyResource 然后以某种方式从目标纹理读取(渲染或移动到系统内存),GPU 驱动程序将首先等待复制完成。
但是,在某些情况下,此工作流会中断。其中之一是 DXGI 表面共享。如果您使用该机制跨图形 API 或跨进程共享纹理,您可能会得到不完整的渲染或其他工件。
由于您的其中一个纹理被命名为 pDstResource_shared
,我认为这就是您正在做的事情。
要解决此问题,请等待复制完成,然后再通过表面共享将目标纹理传递给其他人。方法如下。
启动时,创建 ID3D11Query
对象,类型为 D3D11_QUERY_EVENT
调用 ID3D11DeviceContext.CopyResource
后,调用 ID3D11DeviceContext.Flush
,然后调用 ID3D11DeviceContext.End
,传递该查询。
您现在需要等待 ID3D11DeviceContext.GetData
方法到 return S_OK
该查询。当 GPU 完成 ID3D11DeviceContext.End
之前提交的所有命令时,就会发生这种情况,将所有待处理的更新应用到所有资源。
最终,MS 实现了等待 GPU 的正确方法,使用栅栏而不是查询,ID3D11Fence::SetEventOnCompletion
可以在 GPU 完成工作后发出事件信号,然后您可以使用 [= 使线程休眠20=] 或类似的。但是,这需要足够新的 Windows 10 版本。不记得是哪个版本了,但我认为要么是 2016 年的周年纪念更新,要么是 2017 年的创作者更新。查询更加兼容,它们适用于所有版本的 Win10,甚至 Windows 7 或 8.
virtual void STDMETHODCALLTYPE CopyResource(
/* [annotation] */
_In_ ID3D11Resource *pDstResource,
/* [annotation] */
_In_ ID3D11Resource *pSrcResource);
我对这个功能有疑问,尤其是pDstResource上马上有读写操作的时候,比如下面的代码,因为是异步的,能不能保证每次pDstResource都是新渲染的图片而不是 black_color?
这个怀疑是因为在使用IDXGIOutputDuplication::AcquireNextFrame获取第一帧调用CopyResource之前,Sleep了很短的时间才可以看到复制了pDstResource(从渲染图来看输出)。
参考performance considerations,这里的原理我还是不清楚,是否是WinB要访问pDstResource_shared的时候,Direct3D内部会同步(也就是,执行 CopyResource 命令)?担心误会。
for(;;) { 1, WinA_Clear(black_color) 2, WinA_DrawRedTriangleOnTexture(pSrcResource) 3, WinA_CopyResource(pDstResource_shared, pSrcResource) 4, WinB_Clear(white_color) 5, WinB_RenderTexture(pDstResource_shared) }
Can I ensure that every time pDstResource is a newly rendered image instead of black_color?
与 Direct3D 12 等 lower-level API 不同,在 10 和 11 中,GPU 驱动程序会自动处理。通常做得很好。
如果调用 CopyResource,然后更新源纹理,新的更改将不会在副本中可见。如果您调用 CopyResource 然后以某种方式从目标纹理读取(渲染或移动到系统内存),GPU 驱动程序将首先等待复制完成。
但是,在某些情况下,此工作流会中断。其中之一是 DXGI 表面共享。如果您使用该机制跨图形 API 或跨进程共享纹理,您可能会得到不完整的渲染或其他工件。
由于您的其中一个纹理被命名为 pDstResource_shared
,我认为这就是您正在做的事情。
要解决此问题,请等待复制完成,然后再通过表面共享将目标纹理传递给其他人。方法如下。
启动时,创建
ID3D11Query
对象,类型为D3D11_QUERY_EVENT
调用
ID3D11DeviceContext.CopyResource
后,调用ID3D11DeviceContext.Flush
,然后调用ID3D11DeviceContext.End
,传递该查询。您现在需要等待
ID3D11DeviceContext.GetData
方法到 returnS_OK
该查询。当 GPU 完成ID3D11DeviceContext.End
之前提交的所有命令时,就会发生这种情况,将所有待处理的更新应用到所有资源。
最终,MS 实现了等待 GPU 的正确方法,使用栅栏而不是查询,ID3D11Fence::SetEventOnCompletion
可以在 GPU 完成工作后发出事件信号,然后您可以使用 [= 使线程休眠20=] 或类似的。但是,这需要足够新的 Windows 10 版本。不记得是哪个版本了,但我认为要么是 2016 年的周年纪念更新,要么是 2017 年的创作者更新。查询更加兼容,它们适用于所有版本的 Win10,甚至 Windows 7 或 8.