Skip to content

[SPIR-V] Add descriptor heap RaytracingAccelerationStructure support - #8518

Open
Jonathan Zakharov (jzakharovnv) wants to merge 13 commits into
microsoft:mainfrom
jzakharovnv:pr2-raytracing-accel-struct
Open

[SPIR-V] Add descriptor heap RaytracingAccelerationStructure support#8518
Jonathan Zakharov (jzakharovnv) wants to merge 13 commits into
microsoft:mainfrom
jzakharovnv:pr2-raytracing-accel-struct

Conversation

@jzakharovnv

Copy link
Copy Markdown
Collaborator

Building off of #8517, this PR extends the SPV_EXT_descriptor_heap native heap lowering to cover RaytracingAccelerationStructure resources loaded from ResourceDescriptorHeap. It is part 2/4 in a series.

Acceleration structure descriptors are accessed via OpUntypedAccessChainKHR into a runtime array of OpTypeAccelerationStructureKHR, consistent with the image and sampler paths added in the previous commit.

Assisted by an AI agent

Diego Novillo (@dnovillo)

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

✅ With the latest revision this PR passed the C/C++ code formatter.

@jzakharovnv
Jonathan Zakharov (jzakharovnv) force-pushed the pr2-raytracing-accel-struct branch 3 times, most recently from d899b05 to b12b9ea Compare June 4, 2026 22:59
@jzakharovnv

Copy link
Copy Markdown
Collaborator Author

@microsoft-github-policy-service agree company="NVIDIA"

return true;
}

if (isRaytracingAccelerationStructure(decl->getType())) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since acceleration structures are distinct from image and buffers, do they still fit in max(sizeof(image), sizeof(buffer))? If not, the stride will be too small and heap indexing will land in the wrong spot.

Maybe we need to incorporate acceleration structures when computing the default stride if RT is used?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, it would be correct to include acceleration structures in the computation for the resource heap stride. Will address this in my next set of commits.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -0,0 +1,42 @@
// RUN: %dxc -T lib_6_6 -fspv-use-descriptor-heap -fspv-target-env=vulkan1.3 -fvk-resource-heap-stride 64 -fvk-sampler-heap-stride 32 -fspv-extension=SPV_KHR_ray_tracing -fspv-extension=SPV_EXT_descriptor_heap -fspv-extension=SPV_KHR_untyped_pointers -spirv %s | FileCheck %s

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is using flags introduced in #8519. It will break if the PRs get merged in order. Perhaps move this test to #8519 and add only default stride tests here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another result of some clumsy commits and now outdated commits! Should be able to remove the usage of these flags now that strides are computed automatically. Will address next set of commits.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-project-automation github-project-automation Bot moved this from New to In progress in HLSL Roadmap Jul 17, 2026
@dnovillo Diego Novillo (dnovillo) added the spirv Work related to SPIR-V label Jul 17, 2026
@jzakharovnv
Jonathan Zakharov (jzakharovnv) force-pushed the pr2-raytracing-accel-struct branch 2 times, most recently from 23aff82 to 02f3581 Compare July 23, 2026 19:39

@dnovillo Diego Novillo (dnovillo) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only a question left on detecting RT usage of the heap.

