Skip to content

Array in cbuffer reported as unused by reflection #2772

@Dredhog

Description

@Dredhog

Title

Array in cbuffer reported as unused by reflection when optimization is turned on and there are other members in the cbuffer

Functional impact

This causes our compute shader (form Unity Scriptable Render Pipeline) to read garbage values for light probe data during a lighting loop since the array being read is reported by reflection to be unused and is thus left uninitialized in the cbuffer.

Minimal repro steps

  1. Compile repro_shader.txt with the IDxcCompiler3 interface and -O2 -T cs_6_3 -E CSMain options (same shader shown below)
float4 g_Float4Array[3];                          //Any array type or array size will do
float g_NeedAtLeastOneOtherVariableInTheCBuffer;  //Need another member in the cbuffer to reproduce the issue

RWStructuredBuffer<uint> OptimizationPreventionBuffer;
RWTexture2D<float4>      OutTexture;

[numthreads(1,1,1)]
void CSMain ()
{
    int index = OptimizationPreventionBuffer[2];  // index must not be known at compile time
    index -= 2;                                   // issue disappears without this line
    
    float3 outColor = g_Float4Array[index].xyz;   // Reads garbage value
    OutTexture[uint2(0,0)] = float4(outColor, 1);
}
  1. After compilation get the reflection part out of the result blob similar to:
ComPtr<IDxcBlob> reflectionPart;

if (pResult->HasOutput(DXC_OUT_REFLECTION))
   pResult->GetOutput(DXC_OUT_REFLECTION, __uuidof(IDxcBlob), &reflectionPart, NULL);
  1. Get the D3D12_SHADER_DESC structure:
ComPtr<ID3D12ShaderReflection> shaderReflection;
DxcBuffer buffer = { reflectionPart->GetBufferPointer(), reflectionPart->GetBufferSize(), 0 };
g_pDxcUtils->CreateReflection(&buffer, __uuidof(ID3D12ShaderReflection), &shaderReflection)
D3D12_SHADER_DESC shaderDesc;
shaderReflection->GetDesc(&shaderDesc);
  1. Loop over cbuffers and their elements:
for (UINT i = 0; i < shaderDesc.ConstantBuffers; ++i)
{
    ID3D12ShaderReflectionConstantBuffer* cb = shaderReflection->GetConstantBufferByIndex(i);
    D3D12_SHADER_BUFFER_DESC desc;
    cb->GetDesc(&desc);
    if (desc.Type == D3D11_CT_CBUFFER)
    {
        for (UINT j = 0; j < desc.Variables; ++j)
        {
            ID3D12ShaderReflectionVariable* var = cb->GetVariableByIndex(j);
            D3D12_SHADER_VARIABLE_DESC vdesc;
            var->GetDesc(&vdesc);
            if (!(vdesc.uFlags & D3D_SVF_USED)) // g_Float4Array's vdesc.uFlags == 0
                continue;
            //... Perform further reflection for used members
         }
    }
}

Expected result

The cbuffer member g_Float4Array has the flag D3D_SVF_USED(2) set and the member g_NeedAtLeastOneOtherVariableInTheCBuffer has uFlags == 0

Actual result

The cbuffer member g_Float4Array has uFlags == 0 and g_NeedAtLeastOneOtherVariableInTheCBuffer has the flag D3D_SVF_USED(2) set

Further technical details

Looking at the DXIL this might not be a codegen issue but an issue with the reflection information generation. If only the array g_Float4Array is present in the cbuffer the issue will not reproduce, it will also fail to reproduce with compiler optimization turned off or when the index variable is not modified after declaring it
DXC used was built from most recent source f26d32c

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugBug, regression, crashreflectionRelated to Reflection data

    Type

    No type

    Projects

    Status

    Triaged

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions