Skip to content

Commit cbcae38

Browse files
committed
[SPIR-V] Add SPV_EXT_descriptor_heap + SPV_KHR_untyped_pointers codegen
Building off of #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.
1 parent 517dd5e commit cbcae38

41 files changed

Lines changed: 1818 additions & 103 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/SPIR-V.rst

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ Supported extensions
336336
* SPV_KHR_float_controls
337337
* SPV_NV_shader_subgroup_partitioned
338338
* SPV_KHR_quad_control
339+
* SPV_KHR_untyped_pointers
340+
* SPV_EXT_descriptor_heap
339341

340342
Vulkan specific attributes
341343
--------------------------
@@ -1993,10 +1995,14 @@ responsibility to provide proper numbers and avoid binding overlaps.
19931995
ResourceDescriptorHeaps & SamplerDescriptorHeaps
19941996
------------------------------------------------
19951997

1996-
The SPIR-V backend supported SM6.6 resource heaps, using 2 extensions:
1998+
By default, the SPIR-V backend supports SM6.6 resource heaps by emulating the
1999+
heaps with descriptor-indexing runtime arrays, using 2 extensions:
2000+
19972001
- `SPV_EXT_descriptor_indexing`
19982002
- `VK_EXT_mutable_descriptor_type`
19992003

2004+
This is also the behavior selected by ``-fspv-use-emulated-heap``.
2005+
20002006
Each type loaded from a heap is considered to be an unbounded RuntimeArray
20012007
bound to the descriptor set 0.
20022008

@@ -2074,6 +2080,85 @@ Bindings & sets associated with each heap can be explicitly set using:
20742080
- `-fvk-bind-counter-heap <binding> <set>`: Specify Vulkan binding number
20752081
and set number for the counter heap.
20762082

2083+
Native descriptor heap extension lowering
2084+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2085+
2086+
When ``-fspv-use-descriptor-heap`` is specified, DXC lowers
2087+
``ResourceDescriptorHeap`` and ``SamplerDescriptorHeap`` through
2088+
``SPV_EXT_descriptor_heap`` instead of the default emulated heap path. This
2089+
also requires ``SPV_KHR_untyped_pointers`` and ``-fspv-target-env=vulkan1.3``
2090+
(targeting a lower environment is an error), and a SPIRV-Headers / SPIRV-Tools
2091+
build that defines these extensions. The emitted module declares the heap
2092+
objects as untyped variables in ``UniformConstant`` storage class:
2093+
2094+
.. code:: spirv
2095+
2096+
%uptr_uc = OpTypeUntypedPointerKHR UniformConstant
2097+
%resource_heap = OpUntypedVariableKHR %uptr_uc UniformConstant
2098+
%sampler_heap = OpUntypedVariableKHR %uptr_uc UniformConstant
2099+
OpDecorate %resource_heap BuiltIn ResourceHeapEXT
2100+
OpDecorate %sampler_heap BuiltIn SamplerHeapEXT
2101+
2102+
The concrete descriptor type is selected at each heap access. For image,
2103+
sampler, and texel buffer resources, DXC forms a runtime array of that
2104+
descriptor type and decorates the array with a byte ``ArrayStride``, then uses
2105+
``OpUntypedAccessChainKHR`` followed by ``OpLoad``:
2106+
2107+
.. code:: spirv
2108+
2109+
%image_type = OpTypeImage %float 2D 2 0 0 1 Unknown
2110+
%image_array = OpTypeRuntimeArray %image_type
2111+
OpDecorate %image_array ArrayStride 64
2112+
%descriptor = OpUntypedAccessChainKHR %uptr_uc %image_array %resource_heap %index
2113+
%image = OpLoad %image_type %descriptor
2114+
2115+
For buffer-like resources, DXC uses ``OpTypeBufferEXT`` as the descriptor type
2116+
and ``OpBufferPointerEXT`` to recover the pointer to the buffer data. The
2117+
descriptor storage class matches the recovered buffer pointer storage class; for
2118+
example, ``ConstantBuffer<T>`` uses ``Uniform`` and ``TextureBuffer<T>`` uses
2119+
``StorageBuffer``:
2120+
2121+
.. code:: spirv
2122+
2123+
%buffer_type = OpTypeBufferEXT Uniform
2124+
%buffer_array = OpTypeRuntimeArray %buffer_type
2125+
OpDecorate %buffer_array ArrayStride 64
2126+
%descriptor = OpUntypedAccessChainKHR %uptr_uc %buffer_array %resource_heap %index
2127+
%buffer_ptr = OpBufferPointerEXT %_ptr_Uniform_type_BufferData %descriptor
2128+
2129+
For ``RWTexture`` resources loaded from ``ResourceDescriptorHeap``, interlocked
2130+
operations that need a texel pointer use ``OpUntypedImageTexelPointerEXT``.
2131+
The image descriptor pointer produced by ``OpUntypedAccessChainKHR`` is passed
2132+
directly to the texel-pointer instruction instead of first storing the image
2133+
handle into a function-scope image variable:
2134+
2135+
.. code:: spirv
2136+
2137+
%image_type = OpTypeImage %uint 2D 2 0 0 2 R32ui
2138+
%image_array = OpTypeRuntimeArray %image_type
2139+
%descriptor = OpUntypedAccessChainKHR %uptr_uc %image_array %resource_heap %index
2140+
%uptr_image = OpTypeUntypedPointerKHR Image
2141+
%texel_ptr = OpUntypedImageTexelPointerEXT %uptr_image %image_type %descriptor %coord %sample
2142+
%old = OpAtomicIAdd %uint %texel_ptr %scope %semantics %value
2143+
2144+
This path supports texture, RWTexture, sampler, Buffer/RWBuffer,
2145+
StructuredBuffer/RWStructuredBuffer without associated counter operations,
2146+
ByteAddressBuffer/RWByteAddressBuffer, ConstantBuffer, and TextureBuffer heap
2147+
loads, including direct field and array-element accesses for
2148+
``ConstantBuffer<T>`` and ``TextureBuffer<T>``. ``NonUniformResourceIndex`` is
2149+
accepted but the ``NonUniform`` decoration is not emitted on
2150+
``OpUntypedAccessChainKHR`` or the loaded value; ``SPV_EXT_descriptor_heap``
2151+
deprecates the ``NonUniform`` decoration for heap accesses.
2152+
2153+
Append/consume structured buffers and UAV counter heap lowering are not
2154+
supported by the native descriptor heap path yet. Those forms should continue
2155+
to use the default emulated heap lowering, or DXC will emit a diagnostic for
2156+
unsupported append/consume structured-buffer heap loads. Heap-loaded
2157+
``RWStructuredBuffer`` resources are supported for ordinary data access, but
2158+
associated counter operations such as ``IncrementCounter`` and
2159+
``DecrementCounter`` emit a diagnostic because the native descriptor heap path
2160+
does not recover an associated counter descriptor.
2161+
20772162
HLSL Expressions
20782163
================
20792164

