I call CopyResource to get some data from the GPU to the CPU. If I try to Map immediately I obviously suffer performance hit. So I have a round buffer and I call Map delayed by, say, 3-4 frames. This works way better. Now my question is: how do I know after how many frames I can safely Map without incurring additional performance hit? I have noticed for instance that when I delay by one more frame I get linearly better performance, but after about 5-6 frames, the more frames I wait, the performance stays the same. Is there a way to "Query" DX11 to know when it's "safe" to Map a resource?
CopyResource and when to map?
Although I haven't done this on PC, it should be possible to use ID3D11Fence to tell whether it's safe to map on CPU. This is only available from D3D11.3, so it probably won't be available on Windows 7 :(
Another idea is to use D3D11_QUERY_EVENT with ID3D11DeviceContext::CopyResource() + End() and then just check on CPU using ID3D11DeviceContext::GetData to see if it's done, although something smells about this. Would anybody care to comment if this is going to work with CopyResource? I have a bad feeling that the driver can do asynchronous things and the query will seem finished however the driver might still block.
2 minutes ago, pcmaster said:Although I haven't done this on PC, it should be possible to use ID3D11Fence to tell whether it's safe to map on CPU. This is only available from D3D11.3, so it probably won't be available on Windows 7
![]()
Another idea is to use D3D11_QUERY_EVENT with ID3D11DeviceContext::CopyResource() + End() and then just check on CPU using ID3D11DeviceContext::GetData to see if it's done, although something smells about this. Would anybody care to comment if this is going to work with CopyResource? I have a bad feeling that the driver can do asynchronous things and the query will seem finished however the driver might still block.
IIRC, ID3D11Fence only exists on Windows 10, and was mostly added for D3D11<->D3D12 interop.
Yeah, a ID3D11Query with D3D11_QUERY_EVENT is what I was going to suggest. They are a bit vaguely defined, but my expectation is that "event" queries will only be completed once all commands prior to them have fully retired on the GPU (as opposed to prior commands having reached the GPU's command processor, but potentially still be executing asynchronously). I've used events with this expectation in the past with good results.
4 hours ago, maxest said:I call CopyResource to get some data from the GPU to the CPU. If I try to Map immediately I obviously suffer performance hit. So I have a round buffer and I call Map delayed by, say, 3-4 frames. This works way better. Now my question is: how do I know after how many frames I can safely Map without incurring additional performance hit? I have noticed for instance that when I delay by one more frame I get linearly better performance, but after about 5-6 frames, the more frames I wait, the performance stays the same. Is there a way to "Query" DX11 to know when it's "safe" to Map a resource?
If you're using a staging texture (which you should, because hardware tiling sucks when mapping) and call Map() with the DO_NOT_WAIT-flag, the call should return DXGI_ERROR_WAS_STILL_DRAWING until the copy is complete.
However, if you're copying from a DEFAULT usage resource, initially, the Map() call will still end up flushing the command buffer prematurely, and then stall. To avoid this, _always_ wait 2 frames after issuing the Copy*Resource()-call before calling Map(). This will allow the copy to complete without any stalls, before you map the staging resource.
So in short; always wait for two full frames between copy() and map(), and in case you notice CPU stalls, call map() non-blocking, if possible in your scenario.
The things you learn when you inject way too much functionality in well-optimized games...
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.