microsoft / microsoft/DirectXShaderCompiler

[SPIR-V] `SPV_EXT_descriptor_heap`: acceleration structure heap stride computed before codegen causes false rejections and over-wide strides

Open
#8,714 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug needs-triage spirv
Dominant language
C++
Stars
3.7k
Forks
900
Avg merge
2d 11h
Merged PRs (30d)
44

Description

Apart of #8518

Description

Under -fspv-use-descriptor-heap, all resource-heap runtime arrays must share a single stride (ArrayStrideIdEXT), equal to the largest descriptor size that may appear in the heap. Normally it is just the max of image and buffer descriptor sizes but becomes a three-way max when acceleration structures are present.

The stride value is built once and cached on first use, so the decision must be committed before the codegen loop. Currently the compiler predicts whether acceleration structures will appear in the heap using two proxies: (1) any function in the work queue is a ray-tracing stage, or (2) the user listed SPV_KHR_ray_tracing, SPV_NV_ray_tracing, or SPV_KHR_ray_query via -fspv-extension. Neither proxy is equivalent to "codegen will actually place an acceleration structure in the heap," so they misfire in both directions:

  1. False rejection: A compute shader that loads a RaytracingAccelerationStructure from ResourceDescriptorHeap via inline ray query is rejected it satisfies neither proxy, so the stride is built without the acceleration structure size. Rather than emit a silently incorrect stride, the compiler errors out.
  2. Over-wide stride: A shader that lists a ray extension (e.g. SPV_KHR_ray_query) but never places an acceleration structure in the heap gets the three-way stride and a spurious OpTypeAccelerationStructureKHR in the module, taking a performance penalty.

Root cause: SpirvBuilder::getResourceHeapArrayStride() caches the stride on first use, so the decision must be made before the codegen loop in HandleTranslationUnit(), before reachability or actual heap accesses are known.

Steps to Reproduce

Defect 1: legal shader rejected:

// dxc -T cs_6_6 -E main -fspv-use-descriptor-heap -fspv-target-env=vulkan1.3 -spirv repro.hlsl
RWBuffer<float4> output : register(u0);
[numthreads(1, 1, 1)]
void main(uint3 tid : SV_DispatchThreadID) {
    RaytracingAccelerationStructure scene = ResourceDescriptorHeap[1];
    RayDesc ray;
    ray.Origin    = float3(0, 0, 0);
    ray.Direction = float3(0, 0, 1);
    ray.TMin = 0.0; ray.TMax = 1000.0;
    RayQuery<RAY_FLAG_NONE> q;
    q.TraceRayInline(scene, RAY_FLAG_NONE, 0xff, ray);
    output[tid.x] = float4(q.Proceed() ? 1.0 : 0.0, 0, 0, 0);
}

Expected: compiles; stride widened to max(image, buffer, acceleration_structure).

Defect 2: over-wide stride:

// dxc -T cs_6_6 -E main -fspv-use-descriptor-heap -fspv-target-env=vulkan1.3
//   -fspv-extension=SPV_EXT_descriptor_heap -fspv-extension=SPV_KHR_untyped_pointers
//   -fspv-extension=SPV_KHR_ray_query -spirv repro2.hlsl
RWBuffer<float4> output : register(u0);
[numthreads(1, 1, 1)]
void main(uint3 tid : SV_DispatchThreadID) {
    Texture2D<float4> tex = ResourceDescriptorHeap[0];
    output[tid.x] = tex.Load(int3(tid.x, 0, 0));
}

Expected: two-way stride max(sizeof(image), sizeof(buffer)), no acceleration structure type in the module.

Actual Behavior

Defect 1:

error: acceleration structure loaded from ResourceDescriptorHeap requires the resource heap stride
to account for acceleration structure descriptors; compile with -fspv-extension=SPV_KHR_ray_tracing
or -fspv-extension=SPV_KHR_ray_query

Defect 2: Compiles, but emits a three-way stride and every heap slot is padded to a descriptor size the shader never uses.

Workarounds:

  • Pass -fspv-extension=SPV_KHR_ray_query. -fspv-extension is an exclusive allow-list however, so every other needed extension must be listed too.
  • Pass -fvk-resource-heap-stride N. Requires knowing driver-specific descriptor sizes. Wrong value results on crashes.

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 in SpirvBuilder::getResourceHeapArrayStride() and HandleTranslationUnit(), where the cached stride is selected before the codegen loop. Reproduce both HLSL examples with the shown dxc commands, then trace how acceleration-structure heap accesses are identified. Done means the legal inline-ray-query shader compiles with the widened stride, while the texture-only shader uses the two-way stride without emitting an acceleration-structure type.

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
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.