microsoft / microsoft/DirectXShaderCompiler

[DXIL] Inconsistent register assignments for unused resources without explicit register annotations

Open
#7,931 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.