microsoft / microsoft/DirectXShaderCompiler
[SPIR-V] `SPV_EXT_descriptor_heap`: acceleration structure heap stride computed before codegen causes false rejections and over-wide strides
Nobody has claimed this yet.
- 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:
- False rejection: A compute shader that loads a
RaytracingAccelerationStructurefromResourceDescriptorHeapvia 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. - 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 spuriousOpTypeAccelerationStructureKHRin 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-extensionis 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
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 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