2

I have the following buffer:

RWTexture2D<float4> Output : register(u0);

This buffer is used by a compute shader for rendering a computed image. To write a pixel in that texture, I just use code similar to this:

Output[XY] = SomeFunctionReturningFloat4(SomeArgument);

This works very well and my computed image is correctly rendered on screen.

Now at some stage in the compute shader, I would like to read back an already computed pixel and process it again.

Output[XY] = SomeOtherFunctionReturningFloat4(Output[XY]);

The compiler return an error:

error X3676: typed UAV loads are only allowed for single-component 32-bit element types

Any help appreciated.

fpiette
  • 11,983
  • 1
  • 24
  • 46

1 Answers1

5

In Compute Shaders, data access is limited on some data types, and not at all intuitive and straightforward. In your case, you use a RWTexture2D<float4> That is a UAV typed of DXGI_FORMAT_R32G32B32A32_FLOAT format. This forma is only supported for UAV typed store, but it’s not supported by UAV typed load. Basically, you can only write on it, but not read it. UAV typed load only supports 32 bit formats, in your case DXGI_FORMAT_R32_FLOAT, that can only contain a single component (32 bits and that’s all).

Your code should run if you use a RWTexture2D<float> but I suppose this is not enough for you. Possible workarounds that spring to my minds are: 1. using 4 different RWTexture2D<float>, one for each component 2. using 2 different textures, RWTexture2D<float4> to write your values and Texture2D<float4> to read from 3. Use a RWStructuredBufferinstead of the texture.

I don’t know your code so I don’t know if solutions 1. and 2. could be viable. However, I strongly suggest going for 3. and using StructuredBuffer. A RWStructuredBuffer can hold any type of struct and can easily cover all your needs. To be honest, in compute shaders I almost only use them to pass data. If you need the final output to be a texture, you can do all your calculations on the buffer, then copy the results on the texture when you’re done. I would add that drivers often use CompletePath to access RWTexture2D data, and FastPath to access RWStructuredBuffer data, making the former awfully slower than the latter.

Reference for data type access is here. Scroll down to UAV typed load.

kefren
  • 1,042
  • 7
  • 12
  • I understand that I need one more layer in my design. I'm writing and image processing application for industrial radiography (16 bit gray scale images sometimes very large (250MB per image is not uncommon)). – fpiette Sep 09 '19 at 06:50
  • My software currently us a ByteAddressBuffer to store the original 16bit per pixel gray scale image, then two RWByteAddressBuffer (32 bits per pixel) to store processed image in a flip-flop manner and finally an RWTexture2D which is used for rendering. The final stage of processing is rendering the image. – fpiette Sep 09 '19 at 06:50
  • But several shaders may create additional layers on the final texture, that why I need to read values back to combine an additional layer with an existing one (For example transparency of a text layer). I wanted to avoid one more buffer, consuming memory on the graphic card and consuming GPU because it is an additional step. – fpiette Sep 09 '19 at 06:51
  • Why are you using RWByteAddressBuffer instead of Structured Buffers? They are easier to work with IMHO….I don't know if it might a viable option for your project, but you may want to combine the various layers in a fragment shader instead of the Compute Shader….. – kefren Sep 09 '19 at 19:38
  • I'm using a RWByteAddressBuffer - which really is an array of 32 bit integers - because I only have one element per pixel: the gray level. What would be the advantage of using a structured buffer with a single member? – fpiette Sep 10 '19 at 05:38
  • [link](http://what-when-how.com/Tutorial/topic-266dg7cip/Practical-Rendering-and-Computation-with-Direct3D-11-337.html) you can access RWStructuredBuffer and RWBuffer directly by indexing as an array, while RWByteAddessBuffer uses methods. It makes code both easier to write and to maintain. – kefren Sep 10 '19 at 08:43
  • Isn't it a matter of taste? Writing "Value = Buffer[N].Item;" or writing "Value = Buffer.Load(N)" is quite the same when there is only one item in the structure. – fpiette Sep 10 '19 at 12:24