tools/clang/include/clang/SPIRV/SpirvBuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ class SpirvBuilder {
277277
/// \brief Creates an OpUntypedImageTexelPointerEXT SPIR-V instruction with
278278
/// the given parameters.
279279
SpirvUntypedImageTexelPointerEXT *createUntypedImageTexelPointerEXT(
280-
QualType resultType, SpirvInstruction *image,
280+
QualType resultType, const SpirvType *imageType, SpirvInstruction *image,
281281
SpirvInstruction *coordinate, SpirvInstruction *sample, SourceLocation);
282282

283283
/// \brief Creates an OpConverPtrToU SPIR-V instruction with the given

tools/clang/include/clang/SPIRV/SpirvContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ class SpirvContext {
298298
spv::StorageClass);
299299

300300
const UntypedPointerKHRType *getUntypedPointerKHRType(spv::StorageClass sc);
301+
const BufferEXTType *getBufferEXTType(spv::StorageClass sc);
301302

302303
FunctionType *getFunctionType(const SpirvType *ret,
303304
llvm::ArrayRef<const SpirvType *> param);
@@ -536,6 +537,9 @@ class SpirvContext {
536537
llvm::DenseMap<spv::StorageClass, const UntypedPointerKHRType *,
537538
StorageClassDenseMapInfo>
538539
untypedPointerKHRTypes;
540+
llvm::DenseMap<spv::StorageClass, const BufferEXTType *,
541+
StorageClassDenseMapInfo>
542+
bufferEXTTypes;
539543
llvm::MapVector<QualType, const ForwardPointerType *> forwardPointerTypes;
540544
llvm::MapVector<QualType, const SpirvPointerType *> forwardReferences;
541545
llvm::DenseSet<FunctionType *, FunctionTypeMapInfo> functionTypes;

tools/clang/include/clang/SPIRV/SpirvInstruction.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,6 +2065,7 @@ class SpirvImageTexelPointer : public SpirvInstruction {
20652065
class SpirvUntypedImageTexelPointerEXT : public SpirvInstruction {
20662066
public:
20672067
SpirvUntypedImageTexelPointerEXT(QualType resultType, SourceLocation loc,
2068+
const SpirvType *imageType,
20682069
SpirvInstruction *image,
20692070
SpirvInstruction *coordinate,
20702071
SpirvInstruction *sample);
@@ -2078,11 +2079,22 @@ class SpirvUntypedImageTexelPointerEXT : public SpirvInstruction {
20782079

20792080
bool invokeVisitor(Visitor *v) override;
20802081

2082+
const SpirvType *getImageType() const { return imageType; }
20812083
SpirvInstruction *getImage() const { return image; }
20822084
SpirvInstruction *getCoordinate() const { return coordinate; }
20832085
SpirvInstruction *getSample() const { return sample; }
20842086

2087+
void replaceOperand(
2088+
llvm::function_ref<SpirvInstruction *(SpirvInstruction *)> remapOp,
2089+
bool inEntryFunctionWrapper) override {
2090+
// imageType is a compile-time SpirvType, not an SSA operand.
2091+
image = remapOp(image);
2092+
coordinate = remapOp(coordinate);
2093+
sample = remapOp(sample);
2094+
}
2095+
20852096
private:
2097+
const SpirvType *imageType;
20862098
SpirvInstruction *image;
20872099
SpirvInstruction *coordinate;
20882100
SpirvInstruction *sample;

tools/clang/lib/SPIRV/CapabilityVisitor.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -955,8 +955,10 @@ bool CapabilityVisitor::visit(SpirvModule *, Visitor::Phase phase) {
955955
{spv::Capability::QuadControlKHR});
956956

957957
if (spvOptions.useDescriptorHeap) {
958-
addExtension(Extension::EXT_descriptor_heap, "DescriptorHeap", {});
959-
addExtension(Extension::KHR_untyped_pointers, "DescriptorHeap", {});
958+
const llvm::StringRef feature = "DescriptorHeap";
959+
featureManager.requestTargetEnv(SPV_ENV_VULKAN_1_3, feature, {});
960+
addExtension(Extension::EXT_descriptor_heap, feature, {});
961+
addExtension(Extension::KHR_untyped_pointers, feature, {});
960962
addCapability(spv::Capability::DescriptorHeapEXT);
961963
}
962964

tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,12 @@ DeclResultIdMapper::createFnVar(const VarDecl *var,
11361136
return varInstr;
11371137
}
11381138

1139+
void DeclResultIdMapper::registerFnVarAlias(const VarDecl *var,
1140+
SpirvInstruction *varInstr) {
1141+
if (varInstr)
1142+
registerVariableForDecl(var, createDeclSpirvInfo(varInstr));
1143+
}
1144+
11391145
SpirvDebugGlobalVariable *DeclResultIdMapper::createDebugGlobalVariable(
11401146
SpirvVariable *var, const QualType &type, const SourceLocation &loc,
11411147
const StringRef &name) {

tools/clang/lib/SPIRV/DeclResultIdMapper.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#ifndef LLVM_CLANG_LIB_SPIRV_DECLRESULTIDMAPPER_H
1111
#define LLVM_CLANG_LIB_SPIRV_DECLRESULTIDMAPPER_H
1212

13-
#include <tuple>
1413
#include <vector>
1514

1615
#include "dxc/Support/SPIRVOptions.h"
@@ -286,6 +285,9 @@ class DeclResultIdMapper {
286285
SpirvVariable *createFnVar(const VarDecl *var,
287286
llvm::Optional<SpirvInstruction *> init);
288287

288+
/// \brief Registers a function-scope alias to an existing instruction.
289+
void registerFnVarAlias(const VarDecl *var, SpirvInstruction *varInstr);
290+
289291
/// \brief Creates a file-scope variable and returns its instruction.
290292
SpirvVariable *createFileVar(const VarDecl *var,
291293
llvm::Optional<SpirvInstruction *> init);

tools/clang/lib/SPIRV/EmitVisitor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,7 @@ bool EmitVisitor::visit(SpirvUntypedImageTexelPointerEXT *inst) {
820820
initInstruction(inst);
821821
curInst.push_back(inst->getResultTypeId());
822822
curInst.push_back(getOrAssignResultId<SpirvInstruction>(inst));
823+
curInst.push_back(typeHandler.emitType(inst->getImageType()));
823824
curInst.push_back(getOrAssignResultId<SpirvInstruction>(inst->getImage()));
824825
curInst.push_back(
825826
getOrAssignResultId<SpirvInstruction>(inst->getCoordinate()));

tools/clang/lib/SPIRV/LowerTypeVisitor.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,12 @@ bool LowerTypeVisitor::visitInstruction(SpirvInstruction *instr) {
224224
instr->setResultType(pointerType);
225225
break;
226226
}
227+
case spv::Op::OpUntypedImageTexelPointerEXT: {
228+
instr->setResultType(
229+
spvContext.getUntypedPointerKHRType(spv::StorageClass::Image));
230+
instr->setStorageClass(spv::StorageClass::Image);
231+
break;
232+
}
227233
// Sparse image operations return a sparse residency struct.
228234
case spv::Op::OpImageSparseSampleImplicitLod:
229235
case spv::Op::OpImageSparseSampleExplicitLod:

tools/clang/lib/SPIRV/SpirvBuilder.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,13 +533,14 @@ SpirvImageTexelPointer *SpirvBuilder::createImageTexelPointer(
533533

534534
SpirvUntypedImageTexelPointerEXT *
535535
SpirvBuilder::createUntypedImageTexelPointerEXT(QualType resultType,
536+
const SpirvType *imageType,
536537
SpirvInstruction *image,
537538
SpirvInstruction *coordinate,
538539
SpirvInstruction *sample,
539540
SourceLocation loc) {
540541
assert(insertPoint && "null insert point");
541542
auto *instruction = new (context) SpirvUntypedImageTexelPointerEXT(
542-
resultType, loc, image, coordinate, sample);
543+
resultType, loc, imageType, image, coordinate, sample);
543544
insertPoint->addInstruction(instruction);
544545
return instruction;
545546
}

0 commit comments

Comments
 (0)