Skip to content

Commit 8f0184a

Browse files
pacxxtex3d
authored andcommitted
DXC extension for DXR Payload Access Qualifiers (#3171)
This extension adds qualifiers for payload structures accompanied with semantic checks and code generation. This feature is opt-in for SM 6.6 libraries. The information added by the developer is stored in the DXIL type system and a new metadata node is emitted during code generation. The metadata is not necessary for correct translation of DXIL, so it may be safely ignored, but it provides hints to unlock potential optimizations in payload storage between DXR shader stages.
1 parent 09569b5 commit 8f0184a

38 files changed

Lines changed: 3529 additions & 23 deletions

include/dxc/DXIL/DxilConstants.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,28 @@ namespace DXIL {
14891489
CandidateProceduralPrimitive = 1,
14901490
};
14911491

1492+
enum class PayloadAccessQualifier : uint32_t {
1493+
NoAccess = 0,
1494+
Read = 1,
1495+
Write = 2,
1496+
ReadWrite = 3
1497+
};
1498+
1499+
enum class PayloadAccessShaderStage : uint32_t {
1500+
Caller = 0,
1501+
Closesthit = 1,
1502+
Miss = 2,
1503+
Anyhit = 3,
1504+
Invalid = 0xffffffffu
1505+
};
1506+
1507+
// Allocate 4 bits per shader stage:
1508+
// bits 0-1 for payload access qualifiers
1509+
// bits 2-3 reserved for future use
1510+
const uint32_t PayloadAccessQualifierBitsPerStage = 4;
1511+
const uint32_t PayloadAccessQualifierValidMaskPerStage = 3;
1512+
const uint32_t PayloadAccessQualifierValidMask = 0x00003333;
1513+
14921514
inline bool IsValidHitGroupType(HitGroupType type) {
14931515
return (type >= HitGroupType::Triangle && type < HitGroupType::LastEntry);
14941516
}

include/dxc/DXIL/DxilMetadataHelper.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class MDNode;
3232
class NamedMDNode;
3333
class GlobalVariable;
3434
class StringRef;
35+
class Type;
3536
}
3637

