2
votes

I'm using DirectX 12, trying to render using UAVs. Here is my pixel shader code:

    struct PSInput
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

struct FragmentDataStruct
{
    float4 color;
    float depth;
};

struct FragmentAndLinkStruct
{
    FragmentDataStruct fragmentData;
    uint nextFragment;
};

RWStructuredBuffer <FragmentAndLinkStruct> FLBuffer : register(u0);

RWByteAddressBuffer StartOffsetBuffer : register(u1);

float4 PSMain(PSInput input) : SV_TARGET
{
    input.color.x = float(FLBuffer[0].nextFragment);

    return input.color;
}

It fails compilation when using the D3DCompileFromFile function.

When I replace this line:

input.color.x = float(FLBuffer[0].nextFragment);

with something like this:

FragmentAndLinkStruct otherThing;
otherThing.nextFragment = 1;
input.color.x = float(otherThing.nextFragment);

that has no mention of the RWStructuredBuffer, then it compiles just fine and renders properly.

I don't think I have any issues with bound data (VS Graphics Debugger shows the two UAVs bound properly). I don't think that would affect the compiling of the shader, though.

Any time I reference FLBuffer or StartOffsetBuffer, it won't compile.

What would cause this problem?

1

1 Answers

0
votes

I solved the problem after figuring out how to read the error given by the compiler. The issue here was that the render target output uses the u0 shader register.

To find this, I read out the error given natively from D3DCompileFromFile as an ID3DBlob* by converting it to a char* array using the code below, where error is an ID3DBlob*:

const char* error2 = static_cast<const char*>(error->GetBufferPointer());

I set a breakpoint immediately after the last line and simply read out the error message from the locals tab in VS:

error X4509: UAV registers live in the same name space as outputs, so they
must be bound to at least u1, manual bind to slot u0 failed

The error message is VERY clear and concise. Very helpful.

The updated code:

struct PSInput
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

struct FragmentDataStruct
{
    float4 color;
    float depth;
};

struct FragmentAndLinkStruct
{
    FragmentDataStruct fragmentData;
    uint nextFragment;
};

RWStructuredBuffer <FragmentAndLinkStruct> FLBuffer : register(u1);

RWByteAddressBuffer StartOffsetBuffer : register(u2);

float4 PSMain(PSInput input) : SV_TARGET
{
    uint pixelCount = FLBuffer.IncrementCounter();
    input.color.x = float(pixelCount);

    return input.color;
}

As a note, the compiler won't even look at code that doesn't contribute to the return output. I tested this by adding some code to the PSMain function that interacted with the FLBuffer without affecting input.color, which is returned. Looking at the disassembly, all the superfluous code was removed and not compiled.

Separately, since I didn't reference FLBuffer when it worked, it didn't make any connection between the output shader register and the u0 shader register I bound, so no issue arose.

I then have to assume that it gets rid of superfluous code before sanity checking that code, which makes sense when looking for efficiency. Once it does a sanity check, then it proceeds to compile.

Hopefully this helps someone learning DirectX or HLSL later.