8
\$\begingroup\$

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.

\$\endgroup\$

3 Answers 3

4
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ That's right, Nathan! \$\endgroup\$
    – Marc Costa
    Commented Dec 19, 2012 at 8:31
  • \$\begingroup\$ Although I need ID3D11DeviceContext::CSSetUnorderedAccessViews to set the UAV to the Compute Shader stage instead of the Output Merger stage. \$\endgroup\$
    – Marc Costa
    Commented Dec 19, 2012 at 8:37
  • \$\begingroup\$ 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. \$\endgroup\$
    – Marc Costa
    Commented Dec 19, 2012 at 8:42
3
\$\begingroup\$

Use this:

// Bind both, the consume buffer UAV and the append buffer UAV to the CS.
ID3D11UnorderedAccessView* UAVArray[2] = { mInputUAV, mOutputUAV };
UINT initialCounts[2] = { mNumElements, 0 };
md3dImmediateContext->CSSetUnorderedAccessViews( 0, 2, UAVArray, initialCounts );

just before applying the tech passes in DoComputeWork() public function.

\$\endgroup\$
2
\$\begingroup\$

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?

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .