如何使用 Direct3D11 阻塞等待计算着色器?
how to do a blocking wait for a compute shader with Direct3D11?
我有一个 post 处理管道,它使用计算着色器处理纹理并将其写入 RWByteAddressBuffer。
RWByteAddressBuffer 的内容随后通过直接内存访问(AMD DirectGMA 技术)发送到 FPGA 设备。意思是,我启动了一个外部设备来访问这个缓冲区的物理字节,而 Direct3D api 不知道它。
这里是代码的本质:
_context->CSSetShaderResources(0,1,_nonMsaaSrv.GetAddressOf());
_context->CSSetUnorderedAccessViews(0, 1, _unorderedAccessView.GetAddressOf(),nullptr);
_context->CSSetShader(_converter.Get(),0,0);
_context->Dispatch(1920, 1200, 1);
// ... wait for direct3d compute shader to finish processing?
// send the bytes to the fpga:
_dmaController->StartDMA(_d3dBufferPhysicalAddress, fpgaLogicalAddress);
一切正常,但问题是我找不到阻止线程或获取指示计算着色器在 GPU 上完成其工作的事件的方法。
建议使用 ID3D11Query 进行某种轮询的解决方案。但据我了解,这只是忙等待。我希望找到一个更好的解决方案,可以让线程通过等待某种事件来阻塞。使用 Cuda / OpenCL 等 API,这非常简单。
那么是否可以在 direct3D 11 中阻塞等待计算着色器?如果是怎么办?
ID3D11Query
是您正在寻找的机制; Direct3D 11 中没有任何基于事件的东西。它是一种轮询机制,但与 CPU.
上的正常忙碌等待不同
您始终可以分析它以查看它增加了多少负载,特别是如果您添加延迟以在不同的时间间隔(10 毫秒、100 毫秒等)检查 query->GetData
以查看您的性能是否有所提高。
如果不需要支持 Windows 7 / 8,可以使用更新后的接口 ID3D11Device5、ID3D11DeviceContext4 和 ID3D11Fence 来实现,这些接口在 Windows 10 v1703 及更高版本上可用。
正在创建围栏对象:
HR(_d3dDevice->CreateFence(0, D3D11_FENCE_FLAG_NONE, __uuidof(ID3D11Fence), reinterpret_cast<void**>(_syncFence.GetAddressOf())));
在处理循环中,我们分派计算着色器,并在其后加入一个带有递增计数器的信号:
++_syncCounter;
_context->Dispatch(1920, 1200, 1);
HR(_context->Signal(_syncFence.Get(), _syncCounter));
HR(_syncFence->SetEventOnCompletion(_syncCounter,_syncEvent.get()));
// 等待事件(可以在不同的线程上)
_syncEvent.wait(); // WaitForSingleObject
可以找到示例(虽然对于 Direct3D12)here。
我有一个 post 处理管道,它使用计算着色器处理纹理并将其写入 RWByteAddressBuffer。
RWByteAddressBuffer 的内容随后通过直接内存访问(AMD DirectGMA 技术)发送到 FPGA 设备。意思是,我启动了一个外部设备来访问这个缓冲区的物理字节,而 Direct3D api 不知道它。
这里是代码的本质:
_context->CSSetShaderResources(0,1,_nonMsaaSrv.GetAddressOf());
_context->CSSetUnorderedAccessViews(0, 1, _unorderedAccessView.GetAddressOf(),nullptr);
_context->CSSetShader(_converter.Get(),0,0);
_context->Dispatch(1920, 1200, 1);
// ... wait for direct3d compute shader to finish processing?
// send the bytes to the fpga:
_dmaController->StartDMA(_d3dBufferPhysicalAddress, fpgaLogicalAddress);
一切正常,但问题是我找不到阻止线程或获取指示计算着色器在 GPU 上完成其工作的事件的方法。
那么是否可以在 direct3D 11 中阻塞等待计算着色器?如果是怎么办?
ID3D11Query
是您正在寻找的机制; Direct3D 11 中没有任何基于事件的东西。它是一种轮询机制,但与 CPU.
您始终可以分析它以查看它增加了多少负载,特别是如果您添加延迟以在不同的时间间隔(10 毫秒、100 毫秒等)检查 query->GetData
以查看您的性能是否有所提高。
如果不需要支持 Windows 7 / 8,可以使用更新后的接口 ID3D11Device5、ID3D11DeviceContext4 和 ID3D11Fence 来实现,这些接口在 Windows 10 v1703 及更高版本上可用。
正在创建围栏对象:
HR(_d3dDevice->CreateFence(0, D3D11_FENCE_FLAG_NONE, __uuidof(ID3D11Fence), reinterpret_cast<void**>(_syncFence.GetAddressOf())));
在处理循环中,我们分派计算着色器,并在其后加入一个带有递增计数器的信号:
++_syncCounter;
_context->Dispatch(1920, 1200, 1);
HR(_context->Signal(_syncFence.Get(), _syncCounter));
HR(_syncFence->SetEventOnCompletion(_syncCounter,_syncEvent.get()));
// 等待事件(可以在不同的线程上)
_syncEvent.wait(); // WaitForSingleObject
可以找到示例(虽然对于 Direct3D12)here。