Skip to content

Commit 02fd8e2

Browse files
committed
[SPIR-V] Add sampler & resource heaps for textures
Resource & Sampler heaps are already implemented in DXC, but rely on an emulated heap. A new VK/SPV extension bring actual descriptor heaps. This is the first step toward a complete support. This commits focuses on Texture/Sampler/Buffer resources, which are all backed by OpTypeImage/OpTypeSampler. This path is a bit simpler as we have no ArrayStride, nor OpAccessChain legalization issues: the whole image handle loading is handled in DXC, and the rest follows the normal path. Next step is to implement RWStructuredBuffer/StructuredBuffer support, with counters and chain legalization. Related to #8243
1 parent 539374d commit 02fd8e2

26 files changed

Lines changed: 598 additions & 73 deletions

include/dxc/Support/HLSLOptions.td

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,17 @@ def Wno_vk_emulated_features : Joined<["-"], "Wno-vk-emulated-features">, Group<
429429
HelpText<"Do not emit warnings for emulated features resulting from no direct mapping">;
430430
def fspv_print_all: Flag<["-"], "fspv-print-all">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
431431
HelpText<"Print the SPIR-V module before each pass and after the last one. Useful for debugging SPIR-V legalization and optimization passes.">;
432+
def fspv_use_emulated_heap
433+
: Flag<["-"], "fspv-use-emulated-heap">,
434+
Group<spirv_Group>,
435+
Flags<[CoreOption, DriverOption]>,
436+
HelpText<
437+
"Use emulated descriptor heap using descriptor indexing (default).">;
438+
def fspv_use_descriptor_heap
439+
: Flag<["-"], "fspv-use-descriptor-heap">,
440+
Group<spirv_Group>,
441+
Flags<[CoreOption, DriverOption]>,
442+
HelpText<"Use SPV_EXT_descriptor_heap for HLSL descriptor heaps.">;
432443
def Oconfig : CommaJoined<["-"], "Oconfig=">, Group<spirv_Group>, Flags<[CoreOption]>,
433444
HelpText<"Specify a comma-separated list of SPIRV-Tools passes to customize optimization configuration (see http://khr.io/hlsl2spirv#optimization)">;
434445
def fspv_preserve_bindings : Flag<["-"], "fspv-preserve-bindings">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,

