Skip to content

Commit 9ec9169

Browse files
Greg Rothdamyanp
andauthored
Mesh node attribute support (#6469)
Adds new mesh node attributes NodeMaxInputRecordsPerGraphEntryRecord and OutputTopology including metadata and RDAT generation. Enhances error checking for numthreads consistent with mesh node limits. Adds tests for all mesh node attributes and verifies errors for invalid mesh node attribute usage. Adds minimal support for SV_DispatchGrid annotated struct params in order to enable testing NodeMaxDispatchGrid. Fixes #6443 --------- Co-authored-by: Damyan Pepper <[email protected]>
1 parent 2bdb776 commit 9ec9169

17 files changed

Lines changed: 1008 additions & 16 deletions

File tree

include/dxc/DXIL/DxilFunctionProps.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ struct DxilFunctionProps {
181181
unsigned DispatchGrid[3];
182182
unsigned MaxDispatchGrid[3];
183183
unsigned MaxRecursionDepth;
184+
// BEGIN experimental mesh node properties
185+
DXIL::MeshOutputTopology OutputTopology;
186+
unsigned MaxVertexCount;
187+
unsigned MaxPrimitiveCount;
188+
unsigned MaxInputRecordsPerGraphEntryRecord;
189+
bool MaxInputRecSharedAcrossNodeArray;
190+
// END experimental mesh node properties
184191
} Node;
185192

186193
DXIL::ShaderKind shaderKind;

include/dxc/DXIL/DxilMetadataHelper.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,15 @@ class DxilMDHelper {
320320
static const unsigned kDxilNodeMaxDispatchGridTag = 22;
321321
static const unsigned kDxilRangedWaveSizeTag = 23;
322322

323+
// Experimental Mesh Node tags
324+
// offset by 0x10000(65536) to prevent interfering with future tags
325+
// Note that mesh attribs are represented differently than in mesh shaders,
326+
// using a tag instead of its position in a state block indicating meaning
327+
static const unsigned kDxilNodeMeshOutputTopologyTag = 65536;
328+
static const unsigned kDxilNodeMeshMaxVertexCountTag = 65537;
329+
static const unsigned kDxilNodeMeshMaxPrimitiveCountTag = 655368;
330+
static const unsigned kDxilNodeMaxInputRecordsPerGraphEntryRecordTag = 65539;
331+
323332
// Node Input/Output State.
324333
static const unsigned kDxilNodeOutputIDTag = 0;
325334
static const unsigned kDxilNodeIOFlagsTag = 1;

include/dxc/DxilContainer/DxilRuntimeReflection.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ enum class RuntimeDataPartType : uint32_t {
6767
IONodeTable = 10,
6868
NodeShaderInfoTable = 11,
6969
Last_1_8 = NodeShaderInfoTable,
70+
MaxInputRecordsTable = 12,
71+
Last_1_9 = MaxInputRecordsTable,
7072

7173
// Insert experimental here.
7274
SignatureElementTable,
@@ -113,6 +115,8 @@ enum class RecordTableIndex : unsigned {
113115
IONodeTable,
114116
NodeShaderInfoTable,
115117

118+
MaxInputRecordsTable,
119+
116120
DxilPdbInfoTable,
117121
DxilPdbInfoSourceTable,
118122
DxilPdbInfoLibraryTable,

include/dxc/DxilContainer/RDAT_LibraryTypes.inl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ RDAT_ENUM_START(NodeFuncAttribKind, uint32_t)
265265
RDAT_ENUM_VALUE(MaxRecursionDepth, 5)
266266
RDAT_ENUM_VALUE(LocalRootArgumentsTableIndex, 6)
267267
RDAT_ENUM_VALUE(MaxDispatchGrid, 7)
268+
RDAT_ENUM_VALUE(MeshShaderInfo, 8)
269+
RDAT_ENUM_VALUE(MaxInputRecordsPerGraphEntryRecord, 9)
268270
RDAT_ENUM_VALUE_NODEF(LastValue)
269271
RDAT_ENUM_END()
270272

@@ -344,6 +346,13 @@ RDAT_STRUCT_TABLE(NodeID, NodeIDTable)
344346
RDAT_STRUCT_END()
345347
#undef RECORD_TYPE
346348

349+
#define RECORD_TYPE MaxInputRecords
350+
RDAT_STRUCT_TABLE(MaxInputRecords, MaxInputRecordsTable)
351+
RDAT_VALUE(uint32_t, Count)
352+
RDAT_VALUE(uint32_t, Shared)
353+
RDAT_STRUCT_END()
354+
#undef RECORD_TYPE
355+
347356
#define RECORD_TYPE NodeShaderFuncAttrib
348357
RDAT_STRUCT_TABLE(NodeShaderFuncAttrib, NodeShaderFuncAttribTable)
349358
RDAT_ENUM(uint32_t, hlsl::RDAT::NodeFuncAttribKind, AttribKind)
@@ -375,6 +384,14 @@ RDAT_STRUCT_TABLE(NodeShaderFuncAttrib, NodeShaderFuncAttribTable)
375384
getAttribKind() ==
376385
hlsl::RDAT::NodeFuncAttribKind::MaxDispatchGrid)
377386
RDAT_INDEX_ARRAY_REF(MaxDispatchGrid)
387+
RDAT_UNION_ELIF(MeshShaderInfo,
388+
getAttribKind() ==
389+
hlsl::RDAT::NodeFuncAttribKind::MeshShaderInfo)
390+
RDAT_RECORD_REF(MSInfo, MeshShaderInfo)
391+
RDAT_UNION_ELIF(MaxInputRecordsPerGraphEntryRecord,
392+
getAttribKind() ==
393+
hlsl::RDAT::NodeFuncAttribKind::MaxInputRecordsPerGraphEntryRecord)
394+
RDAT_RECORD_REF(MaxInputRecords, MaxInputRecordsPerGraphEntryRecord)
378395
RDAT_UNION_ENDIF()
379396
RDAT_UNION_END()
380397
RDAT_STRUCT_END()

lib/DXIL/DxilMetadataHelper.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,30 @@ void DxilMDHelper::LoadDxilEntryProperties(const MDOperand &MDO,
19001900
auto &Node = props.Node;
19011901
Node.MaxRecursionDepth = ConstMDToUint32(MDO);
19021902
} break;
1903+
case DxilMDHelper::kDxilNodeMeshOutputTopologyTag: {
1904+
hasNodeTag = true;
1905+
auto &Node = props.Node;
1906+
Node.OutputTopology = (DXIL::MeshOutputTopology)ConstMDToUint32(MDO);
1907+
} break;
1908+
case DxilMDHelper::kDxilNodeMeshMaxVertexCountTag: {
1909+
hasNodeTag = true;
1910+
auto &Node = props.Node;
1911+
Node.MaxVertexCount = ConstMDToUint32(MDO);
1912+
} break;
1913+
case DxilMDHelper::kDxilNodeMeshMaxPrimitiveCountTag: {
1914+
hasNodeTag = true;
1915+
auto &Node = props.Node;
1916+
Node.MaxPrimitiveCount = ConstMDToUint32(MDO);
1917+
} break;
1918+
case DxilMDHelper::kDxilNodeMaxInputRecordsPerGraphEntryRecordTag: {
1919+
hasNodeTag = true;
1920+
auto &Node = props.Node;
1921+
MDNode *pNode = cast<MDNode>(MDO.get());
1922+
Node.MaxInputRecordsPerGraphEntryRecord =
1923+
ConstMDToUint32(pNode->getOperand(0));
1924+
Node.MaxInputRecSharedAcrossNodeArray =
1925+
ConstMDToBool(pNode->getOperand(1));
1926+
} break;
19031927
case DxilMDHelper::kDxilNodeInputsTag: {
19041928
hasNodeTag = true;
19051929
const MDTuple *pNodeInputs = dyn_cast<MDTuple>(MDO.get());
@@ -1957,6 +1981,14 @@ void DxilMDHelper::SerializeNodeProps(SmallVectorImpl<llvm::Metadata *> &MDVals,
19571981
MDVals.push_back(Uint32ToConstMD(NodeProps.MaxDispatchGrid[1]));
19581982
MDVals.push_back(Uint32ToConstMD(NodeProps.MaxDispatchGrid[2]));
19591983
MDVals.push_back(Uint32ToConstMD(NodeProps.MaxRecursionDepth));
1984+
if (DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 9) >= 0) {
1985+
MDVals.emplace_back(Uint32ToConstMD((unsigned)NodeProps.OutputTopology));
1986+
MDVals.emplace_back(Uint32ToConstMD(NodeProps.MaxVertexCount));
1987+
MDVals.emplace_back(Uint32ToConstMD(NodeProps.MaxPrimitiveCount));
1988+
MDVals.push_back(
1989+
Uint32ToConstMD(NodeProps.MaxInputRecordsPerGraphEntryRecord));
1990+
MDVals.push_back(BoolToConstMD(NodeProps.MaxInputRecSharedAcrossNodeArray));
1991+
}
19601992
for (auto &nodeinput : props->InputNodes) {
19611993
MDVals.push_back(Uint32ToConstMD(nodeinput.Flags));
19621994
MDVals.push_back(Uint32ToConstMD(nodeinput.MaxRecords));
@@ -2010,6 +2042,16 @@ void DxilMDHelper::DeserializeNodeProps(const MDTuple *pProps, unsigned &idx,
20102042
NodeProps.MaxDispatchGrid[1] = ConstMDToUint32(pProps->getOperand(idx++));
20112043
NodeProps.MaxDispatchGrid[2] = ConstMDToUint32(pProps->getOperand(idx++));
20122044
NodeProps.MaxRecursionDepth = ConstMDToUint32(pProps->getOperand(idx++));
2045+
if (DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 9) >= 0) {
2046+
NodeProps.OutputTopology =
2047+
(DXIL::MeshOutputTopology)ConstMDToUint32(pProps->getOperand(idx++));
2048+
NodeProps.MaxVertexCount = ConstMDToUint32(pProps->getOperand(idx++));
2049+
NodeProps.MaxPrimitiveCount = ConstMDToUint32(pProps->getOperand(idx++));
2050+
NodeProps.MaxInputRecordsPerGraphEntryRecord =
2051+
ConstMDToUint32(pProps->getOperand(idx++));
2052+
NodeProps.MaxInputRecSharedAcrossNodeArray =
2053+
ConstMDToBool(pProps->getOperand(idx++));
2054+
}
20132055
for (auto &nodeinput : props->InputNodes) {
20142056
nodeinput.Flags = NodeFlags(ConstMDToUint32(pProps->getOperand(idx++)));
20152057
nodeinput.MaxRecords = ConstMDToUint32(pProps->getOperand(idx++));
@@ -2748,6 +2790,36 @@ void DxilMDHelper::EmitDxilNodeState(std::vector<llvm::Metadata *> &MDVals,
27482790
MDVals.emplace_back(Uint32ToConstMD(Node.MaxRecursionDepth));
27492791
}
27502792

2793+
// Experimental mesh node shader properties
2794+
if (Node.OutputTopology != DXIL::MeshOutputTopology::Undefined) {
2795+
MDVals.emplace_back(
2796+
Uint32ToConstMD(DxilMDHelper::kDxilNodeMeshOutputTopologyTag));
2797+
MDVals.emplace_back(Uint32ToConstMD((unsigned)Node.OutputTopology));
2798+
}
2799+
2800+
if (Node.MaxVertexCount > 0) {
2801+
MDVals.emplace_back(
2802+
Uint32ToConstMD(DxilMDHelper::kDxilNodeMeshMaxVertexCountTag));
2803+
MDVals.emplace_back(Uint32ToConstMD(Node.MaxVertexCount));
2804+
}
2805+
2806+
if (Node.MaxPrimitiveCount > 0) {
2807+
MDVals.emplace_back(
2808+
Uint32ToConstMD(DxilMDHelper::kDxilNodeMeshMaxPrimitiveCountTag));
2809+
MDVals.emplace_back(Uint32ToConstMD(Node.MaxPrimitiveCount));
2810+
}
2811+
2812+
if (Node.MaxInputRecordsPerGraphEntryRecord) {
2813+
MDVals.emplace_back(Uint32ToConstMD(
2814+
DxilMDHelper::kDxilNodeMaxInputRecordsPerGraphEntryRecordTag));
2815+
vector<Metadata *> MaxInputRecsVals;
2816+
MaxInputRecsVals.emplace_back(
2817+
Uint32ToConstMD(Node.MaxInputRecordsPerGraphEntryRecord));
2818+
MaxInputRecsVals.emplace_back(
2819+
BoolToConstMD(Node.MaxInputRecSharedAcrossNodeArray));
2820+
MDVals.emplace_back(MDNode::get(m_Ctx, MaxInputRecsVals));
2821+
}
2822+
27512823
if (props.InputNodes.size()) {
27522824
MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilNodeInputsTag));
27532825
vector<Metadata *> NodeInputVals;

lib/DxilContainer/DxilContainerAssembler.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,6 +1656,28 @@ class DxilRDATWriter : public DxilPartWriter {
16561656
funcAttribs.push_back(Builder.InsertRecord(nAttrib));
16571657
}
16581658

1659+
if (props.Node.OutputTopology != DXIL::MeshOutputTopology::Undefined) {
1660+
nAttrib = {};
1661+
nAttrib.AttribKind = (uint32_t)RDAT::NodeFuncAttribKind::MeshShaderInfo;
1662+
RDAT::MSInfo info = {};
1663+
info.MeshOutputTopology = (uint8_t)props.Node.OutputTopology;
1664+
info.MaxOutputVertices = (uint16_t)props.Node.MaxVertexCount;
1665+
info.MaxOutputPrimitives = (uint16_t)props.Node.MaxPrimitiveCount;
1666+
nAttrib.MeshShaderInfo = Builder.InsertRecord(info);
1667+
funcAttribs.push_back(Builder.InsertRecord(nAttrib));
1668+
}
1669+
1670+
if (props.Node.MaxInputRecordsPerGraphEntryRecord) {
1671+
nAttrib = {};
1672+
nAttrib.AttribKind = (uint32_t)
1673+
RDAT::NodeFuncAttribKind::MaxInputRecordsPerGraphEntryRecord;
1674+
RDAT::MaxInputRecords MaxRec = {};
1675+
MaxRec.Count = props.Node.MaxInputRecordsPerGraphEntryRecord;
1676+
MaxRec.Shared = props.Node.MaxInputRecSharedAcrossNodeArray;
1677+
nAttrib.MaxInputRecordsPerGraphEntryRecord = Builder.InsertRecord(MaxRec);
1678+
funcAttribs.push_back(Builder.InsertRecord(nAttrib));
1679+
}
1680+
16591681
nInfo.Attribs = Builder.InsertArray(funcAttribs.begin(), funcAttribs.end());
16601682

16611683
// Add the input and output nodes

tools/clang/include/clang/Basic/Attr.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,12 @@ def HLSLNodeMaxRecursionDepth : InheritableAttr {
986986
let Documentation = [Undocumented];
987987
}
988988

989+
def HLSLNodeMaxInputRecordsPerGraphEntryRecord : InheritableAttr {
990+
let Spellings = [CXX11<"", "nodemaxinputrecordspergraphentryrecord", 2017>];
991+
let Args = [UnsignedArgument<"Count">, BoolArgument<"SharedAcrossNodeArray">];
992+
let Documentation = [Undocumented];
993+
}
994+
989995
def HLSLNodeTrackRWInputSharing : InheritableAttr {
990996
let Spellings = [CXX11<"", "nodetrackrwinputsharing", 2017>];
991997
let Subjects = SubjectList<[CXXRecord]>;

tools/clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7842,7 +7842,11 @@ def err_hlsl_wg_intrinsic_launch_type : Error<
78427842
def err_hlsl_wg_thread_launch_group_size : Error<
78437843
"Thread launch nodes must have a thread group size of (1,1,1)">;
78447844
def warn_hlsl_numthreads_group_size : Warning<
7845-
"Group size of %0 (%1 * %2 * %3) is outside of valid range [1..1024] - "
7845+
"Group size of %0 (%1 * %2 * %3) is outside of valid range [1..%4] - "
7846+
"attribute will be ignored">,
7847+
InGroup<IgnoredAttributes>;
7848+
def warn_hlsl_numthreads_channel_size : Warning<
7849+
"Thread Group %0 size of %1 is outside of valid range [%2..%3] - "
78467850
"attribute will be ignored">,
78477851
InGroup<IgnoredAttributes>;
78487852
def err_hlsl_wg_nodetrackrwinputsharing_missing : Error<

tools/clang/lib/CodeGen/CGHLSLMS.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,6 +1730,10 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
17301730
DXIL::MeshOutputTopology topology =
17311731
StringToMeshOutputTopology(Attr->getTopology());
17321732
funcProps->ShaderProps.MS.outputTopology = topology;
1733+
} else if (isNode) {
1734+
DXIL::MeshOutputTopology topology =
1735+
StringToMeshOutputTopology(Attr->getTopology());
1736+
funcProps->Node.OutputTopology = topology;
17331737
} else if (isEntry && !SM->IsHS() && !SM->IsMS()) {
17341738
unsigned DiagID = Diags.getCustomDiagID(
17351739
DiagnosticsEngine::Warning,
@@ -1857,6 +1861,19 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
18571861
if (const auto *pAttr = FD->getAttr<HLSLNodeMaxRecursionDepthAttr>()) {
18581862
funcProps->Node.MaxRecursionDepth = pAttr->getCount();
18591863
}
1864+
if (const auto *pAttr =
1865+
FD->getAttr<HLSLNodeMaxInputRecordsPerGraphEntryRecordAttr>()) {
1866+
if (!isNode) {
1867+
unsigned DiagID = Diags.getCustomDiagID(
1868+
DiagnosticsEngine::Error, "nodemaxinputrecordspergraphentryrecord "
1869+
"attribute only valid for mesh nodes.");
1870+
Diags.Report(pAttr->getLocation(), DiagID);
1871+
}
1872+
1873+
funcProps->Node.MaxInputRecordsPerGraphEntryRecord = pAttr->getCount();
1874+
funcProps->Node.MaxInputRecSharedAcrossNodeArray =
1875+
pAttr->getSharedAcrossNodeArray();
1876+
}
18601877
if (!FD->getAttr<HLSLNumThreadsAttr>()) {
18611878
// NumThreads wasn't specified.
18621879
// For a Thread launch node the default is (1,1,1,) which we set here.

tools/clang/lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,7 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
821821
case AttributeList::AT_HLSLNodeDispatchGrid:
822822
case AttributeList::AT_HLSLNodeMaxDispatchGrid:
823823
case AttributeList::AT_HLSLNodeMaxRecursionDepth:
824+
case AttributeList::AT_HLSLNodeMaxInputRecordsPerGraphEntryRecord:
824825
case AttributeList::AT_HLSLMaxRecordsSharedWith:
825826
case AttributeList::AT_HLSLMaxRecords:
826827
case AttributeList::AT_HLSLNodeArraySize:

0 commit comments

Comments
 (0)