Skip to content

[SPIR-V] Add SPV_EXT_descriptor_heap + SPV_KHR_untyped_pointers codegen - #8517

Open
Jonathan Zakharov (jzakharovnv) wants to merge 29 commits into
microsoft:mainfrom
jzakharovnv:pr1-descriptor-heap-core
Open

Jonathan Zakharov (jzakharovnv) wants to merge 29 commits into
microsoft:mainfrom
jzakharovnv:pr1-descriptor-heap-core

Conversation

@jzakharovnv

@jzakharovnv Jonathan Zakharov (jzakharovnv) commented Jun 4, 2026 •

Copy link
Copy Markdown
Collaborator

Building off of #8281, this PR adds a native lowering via SPV_EXT_descriptor_heap and SPV_KHR_untyped_pointers and is part 1/3 in a series.

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 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

Copy link
Copy Markdown
Collaborator Author

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

@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.

Thanks for this! I just started looking at it and have a couple of questions. I'll add more as I read the PRs.

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
@github-project-automation github-project-automation Bot moved this from New to In progress in HLSL Roadmap Jun 8, 2026
Comment thread tools/clang/lib/SPIRV/CapabilityVisitor.cpp Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
@Tobski

Tobski commented Jul 7, 2026

Copy link
Copy Markdown

Jonathan Zakharov (@jzakharovnv) I think the OpConstantSizeOfEXT usage in this MR isn't quite right - it looks like you're just taking the stride of the descriptor type being loaded and using that? This works for the sampler heap where there's only one type (samplers), but not for the resource heap.

The stride of all resource descriptors must be the same for all descriptors, and has to be based on the biggest of the buffer/image sizes. This is illustrated in the VK extension doc here: https://docs.vulkan.org/features/latest/features/proposals/VK_EXT_descriptor_heap.html#_shader_model_6_6_samplerheap_and_resourceheap

I might be misunderstanding the code, but I don't see anything for finding the largest of the two sizes? They're both POT, so it is a simple "which is max" calculation, but I don't see it being done in this PR.

@jzakharovnv

Copy link
Copy Markdown
Collaborator Author

Tobski You are right, this is my blunder. Will fix shortly.

@jzakharovnv

Copy link
Copy Markdown
Collaborator Author

Tobski Shared max(image,buffer) stride for descriptor heap resource arrays ought to be closer to the original intent. Please take a look when you can. Thanks!

@Tobski

Tobski commented Jul 13, 2026

Copy link
Copy Markdown

Tobski Shared max(image,buffer) stride for descriptor heap resource arrays ought to be closer to the original intent. Please take a look when you can. Thanks!

Looks right to me now! Thanks!

@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.

A question on changes that have gone in #8519 that we may to reflect here. Not sure how you want to handle it.

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
@dnovillo Diego Novillo (dnovillo) added the spirv Work related to SPIR-V label Jul 17, 2026
@jzakharovnv

Copy link
Copy Markdown
Collaborator Author

Diego Novillo (@dnovillo) In response to your last comment on this PR, yes I think it's more correct to have the TODO commit a part of this initial branch rather than one down the line. Cherrypicked and rebased to reflect this.

@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.

Just one minor change and it's good to from my side.

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated

@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.

LGTM. Just one final nit. Thanks for doing this!

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
@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.

Copilot AI balanced review requested due to automatic review settings August 4, 2026 00:41

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

Adds native SPIR-V descriptor-heap lowering using SPV_EXT_descriptor_heap and SPV_KHR_untyped_pointers.

Changes:

  • Implements native image, sampler, and buffer descriptor access.
  • Adds descriptor-size-based runtime-array strides and image atomic support.
  • Expands tests and documents Vulkan 1.3 requirements and limitations.

Reviewed changes

