0
\$\begingroup\$

I'm working with a basic compute shader which only task is to modify the input color of an UAV. This UAV data should then be passed to an SRV in a pixel shader which should then output this color. The compute shader looks like:

struct Color
{
    float4 color;
};

RWStructuredBuffer<Color> OutputBuffer : register(u0);

[numthreads(1, 1, 1)]
void main(uint3 DispatchThreadID : SV_DispatchThreadID)
{
    //Set the structured buffer to a green color
    OutputBuffer[DispatchThreadID.x].color = float4(0.f, 1.f, 0.f, 1.f);
}

And in the pixel shader we have

struct Color
{
    float4 color;
};

StructuredBuffer<Color> colorBuffer : register(t0); // SRV
...

float4 main(PS_IN input) : SV_TARGET
{
    return colorBuffer[0].color;
}

There is only a single root signature which has two tables, one for the SRV and one for the UAV. There is also a single heap (two descriptors) which is related to the creation of the two buffers (this is omitted since the problem doesn't seem to be related as the SRV works fine without the UAV), but attention should be paid to the binding of the compute shader in the frame function:

//Set compute shader to change the color of the UAV
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_uavBuffer.Get(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS));
m_commandList->SetPipelineState(m_shaders->GetComputeShader(Shaders::ID::BasicCompute).pipelineState.Get());
m_rootSignature->SetComputeRootSignature();
m_srvDescHeap->SetComputeRootDescriptorTable(2, m_srvDescHeap->GetGPUIncrementHandle(1));
m_shaders->SetComputeDispatch(1, 1, 1);
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_uavBuffer.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));

Now when I want to access the UAV data in the pixel shader I believe I only have to pass the GPU handle for the UAV to the SRV binding?

m_srvDescHeap->SetRootDescriptorTable(1, m_srvDescHeap->GetGPUIncrementHandle(1));

Although this only gives me a black color for my primitive and not the green color, something which tells me that the UAV data is not passed correctly. It is also noticeable that I tried the same code on my other computer with a GTX 1060 graphics card and got the green color but with the 960 I get the black color. This is likely driver related but still disturbing. Now, I believe that there are some more steps missing to actually get the UAV data, but I can't find any information about this, does anyone have a clue?

Edit 1: I enabled the GPUBasedValidation and received the following error code:

D3D12 ERROR: GPU-BASED VALIDATION: Draw, Descriptor type doesn't match shader register type: Descriptor Heap Index To DescriptorTableStart: [1], Descriptor Heap Index FromTableStart: [0], Descriptor Type in Heap: D3D12_DESCRIPTOR_RANGE_TYPE_UAV, Register Type: D3D12_DESCRIPTOR_RANGE_TYPE_SRV, Index of Descriptor Range: 0, Shader Stage: PIXEL, Root Parameter Index: [1], Draw Index: [0], Shader Code: E:\DX12_project\DX12_Project\DX12_Project\DX12_Project\src\res\shaders\FragmentShader.hlsl(18,5-32), Asm Instruction Range: [0x44-0x6f], Asm Operand Index: [3], Command List: 0x056FCB98:'Unnamed ID3D12GraphicsCommandList Object', SRV/UAV/CBV Descriptor Heap: 0x0C907578:'Unnamed ID3D12DescriptorHeap Object', Sampler Descriptor Heap: <not set>, Pipeline State: 0x0C906DE8:'Unnamed ID3D12PipelineState Object',  [ EXECUTION ERROR #939: GPU_BASED_VALIDATION_DESCRIPTOR_TYPE_MISMATCH]

thus it seems like the method proposed above is definitely not valid.

Edit 2:

The correct way is:

m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_srvBuffer.Get(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST));
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_uavBuffer.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE));
m_commandList->CopyResource(m_srvBuffer.Get(), m_uavBuffer.Get()); //Copy the data
m_srvDescHeap->SetRootDescriptorTable(1, m_srvDescHeap->GetGPUIncrementHandle(0));
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_uavBuffer.Get(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS));
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_srvBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
\$\endgroup\$
1
\$\begingroup\$

Seems like your Root signature doesn't contain an appropriate descriptor range for referencing Shader Resource Views in the pixel shader stage. In your case your root signature should contain a descriptor table for compute shader stage, with a descriptor range of type UAV containing register 0. For your pixel shader stage, you need to have a descriptor table with pixel shader visibility flag and a descriptor range of type SRV, containing register 0. You also need to ensure that the heaps contain the same layout as the root signature and populated accordingly.

You also have to use a UAV barrier besides the resource transition from UAV to SRV. That will force the GPU to stall the draw call until your compute shader finished actually writing the UAV and flushing its caches.

It is a good idea to have the debug layer enabled, but I also suggest using a graphics debugger like Nvidia Nsight which can visualize your descriptor heap and interpret them as tables. Visual studio also has a graphics debugger, which you can use out-of the box from the toolbar Debug->Graphics->Start Graphics Debugging option.

Good luck!

\$\endgroup\$
  • \$\begingroup\$ There is nothing wrong with the root signature or the descriptor ranges, as I have all the things you have mentioned. I have also tried the debug layer which doesn't complain so I turned to the GPU validation and got the output above which is basically saying I'm trying to bind an UAV to a SRV slot which is illegal. Have you used UAVS in DirectX12 related to compute shaders and got them working? \$\endgroup\$ – Riggs Feb 16 '18 at 16:28
  • \$\begingroup\$ Maybe your root signature is correct, but are your corresponding heaps correct as well? I've got compute shaders working in DX12, they are not much different than any other shader. You should check your heaps with a graphics debugger. \$\endgroup\$ – János Turánszki Feb 16 '18 at 16:37
  • \$\begingroup\$ They are fine and also added another edit with the result. Although I just need to throw in some resource barriers and it should all be fine? \$\endgroup\$ – Riggs Feb 16 '18 at 17:20
  • \$\begingroup\$ Added the correct solution @János Turánszki \$\endgroup\$ – Riggs Feb 16 '18 at 18:06
  • \$\begingroup\$ @Riggs Hm, I wouldn't call that a right solution. Consider when you have a compute shader creating a big texture, you don't want to copy that whole thing. There is something else wrong here.. \$\endgroup\$ – János Turánszki Feb 16 '18 at 18:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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