if (shaderModelKindIsRayTracing(fi->shaderModelKind)) {
needsAccelStruct = true;
break;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would fail for compute/graphics shaders that need to use RayQuery and have AS on the heap. I think this should be a translation unit walk looking for a vardecls and setting the flag on the first match.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ended up being a much harder problem than I anticipated. I filed an issue with #8714 and have provided some work arounds in a revised Included AccelerationStructure in resource heap stride calculation. There also exists the work around of using the options provided in [SPIR-V] Add -fvk-resource-heap-stride / -fvk-sampler-heap-stride.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ended up being a much harder problem than I anticipated. I filed an issue with #8714 and have provided some work arounds in a revised Included AccelerationStructure in resource heap stride calculation. There also exists the work around of using the options provided in [SPIR-V] Add -fvk-resource-heap-stride / -fvk-sampler-heap-stride.

Sure. Thanks for documenting workarounds. I think this is now ready.

Building off of microsoft#8281, this commit adds a native lowering via SPV_EXT_descriptor_heap and SPV_KHR_untyped_pointers.

ResourceDescriptorHeap and SamplerDescriptorHeap are lowered to untyped variables decorated with ResourceHeapEXT and SamplerHeapEXT. Each heap access emits OpUntypedAccessChainKHR into a runtime array of the appropriate descriptor type. Buffer-like resources (StructuredBuffer, ByteAddressBuffer, ConstantBuffer, TextureBuffer) use OpTypeBufferEXT and OpBufferPointerEXT; image and sampler resources use OpLoad. Interlocked operations on RWTexture use OpUntypedImageTexelPointerEXT.

Requires -fspv-target-env=vulkan1.3.

Assisted-by: Claude.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends native SPIR-V descriptor-heap lowering to acceleration structures and broader resource operations.

Changes:

  • Adds descriptor-size-based heap strides, including acceleration structures.
  • Adds native buffer, image, sampler, atomic, and alias lowering.
  • Expands SPIR-V tests and documentation.

Reviewed changes

Copilot reviewed 51 out of 51 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
tools/clang/unittests/SPIRV/SpirvContextTest.cpp Extends runtime-array uniqueness tests.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.typed-formats.hlsl Tests typed image formats.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.texturecube.hlsl Tests cube textures and samplers.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.texture.hlsl Tests texel buffers.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.texture-sampler-assignment.hlsl Tests resource reassignment.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.texture-ms.hlsl Tests multisampled textures.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.texture-dims.hlsl Tests sampled-texture dimensions.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.structured-buffer-atomic.hlsl Tests structured-buffer atomics.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.static-global.hlsl Tests static global resources.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.sampler-comparison.hlsl Tests comparison samplers.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.sample-grad-bias.hlsl Tests gradient and bias sampling.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.rwtexture-dims.hlsl Tests storage-texture dimensions.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.rwtexture-atomics.hlsl Tests untyped image atomics.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.rwbyteaddressbuffer.hlsl Tests writable byte buffers.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.nonuniform.hlsl Tests nonuniform-index handling.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.mixed-bound.hlsl Tests bound and heap resources together.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.load-offset.hlsl Tests texture-load offsets.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.groupshared.hlsl Tests groupshared interoperability.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.gather.hlsl Tests texture gather operations.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.function-params.hlsl Tests resource function parameters.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.discarded.error.hlsl Tests discarded-access diagnostics.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.counter-ops.error.hlsl Tests unsupported counter diagnostics.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.constant-texture-buffer.hlsl Tests constant and texture buffers.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.constant-buffer-assignment.hlsl Tests constant-buffer reassignment.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.buffer.hlsl Tests native buffer lowering.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.array-stride.hlsl Tests shared heap strides.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.array-stride.accelstruct.hlsl Tests acceleration-structure stride inclusion.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.append-consume.error.hlsl Tests append/consume diagnostics.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.acceleration-structure.stride.error.hlsl Tests missing acceleration stride diagnostics.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.acceleration-structure.hlsl Tests acceleration-structure heap loads.
tools/clang/test/CodeGenSPIRV/resource-heap-ext-texture.hlsl Removes the superseded aggregate test.
tools/clang/lib/SPIRV/SpirvType.cpp Includes stride IDs in type equality.
tools/clang/lib/SPIRV/SpirvInstruction.cpp Implements new SPIR-V instructions.
tools/clang/lib/SPIRV/SpirvEmitter.h Declares heap-lowering and alias state.
tools/clang/lib/SPIRV/SpirvEmitter.cpp Implements native heap lowering and acceleration support.
tools/clang/lib/SPIRV/SpirvContext.cpp Canonicalizes buffer and runtime-array types.
tools/clang/lib/SPIRV/SpirvBuilder.cpp Builds descriptor-size constants and strides.
tools/clang/lib/SPIRV/LowerTypeVisitor.cpp Lowers untyped image pointers.
tools/clang/lib/SPIRV/EmitVisitor.h Declares new emission handlers.
tools/clang/lib/SPIRV/EmitVisitor.cpp Emits new instructions and decorations.
tools/clang/lib/SPIRV/DeclResultIdMapper.h Declares function-variable aliases.
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp Registers function-variable aliases.
tools/clang/lib/SPIRV/CapabilityVisitor.cpp Enforces Vulkan 1.3 for native heaps.
tools/clang/lib/SPIRV/AstTypeProbe.cpp Recognizes acceleration-structure types.
tools/clang/include/clang/SPIRV/SpirvVisitor.h Adds visitor methods.
tools/clang/include/clang/SPIRV/SpirvType.h Stores runtime-array stride IDs.
tools/clang/include/clang/SPIRV/SpirvInstruction.h Defines new instruction classes.
tools/clang/include/clang/SPIRV/SpirvContext.h Extends type-context APIs.
tools/clang/include/clang/SPIRV/SpirvBuilder.h Exposes descriptor-stride builders.
tools/clang/include/clang/SPIRV/AstTypeProbe.h Declares acceleration-type probing.
docs/SPIR-V.rst Documents native descriptor heaps.
Comments suppressed due to low confidence (1)

tools/clang/lib/SPIRV/SpirvEmitter.cpp:7072

  • Only casts are stripped here, so a syntactically valid parenthesized heap base such as (ResourceDescriptorHeap)[i] is diagnosed as unsupported even though it still refers directly to the builtin variable. Use IgnoreParenCasts() consistently when resolving the base declaration.
      const auto *declRefExpr = dyn_cast<DeclRefExpr>(baseExpr->IgnoreCasts());
      const auto *decl =
          declRefExpr ? dyn_cast<VarDecl>(declRefExpr->getDecl()) : nullptr;
      if (!decl) {
        emitError("unsupported ResourceDescriptorHeap/SamplerDescriptorHeap "
                  "expression",
                  baseExpr->getExprLoc());
        return nullptr;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// (Dim2D, depth=0, not-arrayed, non-MS, sampled, Unknown format), so
// %[[TexDesc]] serves as both the placeholder for the size calculation and
// the real descriptor type for the Texture2D access below.
// CHECK-DAG: %[[TexDesc:[a-zA-Z0-9_]+]] = OpTypeImage %float 2D 0 0 0 1 Unknown

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing test in next set of commits


// --- Types (user-declared + stride-computation placeholders) ---------------
// CHECK-DAG: %[[Accel:[a-zA-Z0-9_]+]] = OpTypeAccelerationStructureKHR
// CHECK-DAG: %[[Img:[a-zA-Z0-9_]+]] = OpTypeImage %float 2D 0 0 0 1 Unknown

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing test in next set of commits

Comment on lines +864 to +868
if (!needsAccelStruct && !spirvOptions.allowedExtensions.empty())
needsAccelStruct =
featureManager.isExtensionEnabled(Extension::KHR_ray_tracing) ||
featureManager.isExtensionEnabled(Extension::NV_ray_tracing) ||
featureManager.isExtensionEnabled(Extension::KHR_ray_query);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread docs/SPIR-V.rst Outdated
Comment on lines +2102 to +2105
The concrete descriptor type is selected at each heap access. For image,
sampler, and texel buffer resources, DXC forms a runtime array of that
descriptor type and decorates the array with a byte ``ArrayStride``, then uses
``OpUntypedAccessChainKHR`` followed by ``OpLoad``:

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing documentation in next set of commits


// Three distinct descriptor heap sizes exist:
// the image/Texture2D type (%[[TexDesc]]), the Uniform buffer, and the sampler.
// Regression test: make sure of no per-element nor per acces behavior exists

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing test in next set of commits

Comment on lines +5252 to +5259
auto &alias = descriptorHeapImageAliasVars[dstVar];
if (!alias.indexVar)
alias.indexVar = createDescriptorHeapIndexVar(dstVar);
alias.imageType = found->second.imageType;
alias.arrayType = found->second.arrayType;
alias.heap = found->second.heap;
storeDescriptorHeapIndex(alias.indexVar, found->second.index,
found->second.indexType, srcExpr);
Comment thread docs/SPIR-V.rst Outdated
Comment on lines +2144 to +2148
This path supports texture, RWTexture, sampler, Buffer/RWBuffer,
StructuredBuffer/RWStructuredBuffer without associated counter operations,
ByteAddressBuffer/RWByteAddressBuffer, ConstantBuffer, and TextureBuffer heap
loads, including direct field and array-element accesses for
``ConstantBuffer<T>`` and ``TextureBuffer<T>``. ``NonUniformResourceIndex`` is
Comment on lines +7048 to +7059
// The heap index expression must be immediately converted to a concrete
// resource type (an implicit cast inserted by the front-end). If the
// parent is missing or is not a cast (e.g. the result is discarded as
// a statement, or used in a context with no target resource type) we
// cannot determine the resource type.
const auto *parentExpr =
dyn_cast_or_null<CastExpr>(parentMap->getParent(expr));
if (!parentExpr) {
emitError("ResourceDescriptorHeap/SamplerDescriptorHeap indexing must "
"be used as a resource",
expr->getExprLoc());
return nullptr;
Comment on lines +7098 to +7103
emitError("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",
expr->getExprLoc());
Comment on lines +327 to +329

EXPECT_NE(spvContext.getRuntimeArrayType(int32, llvm::None),
spvContext.getRuntimeArrayType(int32, 32));

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix in next set of commits.

@damyanp

Copy link
Copy Markdown
Member

[Auto-generated note from Damyan Pepper (@damyanp)]

This looks like a user-visible bug fix/feature change. Please add (or point to) the corresponding entry in docs/ReleaseNotes.md.

If release-note coverage is planned in a related PR (including one that hasn’t been submitted yet), please mention that plan/link so we can avoid duplicate notes.

Extends the SPV_EXT_descriptor_heap native heap lowering to cover RaytracingAccelerationStructure resources loaded from ResourceDescriptorHeap.

Acceleration structure descriptors are accessed via OpUntypedAccessChainKHR into a runtime array of OpTypeAccelerationStructureKHR, consistent with the image and sampler paths added in the previous commit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 52 out of 52 changed files in this pull request and generated 1 comment.

Suppressed comments (3)

tools/clang/lib/SPIRV/SpirvEmitter.cpp:5315

  • A heap-to-heap reassignment of RaytracingAccelerationStructure also reaches this branch because mixingDetected includes (isASType && wasHeap) regardless of srcIsHeap. That assignment does not mix bound and heap resources, so this diagnostic is misleading; report the unsupported AS reassignment separately.
    emitError("mixing bound and descriptor heap resources in the same variable "
              "is not supported with SPV_EXT_descriptor_heap",
              loc);

tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.array-stride.hlsl:62

  • Use the possessive “its” rather than “it's” (“it is”).
// The sampler array just uses the sampler size as it's stride.

docs/SPIR-V.rst:2089

  • This is a significant user-visible compiler feature, but docs/ReleaseNotes.md has no native descriptor-heap entry. Please add release-note coverage, or point to the shared release note planned for this four-PR series.
When ``-fspv-use-descriptor-heap`` is specified, DXC lowers
``ResourceDescriptorHeap`` and ``SamplerDescriptorHeap`` through
``SPV_EXT_descriptor_heap`` instead of the default emulated heap path. This
also requires ``SPV_KHR_untyped_pointers`` and ``-fspv-target-env=vulkan1.3``

Comment on lines +2105 to +2107
(void)doExpr(init->IgnoreParenCasts());
tryToAssignDescriptorHeapBufferAlias(decl, init);
return true;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, will fix

@dnovillo

Copy link
Copy Markdown
Collaborator

Added an analysis on this series: #8517 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

spirv Work related to SPIR-V

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

4 participants