From 284994cb7d86578f7d4799ba3f824b2cb2edaf0e Mon Sep 17 00:00:00 2001 From: Tex Riddell Date: Wed, 8 Apr 2026 16:38:09 -0700 Subject: [PATCH 1/8] Predicate prerelease RDAT tables on prerelease shader model --- lib/DxilContainer/DxilContainerAssembler.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/DxilContainer/DxilContainerAssembler.cpp b/lib/DxilContainer/DxilContainerAssembler.cpp index 736940b325..01f6f0d3c5 100644 --- a/lib/DxilContainer/DxilContainerAssembler.cpp +++ b/lib/DxilContainer/DxilContainerAssembler.cpp @@ -1006,6 +1006,12 @@ class DxilRDATWriter : public DxilPartWriter { unsigned m_ValMajor, m_ValMinor; + // Prerelease data is guarded behind this flag. Only supported when targeting + // a prerelease shader model. When transitioning data to release, look for + // uses of this flag to update code to check the validator version for the new + // release version instead. + bool m_AllowPrereleaseData = false; + void FindUsingFunctions(const llvm::Value *User, llvm::SmallVectorImpl &functions) { @@ -1547,8 +1553,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 (m_AllowPrereleaseData) { shaderInfo = AddShaderInfo(function, entryProps, *pInfo2, compatInfo.shaderFlags, TGSMInFunc[&function]); @@ -1659,6 +1664,14 @@ class DxilRDATWriter : public DxilPartWriter { RDAT::RuntimeDataPartType maxAllowedType = RDAT::MaxPartTypeForValVer(m_ValMajor, m_ValMinor); + // Only write prerelease tables if the shader model is prerelease, to avoid + // writing prerelease data into release shader models, which might not be + // comatible with newer runtimes. + m_AllowPrereleaseData = mod.GetShaderModel()->IsPreReleaseShaderModel(); + if (!m_AllowPrereleaseData) + maxAllowedType = + std::min(maxAllowedType, RDAT::RuntimeDataPartType::LastRelease); + mod.ComputeShaderCompatInfo(); // Instantiate the parts in the order that validator expects. From 494110075e998cb921051c7b86c3b8d10a769e6b Mon Sep 17 00:00:00 2001 From: Tex Riddell Date: Tue, 7 Apr 2026 17:25:14 -0700 Subject: [PATCH 2/8] Add DxilReleasedMinor to detect experimental version --- include/dxc/DXIL/DxilConstants.h | 6 ++++++ utils/hct/hctdb_instrhelp.py | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) 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/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(): From 3a0060e8dcf74844dbed2456512d853754e9c065 Mon Sep 17 00:00:00 2001 From: Tex Riddell Date: Wed, 10 Jun 2026 13:32:46 -0700 Subject: [PATCH 3/8] DxilRDATBuilder Separate Add/Get to prevent on-demand addition Separating Add and Get to make sure only supported tables are explicitly added, and to prevent any use of unsupported tables by not adding tables on-demand later. Empty parts will always be culled for serialization. --- include/dxc/DxilContainer/DxilRDATBuilder.h | 66 ++++++++++++++------ lib/DxilContainer/DxilContainerAssembler.cpp | 14 ++--- 2 files changed, 54 insertions(+), 26 deletions(-) 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/lib/DxilContainer/DxilContainerAssembler.cpp b/lib/DxilContainer/DxilContainerAssembler.cpp index 01f6f0d3c5..48837ba29b 100644 --- a/lib/DxilContainer/DxilContainerAssembler.cpp +++ b/lib/DxilContainer/DxilContainerAssembler.cpp @@ -1675,24 +1675,24 @@ class DxilRDATWriter : public DxilPartWriter { mod.ComputeShaderCompatInfo(); // Instantiate the parts in the order that validator expects. - Builder.GetStringBufferPart(); - m_pResourceTable = Builder.GetOrAddTable(); - m_pFunctionTable = Builder.GetOrAddTable(); + Builder.AddStringBufferPart(); + m_pResourceTable = Builder.AddTable(); + m_pFunctionTable = Builder.AddTable(); 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.AddIndexArraysPart(); + Builder.AddRawBytesPart(); if (RDAT::RecordTraits::PartType() <= maxAllowedType) - m_pSubobjectTable = Builder.GetOrAddTable(); + m_pSubobjectTable = Builder.AddTable(); // Once per table. #define RDAT_STRUCT_TABLE(type, table) \ if (RDAT::RecordTraits::PartType() <= maxAllowedType) \ - (void)Builder.GetOrAddTable(); + (void)Builder.AddTable(); #define DEF_RDAT_TYPES DEF_RDAT_DEFAULTS #include "dxc/DxilContainer/RDAT_Macros.inl" From cb897574a0db6931a51f3d560f54d7efb6d506c6 Mon Sep 17 00:00:00 2001 From: Tex Riddell Date: Wed, 10 Jun 2026 14:25:37 -0700 Subject: [PATCH 4/8] Add test for experimental RDAT and versioning experimental_rdat.hlsl - test conditions requiring experimental (release+1) support. experimental_rdat_rel_sm.hlsl - test conditions supported on released version. --- .../reflection/experimental_rdat.hlsl | 28 +++++++++++++++++++ .../reflection/experimental_rdat_rel_sm.hlsl | 23 +++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 tools/clang/test/CodeGenDXIL/reflection/experimental_rdat.hlsl create mode 100644 tools/clang/test/CodeGenDXIL/reflection/experimental_rdat_rel_sm.hlsl 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); +} From 5c836f15828d8b5b343324f19880e1aba84894f4 Mon Sep 17 00:00:00 2001 From: Tex Riddell Date: Wed, 10 Jun 2026 14:27:36 -0700 Subject: [PATCH 5/8] RDAT: Add LastReleased part identifier; block experimental RDAT Also require prerelease shader model or unbound validator for experimental RDAT data. --- .../dxc/DxilContainer/DxilRuntimeReflection.h | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/include/dxc/DxilContainer/DxilRuntimeReflection.h b/include/dxc/DxilContainer/DxilRuntimeReflection.h index 1c95d20aa6..cb0b37d06c 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,25 @@ 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::CompareVersions(Major, Minor, 1, DXIL::kDxilReleasedMinor) <= 0 + ? RuntimeDataPartType::LastRelease + : (IsPrereleaseShaderModel || Major == 0) + ? RuntimeDataPartType::LastExperimental + : RuntimeDataPartType::LastRelease; + // For the last condition, we already have a validator version > released + // version, so the remaining rule is: + // - If it's a prerelease shader model or unbound validator, allow + // experimental parts. + // - Otherwise, allow only released parts. } enum class RecordTableIndex : unsigned { From 1cdaa095dbb34631f223adcdbf9318b63786e252 Mon Sep 17 00:00:00 2001 From: Tex Riddell Date: Wed, 10 Jun 2026 14:32:49 -0700 Subject: [PATCH 6/8] RDAT Update prerelease logic Logic for prerelease shader model and unbound validator version moved into MaxPartTypeForValVer, and Builder will return nullptr for GetTable on table that hasn't been added, so base AddShaderInfo on whether a key table in this experimental RDAT is present. --- lib/DxilContainer/DxilContainerAssembler.cpp | 26 ++++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/lib/DxilContainer/DxilContainerAssembler.cpp b/lib/DxilContainer/DxilContainerAssembler.cpp index 48837ba29b..ea12eeb298 100644 --- a/lib/DxilContainer/DxilContainerAssembler.cpp +++ b/lib/DxilContainer/DxilContainerAssembler.cpp @@ -1006,12 +1006,6 @@ class DxilRDATWriter : public DxilPartWriter { unsigned m_ValMajor, m_ValMinor; - // Prerelease data is guarded behind this flag. Only supported when targeting - // a prerelease shader model. When transitioning data to release, look for - // uses of this flag to update code to check the validator version for the new - // release version instead. - bool m_AllowPrereleaseData = false; - void FindUsingFunctions(const llvm::Value *User, llvm::SmallVectorImpl &functions) { @@ -1553,7 +1547,7 @@ class DxilRDATWriter : public DxilPartWriter { if (entryProps.props.IsNode()) { shaderInfo = AddShaderNodeInfo(DM, function, entryProps, *pInfo2, TGSMInFunc[&function]); - } else if (m_AllowPrereleaseData) { + } else if (Builder.GetTable()) { shaderInfo = AddShaderInfo(function, entryProps, *pInfo2, compatInfo.shaderFlags, TGSMInFunc[&function]); @@ -1661,16 +1655,9 @@ 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); - - // Only write prerelease tables if the shader model is prerelease, to avoid - // writing prerelease data into release shader models, which might not be - // comatible with newer runtimes. - m_AllowPrereleaseData = mod.GetShaderModel()->IsPreReleaseShaderModel(); - if (!m_AllowPrereleaseData) - maxAllowedType = - std::min(maxAllowedType, RDAT::RuntimeDataPartType::LastRelease); + RDAT::RuntimeDataPartType maxAllowedType = RDAT::MaxPartTypeForValVer( + m_ValMajor, m_ValMinor, + mod.GetShaderModel()->IsPreReleaseShaderModel()); mod.ComputeShaderCompatInfo(); @@ -1689,9 +1676,10 @@ class DxilRDATWriter : public DxilPartWriter { maxAllowedType) 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) \ + if (RDAT::RecordTraits::PartType() <= maxAllowedType && \ + !Builder.GetTable()) \ (void)Builder.AddTable(); #define DEF_RDAT_TYPES DEF_RDAT_DEFAULTS From d5c38ebb5234cd693851700b762aa4d5026d0aa3 Mon Sep 17 00:00:00 2001 From: Tex Riddell Date: Wed, 10 Jun 2026 15:26:31 -0700 Subject: [PATCH 7/8] RDAT: Automatic record versioning Add minimum validator version to RDAT_STRUCT_TABLE_DERIVED, allowing automatic record versioning (through stride). --- include/dxc/DxilContainer/RDAT_LibraryTypes.inl | 2 +- include/dxc/DxilContainer/RDAT_Macros.inl | 8 ++++---- lib/DxilContainer/DxilContainerAssembler.cpp | 12 +++++++----- 3 files changed, 12 insertions(+), 10 deletions(-) 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 ea12eeb298..d865971e47 100644 --- a/lib/DxilContainer/DxilContainerAssembler.cpp +++ b/lib/DxilContainer/DxilContainerAssembler.cpp @@ -1665,11 +1665,6 @@ class DxilRDATWriter : public DxilPartWriter { Builder.AddStringBufferPart(); m_pResourceTable = Builder.AddTable(); m_pFunctionTable = Builder.AddTable(); - if (DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 8) >= 0) { - m_pFunctionTable->SetRecordStride(sizeof(RuntimeDataFunctionInfo2)); - } else { - m_pFunctionTable->SetRecordStride(sizeof(RuntimeDataFunctionInfo)); - } Builder.AddIndexArraysPart(); Builder.AddRawBytesPart(); if (RDAT::RecordTraits::PartType() <= @@ -1681,6 +1676,13 @@ class DxilRDATWriter : public DxilPartWriter { 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" From 1f4c60060afa922fdb3d3174d592548d2f9e10aa Mon Sep 17 00:00:00 2001 From: Tex Riddell Date: Wed, 10 Jun 2026 15:43:51 -0700 Subject: [PATCH 8/8] Improve MaxPartTypeForValVer logic --- include/dxc/DxilContainer/DxilRuntimeReflection.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/include/dxc/DxilContainer/DxilRuntimeReflection.h b/include/dxc/DxilContainer/DxilRuntimeReflection.h index cb0b37d06c..81d0193e79 100644 --- a/include/dxc/DxilContainer/DxilRuntimeReflection.h +++ b/include/dxc/DxilContainer/DxilRuntimeReflection.h @@ -101,16 +101,12 @@ MaxPartTypeForValVer(unsigned Major, unsigned Minor, ? RuntimeDataPartType::Last_1_3 : DXIL::CompareVersions(Major, Minor, 1, 8) < 0 ? RuntimeDataPartType::Last_1_4 - : DXIL::CompareVersions(Major, Minor, 1, DXIL::kDxilReleasedMinor) <= 0 - ? RuntimeDataPartType::LastRelease - : (IsPrereleaseShaderModel || Major == 0) + : DXIL::IsVersionExperimental(Major, Minor) && + (IsPrereleaseShaderModel || Major == 0) ? RuntimeDataPartType::LastExperimental : RuntimeDataPartType::LastRelease; - // For the last condition, we already have a validator version > released - // version, so the remaining rule is: - // - If it's a prerelease shader model or unbound validator, allow - // experimental parts. - // - Otherwise, allow only released parts. + // If validator version > released version, and it's a prerelease shader model + // or unbound validator, allow experimental parts. } enum class RecordTableIndex : unsigned {