Reading a FRHIStructuredBuffer on the CPU

I have a compute shader that writes to a structured buffer. I would like to read that buffer back on the CPU asynchronously.

I tried using RHILockStructuredBuffer, however that’s slow and blocks the thread it is on. I would like to queue the copy asynchronously at the end of my tick and access the data at the start of the next tick. It looks like I can do that with vertex buffers in 4.22 using CopyToStagingArea and a WriteGPUFence. Is there a way to do it with structured buffers?

Does anyone have a better idea?

I also think I’m quite confused about all this. :wink:

In case someone Google’s this someday, I found a partial solution.

I created FRHIStructuredBufferReadBack, a subclass of FRHIGPUMemoryReadback. It creates an intermediate FRHIVertexBuffer/UAV and a FStagingBufferRHI. Inside EnqueCopy, I copy the structured buffer to the intermediate vertex buffer with a little compute shader that uses RWByteAddressBuffers. Then I queue the copy to the staging buffer using CopyToStagingBuffer.

The difference compared to FRHIBufferReadBack is that extraneous intermediate FRHIVertexBuffer and compute shader. It wouldn’t be necessary if we could create vertex buffers with D3D11_USAGE_STAGING usage, but that’s not exposed in the RHI.

So, this solution is not bad. I can queue an async CPU read, without flushing the render state. The extra copy is not ideal, but it’s way faster than FRHILockStructuredBuffer.

2 Likes

Request for Epic: add a mechanism to create staging buffers, or extend CopyToStagingBuffer to work with structured buffers. :slight_smile:

As for UE 5.3.2 there is a class called FRHIGPUBufferReadback and I found a example of usage over the SkinWeightProfile.cpp, this is probably the kind of implementation that @timtimmy did back in the days, you will need to call the EnqueueCopy function using your buffer, then do the regular lock, unlock functions, it worked like a charm for me, it is way way faster that simply locking a structured buffer