diff --git a/include/dxc/DXIL/DxilConstants.h b/include/dxc/DXIL/DxilConstants.h index 4705b90c55..24036e97f4 100644 --- a/include/dxc/DXIL/DxilConstants.h +++ b/include/dxc/DXIL/DxilConstants.h @@ -30,6 +30,7 @@ const unsigned kDxilMajor = 1; /* hctdb_instrhelp.get_dxil_version_minor()*/ // VALRULE-TEXT:BEGIN const unsigned kDxilMinor = 10; +const unsigned kDxilReleasedMinor = 9; // VALRULE-TEXT:END inline unsigned MakeDxilVersion(unsigned DxilMajor, unsigned DxilMinor) { @@ -60,6 +61,11 @@ inline int CompareVersions(unsigned Major1, unsigned Minor1, unsigned Major2, return 0; } +// Use this instead of fixed version checks to enable experimental features. +inline bool IsVersionExperimental(unsigned Major, unsigned Minor) { + return CompareVersions(Major, Minor, kDxilMajor, kDxilReleasedMinor) > 0; +} + // Utility for updating major,minor to max of current and new. inline bool UpdateToMaxOfVersions(unsigned &major, unsigned &minor, unsigned newMajor, unsigned newMinor) { diff --git a/include/dxc/DxilContainer/DxilRDATBuilder.h b/include/dxc/DxilContainer/DxilRDATBuilder.h index dbd9c8df1f..e4a85da301 100644 --- a/include/dxc/DxilContainer/DxilRDATBuilder.h +++ b/include/dxc/DxilContainer/DxilRDATBuilder.h @@ -41,21 +41,57 @@ class DxilRDATBuilder { public: DxilRDATBuilder(bool allowRecordDuplication); - template RDATTable *GetOrAddTable() { - RDATTable **tablePtr = + // Add all supported parts first to control table ordering and prevent use of + // unsupported parts. + + StringBufferPart *AddStringBufferPart() { + assert(nullptr == m_pStringBufferPart && + "otherwise, string buffer part already exists"); + return GetOrAddPart(&m_pStringBufferPart); + } + IndexArraysPart *AddIndexArraysPart() { + assert(nullptr == m_pIndexArraysPart && + "otherwise, index arrays part already exists"); + return GetOrAddPart(&m_pIndexArraysPart); + } + RawBytesPart *AddRawBytesPart() { + assert(nullptr == m_pRawBytesPart && + "otherwise, raw bytes part already exists"); + return GetOrAddPart(&m_pRawBytesPart); + } + + template RDATTable *AddTable() { + RDATTable **TablePtr = &m_pTables[(size_t)RDAT::RecordTraits::TableIndex()]; - if (!*tablePtr) { - m_Parts.emplace_back(llvm::make_unique()); - *tablePtr = reinterpret_cast(m_Parts.back().get()); - (*tablePtr)->SetRecordStride(sizeof(T)); - (*tablePtr)->SetType(RDAT::RecordTraits::PartType()); - (*tablePtr)->SetDeduplication(m_bRecordDeduplicationEnabled); - } - return *tablePtr; + assert(nullptr == *TablePtr && "otherwise, table already exists"); + RDATTable *Table = GetOrAddPart(TablePtr); + Table->SetRecordStride(sizeof(T)); + Table->SetType(RDAT::RecordTraits::PartType()); + Table->SetDeduplication(m_bRecordDeduplicationEnabled); + return Table; + } + + StringBufferPart &GetStringBufferPart() { + assert(m_pStringBufferPart); + return *m_pStringBufferPart; + } + IndexArraysPart &GetIndexArraysPart() { + assert(m_pIndexArraysPart); + return *m_pIndexArraysPart; + } + RawBytesPart &GetRawBytesPart() { + assert(m_pRawBytesPart); + return *m_pRawBytesPart; + } + + template RDATTable *GetTable() { + return m_pTables[(size_t)RDAT::RecordTraits::TableIndex()]; } template uint32_t InsertRecord(const T &record) { - return GetOrAddTable()->Insert(record); + RDATTable *Table = GetTable(); + assert(Table && "otherwise, missing version check"); + return Table->Insert(record); } uint32_t InsertString(llvm::StringRef str) { return GetStringBufferPart().Insert(str); @@ -73,14 +109,6 @@ class DxilRDATBuilder { return InsertArray(arr.begin(), arr.end()); } - StringBufferPart &GetStringBufferPart() { - return *GetOrAddPart(&m_pStringBufferPart); - } - IndexArraysPart &GetIndexArraysPart() { - return *GetOrAddPart(&m_pIndexArraysPart); - } - RawBytesPart &GetRawBytesPart() { return *GetOrAddPart(&m_pRawBytesPart); } - struct SizeInfo { uint32_t sizeInBytes; uint32_t numParts; diff --git a/include/dxc/DxilContainer/DxilRuntimeReflection.h b/include/dxc/DxilContainer/DxilRuntimeReflection.h index 1c95d20aa6..81d0193e79 100644 --- a/include/dxc/DxilContainer/DxilRuntimeReflection.h +++ b/include/dxc/DxilContainer/DxilRuntimeReflection.h @@ -83,6 +83,7 @@ enum class RuntimeDataPartType : uint32_t { LastPlus1, LastExperimental = LastPlus1 - 1, + LastRelease = Last_1_8, DxilPdbInfoTable = RDAT_PART_ID_WITH_GROUP(RuntimeDataGroup::PdbInfo, 1), DxilPdbInfoSourceTable = @@ -91,17 +92,21 @@ enum class RuntimeDataPartType : uint32_t { RDAT_PART_ID_WITH_GROUP(RuntimeDataGroup::PdbInfo, 3), }; -inline RuntimeDataPartType MaxPartTypeForValVer(unsigned Major, - unsigned Minor) { +inline RuntimeDataPartType +MaxPartTypeForValVer(unsigned Major, unsigned Minor, + bool IsPrereleaseShaderModel = false) { return DXIL::CompareVersions(Major, Minor, 1, 3) < 0 ? RuntimeDataPartType::Invalid // No RDAT before 1.3 : DXIL::CompareVersions(Major, Minor, 1, 4) < 0 ? RuntimeDataPartType::Last_1_3 : DXIL::CompareVersions(Major, Minor, 1, 8) < 0 ? RuntimeDataPartType::Last_1_4 - : DXIL::CompareVersions(Major, Minor, 1, 8) == 0 - ? RuntimeDataPartType::Last_1_8 - : RuntimeDataPartType::LastExperimental; + : DXIL::IsVersionExperimental(Major, Minor) && + (IsPrereleaseShaderModel || Major == 0) + ? RuntimeDataPartType::LastExperimental + : RuntimeDataPartType::LastRelease; + // If validator version > released version, and it's a prerelease shader model + // or unbound validator, allow experimental parts. } enum class RecordTableIndex : unsigned { diff --git a/include/dxc/DxilContainer/RDAT_LibraryTypes.inl b/include/dxc/DxilContainer/RDAT_LibraryTypes.inl index 8f270cc353..60f277691a 100644 --- a/include/dxc/DxilContainer/RDAT_LibraryTypes.inl +++ b/include/dxc/DxilContainer/RDAT_LibraryTypes.inl @@ -459,7 +459,7 @@ RDAT_STRUCT_END() #define RECORD_TYPE RuntimeDataFunctionInfo2 RDAT_STRUCT_TABLE_DERIVED(RuntimeDataFunctionInfo2, RuntimeDataFunctionInfo, - FunctionTable) + FunctionTable, 1, 8) // 128 lanes is maximum that could be supported by HLSL RDAT_VALUE(uint8_t, MinimumExpectedWaveLaneCount) // 0 = none specified diff --git a/include/dxc/DxilContainer/RDAT_Macros.inl b/include/dxc/DxilContainer/RDAT_Macros.inl index 526c67cbc3..de511dbac3 100644 --- a/include/dxc/DxilContainer/RDAT_Macros.inl +++ b/include/dxc/DxilContainer/RDAT_Macros.inl @@ -106,7 +106,7 @@ #define RDAT_FLAGS(sTy, eTy, name) sTy name; #define RDAT_BYTES(name) hlsl::RDAT::BytesRef name; #define RDAT_ARRAY_VALUE(type, count, type_name, name) type_name name; -#define RDAT_STRUCT_TABLE_DERIVED(type, base, table) \ +#define RDAT_STRUCT_TABLE_DERIVED(type, base, table, MajorVer, MinorVer) \ template <> constexpr const char *RecordTraits::TypeName(); \ template <> constexpr RecordTableIndex RecordTraits::TableIndex(); \ template <> constexpr RuntimeDataPartType RecordTraits::PartType(); \ @@ -169,7 +169,7 @@ return BaseRecordReader::asRecord(); \ } #define RDAT_STRUCT_TABLE(type, table) RDAT_STRUCT(type) -#define RDAT_STRUCT_TABLE_DERIVED(type, base, table) \ +#define RDAT_STRUCT_TABLE_DERIVED(type, base, table, MajorVer, MinorVer) \ RDAT_STRUCT_DERIVED(type, base) #define RDAT_UNION_IF(name, expr) \ bool GLUE(RECORD_TYPE, _Reader)::has##name() const { \ @@ -336,7 +336,7 @@ template <> constexpr RuntimeDataPartType RecordTraits::PartType() { \ return RuntimeDataPartType::table; \ } -#define RDAT_STRUCT_TABLE_DERIVED(type, base, table) \ +#define RDAT_STRUCT_TABLE_DERIVED(type, base, table, MajorVer, MinorVer) \ RDAT_STRUCT_DERIVED(type, base) \ template <> constexpr RecordTableIndex RecordTraits::TableIndex() { \ return RecordTableIndex::table; \ @@ -360,7 +360,7 @@ #define RDAT_STRUCT_TABLE(type, table) RDAT_STRUCT(type) #endif #ifndef RDAT_STRUCT_TABLE_DERIVED -#define RDAT_STRUCT_TABLE_DERIVED(type, base, table) \ +#define RDAT_STRUCT_TABLE_DERIVED(type, base, table, MajorVer, MinorVer) \ RDAT_STRUCT_DERIVED(type, base) #endif #ifndef RDAT_STRUCT_END diff --git a/lib/DxilContainer/DxilContainerAssembler.cpp b/lib/DxilContainer/DxilContainerAssembler.cpp index 736940b325..d865971e47 100644 --- a/lib/DxilContainer/DxilContainerAssembler.cpp +++ b/lib/DxilContainer/DxilContainerAssembler.cpp @@ -1547,8 +1547,7 @@ class DxilRDATWriter : public DxilPartWriter { if (entryProps.props.IsNode()) { shaderInfo = AddShaderNodeInfo(DM, function, entryProps, *pInfo2, TGSMInFunc[&function]); - } else if (DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 8) > - 0) { + } else if (Builder.GetTable()) { shaderInfo = AddShaderInfo(function, entryProps, *pInfo2, compatInfo.shaderFlags, TGSMInFunc[&function]); @@ -1656,30 +1655,34 @@ class DxilRDATWriter : public DxilPartWriter { DxilRDATWriter(DxilModule &mod) : Builder(GetRecordDuplicationAllowed(mod)) { // Keep track of validator version so we can make a compatible RDAT mod.GetValidatorVersion(m_ValMajor, m_ValMinor); - RDAT::RuntimeDataPartType maxAllowedType = - RDAT::MaxPartTypeForValVer(m_ValMajor, m_ValMinor); + RDAT::RuntimeDataPartType maxAllowedType = RDAT::MaxPartTypeForValVer( + m_ValMajor, m_ValMinor, + mod.GetShaderModel()->IsPreReleaseShaderModel()); mod.ComputeShaderCompatInfo(); // Instantiate the parts in the order that validator expects. - Builder.GetStringBufferPart(); - m_pResourceTable = Builder.GetOrAddTable(); - m_pFunctionTable = Builder.GetOrAddTable(); - if (DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 8) >= 0) { - m_pFunctionTable->SetRecordStride(sizeof(RuntimeDataFunctionInfo2)); - } else { - m_pFunctionTable->SetRecordStride(sizeof(RuntimeDataFunctionInfo)); - } - Builder.GetIndexArraysPart(); - Builder.GetRawBytesPart(); + Builder.AddStringBufferPart(); + m_pResourceTable = Builder.AddTable(); + m_pFunctionTable = Builder.AddTable(); + Builder.AddIndexArraysPart(); + Builder.AddRawBytesPart(); if (RDAT::RecordTraits::PartType() <= maxAllowedType) - m_pSubobjectTable = Builder.GetOrAddTable(); + m_pSubobjectTable = Builder.AddTable(); -// Once per table. +// Once per table, if not already added. #define RDAT_STRUCT_TABLE(type, table) \ - if (RDAT::RecordTraits::PartType() <= maxAllowedType) \ - (void)Builder.GetOrAddTable(); + if (RDAT::RecordTraits::PartType() <= maxAllowedType && \ + !Builder.GetTable()) \ + (void)Builder.AddTable(); +// Update the record stride for supported derived types. +#define RDAT_STRUCT_TABLE_DERIVED(type, base, table, MajorVer, MinorVer) \ + if (DXIL::CompareVersions(m_ValMajor, m_ValMinor, MajorVer, MinorVer) >= \ + 0 && \ + Builder.GetTable()) { \ + Builder.GetTable()->SetRecordStride(sizeof(RDAT::type)); \ + } #define DEF_RDAT_TYPES DEF_RDAT_DEFAULTS #include "dxc/DxilContainer/RDAT_Macros.inl" diff --git a/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat.hlsl b/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat.hlsl new file mode 100644 index 0000000000..a3f4c18813 --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat.hlsl @@ -0,0 +1,28 @@ +// Note: Base this on highest the experimental version, or released+1. +// REQUIRES: dxil-1-10 +// RUN: %dxc %s -Tlib_6_10 -Vd -validator-version 0.0 -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP +// RUN: %dxc %s -Tlib_6_10 -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP +// RUN: %dxc %s -Tlib_6_10 -validator-version 1.10 -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP + +// No experimental RDAT for released shader models even with default or latest +// validator versions. +// RUN: %dxc %s -Tlib_6_9 -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,NOEXP +// RUN: %dxc %s -Tlib_6_9 -validator-version 1.10 -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,NOEXP + +// Make sure experimental RDAT is not emitted for released shader models, +// unless the validator version is 0.0 (no validation supported). Validator +// version 0.0 is implied for the offline linking target lib_6_x. + +// CHECK: DxilRuntimeData +// EXP: PSInfoTable +// NOEXP-NOT: PSInfoTable + +[shader("pixel")] +float4 main() : SV_Target { + return float4(1.0, 0.0, 0.0, 1.0); +} diff --git a/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat_rel_sm.hlsl b/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat_rel_sm.hlsl new file mode 100644 index 0000000000..bc582dca05 --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat_rel_sm.hlsl @@ -0,0 +1,23 @@ +// Note: Add RUN lines for newer released shader models to this test when available. +// REQUIRES: dxil-1-9 +// RUN: %dxc %s -Tlib_6_x -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP +// RUN: %dxc %s -Tlib_6_9 -Vd -validator-version 0.0 -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP +// RUN: %dxc %s -Tlib_6_9 -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,NOEXP +// RUN: %dxc %s -Tlib_6_9 -validator-version 1.9 -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,NOEXP + +// Make sure experimental RDAT is not emitted for released shader models, +// unless the validator version is 0.0 (no validation supported). Validator +// version 0.0 is implied for the offline linking target lib_6_x. + +// CHECK: DxilRuntimeData +// EXP: PSInfoTable +// NOEXP-NOT: PSInfoTable + +[shader("pixel")] +float4 main() : SV_Target { + return float4(1.0, 0.0, 0.0, 1.0); +} diff --git a/utils/hct/hctdb_instrhelp.py b/utils/hct/hctdb_instrhelp.py index f91012ff75..d7a263a8e1 100644 --- a/utils/hct/hctdb_instrhelp.py +++ b/utils/hct/hctdb_instrhelp.py @@ -1748,7 +1748,8 @@ def get_highest_shader_model(): def get_dxil_version_minor(): - return "const unsigned kDxilMinor = %d;" % highest_minor + return (f"const unsigned kDxilMinor = {highest_minor};\n" + + f"const unsigned kDxilReleasedMinor = {highest_released_minor};") def get_dxil_version_minor_int():