include/dxc/Support/SPIRVOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct SpirvCodeGenOptions {
7272
bool enableMaximalReconvergence = false;
7373
bool useVulkanMemoryModel = false;
7474
bool useUnknownImageFormat = false;
75+
bool useDescriptorHeap = false;
7576
bool IEEEStrict = false;
7677
/// Maximum length in words for the OpString literal containing the shader
7778
/// source for DebugSource and DebugSourceContinued. If the source code length

lib/DxcSupport/HLSLOptions.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,9 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
11391139
opts.SpirvOptions.useUnknownImageFormat =
11401140
Args.hasFlag(OPT_fspv_use_unknown_image_format, OPT_INVALID, false);
11411141

1142+
opts.SpirvOptions.useDescriptorHeap = Args.hasFlag(
1143+
OPT_fspv_use_descriptor_heap, OPT_fspv_use_emulated_heap, false);
1144+
11421145
if (!handleVkShiftArgs(Args, OPT_fvk_b_shift, "b", &opts.SpirvOptions.bShift,
11431146
errors) ||
11441147
!handleVkShiftArgs(Args, OPT_fvk_t_shift, "t", &opts.SpirvOptions.tShift,
@@ -1295,6 +1298,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
12951298
Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false) ||
12961299
Args.hasFlag(OPT_fspv_fix_func_call_arguments, OPT_INVALID, false) ||
12971300
Args.hasFlag(OPT_fspv_print_all, OPT_INVALID, false) ||
1301+
Args.hasFlag(OPT_fspv_use_emulated_heap, OPT_INVALID, false) ||
1302+
Args.hasFlag(OPT_fspv_use_descriptor_heap, OPT_INVALID, false) ||
12981303
Args.hasFlag(OPT_Wno_vk_ignored_features, OPT_INVALID, false) ||
12991304
Args.hasFlag(OPT_Wno_vk_emulated_features, OPT_INVALID, false) ||
13001305
Args.hasFlag(OPT_fvk_auto_shift_bindings, OPT_INVALID, false) ||

tools/clang/include/clang/SPIRV/FeatureManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ enum class Extension {
6666
KHR_float_controls,
6767
NV_shader_subgroup_partitioned,
6868
KHR_quad_control,
69+
EXT_descriptor_heap,
70+
KHR_untyped_pointers,
6971
Unknown,
7072
};
7173

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

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,12 @@ class SpirvBuilder {
274274
SpirvInstruction *sample,
275275
SourceLocation);
276276

277+
/// \brief Creates an OpUntypedImageTexelPointerEXT SPIR-V instruction with
278+
/// the given parameters.
279+
SpirvUntypedImageTexelPointerEXT *createUntypedImageTexelPointerEXT(
280+
QualType resultType, SpirvInstruction *image,
281+
SpirvInstruction *coordinate, SpirvInstruction *sample, SourceLocation);
282+
277283
/// \brief Creates an OpConverPtrToU SPIR-V instruction with the given
278284
/// parameters.
279285
SpirvConvertPtrToU *createConvertPtrToU(SpirvInstruction *ptr, QualType type);
@@ -282,6 +288,12 @@ class SpirvBuilder {
282288
/// parameters.
283289
SpirvConvertUToPtr *createConvertUToPtr(SpirvInstruction *val, QualType type);
284290

291+
/// \brief Creates an OpBufferPointerEXT SPIR-V instruction with the given
292+
/// parameters.
293+
SpirvBufferPointerEXT *createBufferPointerEXT(const SpirvType *resultType,
294+
SpirvInstruction *buffer,
295+
SourceLocation);
296+
285297
/// \brief Creates SPIR-V instructions for sampling the given image.
286298
///
287299
/// If compareVal is given a non-zero value, *Dref* variants of OpImageSample*
@@ -630,8 +642,7 @@ class SpirvBuilder {
630642
/// support a single entry point per module for now.
631643
inline void addEntryPoint(spv::ExecutionModel em, SpirvFunction *target,
632644
llvm::StringRef targetName,
633-
llvm::ArrayRef<SpirvVariable *> interfaces);
634-
645+
llvm::ArrayRef<SpirvInstruction *> interfaces);
635646
/// \brief Sets the shader model version, source file name, and source file
636647
/// content. Returns the SpirvString instruction of the file name.
637648
inline SpirvString *setDebugSource(uint32_t major, uint32_t minor,
@@ -708,6 +719,18 @@ class SpirvBuilder {
708719
llvm::Optional<SpirvInstruction *> init = llvm::None,
709720
SourceLocation loc = {});
710721

722+
/// \brief Adds an untyped module variable.
723+
SpirvUntypedVariableKHR *createUntypedVariableKHR(
724+
const SpirvType *valueType, spv::StorageClass storageClass,
725+
SourceLocation loc = {}, llvm::StringRef name = "heap");
726+
727+
/// \brief Creates an OpUntypedAccessChainKHR instruction.
728+
SpirvUntypedAccessChainKHR *
729+
createUntypedAccessChainKHR(const SpirvType *resultType,
730+
const SpirvType *baseType, SpirvInstruction *base,
731+
llvm::ArrayRef<SpirvInstruction *> indexes,
732+
SourceLocation loc);
733+
711734
/// \brief Decorates the given target with the given location.
712735
void decorateLocation(SpirvInstruction *target, uint32_t location);
713736

@@ -974,13 +997,12 @@ void SpirvBuilder::setMemoryModel(spv::AddressingModel addrModel,
974997
mod->setMemoryModel(new (context) SpirvMemoryModel(addrModel, memModel));
975998
}
976999

977-
void SpirvBuilder::addEntryPoint(spv::ExecutionModel em, SpirvFunction *target,
978-
llvm::StringRef targetName,
979-
llvm::ArrayRef<SpirvVariable *> interfaces) {
1000+
void SpirvBuilder::addEntryPoint(
1001+
spv::ExecutionModel em, SpirvFunction *target, llvm::StringRef targetName,
1002+
llvm::ArrayRef<SpirvInstruction *> interfaces) {
9801003
mod->addEntryPoint(new (context) SpirvEntryPoint(
9811004
target->getSourceLocation(), em, target, targetName, interfaces));
9821005
}
983-
9841006
SpirvString *
9851007
SpirvBuilder::setDebugSource(uint32_t major, uint32_t minor,
9861008
const std::vector<llvm::StringRef> &fileNames,

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,8 @@ class SpirvContext {
297297
const SpirvPointerType *getPointerType(const SpirvType *pointee,
298298
spv::StorageClass);
299299

300+
const UntypedPointerKHRType *getUntypedPointerKHRType(spv::StorageClass sc);
301+
300302
FunctionType *getFunctionType(const SpirvType *ret,
301303
llvm::ArrayRef<const SpirvType *> param);
302304

@@ -531,6 +533,9 @@ class SpirvContext {
531533
llvm::SmallVector<const HybridStructType *, 8> hybridStructTypes;
532534
llvm::DenseMap<const SpirvType *, SCToPtrTyMap> pointerTypes;
533535
llvm::SmallVector<const HybridPointerType *, 8> hybridPointerTypes;
536+
llvm::DenseMap<spv::StorageClass, const UntypedPointerKHRType *,
537+
StorageClassDenseMapInfo>
538+
untypedPointerKHRTypes;
534539
llvm::MapVector<QualType, const ForwardPointerType *> forwardPointerTypes;
535540
llvm::MapVector<QualType, const SpirvPointerType *> forwardReferences;
536541
llvm::DenseSet<FunctionType *, FunctionTypeMapInfo> functionTypes;

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

Lines changed: 131 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,20 @@ class SpirvInstruction {
4848
// "Metadata" kinds
4949
// In the order of logical layout
5050

51-
IK_Capability, // OpCapability
52-
IK_Extension, // OpExtension
53-
IK_ExtInstImport, // OpExtInstImport
54-
IK_MemoryModel, // OpMemoryModel
55-
IK_EntryPoint, // OpEntryPoint
56-
IK_ExecutionMode, // OpExecutionMode
57-
IK_ExecutionModeId, // OpExecutionModeId
58-
IK_String, // OpString (debug)
59-
IK_Source, // OpSource (debug)
60-
IK_ModuleProcessed, // OpModuleProcessed (debug)
61-
IK_Decoration, // Op*Decorate
62-
IK_Type, // OpType*
63-
IK_Variable, // OpVariable
51+
IK_Capability, // OpCapability
52+
IK_Extension, // OpExtension
53+
IK_ExtInstImport, // OpExtInstImport
54+
IK_MemoryModel, // OpMemoryModel
55+
IK_EntryPoint, // OpEntryPoint
56+
IK_ExecutionMode, // OpExecutionMode
57+
IK_ExecutionModeId, // OpExecutionModeId
58+
IK_String, // OpString (debug)
59+
IK_Source, // OpSource (debug)
60+
IK_ModuleProcessed, // OpModuleProcessed (debug)
61+
IK_Decoration, // Op*Decorate
62+
IK_Type, // OpType*
63+
IK_Variable, // OpVariable
64+
IK_UntypedVariableKHR, // OpUntypedVariableKHR
6465

6566
// Different kind of constants. Order matters.
6667
IK_ConstantBoolean,
@@ -73,6 +74,7 @@ class SpirvInstruction {
7374
// Pointer <-> uint conversions.
7475
IK_ConvertPtrToU,
7576
IK_ConvertUToPtr,
77+
IK_BufferPointerEXT, // OpBufferPointerEXT
7678

7779
// OpUndef
7880
IK_Undef,
@@ -101,6 +103,7 @@ class SpirvInstruction {
101103
// In alphabetical order
102104

103105
IK_AccessChain, // OpAccessChain
106+
IK_UntypedAccessChainKHR, // OpUntypedAccessChainKHR
104107
IK_ArrayLength, // OpArrayLength
105108
IK_Atomic, // OpAtomic*
106109
IK_Barrier, // Op*Barrier
@@ -123,23 +126,24 @@ class SpirvInstruction {
123126

124127
IK_GroupNonUniformOp, // Group non-uniform operations
125128

126-
IK_ImageOp, // OpImage*
127-
IK_ImageQuery, // OpImageQuery*
128-
IK_ImageSparseTexelsResident, // OpImageSparseTexelsResident
129-
IK_ImageTexelPointer, // OpImageTexelPointer
130-
IK_Load, // OpLoad
131-
IK_RayQueryOpKHR, // KHR rayquery ops
132-
IK_RayTracingOpNV, // NV raytracing ops
133-
IK_ReadClock, // OpReadClock
134-
IK_SampledImage, // OpSampledImage
135-
IK_Select, // OpSelect
136-
IK_SpecConstantBinaryOp, // SpecConstant binary operations
137-
IK_SpecConstantUnaryOp, // SpecConstant unary operations
138-
IK_Store, // OpStore
139-
IK_UnaryOp, // Unary operations
140-
IK_NullaryOp, // Nullary operations
141-
IK_VectorShuffle, // OpVectorShuffle
142-
IK_SpirvIntrinsicInstruction, // Spirv Intrinsic Instructions
129+
IK_ImageOp, // OpImage*
130+
IK_ImageQuery, // OpImageQuery*
131+
IK_ImageSparseTexelsResident, // OpImageSparseTexelsResident
132+
IK_ImageTexelPointer, // OpImageTexelPointer
133+
IK_UntypedImageTexelPointerEXT, // OpUntypedImageTexelPointerEXT
134+
IK_Load, // OpLoad
135+
IK_RayQueryOpKHR, // KHR rayquery ops
136+
IK_RayTracingOpNV, // NV raytracing ops
137+
IK_ReadClock, // OpReadClock
138+
IK_SampledImage, // OpSampledImage
139+
IK_Select, // OpSelect
140+
IK_SpecConstantBinaryOp, // SpecConstant binary operations
141+
IK_SpecConstantUnaryOp, // SpecConstant unary operations
142+
IK_Store, // OpStore
143+
IK_UnaryOp, // Unary operations
144+
IK_NullaryOp, // Nullary operations
145+
IK_VectorShuffle, // OpVectorShuffle
146+
IK_SpirvIntrinsicInstruction, // Spirv Intrinsic Instructions
143147

144148
// For DebugInfo instructions defined in
145149
// OpenCL.DebugInfo.100 and NonSemantic.Shader.DebugInfo.100
@@ -387,7 +391,7 @@ class SpirvEntryPoint : public SpirvInstruction {
387391
public:
388392
SpirvEntryPoint(SourceLocation loc, spv::ExecutionModel executionModel,
389393
SpirvFunction *entryPoint, llvm::StringRef nameStr,
390-
llvm::ArrayRef<SpirvVariable *> iface);
394+
llvm::ArrayRef<SpirvInstruction *> iface);
391395

392396
DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvEntryPoint)
393397

@@ -401,13 +405,15 @@ class SpirvEntryPoint : public SpirvInstruction {
401405
spv::ExecutionModel getExecModel() const { return execModel; }
402406
SpirvFunction *getEntryPoint() const { return entryPoint; }
403407
llvm::StringRef getEntryPointName() const { return name; }
404-
llvm::ArrayRef<SpirvVariable *> getInterface() const { return interfaceVec; }
408+
llvm::ArrayRef<SpirvInstruction *> getInterface() const {
409+
return interfaceVec;
410+
}
405411

406412
private:
407413
spv::ExecutionModel execModel;
408414
SpirvFunction *entryPoint;
409415
std::string name;
410-
llvm::SmallVector<SpirvVariable *, 8> interfaceVec;
416+
llvm::SmallVector<SpirvInstruction *, 8> interfaceVec;
411417
};
412418

413419
class SpirvExecutionModeBase : public SpirvInstruction {
@@ -640,6 +646,52 @@ class SpirvVariable : public SpirvInstruction {
640646
std::string hlslUserType;
641647
};
642648

649+
/// \brief OpUntypedVariableKHR instruction
650+
class SpirvUntypedVariableKHR : public SpirvInstruction {
651+
public:
652+
SpirvUntypedVariableKHR(QualType resultType, SourceLocation loc,
653+
spv::StorageClass sc);
654+
655+
SpirvUntypedVariableKHR(const SpirvType *spvType, SourceLocation loc,
656+
spv::StorageClass sc);
657+
658+
DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvUntypedVariableKHR)
659+
660+
// For LLVM-style RTTI
661+
static bool classof(const SpirvInstruction *inst) {
662+
return inst->getKind() == IK_UntypedVariableKHR;
663+
}
664+
665+
bool invokeVisitor(Visitor *v) override;
666+
};
667+
668+
/// \brief Untyped Access Chain instruction representation
669+
/// (OpUntypedAccessChainKHR)
670+
class SpirvUntypedAccessChainKHR : public SpirvInstruction {
671+
public:
672+
SpirvUntypedAccessChainKHR(const SpirvType *resultType, SourceLocation loc,
673+
const SpirvType *baseType, SpirvInstruction *base,
674+
llvm::ArrayRef<SpirvInstruction *> indexVec);
675+
676+
DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvUntypedAccessChainKHR)
677+
678+
// For LLVM-style RTTI
679+
static bool classof(const SpirvInstruction *inst) {
680+
return inst->getKind() == IK_UntypedAccessChainKHR;
681+
}
682+
683+
bool invokeVisitor(Visitor *v) override;
684+
685+
SpirvInstruction *getBase() const { return base; }
686+
const SpirvType *getBaseType() const { return baseType; };
687+
llvm::ArrayRef<SpirvInstruction *> getIndices() const { return indices; }
688+
689+
private:
690+
const SpirvType *baseType;
691+
SpirvInstruction *base;
692+
llvm::SmallVector<SpirvInstruction *, 4> indices;
693+
};
694+
643695
class SpirvFunctionParameter : public SpirvInstruction {
644696
public:
645697
SpirvFunctionParameter(QualType resultType, bool isPrecise, bool isNointerp,
@@ -1542,6 +1594,26 @@ class SpirvConvertUToPtr : public SpirvInstruction {
15421594
SpirvInstruction *val;
15431595
};
15441596

1597+
class SpirvBufferPointerEXT : public SpirvInstruction {
1598+
public:
1599+
SpirvBufferPointerEXT(const SpirvType *resultType, SourceLocation loc,
1600+
SpirvInstruction *buffer);
1601+
1602+
DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvBufferPointerEXT)
1603+
1604+
// For LLVM-style RTTI
1605+
static bool classof(const SpirvInstruction *inst) {
1606+
return inst->getKind() == IK_BufferPointerEXT;
1607+
}
1608+
1609+
bool invokeVisitor(Visitor *v) override;
1610+
1611+
SpirvInstruction *getBuffer() const { return buffer; }
1612+
1613+
private:
1614+
SpirvInstruction *buffer;
1615+
};
1616+
15451617
class SpirvUndef : public SpirvInstruction {
15461618
public:
15471619
SpirvUndef(QualType type);
@@ -2002,6 +2074,32 @@ class SpirvImageTexelPointer : public SpirvInstruction {
20022074
SpirvInstruction *sample;
20032075
};
20042076

2077+
class SpirvUntypedImageTexelPointerEXT : public SpirvInstruction {
2078+
public:
2079+
SpirvUntypedImageTexelPointerEXT(QualType resultType, SourceLocation loc,
2080+
SpirvInstruction *image,
2081+
SpirvInstruction *coordinate,
2082+
SpirvInstruction *sample);
2083+
2084+
DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvUntypedImageTexelPointerEXT)
2085+
2086+
// For LLVM-style RTTI
2087+
static bool classof(const SpirvInstruction *inst) {
2088+
return inst->getKind() == IK_UntypedImageTexelPointerEXT;
2089+
}
2090+
2091+
bool invokeVisitor(Visitor *v) override;
2092+
2093+
SpirvInstruction *getImage() const { return image; }
2094+
SpirvInstruction *getCoordinate() const { return coordinate; }
2095+
SpirvInstruction *getSample() const { return sample; }
2096+
2097+
private:
2098+
SpirvInstruction *image;
2099+
SpirvInstruction *coordinate;
2100+
SpirvInstruction *sample;
2101+
};
2102+
20052103
/// \brief Load instruction representation
20062104
class SpirvLoad : public SpirvInstruction {
20072105
public:

0 commit comments

Comments
 (0)