如何使用 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