microsoft / microsoft/DirectXShaderCompiler
Incorrect 'D3D_SVF_USED' flag with fields in $Globals_cbuffer
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 3.7k
- Forks
- 900
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 44
Description
Hi,
I'm seeing an incorrect 'D3D_SVF_USED' flag with fields in $Globals_cbuffer for below shader:
#define PROBE_COUNT 6
#define PROBE_VOLUME_SIZE 32
struct FProbeUpdateData
{
uint3 Coord;
};
float4 WorldPosToProbeCoord[PROBE_COUNT];
float4 ProbeCoordToWorldPos[PROBE_COUNT];
RWBuffer<uint> RWProbeUpdateAllocator;
RWBuffer<uint> RWProbeUpdateBuffer;
RWBuffer<uint> RWProbeLightingBuffer;
float4 SkyLightColor;
FProbeUpdateData DecodeProbeUpdateData(uint2 ProbeDataEncoded)
{
FProbeUpdateData ProbeData;
ProbeData.Coord.x = ProbeDataEncoded.x & 0xFF;
ProbeData.Coord.y = (ProbeDataEncoded.x >> 8) & 0xFF;
ProbeData.Coord.z = (ProbeDataEncoded.x >> 16) & 0xFF;
return ProbeData;
}
int3 WorldPosToProbeCoordInternal(float3 WorldPos, uint index)
{
return floor(WorldPos * WorldPosToProbeCoord[index].w + WorldPosToProbeCoord[index].xyz);
}
uint3 WorldPosToProbeCoordIndex(float3 WorldPos, uint index)
{
int3 ProbeCoord;
ProbeCoord = WorldPosToProbeCoordInternal(WorldPos, index);
ProbeCoord.x += index * PROBE_VOLUME_SIZE;
return ProbeCoord;
}
float3 ProbeCoordToWorldPosCoord(uint3 ProbeCoord)
{
uint index = ProbeCoord.x / PROBE_VOLUME_SIZE;
ProbeCoord.x -= index * PROBE_VOLUME_SIZE;
return (float3)ProbeCoord * ProbeCoordToWorldPos[index].w + ProbeCoordToWorldPos[index].xyz;
}
[numthreads(64, 1, 1)]
void ResampleCS(uint3 DispatchThreadID : SV_DispatchThreadID, uint3 GroupID : SV_GroupID)
{
uint NewProbeID = DispatchThreadID.x;
uint ProbeUpdateIndex = RWProbeUpdateAllocator[0] + NewProbeID;
uint2 ProbeDataEncoded;
ProbeDataEncoded.x = RWProbeUpdateBuffer[ProbeUpdateIndex * 2];
ProbeDataEncoded.y = RWProbeUpdateBuffer[ProbeUpdateIndex * 2 + 1];
FProbeUpdateData ProbeData = DecodeProbeUpdateData(ProbeDataEncoded);
float3 ProbePos = ProbeCoordToWorldPosCoord(ProbeData.Coord);
uint ProbeIndex = ProbeData.Coord.x / PROBE_VOLUME_SIZE;
uint3 SourceProbeCoord = WorldPosToProbeCoordIndex(ProbePos + 0.5f, ProbeIndex - 1);
RWProbeLightingBuffer[SourceProbeCoord.x] = SourceProbeCoord.y;
}
The global constant 'SkyLightColor' is not used in this shader, but ID3D12ShaderReflection is giving 'D3D_SVF_USED' flag to it.
I digged into the compiler source code and had a bit of clue:
'ProbeIndex - 1' is used to index global constant 'WorldPosToProbeCoord[6]', but since 'ProbIndex' is a dynamic variable, it is deduced to value 0 in the compiler. This will lead to use offset '-1' to access $Globals_cbuffer with CBufferLoadLegacy.
In latest DXilCondeseResources.cpp, MarkCBUse() used upper_bound() for offset to determine accessed field in $Globals_cbuffer struct:
static void MarkCBUse(unsigned offset, FieldAnnotationByOffsetMap &fieldMap) {
auto it = fieldMap.upper_bound(offset);
it--;
if (it != fieldMap.end())
it->second->SetCBVarUsed(true);
}
if 'offset' is -1, the last field in the struct will be marked used incorrectly no matter what. Maybe field and struct size should be taken into consideration when determine the field usages. Please take a look.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in DXilCondeseResources.cpp at MarkCBUse() and trace how the dynamic ProbeIndex - 1 access produces a -1 CBufferLoadLegacy offset. Reproduce the shader and inspect ID3D12ShaderReflection for D3D_SVF_USED; done means SkyLightColor is not marked used when it is absent from the shader's actual accesses.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100