ConsumeStructuredBuffer, what am I doing wrong?

Dec 17, 2012 at 1:16 PM
Edited Dec 18, 2012 at 12:37 PM

I'm trying to implement a simple test for Consume/Append Structured buffers in a Compute Shader to calculate the length of 64 vectors.

For what I've read, [Consume|Append]StructuredBuffers are bound to the pipeline using UnorderedAccessViews (as long as they use the D3D11_BUFFER_UAV_FLAG_APPEND, and the buffers have both D3D11_BIND_SHADER_RESOURCE and D3D11_BIND_UNORDERED_ACCESS bind flags).

Problem is: my AppendStructuredBuffer works, since I can append data to it and retrieve it from the application to write to a results file, but the ConsumeStructuredBuffer always returns zeroed data. Data is in the buffer, since if I change the UAV to a ShaderResourceView and to a StructuredBuffer in the HLSL side it works.

I don't know what I am missing:

  • Should I initialize the ConsumeStructuredBuffer on the GPU, or can I do it when I create the buffer (as I amb currently doing)?.
  • Is it OK to bind the buffer with a UAV as described above? Do I need to bind it as a ShaderResourceView somehow?
  • Maybe I am missing some step?

The particle system simulation in this book/site (code, shader1, shader2) is the only example I've seen that uses Consume/Append Structured buffers, and the initialization of the buffers is all done in the GPU. I'd say this is the problem, but I don't see the point in not having the option to initialize the buffer with data from CPU at creation time like all the others buffers can do. Has anyone used a ConsumeStructuredBuffer with data from CPU successfully?

This is the declaration of buffers in the Compute Shader:

 

struct Data
{
    float3 v;
};

struct Result
{
    float l;
};

ConsumeStructuredBuffer<Data> gInput;
AppendStructuredBuffer<Result> gOutput;

 

And here the creation of the buffer and UAV for input data:

D3D11_BUFFER_DESC inputDesc;
inputDesc.Usage = D3D11_USAGE_DEFAULT;
inputDesc.ByteWidth = sizeof(Data) * mNumElements;
inputDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
inputDesc.CPUAccessFlags = 0;
inputDesc.StructureByteStride = sizeof(Data);
inputDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;

D3D11_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = &data[0];

HR(md3dDevice->CreateBuffer(&inputDesc, &vinitData, &mInputBuffer));

D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_APPEND;
uavDesc.Buffer.NumElements = mNumElements;

md3dDevice->CreateUnorderedAccessView(mInputBuffer, &uavDesc, &mInputUAV);

Initial data is an array of Data structs, which contain a XMFLOAT3 with random data.

I bind the UAV to the shader using the Effects framework:

 

ID3DX11EffectUnorderedAccessViewVariable* Input = mFX->GetVariableByName("gInput")->AsUnorderedAccessView();

Input->SetUnorderedAccessView(uav); // uav is mInputUAV

 

Any ideas?

Thank you.

Dec 18, 2012 at 8:12 AM

I started to think the problem was with the idea of "initializing a ConsumeStructuredBuffer from the CPU". Since it "acts" as a stack of elements, it makes sense that the data must be "pushed" into the stack before "poping" it out.

So, this is what I did: I created a new simple shader which takes a StructuredBuffer as an input and an AppendStructuredBuffer as an output. The StructuredBuffer can be initialized from CPU. All the shader had to do was fill the AppendStructuredBuffer with the data from the StructuredBuffer.

Now, the actual calculation: After that, I bound the aforementioned AppendStructuredBuffer to a ConsumeStructuredBuffer, and the original output buffer to a new AppendStructuredBuffer HLSL variable.

And that worked as charm!

Further investigation led me to think that the presence of the D3D11_BIND_UNORDERED_ACCESS bind flag in a D3D11_BUFFER_DESC make the CreateBuffer function discard any initial data: if I created the Shader Resource View (for input to the first shader) with the same D3D11_BUFFER_DESC as the original input Unordered Access View there was no loaded data. When I removed the D3D11_BIND_UNORDERED_ACCESS bind flag (leaving only D3D11_BIND_SHADER_RESOURCE), the data was loaded successfully.

I couldn't find this "feature" documented anywhere, though. Anybody can confirm it?

Coordinator
Dec 18, 2012 at 1:38 PM

I am away from my computer at the moment (typing on smart phones is way too slow...), so I can answer in more detail later.  I think your issue has to xo with the initial count value that is given when binding the buffer with a UAV.  You have data initialized within the buffer, but if your initial count is zero then consuming will just return zero.  Try setting that to the appropriate number of elements and see if your tests work out.

Dec 18, 2012 at 2:40 PM
Edited Dec 18, 2012 at 3:24 PM

That actually makes a lot more sense! Thank you!

Although, I know I can get the count from the buffer via the ID3D11DeviceContext::CopyStructureCount method, but I can't find any function to modify it.

========== EDIT ==========

I realized that the function ID3D11DeviceContext::CSSetUnorderedAccessViews has an "initialCount" parameter, so I must use it.

Since I'm using the D3D11 Effects framework (from another book codebase) the function I had available was: ID3DX11EffectUnorderedAccessViewVariable::SetUnorderedAccessView, which only accepts an UnorderedAccessView resource, but no initial counts.

I'll refactor the code to use the ID3D11DeviceContext::CSSetUnorderedAccessViews method.

Dec 19, 2012 at 7:39 AM
Edited Dec 19, 2012 at 7:40 AM
mcast wrote:

Since I'm using the D3D11 Effects framework (from another book codebase) the function I had available was: ID3DX11EffectUnorderedAccessViewVariable::SetUnorderedAccessView, which only accepts an UnorderedAccessView resource, but no initial counts.

I'll refactor the code to use the ID3D11DeviceContext::CSSetUnorderedAccessViews method.

I just did it and it worked. No need for a 'data injection' shader anymore!

Thank you, jzink!

Coordinator
Dec 19, 2012 at 11:13 AM

Great! If you have any more trouble, be sure to post here, and of course you can always post a screen shot too :)

Nov 8, 2013 at 5:05 AM
mcast wrote:
mcast wrote: Since I'm using the D3D11 Effects framework (from another book codebase) the function I had available was: ID3DX11EffectUnorderedAccessViewVariable::SetUnorderedAccessView, which only accepts an UnorderedAccessView resource, but no initial counts. I'll refactor the code to use the ID3D11DeviceContext::CSSetUnorderedAccessViews method. I just did it and it worked. No need for a 'data injection' shader anymore! Thank you, jzink!
Could you tell me how to do it? I am also trying to implement OIT using effect framework and facing the same problem.
Nov 8, 2013 at 7:58 AM
pnt1614 wrote:
mcast wrote:
mcast wrote: Since I'm using the D3D11 Effects framework (from another book codebase) the function I had available was: ID3DX11EffectUnorderedAccessViewVariable::SetUnorderedAccessView, which only accepts an UnorderedAccessView resource, but no initial counts. I'll refactor the code to use the ID3D11DeviceContext::CSSetUnorderedAccessViews method. I just did it and it worked. No need for a 'data injection' shader anymore! Thank you, jzink!
Could you tell me how to do it? I am also trying to implement OIT using effect framework and facing the same problem.
You can't use the D3D11 effect framework for this. You have to use D3D11 context calls directly and set everything manually for Compute Shaders.