Copilot reviewed 47 out of 47 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tools/clang/unittests/SPIRV/SpirvContextTest.cpp Tests runtime-array type uniqueness.
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 sampling operands.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.rwtexture-dims.hlsl Tests RW 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 divergent heap indexing.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.mixed-bound.hlsl Tests bound/native resource coexistence.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.mixed-alias.error.hlsl Tests mixed-alias diagnostics.
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 coexistence.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.gather.hlsl Tests 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-index 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 descriptor-array strides.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.append-consume.error.hlsl Tests append/consume diagnostics.
tools/clang/test/CodeGenSPIRV/resource-heap-ext-texture.hlsl Removes superseded coverage.
tools/clang/lib/SPIRV/SpirvType.cpp Extends runtime-array 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 code generation.
tools/clang/lib/SPIRV/SpirvContext.cpp Uniques buffer and stride-ID types.
tools/clang/lib/SPIRV/SpirvBuilder.cpp Builds descriptor sizes 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 Serializes new instructions and decorations.
tools/clang/lib/SPIRV/DeclResultIdMapper.h Declares function alias registration.
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp Implements alias registration.
tools/clang/lib/SPIRV/CapabilityVisitor.cpp Requires Vulkan 1.3 and extensions.
tools/clang/include/clang/SPIRV/SpirvVisitor.h Adds visitor hooks.
tools/clang/include/clang/SPIRV/SpirvType.h Adds stride-ID runtime arrays.
tools/clang/include/clang/SPIRV/SpirvInstruction.h Defines new instruction classes.
tools/clang/include/clang/SPIRV/SpirvContext.h Adds type caches and APIs.
tools/clang/include/clang/SPIRV/SpirvBuilder.h Exposes descriptor-stride builders.
docs/SPIR-V.rst Documents native descriptor heaps.

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp
Comment thread docs/SPIR-V.rst Outdated
Damyan Pepper (damyanp) added a commit that referenced this pull request Aug 6, 2026
Fixes #8603: MergeBinaryOpSelect produced an OpSelect with a vector
result type and a scalar condition, which is only legal in SPIR-V 1.4+
(KhronosGroup/SPIRV-Tools#6827).

This exposes #8740 where the resource-heap-ext-texture.hlsl test fails
validation - for now this is worked around by disabling the test, since
#8517 looks like it is reworking it anyway.

Assisted-by: copilot

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b04b21af-2d8b-4af5-b9ad-1b84073588f5

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.

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated

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.

Copilot review overview

🔵 Needs a closer look

Resource-stride handling and alias classification contain correctness gaps that can produce invalid descriptor accesses or SPIR-V.

Review effort: Balanced
Findings: None

Resolved since last review (2)
Previously missed (2)

In code that hasn't changed since last review

Medium severity Normalize chained assignment RHS values for heap aliasing

tools/​clang/​lib/​SPIRV/​SpirvEmitter.cpp:8540

This predicate misses valid value-producing expressions such as chained assignments. For RWTexture2D<uint> a, b; a = b = ResourceDescriptorHeap[0];, the inner assignment returns the heap handle, but the outer RHS is a BinaryOperator, so a is marked bound and never receives heap-index metadata; an atomic through a then falls back to invalid OpImageTexelPointer. Buffer aliases similarly fall through the normal whole-resource path. Recursively normalize assignment RHS values (or reject these forms explicitly) before classification and alias propagation.

Low severity Correct references to image alias regression tests

tools/​clang/​test/​CodeGenSPIRV/​sm6_6.descriptorheap.ext.alias-fn-readwrite.hlsl:12

These references point to the wrong filenames: alias-return.hlsl covers buffer returns and explicitly excludes image aliases, while the image atomic regressions are in the two .error.hlsl files. Point readers to the actual image return and parameter tests.

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.

Copilot review overview

🟡 Changes recommended

Descriptor strides omit acceleration structures, and function-boundary diagnostics can depend on emission order.

Review effort: Balanced
Findings: 1 High severity

Open (1)
Previously missed (1)

In code that hasn't changed since last review

Low severity Use possessive “its”

tools/​clang/​lib/​SPIRV/​SpirvEmitter.cpp:11339

Use the possessive “its” here.

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
Copilot AI balanced review requested due to automatic review settings September 29, 2026 18:40

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.

Copilot review overview

🟡 Changes recommended

Heap stride computation and alias-boundary detection leave supported shader patterns capable of producing invalid SPIR-V.

Review effort: Balanced
Findings: 1 High severity

Open (1)
Resolved since last review (1)

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp
Copilot AI balanced review requested due to automatic review settings September 29, 2026 20:12

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.

Copilot review overview

🟡 Changes recommended

Acceleration-structure stride handling and cross-function heap-image detection have correctness gaps.

Review effort: Balanced
Findings: 1 High severity

Open (1)
Resolved since last review (1)

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.h Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.h Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.h Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.h Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.h Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.h Outdated
Copilot AI balanced review requested due to automatic review settings September 29, 2026 21:55

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.

Copilot review overview

🔵 Needs a closer look

Descriptor stride and alias-provenance gaps can produce incorrect lowering or invalid SPIR-V for supported HLSL patterns.

Review effort: Balanced
Findings: 1 High severity

Open (1)
Previously missed (3)

In code that hasn't changed since last review

Medium severity Track heap-sourced images returned from function calls

tools/​clang/​lib/​SPIRV/​SpirvEmitter.cpp:5307

isHeapSourcedValue does not recognize a call that returns a heap-sourced image. Consequently, RWTexture2D x = makeHeapImage(); records x as Bound, and a later x = ResourceDescriptorHeap[i] is rejected as bound/heap mixing even though both sources are heap-backed. Function-returned image handles are explicitly supported for ordinary reads/writes, so this rejects an otherwise supported reassignment; classify heap-returning calls (and their forwarded locals) separately from genuinely bound resources here.

Medium severity Preserve heap provenance through conditional image selection

tools/​clang/​lib/​SPIRV/​SpirvEmitter.cpp:8598

Valid HLSL heap provenance is not limited to a direct subscript or DeclRefExpr; conditional selection is commonly used (for example, RWTexture2D t = cond ? ResourceDescriptorHeap[a] : ResourceDescriptorHeap[b]). This returns false for that expression, so buffer resources fall back to storing OpBufferPointerEXT values through an ordinary function variable, while an image atomic later has no descriptor index and falls back to invalid OpImageTexelPointer. Track/merge both heap indices through conditionals, or diagnose this form before lowering it.

Medium severity Scan nested declaration contexts for heap image callers

tools/​clang/​lib/​SPIRV/​SpirvEmitter.cpp:8715

This caller search skips function bodies nested in record/namespace declaration contexts. HLSL supports member functions, so a member can load an RWTexture from ResourceDescriptorHeap and pass it to a free function whose parameter is used by an interlocked operation; that call site is never found here, and the callee falls back to the invalid OpImageTexelPointer path this check is intended to prevent. Traverse nested declaration contexts (or a TU-wide call graph) so every user-function body is scanned.

Copilot AI balanced review requested due to automatic review settings September 29, 2026 23:11

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.

Copilot review overview

🟡 Changes recommended

Acceleration-structure stride handling and nested call-site analysis can produce invalid descriptor accesses.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (1)

Comment on lines +8718 to +8723
// No call graph is available, so finding param's callers means walking
// every function body in the TU for a CallExpr targeting owner.
// Shallow scan of TU decls, dont visit methods on user-defined types.
for (const Decl *d : astContext.getTranslationUnitDecl()->decls()) {
const auto *caller = dyn_cast<FunctionDecl>(d);
if (!caller || !caller->getBody())

This branch has not been deployed

No deployments
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.

6 participants