2
votes

I have a D3D11 buffer with a few million elements that is supposed to hold data in the R8G8B8A8_UNorm format.

The desired behavior is the following: One shader calculates a vec4 and writes it to the buffer in a random access pattern. In the next pass, another shader reads the data in a random access pattern and processes them further.

My best guess would be to create an UnorderedAccessView with the R8G8B8A8_UNorm format. But how do I declare the RWBuffer<?> in HLSL, and how do I write to and read from it? Is it necessary to declare it as RWBuffer<uint> and do the packing from vec4 to uint manually?

In OpenGL I would create a buffer and a buffer texture. Then I can declare an imageBuffer with the rgba8 format in the shader, access it with imageLoad and imageStore, and the hardware does all the conversions for me. Is this possible in D3D11?

1

1 Answers

3
votes

This is a little tricky due to a lot of different gotchas, but you should be able to do something like this.

In your shader that writes to the buffer declare:

RWBuffer<float4> WriteBuf : register( u1 );

Note that it is bound to register u1 instead of u0. Unordered access views (UAV) must start at slot 1 because the u# register is also used for render targets.

To write to the buffer just do something like:

WriteBuf[0] = float4(0.5, 0.5, 0, 1);

Note that you must write all 4 values at once.

In your C++ code, you must create an unordered access buffer, and bind it to a UAV. You can use the DXGI_FORMAT_R8G8B8A8_UNORM format. When you write 4 floats to it, the values will automatically be converted and packed. The UAV can be bound to the pipeline using OMSetRenderTargetsAndUnorderedAccessViews.

In your shader that reads from the buffer declare a read only buffer:

Buffer<float4> ReadBuf : register( t0 );

Note that this buffer uses t0 because it will be bound as a shader resource view (SRV) instead of UAV.

To access the buffer use something like:

float4 val = ReadBuf[0];

In your C++ code, you can bind the same buffer you created earlier to an SRV instead of a UAV. The SRV can be bound to the pipeline using PSSetShaderResources and can also be created with DXGI_FORMAT_R8G8B8A8_UNORM.

You can't bind both the SRV and UAV using the same buffer to the pipeline at the same time. So you must bind the UAV first and run your first shader pass. Then unbind the UAV, bind SRV, and run the second shader pass.

There are probably other ways to do this as well. Note that all of this requires shader model 5.