3738
namespace hlsl {
@@ -48,6 +49,8 @@ class DxilSampler;
4849
class DxilTypeSystem;
4950
class DxilStructAnnotation;
5051
class DxilFieldAnnotation;
52+
class DxilPayloadAnnotation;
53+
class DxilPayloadFieldAnnotation;
5154
class DxilTemplateArgAnnotation;
5255
class DxilFunctionAnnotation;
5356
class DxilParameterAnnotation;
@@ -217,6 +220,10 @@ class DxilMDHelper {
217220
static const unsigned kDxilFieldAnnotationPreciseTag = 8;
218221
static const unsigned kDxilFieldAnnotationCBUsedTag = 9;
219222

223+
// DXR Payload Annotations
224+
static const unsigned kDxilPayloadAnnotationStructTag = 0;
225+
static const unsigned kDxilPayloadFieldAnnotationAccessTag = 0;
226+
220227
// StructAnnotation extended property tags (DXIL 1.5+ only, appended)
221228
static const unsigned kDxilTemplateArgumentsTag = 0; // Name for name-value list of extended struct properties
222229
// TemplateArgument tags
@@ -249,6 +256,9 @@ class DxilMDHelper {
249256
static const char kDxilValidatorVersionMDName[];
250257
// Validator version uses the same constants for fields as kDxilVersion*
251258

259+
// DXR Payload Annotations metadata.
260+
static const char kDxilDxrPayloadAnnotationsMDName[];
261+
252262
// Extended shader property tags.
253263
static const unsigned kDxilShaderFlagsTag = 0;
254264
static const unsigned kDxilGSStateTag = 1;
@@ -414,6 +424,16 @@ class DxilMDHelper {
414424
llvm::Metadata *EmitDxilTemplateArgAnnotation(const DxilTemplateArgAnnotation &annotation);
415425
void LoadDxilTemplateArgAnnotation(const llvm::MDOperand &MDO, DxilTemplateArgAnnotation &annotation);
416426

427+
// DXR Payload Annotations
428+
void EmitDxrPayloadAnnotations(DxilTypeSystem &TypeSystem);
429+
llvm::Metadata *EmitDxrPayloadStructAnnotation(const DxilPayloadAnnotation& SA);
430+
llvm::Metadata *EmitDxrPayloadFieldAnnotation(const DxilPayloadFieldAnnotation &FA, llvm::Type* fieldType);
431+
void LoadDxrPayloadAnnotationNode(const llvm::MDTuple &MDT, DxilTypeSystem &TypeSystem);
432+
void LoadDxrPayloadAnnotations(DxilTypeSystem &TypeSystem);
433+
void LoadDxrPayloadFieldAnnoations(const llvm::MDOperand& MDO, DxilPayloadAnnotation& SA);
434+
void LoadDxrPayloadFieldAnnoation(const llvm::MDOperand &MDO, DxilPayloadFieldAnnotation &FA);
435+
void LoadDxrPayloadAccessQualifiers(const llvm::MDOperand &MDO, DxilPayloadFieldAnnotation &FA);
436+
417437
// Function props.
418438
llvm::MDTuple *EmitDxilFunctionProps(const hlsl::DxilFunctionProps *props,
419439
const llvm::Function *F);

include/dxc/DXIL/DxilModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ class DxilModule {
166166

167167
// DXIL type system.
168168
DxilTypeSystem &GetTypeSystem();
169+
const DxilTypeSystem &GetTypeSystem() const;
169170

170171
/// Emit llvm.used array to make sure that optimizations do not remove unreferenced globals.
171172
void EmitLLVMUsed();
@@ -386,6 +387,9 @@ class DxilModule {
386387
uint32_t m_IntermediateFlags;
387388
uint32_t m_AutoBindingSpace;
388389

390+
// porperties infered from the DXILTypeSystem
391+
bool m_bHasPayloadQualifiers;
392+
389393
std::unique_ptr<DxilSubobjects> m_pSubobjects;
390394

391395
// m_bMetadataErrors is true if non-fatal metadata errors were encountered.

include/dxc/DXIL/DxilTypeSystem.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#pragma once
1313
#include "llvm/ADT/StringRef.h"
1414
#include "llvm/ADT/MapVector.h"
15+
#include "dxc/DXIL/DxilConstants.h"
1516
#include "dxc/DXIL/DxilCompType.h"
1617
#include "dxc/DXIL/DxilInterpolationMode.h"
1718

@@ -140,6 +141,46 @@ class DxilStructAnnotation {
140141
};
141142

142143

144+
/// Use this class to represent type annotation for DXR payload field.
145+
class DxilPayloadFieldAnnotation {
146+
public:
147+
148+
static unsigned GetBitOffsetForShaderStage(DXIL::PayloadAccessShaderStage shaderStage);
149+
150+
DxilPayloadFieldAnnotation() = default;
151+
152+
bool HasCompType() const;
153+
const CompType &GetCompType() const;
154+
void SetCompType(CompType::Kind kind);
155+
156+
uint32_t GetPayloadFieldQualifierMask() const;
157+
void SetPayloadFieldQualifierMask(uint32_t fieldBitmask);
158+
void AddPayloadFieldQualifier(DXIL::PayloadAccessShaderStage shaderStage, DXIL::PayloadAccessQualifier qualifier);
159+
DXIL::PayloadAccessQualifier GetPayloadFieldQualifier(DXIL::PayloadAccessShaderStage shaderStage) const;
160+
bool HasAnnotations() const;
161+
162+
private:
163+
CompType m_CompType;
164+
unsigned m_bitmask = 0;
165+
};
166+
167+
/// Use this class to represent DXR payload structures.
168+
class DxilPayloadAnnotation {
169+
friend class DxilTypeSystem;
170+
171+
public:
172+
unsigned GetNumFields() const;
173+
DxilPayloadFieldAnnotation &GetFieldAnnotation(unsigned FieldIdx);
174+
const DxilPayloadFieldAnnotation &GetFieldAnnotation(unsigned FieldIdx) const;
175+
const llvm::StructType *GetStructType() const;
176+
void SetStructType(const llvm::StructType *Ty);
177+
178+
private:
179+
const llvm::StructType *m_pStructType;
180+
std::vector<DxilPayloadFieldAnnotation> m_FieldAnnotations;
181+
};
182+
183+
143184
enum class DxilParamInputQual {
144185
In,
145186
Out,
@@ -192,6 +233,7 @@ class DxilFunctionAnnotation {
192233
class DxilTypeSystem {
193234
public:
194235
using StructAnnotationMap = llvm::MapVector<const llvm::StructType *, std::unique_ptr<DxilStructAnnotation> >;
236+
using PayloadAnnotationMap = llvm::MapVector<const llvm::StructType *, std::unique_ptr<DxilPayloadAnnotation> >;
195237
using FunctionAnnotationMap = llvm::MapVector<const llvm::Function *, std::unique_ptr<DxilFunctionAnnotation> >;
196238

197239
DxilTypeSystem(llvm::Module *pModule);
@@ -202,6 +244,15 @@ class DxilTypeSystem {
202244
void EraseStructAnnotation(const llvm::StructType *pStructType);
203245

204246
StructAnnotationMap &GetStructAnnotationMap();
247+
const StructAnnotationMap &GetStructAnnotationMap() const;
248+
249+
DxilPayloadAnnotation *AddPayloadAnnotation(const llvm::StructType *pStructType);
250+
DxilPayloadAnnotation *GetPayloadAnnotation(const llvm::StructType *pStructType);
251+
const DxilPayloadAnnotation *GetPayloadAnnotation(const llvm::StructType *pStructType) const;
252+
void ErasePayloadAnnotation(const llvm::StructType *pStructType);
253+
254+
PayloadAnnotationMap &GetPayloadAnnotationMap();
255+
const PayloadAnnotationMap &GetPayloadAnnotationMap() const;
205256

206257
DxilFunctionAnnotation *AddFunctionAnnotation(const llvm::Function *pFunction);
207258
DxilFunctionAnnotation *GetFunctionAnnotation(const llvm::Function *pFunction);
@@ -227,6 +278,7 @@ class DxilTypeSystem {
227278
private:
228279
llvm::Module *m_pModule;
229280
StructAnnotationMap m_StructAnnotations;
281+
PayloadAnnotationMap m_PayloadAnnotations;
230282
FunctionAnnotationMap m_FunctionAnnotations;
231283

232284
DXIL::LowPrecisionMode m_LowPrecisionMode;

include/dxc/Support/HLSLOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ class DxcOpts {
200200
std::map<std::string, std::string> DxcOptimizationSelects; // OPT_opt_select
201201

202202
bool PrintAfterAll; // OPT_print_after_all
203+
bool EnablePayloadQualifiers = false; // OPT_enable_payload_qualifiers
203204

204205
// Rewriter Options
205206
RewriterOpts RWOpt;

include/dxc/Support/HLSLOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@ def enable_lifetime_markers : Flag<["-", "/"], "enable-lifetime-markers">, Group
277277
HelpText<"Enable generation of lifetime markers">;
278278
def disable_lifetime_markers : Flag<["-", "/"], "disable-lifetime-markers">, Group<hlslcomp_Group>, Flags<[CoreOption, HelpHidden]>,
279279
HelpText<"Disable generation of lifetime markers where they would be otherwise (6.6+)">;
280+
def enable_payload_qualifiers : Flag<["-", "/"], "enable-payload-qualifiers">, Group<hlslcomp_Group>, Flags<[CoreOption, RewriteOption, DriverOption]>,
281+
HelpText<"Enables support for payload access qualifiers for raytracing payloads in SM 6.6.">;
282+
def disable_payload_qualifiers : Flag<["-", "/"], "disable-payload-qualifiers">, Group<hlslcomp_Group>, Flags<[CoreOption, RewriteOption, DriverOption]>,
283+
HelpText<"Disables support for payload access qualifiers for raytracing payloads in SM 6.7.">;
280284

281285
// Used with API only
282286
def skip_serialization : Flag<["-", "/"], "skip-serialization">, Group<hlslcore_Group>, Flags<[CoreOption, HelpHidden]>,

lib/DXIL/DxilMetadataHelper.cpp

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const char DxilMDHelper::kDxilTempAllocaMDName[] = "dx.temp
5757
const char DxilMDHelper::kDxilNonUniformAttributeMDName[] = "dx.nonuniform";
5858
const char DxilMDHelper::kHLDxilResourceAttributeMDName[] = "dx.hl.resource.attribute";
5959
const char DxilMDHelper::kDxilValidatorVersionMDName[] = "dx.valver";
60+
const char DxilMDHelper::kDxilDxrPayloadAnnotationsMDName[] = "dx.dxrPayloadAnnotations";
6061

6162
// This named metadata is not valid in final module (should be moved to DxilContainer)
6263
const char DxilMDHelper::kDxilRootSignatureMDName[] = "dx.rootSignature";
@@ -77,14 +78,15 @@ const char DxilMDHelper::kDxilSourceArgsOldMDName[] = "llvm.db
7778
// This is reflection-only metadata
7879
const char DxilMDHelper::kDxilCountersMDName[] = "dx.counters";
7980

80-
static std::array<const char *, 7> DxilMDNames = { {
81+
static std::array<const char *, 8> DxilMDNames = { {
8182
DxilMDHelper::kDxilVersionMDName,
8283
DxilMDHelper::kDxilShaderModelMDName,
8384
DxilMDHelper::kDxilEntryPointsMDName,
8485
DxilMDHelper::kDxilResourcesMDName,
8586
DxilMDHelper::kDxilTypeSystemMDName,
8687
DxilMDHelper::kDxilValidatorVersionMDName,
8788
DxilMDHelper::kDxilViewIdStateMDName,
89+
DxilMDHelper::kDxilDxrPayloadAnnotationsMDName,
8890
}};
8991

9092
DxilMDHelper::DxilMDHelper(Module *pModule, std::unique_ptr<ExtraPropertyHelper> EPH)
@@ -850,6 +852,130 @@ void DxilMDHelper::LoadDxilTypeSystem(DxilTypeSystem &TypeSystem) {
850852
}
851853
}
852854

855+
void DxilMDHelper::EmitDxrPayloadAnnotations(DxilTypeSystem &TypeSystem) {
856+
auto &TypeMap = TypeSystem.GetPayloadAnnotationMap();
857+
vector<Metadata *> MDVals;
858+
MDVals.emplace_back(Uint32ToConstMD(kDxilPayloadAnnotationStructTag)); // Tag
859+
unsigned GVIdx = 0;
860+
for (auto it = TypeMap.begin(); it != TypeMap.end(); ++it, GVIdx++) {
861+
StructType *pStructType = const_cast<StructType *>(it->first);
862+
DxilPayloadAnnotation *pA = it->second.get();
863+
// Emit struct type field annotations.
864+
Metadata *pMD = EmitDxrPayloadStructAnnotation(*pA);
865+
866+
MDVals.push_back(ValueAsMetadata::get(UndefValue::get(pStructType)));
867+
MDVals.push_back(pMD);
868+
}
869+
870+
NamedMDNode *pDxrPayloadAnnotationsMD = m_pModule->getNamedMetadata(kDxilDxrPayloadAnnotationsMDName);
871+
if (pDxrPayloadAnnotationsMD != nullptr) {
872+
m_pModule->eraseNamedMetadata(pDxrPayloadAnnotationsMD);
873+
}
874+
875+
if (MDVals.size() > 1) {
876+
pDxrPayloadAnnotationsMD = m_pModule->getOrInsertNamedMetadata(kDxilDxrPayloadAnnotationsMDName);
877+
pDxrPayloadAnnotationsMD->addOperand(MDNode::get(m_Ctx, MDVals));
878+
}
879+
}
880+
881+
Metadata *
882+
DxilMDHelper::EmitDxrPayloadStructAnnotation(const DxilPayloadAnnotation &SA) {
883+
vector<Metadata *> MDVals;
884+
MDVals.reserve(SA.GetNumFields());
885+
MDVals.resize(SA.GetNumFields());
886+
887+
const StructType* STy = SA.GetStructType();
888+
for (unsigned i = 0; i < SA.GetNumFields(); i++) {
889+
MDVals[i] = EmitDxrPayloadFieldAnnotation(SA.GetFieldAnnotation(i), STy->getElementType(i));
890+
}
891+
892+
return MDNode::get(m_Ctx, MDVals);
893+
}
894+
895+
void DxilMDHelper::LoadDxrPayloadAccessQualifiers(const MDOperand &MDO,
896+
DxilPayloadFieldAnnotation &FA) {
897+
unsigned fieldBitmask = ConstMDToInt32(MDO);
898+
if (fieldBitmask & ~DXIL::PayloadAccessQualifierValidMask) {
899+
DXASSERT(false, "Unknown payload access qualifier bits set");
900+
m_bExtraMetadata = true;
901+
}
902+
fieldBitmask &= DXIL::PayloadAccessQualifierValidMask;
903+
FA.SetPayloadFieldQualifierMask(fieldBitmask);
904+
}
905+
906+
void DxilMDHelper::LoadDxrPayloadFieldAnnoation(
907+
const MDOperand &MDO, DxilPayloadFieldAnnotation &FA) {
908+
IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
909+
const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); // Tag-Value list.
910+
IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
911+
IFTBOOL((pTupleMD->getNumOperands() & 0x1) == 0, DXC_E_INCORRECT_DXIL_METADATA);
912+
913+
for (unsigned i = 0; i < pTupleMD->getNumOperands(); i += 2) {
914+
unsigned Tag = ConstMDToUint32(pTupleMD->getOperand(i));
915+
const MDOperand &MDO = pTupleMD->getOperand(i + 1);
916+
IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
917+
918+
switch (Tag) {
919+
case kDxilPayloadFieldAnnotationAccessTag:
920+
LoadDxrPayloadAccessQualifiers(MDO, FA);
921+
break;
922+
default:
923+
DXASSERT(false, "Unknown payload field annotation tag");
924+
m_bExtraMetadata = true;
925+
break;
926+
}
927+
}
928+
}
929+
930+
void DxilMDHelper::LoadDxrPayloadFieldAnnoations(const MDOperand &MDO,
931+
DxilPayloadAnnotation &SA) {
932+
IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
933+
const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get());
934+
IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
935+
IFTBOOL(pTupleMD->getNumOperands() == SA.GetNumFields(),
936+
DXC_E_INCORRECT_DXIL_METADATA);
937+
for (unsigned i = 0; i < SA.GetNumFields(); ++i) {
938+
LoadDxrPayloadFieldAnnoation(pTupleMD->getOperand(i), SA.GetFieldAnnotation(i));
939+
}
940+
}
941+
942+
void DxilMDHelper::LoadDxrPayloadAnnotationNode(const llvm::MDTuple &MDT,
943+
DxilTypeSystem &TypeSystem) {
944+
unsigned Tag = ConstMDToUint32(MDT.getOperand(0));
945+
IFTBOOL(Tag == kDxilPayloadAnnotationStructTag, DXC_E_INCORRECT_DXIL_METADATA)
946+
IFTBOOL((MDT.getNumOperands() & 0x1) == 1, DXC_E_INCORRECT_DXIL_METADATA);
947+
948+
Constant *pGV = dyn_cast<Constant>(ValueMDToValue(MDT.getOperand(1)));
949+
IFTBOOL(pGV != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
950+
StructType *pGVType = dyn_cast<StructType>(pGV->getType());
951+
IFTBOOL(pGVType != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
952+
953+
// Check if this struct is already part of the DXIL Type System
954+
DxilPayloadAnnotation *pPA = TypeSystem.AddPayloadAnnotation(pGVType);
955+
956+
LoadDxrPayloadFieldAnnoations(MDT.getOperand(2), *pPA);
957+
}
958+
959+
void DxilMDHelper::LoadDxrPayloadAnnotations(DxilTypeSystem &TypeSystem) {
960+
NamedMDNode *pDxilPayloadAnnotationsMD =
961+
m_pModule->getNamedMetadata(kDxilDxrPayloadAnnotationsMDName);
962+
if (pDxilPayloadAnnotationsMD == nullptr)
963+
return;
964+
965+
if (DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 6) < 0) {
966+
DXASSERT(false, "payload access qualifier emitted for dxil version < 1.6");
967+
m_bExtraMetadata = true;
968+
}
969+
DXASSERT(pDxilPayloadAnnotationsMD->getNumOperands() != 0, "empty metadata node?");
970+
971+
for (unsigned i = 0; i < pDxilPayloadAnnotationsMD->getNumOperands(); i++) {
972+
const MDTuple *pTupleMD =
973+
dyn_cast<MDTuple>(pDxilPayloadAnnotationsMD->getOperand(i));
974+
IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
975+
LoadDxrPayloadAnnotationNode(*pTupleMD, TypeSystem);
976+
}
977+
}
978+
853979
Metadata *DxilMDHelper::EmitDxilTemplateArgAnnotation(const DxilTemplateArgAnnotation &annotation) {
854980
SmallVector<Metadata *, 2> MDVals;
855981
if (annotation.IsType()) {
@@ -1065,6 +1191,7 @@ Metadata *DxilMDHelper::EmitDxilFieldAnnotation(const DxilFieldAnnotation &FA) {
10651191
return MDNode::get(m_Ctx, MDVals);
10661192
}
10671193

1194+
10681195
void DxilMDHelper::LoadDxilFieldAnnotation(const MDOperand &MDO, DxilFieldAnnotation &FA) {
10691196
IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
10701197
const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get());
@@ -1116,6 +1243,17 @@ void DxilMDHelper::LoadDxilFieldAnnotation(const MDOperand &MDO, DxilFieldAnnota
11161243
}
11171244
}
11181245

1246+
Metadata *
1247+
DxilMDHelper::EmitDxrPayloadFieldAnnotation(const DxilPayloadFieldAnnotation &FA, Type* fieldType) {
1248+
vector<Metadata *> MDVals; // Tag-Value list.
1249+
MDVals.emplace_back(Uint32ToConstMD(kDxilPayloadFieldAnnotationAccessTag));
1250+
1251+
auto mask = FA.GetPayloadFieldQualifierMask();
1252+
MDVals.emplace_back(Uint32ToConstMD(mask));
1253+
1254+
return MDNode::get(m_Ctx, MDVals);
1255+
}
1256+
11191257
const Function *DxilMDHelper::LoadDxilFunctionProps(const MDTuple *pProps,
11201258
hlsl::DxilFunctionProps *props) {
11211259
unsigned idx = 0;

0 commit comments

Comments
 (0)