Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm trying to implement the 3rd exercise in chapter 12 of Introduction to 3D Game Programming with DirectX 11, that is:

  • Implement a Compute Shader to calculate the length of 64 vectors.

Previous exercises ask you to do the same with typed buffers and regular structured buffers and I had no problems with them.

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?

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.

share|improve this question
add comment

2 Answers

up vote 1 down vote accepted

I started to think the problem was with the idea of "initializing a ConsumeStructuredBuffer from the CPU".

When you bind your consume buffer UAV, are you setting the count? In OMSetRenderTargetsAndUnorderedAccessViews, there is a parameter to pass the initial count for each UAV. I believe with a consume buffer that's set up on the CPU, you will need to set the initial count here as well as in the uavDesc. (The count in the uavDesc is the maximum count, i.e. the number of elements to allocate memory for, while the count in OMSetRenderTargetsAndUnorderedAccessViews is the current actual count of elements that have valid data.) Without this, it probably thinks the initial count is zero, leading it to simply return zeros when you try to read from the consume buffer.

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.

Strange; I would expect this to work, although I haven't tried it on my own machine. I wonder if it might work to load the data after creating the buffer, either by using UpdateSubresource() or by doing Map()/Unmap() and copying the data in manually. It's also worth making sure your drivers are up to date, in case this is a driver bug that has been fixed.

share|improve this answer
    
That's right, Nathan! –  Marc Costa Dec 19 '12 at 8:31
    
Although I need ID3D11DeviceContext::CSSetUnorderedAccessViews to set the UAV to the Compute Shader stage instead of the Output Merger stage. –  Marc Costa Dec 19 '12 at 8:37
    
Regarding the last part, I didn't make more tests, but it is strange, indeed. I'm using the latest NVidia drivers (310.70) with a GTX 460. –  Marc Costa Dec 19 '12 at 8:42
add comment

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?

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.