microsoft / microsoft/DirectXShaderCompiler
[DXIL] Inconsistent register assignments for unused resources without explicit register annotations
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 3.7k
- Forks
- 900
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 44
Description
Description
When HLSL shaders declare resources without explicit register() bindings, DXC assigns registers only after GlobalDCE eliminates unused resources. Because the set of unused resources varies depending on the entry point and optimization path taken, this results in inconsistent register assignments across entry points within the same shader file or when compiling as a library.
This is especially problematic in poor man's bindless (with : register(space1) only), where numerous textures or buffers are declared in shared includes but only some are referenced by each entry point. The resulting binaries may disagree on resource IDs, breaking pipelines that rely on stable binding locations.
This results into:
- Register assignments not being deterministic across compilation modes or entry points.
- Shader libraries cannot rely on stable bindings when resources have no explicit register annotation.
- Engine pipelines and reflection systems may break due to mismatched IDs.
- Many build systems currently resort to custom preprocessing to impose binding order, which is fragile and error-prone.
Note: Relates to https://github.com/microsoft/DirectXShaderCompiler/issues/5105
Steps to Reproduce
// %dxc -E main -T cs_6_0
// %dxc -E main2 -T cs_6_0
Texture2D a;
Texture2D b;
RWTexture2D<float4> c;
[numthreads(1,1,1)]
void main() {
c[0.xx] = b[0.xx];
}
[numthreads(1,1,1)]
void main2() {
c[0.xx] = a[0.xx];
}
Depending on the entry point chosen during compilation, GlobalDCE may remove different resources. Since DXC assigns bindings after DCE, resources may be rebound to different registers between main and main2. This also affects library compilation when DXC aggregates multiple entry points.
Actual Behavior
Introduce a mechanism to ensure that binding assignment happens with the full resource list intact, even if some resources are not used by an entry point and strip these resources afterwards. This would guarantee stable bindings across compilation paths and enable consistent reflection output.
Environment
- DXC version: All
- Host Operating System: N/A
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 by reproducing the issue with the provided dxc commands for main and main2, then compare their resource bindings and reflection output. Trace how GlobalDCE and binding assignment affect the resources a, b, and c; done means unused resources can be stripped without changing bindings across entry points or library compilation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100