From 5155b0934c55cc79c420309b6de0f87f12c03b8d Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Thu, 19 Sep 2024 07:24:28 -0700 Subject: [PATCH] [Validator] Check content of PSV0 part in validation (#6859) Replace the memcpy check for PSV0 part. Build DxilPipelineStateValidation object from data in PSV0 part. Then compare the content with information from input DxilModule. With this change, the order of signature elements and resources could be different between the container and the DxilModule. And the StringTable could be in different order as well. Second step for #6817 --- .../DxilPipelineStateValidation.h | 44 +- lib/DxilContainer/DxilContainerAssembler.cpp | 29 +- .../DxilPipelineStateValidation.cpp | 202 ++- .../DxilContainerValidation.cpp | 375 +++- .../lib/DxbcConverter/DxbcConverter.cpp | 35 +- tools/clang/test/DXC/dumpPSV_HS.hlsl | 19 +- .../test/DXILValidation/hs_signatures.hlsl | 47 + tools/clang/unittests/HLSL/ValidationTest.cpp | 1511 +++++++++++++++++ utils/hct/hctdb.py | 11 +- 9 files changed, 2121 insertions(+), 152 deletions(-) create mode 100644 tools/clang/test/DXILValidation/hs_signatures.hlsl diff --git a/include/dxc/DxilContainer/DxilPipelineStateValidation.h b/include/dxc/DxilContainer/DxilPipelineStateValidation.h index 50d0f8174..ed482b39a 100644 --- a/include/dxc/DxilContainer/DxilPipelineStateValidation.h +++ b/include/dxc/DxilContainer/DxilPipelineStateValidation.h @@ -260,6 +260,13 @@ struct PSVComponentMask { } return *this; } + bool operator!=(const PSVComponentMask &other) const { + if (NumVectors != other.NumVectors) + return true; + return memcmp(Mask, other.Mask, + PSVComputeMaskDwordsFromVectors(NumVectors) * + sizeof(uint32_t)); + } bool Get(uint32_t ComponentIndex) const { if (ComponentIndex < NumVectors * 4) return (bool)(Mask[ComponentIndex >> 5] & (1 << (ComponentIndex & 0x1F))); @@ -295,6 +302,15 @@ struct PSVDependencyTable { const PSVComponentMask GetMaskForInput(uint32_t inputComponentIndex) const { return getMaskForInput(inputComponentIndex); } + bool operator!=(const PSVDependencyTable &other) const { + if (InputVectors != other.InputVectors || + OutputVectors != other.OutputVectors) + return true; + return memcmp( + Table, other.Table, + PSVComputeInputOutputTableDwords(InputVectors, OutputVectors) * + sizeof(uint32_t)); + } bool IsValid() const { return Table != nullptr; } void Print(llvm::raw_ostream &, const char *, const char *) const; @@ -449,6 +465,8 @@ public: return !m_pElement0 ? 0 : (uint32_t)m_pElement0->DynamicMaskAndStream & 0xF; } void Print(llvm::raw_ostream &O) const; + void Print(llvm::raw_ostream &O, const char *Name, + const uint32_t *SemanticIndexes) const; }; #define MAX_PSV_VERSION 3 @@ -595,6 +613,14 @@ public: return ReadOrWrite(pBuffer, pSize, Mode, initInfo); } + uint32_t GetRuntimeInfoSize() const { return m_uPSVRuntimeInfoSize; } + uint32_t GetResourceBindInfoSize() const { + return m_uPSVResourceBindInfoSize; + } + uint32_t GetSignatureElementSize() const { + return m_uPSVSignatureElementSize; + } + PSVRuntimeInfo0 *GetPSVRuntimeInfo0() const { return m_pPSVRuntimeInfo0; } PSVRuntimeInfo1 *GetPSVRuntimeInfo1() const { return m_pPSVRuntimeInfo1; } @@ -752,6 +778,7 @@ public: } void PrintPSVRuntimeInfo(llvm::raw_ostream &O, uint8_t ShaderKind, const char *Comment) const; + void PrintViewIDState(llvm::raw_ostream &OS) const; void Print(llvm::raw_ostream &O, uint8_t ShaderKind) const; }; @@ -1084,6 +1111,9 @@ public: ViewIDValidator *NewViewIDValidator(unsigned viewIDCount, unsigned gsRastStreamIndex); +uint32_t GetPSVVersion(uint32_t ValidatorMajorVersion, + uint32_t ValidatorMinorVersion); + void InitPSVResourceBinding(PSVResourceBindInfo0 *, PSVResourceBindInfo1 *, DxilResourceBase *); @@ -1093,11 +1123,15 @@ void InitPSVSignatureElement(PSVSignatureElement0 &E, const DxilSignatureElement &SE, bool i1ToUnknownCompat); -// Setup PSVRuntimeInfo* with DxilModule. -// Note that the EntryFunctionName is not done. -void InitPSVRuntimeInfo(PSVRuntimeInfo0 *pInfo, PSVRuntimeInfo1 *pInfo1, - PSVRuntimeInfo2 *pInfo2, PSVRuntimeInfo3 *pInfo3, - const DxilModule &DM); +// Setup shader properties for PSVRuntimeInfo* with DxilModule. +void SetShaderProps(PSVRuntimeInfo0 *pInfo, const DxilModule &DM); +void SetShaderProps(PSVRuntimeInfo1 *pInfo1, const DxilModule &DM); +void SetShaderProps(PSVRuntimeInfo2 *pInfo2, const DxilModule &DM); + +void PrintPSVRuntimeInfo(llvm::raw_ostream &OS, PSVRuntimeInfo0 *pInfo0, + PSVRuntimeInfo1 *pInfo1, PSVRuntimeInfo2 *pInfo2, + PSVRuntimeInfo3 *pInfo3, uint8_t ShaderKind, + const char *EntryName, const char *Comment); } // namespace hlsl diff --git a/lib/DxilContainer/DxilContainerAssembler.cpp b/lib/DxilContainer/DxilContainerAssembler.cpp index ffc1943be..d7d006bd4 100644 --- a/lib/DxilContainer/DxilContainerAssembler.cpp +++ b/lib/DxilContainer/DxilContainerAssembler.cpp @@ -50,8 +50,9 @@ static_assert((unsigned)PSVShaderKind::Invalid == (unsigned)DXIL::ShaderKind::Invalid, "otherwise, PSVShaderKind enum out of sync."); -static DxilProgramSigSemantic -KindToSystemValue(Semantic::Kind kind, DXIL::TessellatorDomain domain) { +DxilProgramSigSemantic +hlsl::SemanticKindToSystemValue(Semantic::Kind kind, + DXIL::TessellatorDomain domain) { switch (kind) { case Semantic::Kind::Arbitrary: return DxilProgramSigSemantic::Undefined; @@ -291,7 +292,7 @@ private: memset(&sig, 0, sizeof(DxilProgramSignatureElement)); sig.Stream = pElement->GetOutputStream(); sig.SemanticName = GetSemanticOffset(pElement); - sig.SystemValue = KindToSystemValue(pElement->GetKind(), m_domain); + sig.SystemValue = SemanticKindToSystemValue(pElement->GetKind(), m_domain); sig.CompType = CompTypeToSigCompType(pElement->GetCompType().GetKind(), m_bCompat_1_4); sig.Register = pElement->GetStartRow(); @@ -738,17 +739,9 @@ public: : m_Module(mod), m_PSVInitInfo(PSVVersion) { m_Module.GetValidatorVersion(m_ValMajor, m_ValMinor); // Constraint PSVVersion based on validator version - if (PSVVersion > 0 && - DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 1) < 0) - m_PSVInitInfo.PSVVersion = 0; - else if (PSVVersion > 1 && - DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 6) < 0) - m_PSVInitInfo.PSVVersion = 1; - else if (PSVVersion > 2 && - DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 8) < 0) - m_PSVInitInfo.PSVVersion = 2; - else if (PSVVersion > MAX_PSV_VERSION) - m_PSVInitInfo.PSVVersion = MAX_PSV_VERSION; + uint32_t PSVVersionConstraint = hlsl::GetPSVVersion(m_ValMajor, m_ValMinor); + if (PSVVersion > PSVVersionConstraint) + m_PSVInitInfo.PSVVersion = PSVVersionConstraint; const ShaderModel *SM = m_Module.GetShaderModel(); UINT uCBuffers = m_Module.GetCBuffers().size(); @@ -834,8 +827,12 @@ public: PSVRuntimeInfo1 *pInfo1 = m_PSV.GetPSVRuntimeInfo1(); PSVRuntimeInfo2 *pInfo2 = m_PSV.GetPSVRuntimeInfo2(); PSVRuntimeInfo3 *pInfo3 = m_PSV.GetPSVRuntimeInfo3(); - - hlsl::InitPSVRuntimeInfo(pInfo, pInfo1, pInfo2, pInfo3, m_Module); + if (pInfo) + hlsl::SetShaderProps(pInfo, m_Module); + if (pInfo1) + hlsl::SetShaderProps(pInfo1, m_Module); + if (pInfo2) + hlsl::SetShaderProps(pInfo2, m_Module); if (pInfo3) pInfo3->EntryFunctionName = EntryFunctionName; diff --git a/lib/DxilContainer/DxilPipelineStateValidation.cpp b/lib/DxilContainer/DxilPipelineStateValidation.cpp index 5576fdd72..9f04c0994 100644 --- a/lib/DxilContainer/DxilPipelineStateValidation.cpp +++ b/lib/DxilContainer/DxilPipelineStateValidation.cpp @@ -24,6 +24,18 @@ using namespace hlsl; using namespace llvm; +uint32_t hlsl::GetPSVVersion(uint32_t ValMajor, uint32_t ValMinor) { + unsigned PSVVersion = MAX_PSV_VERSION; + // Constraint PSVVersion based on validator version + if (DXIL::CompareVersions(ValMajor, ValMinor, 1, 1) < 0) + PSVVersion = 0; + else if (DXIL::CompareVersions(ValMajor, ValMinor, 1, 6) < 0) + PSVVersion = 1; + else if (DXIL::CompareVersions(ValMajor, ValMinor, 1, 8) < 0) + PSVVersion = 2; + return PSVVersion; +} + void hlsl::InitPSVResourceBinding(PSVResourceBindInfo0 *Bind0, PSVResourceBindInfo1 *Bind1, DxilResourceBase *Res) { @@ -98,9 +110,7 @@ void hlsl::InitPSVSignatureElement(PSVSignatureElement0 &E, E.DynamicMaskAndStream |= (SE.GetDynIdxCompMask()) & 0xF; } -void hlsl::InitPSVRuntimeInfo(PSVRuntimeInfo0 *pInfo, PSVRuntimeInfo1 *pInfo1, - PSVRuntimeInfo2 *pInfo2, PSVRuntimeInfo3 *pInfo3, - const DxilModule &DM) { +void hlsl::SetShaderProps(PSVRuntimeInfo0 *pInfo, const DxilModule &DM) { const ShaderModel *SM = DM.GetShaderModel(); pInfo->MinimumExpectedWaveLaneCount = 0; pInfo->MaximumExpectedWaveLaneCount = (uint32_t)-1; @@ -205,7 +215,6 @@ void hlsl::InitPSVRuntimeInfo(PSVRuntimeInfo0 *pInfo, PSVRuntimeInfo1 *pInfo1, case ShaderModel::Kind::Mesh: { pInfo->MS.MaxOutputVertices = (uint16_t)DM.GetMaxOutputVertices(); pInfo->MS.MaxOutputPrimitives = (uint16_t)DM.GetMaxOutputPrimitives(); - pInfo1->MS1.MeshOutputTopology = (uint8_t)DM.GetMeshOutputTopology(); Module *mod = DM.GetModule(); const DataLayout &DL = mod->getDataLayout(); unsigned totalByteSize = 0; @@ -226,22 +235,36 @@ void hlsl::InitPSVRuntimeInfo(PSVRuntimeInfo0 *pInfo, PSVRuntimeInfo1 *pInfo1, break; } } +} - // Write MaxVertexCount - if (pInfo1) { - if (SM->GetKind() == ShaderModel::Kind::Geometry) - pInfo1->MaxVertexCount = (uint16_t)DM.GetMaxVertexCount(); +void hlsl::SetShaderProps(PSVRuntimeInfo1 *pInfo1, const DxilModule &DM) { + assert(pInfo1); + const ShaderModel *SM = DM.GetShaderModel(); + switch (SM->GetKind()) { + case ShaderModel::Kind::Geometry: + pInfo1->MaxVertexCount = (uint16_t)DM.GetMaxVertexCount(); + break; + case ShaderModel::Kind::Mesh: + pInfo1->MS1.MeshOutputTopology = (uint8_t)DM.GetMeshOutputTopology(); + break; + default: + break; } - if (pInfo2) { - switch (SM->GetKind()) { - case ShaderModel::Kind::Compute: - case ShaderModel::Kind::Mesh: - case ShaderModel::Kind::Amplification: - pInfo2->NumThreadsX = DM.GetNumThreads(0); - pInfo2->NumThreadsY = DM.GetNumThreads(1); - pInfo2->NumThreadsZ = DM.GetNumThreads(2); - break; - } +} + +void hlsl::SetShaderProps(PSVRuntimeInfo2 *pInfo2, const DxilModule &DM) { + assert(pInfo2); + const ShaderModel *SM = DM.GetShaderModel(); + switch (SM->GetKind()) { + case ShaderModel::Kind::Compute: + case ShaderModel::Kind::Mesh: + case ShaderModel::Kind::Amplification: + pInfo2->NumThreadsX = DM.GetNumThreads(0); + pInfo2->NumThreadsY = DM.GetNumThreads(1); + pInfo2->NumThreadsZ = DM.GetNumThreads(2); + break; + default: + break; } } @@ -360,10 +383,14 @@ void PSVResourceBindInfo1::Print(raw_ostream &OS) const { } void PSVSignatureElement::Print(raw_ostream &OS) const { + Print(OS, GetSemanticName(), GetSemanticIndexes()); +} + +void PSVSignatureElement::Print(raw_ostream &OS, const char *Name, + const uint32_t *SemanticIndexes) const { OS << "PSVSignatureElement:\n"; - OS << " SemanticName: " << GetSemanticName() << "\n"; + OS << " SemanticName: " << Name << "\n"; OS << " SemanticIndex: "; - const uint32_t *SemanticIndexes = GetSemanticIndexes(); for (unsigned i = 0; i < GetRows(); ++i) { OS << *(SemanticIndexes + i) << " "; } @@ -518,13 +545,10 @@ void PSVDependencyTable::Print(raw_ostream &OS, const char *InputSetName, } } -void DxilPipelineStateValidation::PrintPSVRuntimeInfo( - raw_ostream &OS, uint8_t ShaderKind, const char *Comment) const { - PSVRuntimeInfo0 *pInfo0 = m_pPSVRuntimeInfo0; - PSVRuntimeInfo1 *pInfo1 = m_pPSVRuntimeInfo1; - PSVRuntimeInfo2 *pInfo2 = m_pPSVRuntimeInfo2; - PSVRuntimeInfo3 *pInfo3 = m_pPSVRuntimeInfo3; - +void hlsl::PrintPSVRuntimeInfo(llvm::raw_ostream &OS, PSVRuntimeInfo0 *pInfo0, + PSVRuntimeInfo1 *pInfo1, PSVRuntimeInfo2 *pInfo2, + PSVRuntimeInfo3 *pInfo3, uint8_t ShaderKind, + const char *EntryName, const char *Comment) { if (pInfo1 && pInfo1->ShaderStage != ShaderKind) ShaderKind = pInfo1->ShaderStage; OS << Comment << "PSVRuntimeInfo:\n"; @@ -817,9 +841,74 @@ void DxilPipelineStateValidation::PrintPSVRuntimeInfo( } } if (pInfo3) - OS << Comment - << " EntryFunctionName: " << m_StringTable.Get(pInfo3->EntryFunctionName) - << "\n"; + OS << Comment << " EntryFunctionName: " << EntryName << "\n"; +} + +void DxilPipelineStateValidation::PrintPSVRuntimeInfo( + raw_ostream &OS, uint8_t ShaderKind, const char *Comment) const { + PSVRuntimeInfo0 *pInfo0 = m_pPSVRuntimeInfo0; + PSVRuntimeInfo1 *pInfo1 = m_pPSVRuntimeInfo1; + PSVRuntimeInfo2 *pInfo2 = m_pPSVRuntimeInfo2; + PSVRuntimeInfo3 *pInfo3 = m_pPSVRuntimeInfo3; + + hlsl::PrintPSVRuntimeInfo( + OS, pInfo0, pInfo1, pInfo2, pInfo3, ShaderKind, + m_pPSVRuntimeInfo3 ? m_StringTable.Get(pInfo3->EntryFunctionName) : "", + Comment); +} + +void DxilPipelineStateValidation::PrintViewIDState(raw_ostream &OS) const { + unsigned NumStreams = IsGS() ? PSV_GS_MAX_STREAMS : 1; + + if (m_pPSVRuntimeInfo1->UsesViewID) { + for (unsigned i = 0; i < NumStreams; ++i) { + OS << "Outputs affected by ViewID as a bitmask for stream " << i + << ":\n "; + uint8_t OutputVectors = m_pPSVRuntimeInfo1->SigOutputVectors[i]; + const PSVComponentMask ViewIDMask(m_pViewIDOutputMask[i], OutputVectors); + std::string OutputSetName = "Outputs"; + OutputSetName += "[" + std::to_string(i) + "]"; + ViewIDMask.Print(OS, "ViewID", OutputSetName.c_str()); + } + + if (IsHS() || IsMS()) { + OS << "PCOutputs affected by ViewID as a bitmask:\n"; + uint8_t OutputVectors = m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors; + const PSVComponentMask ViewIDMask(m_pViewIDPCOrPrimOutputMask, + OutputVectors); + ViewIDMask.Print(OS, "ViewID", "PCOutputs"); + } + } + + for (unsigned i = 0; i < NumStreams; ++i) { + OS << "Outputs affected by inputs as a table of bitmasks for stream " << i + << ":\n"; + uint8_t InputVectors = m_pPSVRuntimeInfo1->SigInputVectors; + uint8_t OutputVectors = m_pPSVRuntimeInfo1->SigOutputVectors[i]; + const PSVDependencyTable Table(m_pInputToOutputTable[i], InputVectors, + OutputVectors); + std::string OutputSetName = "Outputs"; + OutputSetName += "[" + std::to_string(i) + "]"; + Table.Print(OS, "Inputs", OutputSetName.c_str()); + } + + if (IsHS()) { + OS << "Patch constant outputs affected by inputs as a table of " + "bitmasks:\n"; + uint8_t InputVectors = m_pPSVRuntimeInfo1->SigInputVectors; + uint8_t OutputVectors = m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors; + const PSVDependencyTable Table(m_pInputToPCOutputTable, InputVectors, + OutputVectors); + Table.Print(OS, "Inputs", "PatchConstantOutputs"); + } else if (IsDS()) { + OS << "Outputs affected by patch constant inputs as a table of " + "bitmasks:\n"; + uint8_t InputVectors = m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors; + uint8_t OutputVectors = m_pPSVRuntimeInfo1->SigOutputVectors[0]; + const PSVDependencyTable Table(m_pPCInputToOutputTable, InputVectors, + OutputVectors); + Table.Print(OS, "PatchConstantInputs", "Outputs"); + } } void DxilPipelineStateValidation::Print(raw_ostream &OS, @@ -866,57 +955,6 @@ void DxilPipelineStateValidation::Print(raw_ostream &OS, PSVSE.Print(OS); } - unsigned NumStreams = IsGS() ? PSV_GS_MAX_STREAMS : 1; - - if (m_pPSVRuntimeInfo1->UsesViewID) { - for (unsigned i = 0; i < NumStreams; ++i) { - OS << "Outputs affected by ViewID as a bitmask for stream " << i - << ":\n "; - uint8_t OutputVectors = m_pPSVRuntimeInfo1->SigOutputVectors[i]; - const PSVComponentMask ViewIDMask(m_pViewIDOutputMask[i], - OutputVectors); - std::string OutputSetName = "Outputs"; - OutputSetName += "[" + std::to_string(i) + "]"; - ViewIDMask.Print(OS, "ViewID", OutputSetName.c_str()); - } - - if (IsHS() || IsMS()) { - OS << "PCOutputs affected by ViewID as a bitmask:\n"; - uint8_t OutputVectors = m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors; - const PSVComponentMask ViewIDMask(m_pViewIDPCOrPrimOutputMask, - OutputVectors); - ViewIDMask.Print(OS, "ViewID", "PCOutputs"); - } - } - - for (unsigned i = 0; i < NumStreams; ++i) { - OS << "Outputs affected by inputs as a table of bitmasks for stream " << i - << ":\n"; - uint8_t InputVectors = m_pPSVRuntimeInfo1->SigInputVectors; - uint8_t OutputVectors = m_pPSVRuntimeInfo1->SigOutputVectors[i]; - const PSVDependencyTable Table(m_pInputToOutputTable[i], InputVectors, - OutputVectors); - std::string OutputSetName = "Outputs"; - OutputSetName += "[" + std::to_string(i) + "]"; - Table.Print(OS, "Inputs", OutputSetName.c_str()); - } - - if (IsHS()) { - OS << "Patch constant outputs affected by inputs as a table of " - "bitmasks:\n"; - uint8_t InputVectors = m_pPSVRuntimeInfo1->SigInputVectors; - uint8_t OutputVectors = m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors; - const PSVDependencyTable Table(m_pInputToPCOutputTable, InputVectors, - OutputVectors); - Table.Print(OS, "Inputs", "PatchConstantOutputs"); - } else if (IsDS()) { - OS << "Outputs affected by patch constant inputs as a table of " - "bitmasks:\n"; - uint8_t InputVectors = m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors; - uint8_t OutputVectors = m_pPSVRuntimeInfo1->SigOutputVectors[0]; - const PSVDependencyTable Table(m_pPCInputToOutputTable, InputVectors, - OutputVectors); - Table.Print(OS, "PatchConstantInputs", "Outputs"); - } + PrintViewIDState(OS); } } diff --git a/lib/DxilValidation/DxilContainerValidation.cpp b/lib/DxilValidation/DxilContainerValidation.cpp index 48fbfce8a..a5e68eb5e 100644 --- a/lib/DxilValidation/DxilContainerValidation.cpp +++ b/lib/DxilValidation/DxilContainerValidation.cpp @@ -23,6 +23,7 @@ #include "dxc/DXIL/DxilModule.h" #include "dxc/DXIL/DxilUtil.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Module.h" @@ -32,6 +33,10 @@ #include "DxilValidationUtils.h" #include +#include + +using namespace llvm; +using namespace hlsl; using std::unique_ptr; using std::unordered_set; @@ -73,6 +78,359 @@ private: static void emitDxilDiag(LLVMContext &Ctx, const char *str) { hlsl::dxilutil::EmitErrorOnContext(Ctx, str); } + +class PSVContentVerifier { + DxilModule &DM; + DxilPipelineStateValidation &PSV; + ValidationContext &ValCtx; + bool PSVContentValid = true; + +public: + PSVContentVerifier(DxilPipelineStateValidation &PSV, DxilModule &DM, + ValidationContext &ValCtx) + : DM(DM), PSV(PSV), ValCtx(ValCtx) {} + void Verify(); + +private: + void VerifySignatures(unsigned ValMajor, unsigned ValMinor); + void VerifySignature(const DxilSignature &, PSVSignatureElement0 *Base, + unsigned Count, std::string Name, + bool i1ToUnknownCompat); + void VerifySignatureElement(const DxilSignatureElement &, + PSVSignatureElement0 *, const PSVStringTable &, + const PSVSemanticIndexTable &, std::string, bool); + void VerifyResources(unsigned PSVVersion); + template + void VerifyResourceTable(T &ResTab, unsigned &ResourceIndex, + unsigned PSVVersion); + void VerifyViewIDDependence(PSVRuntimeInfo1 *PSV1, unsigned PSVVersion); + void VerifyEntryProperties(const ShaderModel *SM, PSVRuntimeInfo0 *PSV0, + PSVRuntimeInfo1 *PSV1, PSVRuntimeInfo2 *PSV2); + void EmitMismatchError(StringRef Name, StringRef PartContent, + StringRef ModuleContent) { + ValCtx.EmitFormatError(ValidationRule::ContainerContentMatches, + {Name, "PSV0", PartContent, ModuleContent}); + PSVContentValid = false; + } + void EmitInvalidError(StringRef Name) { + ValCtx.EmitFormatError(ValidationRule::ContainerContentInvalid, {Name}); + PSVContentValid = false; + } + template static std::string GetDump(const Ty &T) { + std::string Str; + raw_string_ostream OS(Str); + T.Print(OS); + OS.flush(); + return Str; + } +}; + +void PSVContentVerifier::VerifyViewIDDependence(PSVRuntimeInfo1 *PSV1, + unsigned PSVVersion) { + std::vector ViewStateInPSV; + unsigned OutputSizeInUInts = hlsl::LoadViewIDStateFromPSV(nullptr, 0, PSV); + if (OutputSizeInUInts) { + ViewStateInPSV.assign(OutputSizeInUInts, 0); + hlsl::LoadViewIDStateFromPSV(ViewStateInPSV.data(), + (unsigned)ViewStateInPSV.size(), PSV); + } + // In case the num of input/output scalars are aligned to 4, the + // ViewStateInPSV could match the DxilModule's view state directly. + std::vector ViewStateInDxilModule = + DM.GetSerializedViewIdState(); + if (ViewStateInPSV == ViewStateInDxilModule) + return; + if (ViewStateInDxilModule.empty() && + std::all_of(ViewStateInPSV.begin(), ViewStateInPSV.end(), + [](unsigned int i) { return i == 0; })) + return; + + std::string Str; + raw_string_ostream OS(Str); + PSV.PrintViewIDState(OS); + OS.flush(); + + // Create a Temp PSV from DxilModule to print the ViewIDState. + unique_ptr pWriter(NewPSVWriter(DM, PSVVersion)); + CComPtr pOutputStream; + IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pOutputStream)); + pOutputStream->Reserve(pWriter->size()); + pWriter->write(pOutputStream); + + DxilPipelineStateValidation PSVFromDxilModule; + if (!PSVFromDxilModule.InitFromPSV0(pOutputStream->GetPtr(), + pOutputStream->GetPtrSize())) { + ValCtx.EmitFormatError( + ValidationRule::ContainerPartMatches, + {"Pipeline State Validation generated from DxiModule"}); + return; + } + + ViewStateInDxilModule.clear(); + OutputSizeInUInts = + hlsl::LoadViewIDStateFromPSV(nullptr, 0, PSVFromDxilModule); + if (OutputSizeInUInts) { + ViewStateInDxilModule.assign(OutputSizeInUInts, 0); + hlsl::LoadViewIDStateFromPSV(ViewStateInDxilModule.data(), + OutputSizeInUInts, PSVFromDxilModule); + } + // ViewStateInDxilModule and ViewStateInPSV all go through + // LoadViewIDStateFromPSV here, so they should match. + if (ViewStateInPSV == ViewStateInDxilModule) + return; + + std::string Str1; + raw_string_ostream OS1(Str1); + PSVFromDxilModule.PrintViewIDState(OS1); + OS1.flush(); + EmitMismatchError("ViewIDState", Str, Str1); +} + +void PSVContentVerifier::VerifySignatures(unsigned ValMajor, + unsigned ValMinor) { + bool i1ToUnknownCompat = DXIL::CompareVersions(ValMajor, ValMinor, 1, 5) < 0; + // Verify input signature + VerifySignature(DM.GetInputSignature(), PSV.GetInputElement0(0), + PSV.GetSigInputElements(), "SigInput", i1ToUnknownCompat); + // Verify output signature + VerifySignature(DM.GetOutputSignature(), PSV.GetOutputElement0(0), + PSV.GetSigOutputElements(), "SigOutput", i1ToUnknownCompat); + // Verify patch constant signature + VerifySignature(DM.GetPatchConstOrPrimSignature(), + PSV.GetPatchConstOrPrimElement0(0), + PSV.GetSigPatchConstOrPrimElements(), + "SigPatchConstantOrPrim", i1ToUnknownCompat); +} + +void PSVContentVerifier::VerifySignature(const DxilSignature &Sig, + PSVSignatureElement0 *Base, + unsigned Count, std::string Name, + bool i1ToUnknownCompat) { + if (Count != Sig.GetElements().size()) { + EmitMismatchError(Name + "Elements", std::to_string(Count), + std::to_string(Sig.GetElements().size())); + return; + } + + // Verify each element in DxilSignature. + const PSVStringTable &StrTab = PSV.GetStringTable(); + const PSVSemanticIndexTable &IndexTab = PSV.GetSemanticIndexTable(); + for (unsigned i = 0; i < Count; i++) + VerifySignatureElement(Sig.GetElement(i), + PSV.GetRecord( + Base, PSV.GetSignatureElementSize(), Count, i), + StrTab, IndexTab, Name, i1ToUnknownCompat); +} + +void PSVContentVerifier::VerifySignatureElement( + const DxilSignatureElement &SE, PSVSignatureElement0 *PSVSE0, + const PSVStringTable &StrTab, const PSVSemanticIndexTable &IndexTab, + std::string Name, bool i1ToUnknownCompat) { + // Find the signature element in the set. + PSVSignatureElement0 ModulePSVSE0; + InitPSVSignatureElement(ModulePSVSE0, SE, i1ToUnknownCompat); + + // Check the Name and SemanticIndex. + bool Mismatch = false; + const std::vector &SemanticIndexVec = SE.GetSemanticIndexVec(); + llvm::ArrayRef PSVSemanticIndexVec( + IndexTab.Get(PSVSE0->SemanticIndexes), PSVSE0->Rows); + if (SemanticIndexVec.size() == PSVSemanticIndexVec.size()) + Mismatch |= memcmp(PSVSemanticIndexVec.data(), SemanticIndexVec.data(), + SemanticIndexVec.size() * sizeof(uint32_t)) != 0; + else + Mismatch = true; + + ModulePSVSE0.SemanticIndexes = PSVSE0->SemanticIndexes; + + PSVSignatureElement PSVSE(StrTab, IndexTab, PSVSE0); + if (SE.IsArbitrary()) + Mismatch |= strcmp(PSVSE.GetSemanticName(), SE.GetName()); + else + Mismatch |= PSVSE0->SemanticKind != static_cast(SE.GetKind()); + + ModulePSVSE0.SemanticName = PSVSE0->SemanticName; + // Compare all fields. + Mismatch |= memcmp(&ModulePSVSE0, PSVSE0, sizeof(PSVSignatureElement0)) != 0; + if (Mismatch) { + PSVSignatureElement ModulePSVSE(StrTab, IndexTab, &ModulePSVSE0); + std::string ModuleStr; + raw_string_ostream OS(ModuleStr); + ModulePSVSE.Print(OS, SE.GetName(), SemanticIndexVec.data()); + OS.flush(); + std::string PartStr; + raw_string_ostream OS1(PartStr); + PSVSE.Print(OS1, PSVSE.GetSemanticName(), PSVSemanticIndexVec.data()); + OS1.flush(); + EmitMismatchError(Name + "Element", PartStr, ModuleStr); + } +} + +template +void PSVContentVerifier::VerifyResourceTable(T &ResTab, unsigned &ResourceIndex, + unsigned PSVVersion) { + for (auto &&R : ResTab) { + PSVResourceBindInfo1 BI; + InitPSVResourceBinding(&BI, &BI, R.get()); + + if (PSVVersion > 1) { + PSVResourceBindInfo1 *BindInfo = + PSV.GetPSVResourceBindInfo1(ResourceIndex); + if (memcmp(&BI, BindInfo, sizeof(PSVResourceBindInfo1)) != 0) { + std::string ModuleStr = GetDump(BI); + std::string PartStr = GetDump(*BindInfo); + EmitMismatchError("ResourceBindInfo", PartStr, ModuleStr); + } + } else { + PSVResourceBindInfo0 *BindInfo = + PSV.GetPSVResourceBindInfo0(ResourceIndex); + if (memcmp(&BI, BindInfo, sizeof(PSVResourceBindInfo0)) != 0) { + std::string ModuleStr = GetDump(BI); + std::string PartStr = GetDump(*BindInfo); + EmitMismatchError("ResourceBindInfo", PartStr, ModuleStr); + } + } + ResourceIndex++; + } +} + +void PSVContentVerifier::VerifyResources(unsigned PSVVersion) { + UINT uCBuffers = DM.GetCBuffers().size(); + UINT uSamplers = DM.GetSamplers().size(); + UINT uSRVs = DM.GetSRVs().size(); + UINT uUAVs = DM.GetUAVs().size(); + unsigned ResourceCount = uCBuffers + uSamplers + uSRVs + uUAVs; + if (PSV.GetBindCount() != ResourceCount) { + EmitMismatchError("ResourceCount", std::to_string(PSV.GetBindCount()), + std::to_string(ResourceCount)); + return; + } + // Verify each resource table. + unsigned ResIndex = 0; + // CBV + VerifyResourceTable(DM.GetCBuffers(), ResIndex, PSVVersion); + // Sampler + VerifyResourceTable(DM.GetSamplers(), ResIndex, PSVVersion); + // SRV + VerifyResourceTable(DM.GetSRVs(), ResIndex, PSVVersion); + // UAV + VerifyResourceTable(DM.GetUAVs(), ResIndex, PSVVersion); +} + +void PSVContentVerifier::VerifyEntryProperties(const ShaderModel *SM, + PSVRuntimeInfo0 *PSV0, + PSVRuntimeInfo1 *PSV1, + PSVRuntimeInfo2 *PSV2) { + PSVRuntimeInfo3 DMPSV; + memset(&DMPSV, 0, sizeof(PSVRuntimeInfo3)); + + hlsl::SetShaderProps((PSVRuntimeInfo0 *)&DMPSV, DM); + hlsl::SetShaderProps((PSVRuntimeInfo1 *)&DMPSV, DM); + hlsl::SetShaderProps((PSVRuntimeInfo2 *)&DMPSV, DM); + if (PSV1) { + // Init things not set in InitPSVRuntimeInfo. + DMPSV.ShaderStage = static_cast(SM->GetKind()); + DMPSV.SigInputElements = DM.GetInputSignature().GetElements().size(); + DMPSV.SigOutputElements = DM.GetOutputSignature().GetElements().size(); + DMPSV.SigPatchConstOrPrimElements = + DM.GetPatchConstOrPrimSignature().GetElements().size(); + // Set up ViewID and signature dependency info + DMPSV.UsesViewID = DM.m_ShaderFlags.GetViewID() ? true : false; + DMPSV.SigInputVectors = DM.GetInputSignature().NumVectorsUsed(0); + for (unsigned streamIndex = 0; streamIndex < 4; streamIndex++) + DMPSV.SigOutputVectors[streamIndex] = + DM.GetOutputSignature().NumVectorsUsed(streamIndex); + if (SM->IsHS() || SM->IsDS() || SM->IsMS()) + DMPSV.SigPatchConstOrPrimVectors = + DM.GetPatchConstOrPrimSignature().NumVectorsUsed(0); + } + bool Mismatched = false; + if (PSV2) + Mismatched = memcmp(PSV2, &DMPSV, sizeof(PSVRuntimeInfo2)) != 0; + else if (PSV1) + Mismatched = memcmp(PSV1, &DMPSV, sizeof(PSVRuntimeInfo1)) != 0; + else + Mismatched = memcmp(PSV0, &DMPSV, sizeof(PSVRuntimeInfo0)) != 0; + + if (Mismatched) { + std::string Str; + raw_string_ostream OS(Str); + hlsl::PrintPSVRuntimeInfo(OS, &DMPSV, &DMPSV, &DMPSV, &DMPSV, + static_cast(SM->GetKind()), + DM.GetEntryFunctionName().c_str(), ""); + OS.flush(); + std::string Str1; + raw_string_ostream OS1(Str1); + PSV.PrintPSVRuntimeInfo(OS1, static_cast(PSVShaderKind::Library), + ""); + OS1.flush(); + EmitMismatchError("PSVRuntimeInfo", Str, Str1); + } +} + +void PSVContentVerifier::Verify() { + unsigned ValMajor, ValMinor; + DM.GetValidatorVersion(ValMajor, ValMinor); + unsigned PSVVersion = hlsl::GetPSVVersion(ValMajor, ValMinor); + + PSVInitInfo PSVInfo(PSVVersion); + if (PSV.GetRuntimeInfoSize() != PSVInfo.RuntimeInfoSize()) { + EmitMismatchError("PSVRuntimeInfoSize", + std::to_string(PSV.GetRuntimeInfoSize()), + std::to_string(PSVInfo.RuntimeInfoSize())); + return; + } + + if (PSV.GetBindCount() > 0 && + PSV.GetResourceBindInfoSize() != PSVInfo.ResourceBindInfoSize()) { + EmitMismatchError("ResourceBindInfoSize", + std::to_string(PSV.GetResourceBindInfoSize()), + std::to_string(PSVInfo.ResourceBindInfoSize())); + return; + } + VerifyResources(PSVVersion); + + PSVRuntimeInfo0 *PSV0 = PSV.GetPSVRuntimeInfo0(); + PSVRuntimeInfo1 *PSV1 = PSV.GetPSVRuntimeInfo1(); + PSVRuntimeInfo2 *PSV2 = PSV.GetPSVRuntimeInfo2(); + + const ShaderModel *SM = DM.GetShaderModel(); + VerifyEntryProperties(SM, PSV0, PSV1, PSV2); + if (PSVVersion > 0) { + if (((PSV.GetSigInputElements() + PSV.GetSigOutputElements() + + PSV.GetSigPatchConstOrPrimElements()) > 0) && + PSV.GetSignatureElementSize() != PSVInfo.SignatureElementSize()) { + EmitMismatchError("SignatureElementSize", + std::to_string(PSV.GetSignatureElementSize()), + std::to_string(PSVInfo.SignatureElementSize())); + return; + } + uint8_t ShaderStage = static_cast(SM->GetKind()); + if (PSV1->ShaderStage != ShaderStage) { + EmitMismatchError("ShaderStage", std::to_string(PSV1->ShaderStage), + std::to_string(ShaderStage)); + return; + } + if (PSV1->UsesViewID != DM.m_ShaderFlags.GetViewID()) + EmitMismatchError("UsesViewID", std::to_string(PSV1->UsesViewID), + std::to_string(DM.m_ShaderFlags.GetViewID())); + + VerifySignatures(ValMajor, ValMinor); + + VerifyViewIDDependence(PSV1, PSVVersion); + } + // PSV2 only added NumThreadsX/Y/Z which verified in VerifyEntryProperties. + if (PSVVersion > 2) { + if (DM.GetEntryFunctionName() != PSV.GetEntryFunctionName()) + EmitMismatchError("EntryFunctionName", PSV.GetEntryFunctionName(), + DM.GetEntryFunctionName()); + } + + if (!PSVContentValid) + ValCtx.EmitFormatError(ValidationRule::ContainerPartMatches, + {"Pipeline State Validation"}); +} + } // namespace namespace hlsl { @@ -151,17 +509,14 @@ bool VerifySignatureMatches(llvm::Module *pModule, DXIL::SignatureKind SigKind, static void VerifyPSVMatches(ValidationContext &ValCtx, const void *pPSVData, uint32_t PSVSize) { - uint32_t PSVVersion = - MAX_PSV_VERSION; // This should be set to the newest version - unique_ptr pWriter(NewPSVWriter(ValCtx.DxilMod, PSVVersion)); - // Try each version in case an earlier version matches module - while (PSVVersion && pWriter->size() != PSVSize) { - PSVVersion--; - pWriter.reset(NewPSVWriter(ValCtx.DxilMod, PSVVersion)); + DxilPipelineStateValidation PSV; + if (!PSV.InitFromPSV0(pPSVData, PSVSize)) { + ValCtx.EmitFormatError(ValidationRule::ContainerPartMatches, + {"Pipeline State Validation"}); + return; } - // generate PSV data from module and memcmp - VerifyBlobPartMatches(ValCtx, "Pipeline State Validation", pWriter.get(), - pPSVData, PSVSize); + PSVContentVerifier Verifier(PSV, ValCtx.DxilMod, ValCtx); + Verifier.Verify(); } static void VerifyFeatureInfoMatches(ValidationContext &ValCtx, diff --git a/projects/dxilconv/lib/DxbcConverter/DxbcConverter.cpp b/projects/dxilconv/lib/DxbcConverter/DxbcConverter.cpp index ff7d67e14..d0f00f7c7 100644 --- a/projects/dxilconv/lib/DxbcConverter/DxbcConverter.cpp +++ b/projects/dxilconv/lib/DxbcConverter/DxbcConverter.cpp @@ -1232,55 +1232,28 @@ AddDxilPipelineStateValidationToDXBC(DxilModule *pModule, DXASSERT_LOCALVAR_NOMSG(uTotalResources, uResIndex < uTotalResources); PSVResourceBindInfo0 *pBindInfo = PSV.GetPSVResourceBindInfo0(uResIndex); DXASSERT_NOMSG(pBindInfo); - pBindInfo->ResType = (UINT)PSVResourceType::CBV; - pBindInfo->Space = R->GetSpaceID(); - pBindInfo->LowerBound = R->GetLowerBound(); - pBindInfo->UpperBound = R->GetUpperBound(); + InitPSVResourceBinding(pBindInfo, nullptr, R.get()); uResIndex++; } for (auto &&R : pModule->GetSamplers()) { DXASSERT_NOMSG(uResIndex < uTotalResources); PSVResourceBindInfo0 *pBindInfo = PSV.GetPSVResourceBindInfo0(uResIndex); DXASSERT_NOMSG(pBindInfo); - pBindInfo->ResType = (UINT)PSVResourceType::Sampler; - pBindInfo->Space = R->GetSpaceID(); - pBindInfo->LowerBound = R->GetLowerBound(); - pBindInfo->UpperBound = R->GetUpperBound(); + InitPSVResourceBinding(pBindInfo, nullptr, R.get()); uResIndex++; } for (auto &&R : pModule->GetSRVs()) { DXASSERT_NOMSG(uResIndex < uTotalResources); PSVResourceBindInfo0 *pBindInfo = PSV.GetPSVResourceBindInfo0(uResIndex); DXASSERT_NOMSG(pBindInfo); - if (R->IsStructuredBuffer()) { - pBindInfo->ResType = (UINT)PSVResourceType::SRVStructured; - } else if (R->IsRawBuffer()) { - pBindInfo->ResType = (UINT)PSVResourceType::SRVRaw; - } else { - pBindInfo->ResType = (UINT)PSVResourceType::SRVTyped; - } - pBindInfo->Space = R->GetSpaceID(); - pBindInfo->LowerBound = R->GetLowerBound(); - pBindInfo->UpperBound = R->GetUpperBound(); + InitPSVResourceBinding(pBindInfo, nullptr, R.get()); uResIndex++; } for (auto &&R : pModule->GetUAVs()) { DXASSERT_NOMSG(uResIndex < uTotalResources); PSVResourceBindInfo0 *pBindInfo = PSV.GetPSVResourceBindInfo0(uResIndex); DXASSERT_NOMSG(pBindInfo); - if (R->IsStructuredBuffer()) { - if (R->HasCounter()) - pBindInfo->ResType = (UINT)PSVResourceType::UAVStructuredWithCounter; - else - pBindInfo->ResType = (UINT)PSVResourceType::UAVStructured; - } else if (R->IsRawBuffer()) { - pBindInfo->ResType = (UINT)PSVResourceType::UAVRaw; - } else { - pBindInfo->ResType = (UINT)PSVResourceType::UAVTyped; - } - pBindInfo->Space = R->GetSpaceID(); - pBindInfo->LowerBound = R->GetLowerBound(); - pBindInfo->UpperBound = R->GetUpperBound(); + InitPSVResourceBinding(pBindInfo, nullptr, R.get()); uResIndex++; } DXASSERT_NOMSG(uResIndex == uTotalResources); diff --git a/tools/clang/test/DXC/dumpPSV_HS.hlsl b/tools/clang/test/DXC/dumpPSV_HS.hlsl index 0cc4830bd..6a4e2957a 100644 --- a/tools/clang/test/DXC/dumpPSV_HS.hlsl +++ b/tools/clang/test/DXC/dumpPSV_HS.hlsl @@ -11,7 +11,7 @@ // CHECK-NEXT: OutputPrimitive=triangle_cw // CHECK-NEXT: MinimumExpectedWaveLaneCount: 0 // CHECK-NEXT: MaximumExpectedWaveLaneCount: 4294967295 -// CHECK-NEXT: UsesViewID: false +// CHECK-NEXT: UsesViewID: true // CHECK-NEXT: SigInputElements: 3 // CHECK-NEXT: SigOutputElements: 3 // CHECK-NEXT: SigPatchConstOrPrimElements: 2 @@ -126,6 +126,10 @@ // CHECK-NEXT: OutputStream: 0 // CHECK-NEXT: ComponentType: 3 // CHECK-NEXT: DynamicIndexMask: 0 +// CHECK-NEXT: Outputs affected by ViewID as a bitmask for stream 0: +// CHECK-NEXT: ViewID influencing Outputs[0] : 8 9 10 +// CHECK-NEXT: PCOutputs affected by ViewID as a bitmask: +// CHECK-NEXT: ViewID influencing PCOutputs : 12 // CHECK-NEXT: Outputs affected by inputs as a table of bitmasks for stream 0: // CHECK-NEXT: Inputs contributing to computation of Outputs[0]: // CHECK-NEXT: Inputs[0] influencing Outputs[0] : 0 @@ -142,7 +146,7 @@ // CHECK-NEXT: Inputs[11] influencing Outputs[0] : None // CHECK-NEXT: Patch constant outputs affected by inputs as a table of bitmasks: // CHECK-NEXT: Inputs contributing to computation of PatchConstantOutputs: -// CHECK-NEXT: Inputs[0] influencing PatchConstantOutputs : None +// CHECK-NEXT: Inputs[0] influencing PatchConstantOutputs : 3 // CHECK-NEXT: Inputs[1] influencing PatchConstantOutputs : None // CHECK-NEXT: Inputs[2] influencing PatchConstantOutputs : None // CHECK-NEXT: Inputs[3] influencing PatchConstantOutputs : None @@ -184,14 +188,14 @@ float4 HSPerPatchFunc() return 1.8; } -HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 3 > points ) +HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 3 > points ,uint vid : SV_ViewID) { HSPerPatchData d; - d.edges[ 0 ] = 1; + d.edges[ 0 ] = points[0].pos.x; d.edges[ 1 ] = 1; d.edges[ 2 ] = 1; - d.inside = 1; + d.inside = vid; return d; } @@ -203,12 +207,13 @@ HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 3 > points ) [patchconstantfunc("HSPerPatchFunc")] [outputcontrolpoints(3)] HSPerVertexData main( const uint id : SV_OutputControlPointID, - const InputPatch< PSSceneIn, 3 > points ) + uint vid : SV_ViewID, + const InputPatch< PSSceneIn, 3 > points ) { HSPerVertexData v; // Just forward the vertex v.v = points[ id ]; - + v.v.norm += vid; return v; } diff --git a/tools/clang/test/DXILValidation/hs_signatures.hlsl b/tools/clang/test/DXILValidation/hs_signatures.hlsl new file mode 100644 index 000000000..0a174156c --- /dev/null +++ b/tools/clang/test/DXILValidation/hs_signatures.hlsl @@ -0,0 +1,47 @@ +// For Validation::PSVSignatureTableReorder. + +struct PSSceneIn +{ + float4 pos : SV_Position; + float2 tex : TEXCOORD2; + float3 norm : NORMAL3; +}; + +struct HSPerVertexData +{ + PSSceneIn v; +}; + +struct HSPerPatchData +{ + float edges[2] : SV_TessFactor; + float t : PN_POSITION; +}; + +HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 2 > points, const OutputPatch< HSPerVertexData, 2 > opoints ) +{ + HSPerPatchData d; + + d.edges[0] = points[0].tex.x; + d.edges[1] = opoints[1].v.tex.x; + d.t = 2; + + return d; +} + +// hull per-control point shader +[domain("isoline")] +[partitioning("fractional_odd")] +[outputtopology("line")] +[patchconstantfunc("HSPerPatchFunc")] +[outputcontrolpoints(2)] +HSPerVertexData main( const uint id : SV_OutputControlPointID, + const InputPatch< PSSceneIn, 2 > points ) +{ + HSPerVertexData v; + + // Just forward the vertex + v.v = points[ id ]; + + return v; +} diff --git a/tools/clang/unittests/HLSL/ValidationTest.cpp b/tools/clang/unittests/HLSL/ValidationTest.cpp index 8f6236b8a..339ff1fbb 100644 --- a/tools/clang/unittests/HLSL/ValidationTest.cpp +++ b/tools/clang/unittests/HLSL/ValidationTest.cpp @@ -18,7 +18,9 @@ #include "dxc/DxilContainer/DxilContainer.h" #include "dxc/DxilContainer/DxilContainerAssembler.h" +#include "dxc/DxilContainer/DxilPipelineStateValidation.h" #include "dxc/DxilHash/DxilHash.h" +#include "dxc/Support/WinIncludes.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Regex.h" @@ -309,6 +311,17 @@ public: TEST_METHOD(CacheInitWithMinPrec) TEST_METHOD(CacheInitWithLowPrec) + TEST_METHOD(PSVStringTableReorder) + TEST_METHOD(PSVSemanticIndexTableReorder) + TEST_METHOD(PSVContentValidationVS) + TEST_METHOD(PSVContentValidationHS) + TEST_METHOD(PSVContentValidationDS) + TEST_METHOD(PSVContentValidationGS) + TEST_METHOD(PSVContentValidationPS) + TEST_METHOD(PSVContentValidationCS) + TEST_METHOD(PSVContentValidationMS) + TEST_METHOD(PSVContentValidationAS) + dxc::DxcDllSupport m_dllSupport; VersionSupportInfo m_ver; @@ -402,6 +415,18 @@ public: return true; } + bool CompileFile(LPCWSTR fileName, LPCSTR pShaderModel, + IDxcBlob **pResultBlob) { + std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(fileName); + CComPtr pLibrary; + CComPtr pSource; + VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary)); + VERIFY_SUCCEEDED( + pLibrary->CreateBlobFromFile(fullPath.c_str(), nullptr, &pSource)); + return CompileSource(pSource, pShaderModel, nullptr, 0, nullptr, 0, + pResultBlob); + } + bool CompileSource(IDxcBlobEncoding *pSource, LPCSTR pShaderModel, IDxcBlob **pResultBlob) { return CompileSource(pSource, pShaderModel, nullptr, 0, nullptr, 0, @@ -4523,3 +4548,1489 @@ TEST_F(ValidationTest, CacheInitWithLowPrec) { // Ensures type cache is property initialized when in exact low-precision mode TestCheck(L"..\\DXILValidation\\val-dx-type-lowprec.ll"); } + +TEST_F(ValidationTest, PSVStringTableReorder) { + if (!m_ver.m_InternalValidator) + if (m_ver.SkipDxilVersion(1, 8)) + return; + + CComPtr pProgram; + CompileSource("float4 main(float a:A, float b:B) : SV_Target { return 1; }", + "ps_6_0", &pProgram); + + CComPtr pValidator; + CComPtr pResult; + unsigned Flags = 0; + VERIFY_SUCCEEDED( + m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator)); + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pResult)); + // Make sure the validation was successful. + HRESULT status; + VERIFY_IS_NOT_NULL(pResult); + VERIFY_SUCCEEDED(pResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); + + // Update string table. + hlsl::DxilContainerHeader *pHeader; + hlsl::DxilPartIterator pPartIter(nullptr, 0); + pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer(); + pPartIter = + std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader), + hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation)); + VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter); + + const DxilPartHeader *pPSVPart = (const DxilPartHeader *)(*pPartIter); + const uint32_t *PSVPtr = (const uint32_t *)GetDxilPartData(pPSVPart); + + uint32_t PSVRuntimeInfo_size = *(PSVPtr++); + VERIFY_ARE_EQUAL(sizeof(PSVRuntimeInfo3), PSVRuntimeInfo_size); + PSVRuntimeInfo3 *PSVInfo = + const_cast((const PSVRuntimeInfo3 *)PSVPtr); + VERIFY_ARE_EQUAL(2u, PSVInfo->SigInputElements); + PSVPtr += PSVRuntimeInfo_size / 4; + uint32_t ResourceCount = *(PSVPtr++); + VERIFY_ARE_EQUAL(0u, ResourceCount); + uint32_t StringTableSize = *(PSVPtr++); + VERIFY_ARE_EQUAL(12u, StringTableSize); + const char *StringTable = (const char *)PSVPtr; + VERIFY_ARE_EQUAL('\0', StringTable[0]); + PSVPtr += StringTableSize / 4; + uint32_t SemanticIndexTableEntries = *(PSVPtr++); + VERIFY_ARE_EQUAL(1u, SemanticIndexTableEntries); + PSVPtr += sizeof(SemanticIndexTableEntries) / 4; + uint32_t PSVSignatureElement_size = *(PSVPtr++); + VERIFY_ARE_EQUAL(sizeof(PSVSignatureElement0), PSVSignatureElement_size); + PSVSignatureElement0 *SigInput = + const_cast((const PSVSignatureElement0 *)PSVPtr); + PSVSignatureElement0 *SigInput1 = SigInput + 1; + PSVSignatureElement0 *SigOutput = SigInput + 2; + // Update StringTable only. + const char OrigStringTable[12] = {0, 'A', 0, 'B', 0, 'm', + 'a', 'i', 'n', 0, 0, 0}; + VERIFY_ARE_EQUAL(0, memcmp(OrigStringTable, StringTable, 12)); + const char UpdatedStringTable[12] = {'B', 0, 'A', 0, 'm', 'a', + 'i', 'n', 0, 0, 0, 0}; + memcpy((void *)StringTable, (void *)UpdatedStringTable, 12); + + // Run validation again. + CComPtr pUpdatedTableResult; + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedTableResult)); + // Make sure the validation was fail. + VERIFY_IS_NOT_NULL(pUpdatedTableResult); + VERIFY_SUCCEEDED(pUpdatedTableResult->GetStatus(&status)); + VERIFY_FAILED(status); + CheckOperationResultMsgs( + pUpdatedTableResult, + {"error: DXIL container mismatch for 'SigInputElement' between 'PSV0' " + "part:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 1", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 1", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'SigInputElement' between 'PSV0' " + "part:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 1", + " Rows: 1", + " Cols: 1", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 1", + " Rows: 1", + " Cols: 1", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'EntryFunctionName' between 'PSV0' " + "part:('ain') and DXIL module:('main')", + "error: Container part 'Pipeline State Validation' does not match " + "expected for module.", + "Validation failed."}, + /*maySucceedAnyway*/ false, /*bRegex*/ false); + + // Update string table index. + SigInput->SemanticName = 2; + SigInput1->SemanticName = 0; + PSVInfo->EntryFunctionName = 4; + SigOutput->SemanticName = 1; + + // Run validation again. + CComPtr pUpdatedResult; + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult)); + // Make sure the validation was successful. + VERIFY_IS_NOT_NULL(pUpdatedResult); + VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); +} + +class SemanticIndexRotator { + llvm::MutableArrayRef SignatureElements; + +public: + SemanticIndexRotator(PSVSignatureElement0 *SigInput, + unsigned NumSignatureElements) + : SignatureElements(SigInput, NumSignatureElements) {} + + void Rotate(uint32_t SemanticIndexTableEntries) { + for (unsigned i = 0; i < SignatureElements.size(); ++i) + if (SignatureElements[i].SemanticIndexes == 0) + SignatureElements[i].SemanticIndexes = SemanticIndexTableEntries - 1; + else + SignatureElements[i].SemanticIndexes = + SignatureElements[i].SemanticIndexes - 1; + } +}; + +TEST_F(ValidationTest, PSVSemanticIndexTableReorder) { + if (!m_ver.m_InternalValidator) + if (m_ver.SkipDxilVersion(1, 8)) + return; + + CComPtr pProgram; + CompileFile(L"..\\DXILValidation\\hs_signatures.hlsl", "hs_6_0", &pProgram); + + CComPtr pValidator; + CComPtr pResult; + unsigned Flags = 0; + VERIFY_SUCCEEDED( + m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator)); + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pResult)); + // Make sure the validation was successful. + HRESULT status; + VERIFY_IS_NOT_NULL(pResult); + VERIFY_SUCCEEDED(pResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); + + // Update input signature semantic index table. + hlsl::DxilContainerHeader *pHeader; + hlsl::DxilPartIterator pPartIter(nullptr, 0); + pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer(); + pPartIter = + std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader), + hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation)); + VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter); + + const DxilPartHeader *pPSVPart = (const DxilPartHeader *)(*pPartIter); + const uint32_t *PSVPtr = (const uint32_t *)GetDxilPartData(pPSVPart); + + uint32_t PSVRuntimeInfo_size = *(PSVPtr++); + VERIFY_ARE_EQUAL(sizeof(PSVRuntimeInfo3), PSVRuntimeInfo_size); + PSVRuntimeInfo3 *PSVInfo = + const_cast((const PSVRuntimeInfo3 *)PSVPtr); + VERIFY_ARE_EQUAL(PSVInfo->SigInputElements, 3u); + VERIFY_ARE_EQUAL(PSVInfo->SigOutputElements, 3u); + VERIFY_ARE_EQUAL(PSVInfo->SigPatchConstOrPrimElements, 2u); + PSVPtr += PSVRuntimeInfo_size / 4; + uint32_t ResourceCount = *(PSVPtr++); + VERIFY_ARE_EQUAL(ResourceCount, 0u); + + uint32_t StringTableSize = *(PSVPtr++); + PSVPtr += StringTableSize / 4; + + uint32_t SemanticIndexTableEntries = *(PSVPtr++); + llvm::MutableArrayRef SemanticTable(const_cast(PSVPtr), + SemanticIndexTableEntries); + + PSVPtr += SemanticIndexTableEntries; + + uint32_t PSVSignatureElement_size = *(PSVPtr++); + VERIFY_ARE_EQUAL(PSVSignatureElement_size, sizeof(PSVSignatureElement0)); + + SemanticIndexRotator InputRotator( + const_cast((const PSVSignatureElement0 *)PSVPtr), + PSVInfo->SigInputElements); + + PSVPtr += PSVSignatureElement_size * PSVInfo->SigInputElements / 4; + SemanticIndexRotator OutputRotator( + const_cast((const PSVSignatureElement0 *)PSVPtr), + PSVInfo->SigOutputElements); + + PSVPtr += PSVSignatureElement_size * PSVInfo->SigOutputElements / 4; + SemanticIndexRotator PatchConstOrPrimRotator( + const_cast((const PSVSignatureElement0 *)PSVPtr), + PSVInfo->SigPatchConstOrPrimElements); + + // Update SemanticTable by rotating. + std::rotate(SemanticTable.begin(), SemanticTable.begin() + 1, + SemanticTable.end()); + + // Run validation again. + CComPtr pParitalUpdatedResult; + VERIFY_SUCCEEDED( + pValidator->Validate(pProgram, Flags, &pParitalUpdatedResult)); + // Make sure the validation was fail. + VERIFY_IS_NOT_NULL(pParitalUpdatedResult); + VERIFY_SUCCEEDED(pParitalUpdatedResult->GetStatus(&status)); + VERIFY_FAILED(status); + + CheckOperationResultMsgs( + pParitalUpdatedResult, + {"error: DXIL container mismatch for 'SigInputElement' between 'PSV0' " + "part:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 2 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 4", + " SemanticKind: Position", + " InterpolationMode: 4", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 4", + " SemanticKind: Position", + " InterpolationMode: 4", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'SigInputElement' between 'PSV0' " + "part:('PSVSignatureElement:", + " SemanticName: TEXCOORD", + " SemanticIndex: 3 ", + " IsAllocated: 1", + " StartRow: 1", + " StartCol: 0", + " Rows: 1", + " Cols: 2", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: TEXCOORD", + " SemanticIndex: 2 ", + " IsAllocated: 1", + " StartRow: 1", + " StartCol: 0", + " Rows: 1", + " Cols: 2", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'SigInputElement' between 'PSV0' " + "part:('PSVSignatureElement:", + " SemanticName: NORMAL", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 2", + " StartCol: 0", + " Rows: 1", + " Cols: 3", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: NORMAL", + " SemanticIndex: 3 ", + " IsAllocated: 1", + " StartRow: 2", + " StartCol: 0", + " Rows: 1", + " Cols: 3", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'SigOutputElement' between 'PSV0' " + "part:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 2 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 4", + " SemanticKind: Position", + " InterpolationMode: 4", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 4", + " SemanticKind: Position", + " InterpolationMode: 4", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'SigOutputElement' between 'PSV0' " + "part:('PSVSignatureElement:", + " SemanticName: TEXCOORD", + " SemanticIndex: 3 ", + " IsAllocated: 1", + " StartRow: 1", + " StartCol: 0", + " Rows: 1", + " Cols: 2", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: TEXCOORD", + " SemanticIndex: 2 ", + " IsAllocated: 1", + " StartRow: 1", + " StartCol: 0", + " Rows: 1", + " Cols: 2", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'SigOutputElement' between 'PSV0' " + "part:('PSVSignatureElement:", + " SemanticName: NORMAL", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 2", + " StartCol: 0", + " Rows: 1", + " Cols: 3", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: NORMAL", + " SemanticIndex: 3 ", + " IsAllocated: 1", + " StartRow: 2", + " StartCol: 0", + " Rows: 1", + " Cols: 3", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'SigPatchConstantOrPrimElement' " + "between 'PSV0' part:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 1 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 3", + " Rows: 2", + " Cols: 1", + " SemanticKind: TessFactor", + " InterpolationMode: 0", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 0 1 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 3", + " Rows: 2", + " Cols: 1", + " SemanticKind: TessFactor", + " InterpolationMode: 0", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'SigPatchConstantOrPrimElement' " + "between 'PSV0' part:('PSVSignatureElement:", + " SemanticName: PN_POSITION", + " SemanticIndex: 2 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 1", + " SemanticKind: Arbitrary", + " InterpolationMode: 0", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: PN_POSITION", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 1", + " SemanticKind: Arbitrary", + " InterpolationMode: 0", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: Container part 'Pipeline State Validation' does not match " + "expected for module.", + "Validation failed." + + }, + /*maySucceedAnyway*/ false, /*bRegex*/ false); + // Update SemanticIndexes. + InputRotator.Rotate(SemanticIndexTableEntries); + OutputRotator.Rotate(SemanticIndexTableEntries); + PatchConstOrPrimRotator.Rotate(SemanticIndexTableEntries); + + // Run validation again. + CComPtr pUpdatedResult; + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult)); + // Make sure the validation was successful. + VERIFY_IS_NOT_NULL(pUpdatedResult); + VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); +} + +struct SimplePSV { + PSVRuntimeInfo3 *PSVInfo; + llvm::MutableArrayRef ResourceBindInfo; + llvm::MutableArrayRef StringTable; + llvm::MutableArrayRef SemanticIndexTable; + + llvm::MutableArrayRef SigInput; + llvm::MutableArrayRef SigOutput; + llvm::MutableArrayRef SigPatchConstOrPrim; + + llvm::MutableArrayRef InputToOutputTable[DXIL::kNumOutputStreams]; + llvm::MutableArrayRef InputToPCOutputTable; + llvm::MutableArrayRef PCInputToOutputTable; + llvm::MutableArrayRef ViewIDOutputMask[DXIL::kNumOutputStreams]; + llvm::MutableArrayRef ViewIDPCOutputMask; + SimplePSV(const DxilPartHeader *pPSVPart); +}; + +SimplePSV::SimplePSV(const DxilPartHeader *pPSVPart) { + uint32_t PartSize = pPSVPart->PartSize; + uint32_t *PSVPtr = + const_cast((const uint32_t *)GetDxilPartData(pPSVPart)); + const uint32_t *PSVPtrEnd = PSVPtr + PartSize / 4; + + uint32_t PSVRuntimeInfoSize = *(PSVPtr++); + VERIFY_ARE_EQUAL(sizeof(PSVRuntimeInfo3), PSVRuntimeInfoSize); + PSVRuntimeInfo3 *PSVInfo3 = + const_cast((const PSVRuntimeInfo3 *)PSVPtr); + PSVInfo = PSVInfo3; + + PSVPtr += PSVRuntimeInfoSize / 4; + uint32_t ResourceCount = *(PSVPtr++); + if (ResourceCount) { + uint32_t ResourceBindInfoSize = *(PSVPtr++); + VERIFY_ARE_EQUAL(sizeof(PSVResourceBindInfo1), ResourceBindInfoSize); + ResourceBindInfo = llvm::MutableArrayRef( + (PSVResourceBindInfo1 *)PSVPtr, ResourceCount); + } + PSVPtr += ResourceCount * sizeof(PSVResourceBindInfo1) / 4; + uint32_t StringTableSize = *(PSVPtr++); + if (StringTableSize) + StringTable = llvm::MutableArrayRef((char *)PSVPtr, StringTableSize); + PSVPtr += StringTableSize / 4; + uint32_t SemanticIndexTableEntries = *(PSVPtr++); + if (SemanticIndexTableEntries) + SemanticIndexTable = llvm::MutableArrayRef( + (uint32_t *)PSVPtr, SemanticIndexTableEntries); + PSVPtr += SemanticIndexTableEntries; + if (PSVInfo3->SigInputElements || PSVInfo3->SigOutputElements || + PSVInfo3->SigPatchConstOrPrimElements) { + uint32_t PSVSignatureElementSize = *(PSVPtr++); + VERIFY_ARE_EQUAL(sizeof(PSVSignatureElement0), PSVSignatureElementSize); + } + if (PSVInfo3->SigInputElements) + SigInput = llvm::MutableArrayRef( + (PSVSignatureElement0 *)PSVPtr, PSVInfo->SigInputElements); + PSVPtr += PSVInfo3->SigInputElements * sizeof(PSVSignatureElement0) / 4; + + if (PSVInfo3->SigOutputElements) + SigOutput = llvm::MutableArrayRef( + (PSVSignatureElement0 *)PSVPtr, PSVInfo->SigOutputElements); + PSVPtr += PSVInfo3->SigOutputElements * sizeof(PSVSignatureElement0) / 4; + + if (PSVInfo3->SigPatchConstOrPrimElements) + SigPatchConstOrPrim = llvm::MutableArrayRef( + (PSVSignatureElement0 *)PSVPtr, PSVInfo->SigPatchConstOrPrimElements); + PSVPtr += + PSVInfo3->SigPatchConstOrPrimElements * sizeof(PSVSignatureElement0) / 4; + + if (PSVInfo3->UsesViewID) { + + for (unsigned i = 0; i < DXIL::kNumOutputStreams; i++) { + if (PSVInfo3->SigOutputVectors[i] == 0) + continue; + ViewIDOutputMask[i] = llvm::MutableArrayRef( + (uint32_t *)PSVPtr, + llvm::RoundUpToAlignment(PSVInfo3->SigOutputVectors[i], 8) / 8); + PSVPtr += ViewIDOutputMask[i].size(); + } + if ((PSVInfo3->ShaderStage == static_cast(PSVShaderKind::Hull) || + PSVInfo3->ShaderStage == static_cast(PSVShaderKind::Mesh)) && + PSVInfo3->SigPatchConstOrPrimVectors != 0) { + ViewIDPCOutputMask = llvm::MutableArrayRef( + (uint32_t *)PSVPtr, + llvm::RoundUpToAlignment(PSVInfo3->SigPatchConstOrPrimVectors, 8) / + 8); + PSVPtr += ViewIDPCOutputMask.size(); + } + } + + for (unsigned i = 0; i < DXIL::kNumOutputStreams; i++) { + if (PSVInfo3->SigInputVectors == 0 || PSVInfo3->SigOutputVectors[i] == 0) + continue; + InputToOutputTable[i] = llvm::MutableArrayRef( + (uint32_t *)PSVPtr, + 4 * PSVInfo3->SigInputVectors * + llvm::RoundUpToAlignment(PSVInfo3->SigOutputVectors[i], 8) / 8); + PSVPtr += InputToOutputTable[i].size(); + } + if ((PSVInfo3->ShaderStage == static_cast(PSVShaderKind::Hull) || + PSVInfo3->ShaderStage == static_cast(PSVShaderKind::Mesh)) && + PSVInfo3->SigInputVectors != 0 && + PSVInfo3->SigPatchConstOrPrimVectors != 0) { + InputToPCOutputTable = llvm::MutableArrayRef( + (uint32_t *)PSVPtr, + 4 * PSVInfo3->SigInputVectors * + llvm::RoundUpToAlignment(PSVInfo3->SigPatchConstOrPrimVectors, 8) / + 8); + PSVPtr += InputToPCOutputTable.size(); + } else if (PSVInfo3->ShaderStage == + static_cast(PSVShaderKind::Domain) && + PSVInfo3->SigOutputVectors[0] != 0 && + PSVInfo3->SigPatchConstOrPrimVectors != 0) { + PCInputToOutputTable = llvm::MutableArrayRef( + (uint32_t *)PSVPtr, + 4 * PSVInfo3->SigPatchConstOrPrimVectors * + llvm::RoundUpToAlignment(PSVInfo3->SigOutputVectors[0], 8) / 8); + PSVPtr += PCInputToOutputTable.size(); + } + VERIFY_ARE_EQUAL(PSVPtr, PSVPtrEnd); +} + +TEST_F(ValidationTest, PSVContentValidationVS) { + if (!m_ver.m_InternalValidator) + if (m_ver.SkipDxilVersion(1, 8)) + return; + + CComPtr pProgram; + CompileFile(L"..\\DXC\\dumpPSV_VS.hlsl", "vs_6_8", &pProgram); + + CComPtr pValidator; + CComPtr pResult; + unsigned Flags = 0; + VERIFY_SUCCEEDED( + m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator)); + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pResult)); + // Make sure the validation was successful. + HRESULT status; + VERIFY_IS_NOT_NULL(pResult); + VERIFY_SUCCEEDED(pResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); + + // Get PSV part. + hlsl::DxilContainerHeader *pHeader; + hlsl::DxilPartIterator pPartIter(nullptr, 0); + pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer(); + pPartIter = + std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader), + hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation)); + VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter); + + const DxilPartHeader *pPSVPart = (const DxilPartHeader *)(*pPartIter); + SimplePSV PSV(pPSVPart); + + // Update PSV. + PSV.SigInput[0].InterpolationMode = 20; + PSV.SigOutput[0].InterpolationMode = 20; + PSV.ResourceBindInfo[0].ResFlags = 20; + memset(PSV.InputToOutputTable[0].data(), 0, + PSV.InputToOutputTable[0].size() * sizeof(uint32_t)); + // Run validation again. + CComPtr pUpdatedTableResult; + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedTableResult)); + // Make sure the validation was fail. + VERIFY_IS_NOT_NULL(pUpdatedTableResult); + VERIFY_SUCCEEDED(pUpdatedTableResult->GetStatus(&status)); + VERIFY_FAILED(status); + CheckOperationResultMsgs( + pUpdatedTableResult, + {"error: DXIL container mismatch for 'ResourceBindInfo' between 'PSV0' " + "part:('PSVResourceBindInfo:", + " Space: 0", + " LowerBound: 5", + " UpperBound: 5", + " ResType: CBV", + " ResKind: CBuffer", + " ResFlags: ", + "') and DXIL module:('PSVResourceBindInfo:", + " Space: 0", + " LowerBound: 5", + " UpperBound: 5", + " ResType: CBV", + " ResKind: CBuffer", + " ResFlags: None", + "')", + "error: DXIL container mismatch for 'SigInputElement' between 'PSV0' " + "part:('PSVSignatureElement:", + " SemanticName: POSITION", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 3", + " SemanticKind: Arbitrary", + " InterpolationMode: 20", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: POSITION", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 3", + " SemanticKind: Arbitrary", + " InterpolationMode: 0", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'SigOutputElement' between 'PSV0' " + "part:('PSVSignatureElement:", + " SemanticName: NORMAL", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 3", + " SemanticKind: Arbitrary", + " InterpolationMode: 20", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: NORMAL", + " SemanticIndex: 0 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 0", + " Rows: 1", + " Cols: 3", + " SemanticKind: Arbitrary", + " InterpolationMode: 2", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'ViewIDState' between 'PSV0' " + "part:('Outputs affected by inputs as a table of bitmasks for stream 0:", + "Inputs contributing to computation of Outputs[0]:", + " Inputs[0] influencing Outputs[0] : None", + " Inputs[1] influencing Outputs[0] : None", + " Inputs[2] influencing Outputs[0] : None", + " Inputs[3] influencing Outputs[0] : None", + " Inputs[4] influencing Outputs[0] : None", + " Inputs[5] influencing Outputs[0] : None", + " Inputs[6] influencing Outputs[0] : None", + " Inputs[7] influencing Outputs[0] : None", + " Inputs[8] influencing Outputs[0] : None", + " Inputs[9] influencing Outputs[0] : None", + " Inputs[10] influencing Outputs[0] : None", + " Inputs[11] influencing Outputs[0] : None", + "') and DXIL module:('Outputs affected by inputs as a table of bitmasks " + "for stream 0:", + "Inputs contributing to computation of Outputs[0]:", + " Inputs[0] influencing Outputs[0] : 8 9 10 11 ", + " Inputs[1] influencing Outputs[0] : 8 9 10 11 ", + " Inputs[2] influencing Outputs[0] : 8 9 10 11 ", + " Inputs[3] influencing Outputs[0] : None", + " Inputs[4] influencing Outputs[0] : 0 1 2 ", + " Inputs[5] influencing Outputs[0] : 0 1 2 ", + " Inputs[6] influencing Outputs[0] : 0 1 2 ", + " Inputs[7] influencing Outputs[0] : None", + " Inputs[8] influencing Outputs[0] : 4 ", + " Inputs[9] influencing Outputs[0] : 5 ", + " Inputs[10] influencing Outputs[0] : None", + " Inputs[11] influencing Outputs[0] : None", + "')", + "error: Container part 'Pipeline State Validation' does not match " + "expected for module.", + "Validation failed."}, + /*maySucceedAnyway*/ false, /*bRegex*/ false); +} + +TEST_F(ValidationTest, PSVContentValidationHS) { + if (!m_ver.m_InternalValidator) + if (m_ver.SkipDxilVersion(1, 8)) + return; + + CComPtr pProgram; + CompileFile(L"..\\DXC\\dumpPSV_HS.hlsl", "hs_6_8", &pProgram); + + CComPtr pValidator; + CComPtr pResult; + unsigned Flags = 0; + VERIFY_SUCCEEDED( + m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator)); + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pResult)); + // Make sure the validation was successful. + HRESULT status; + VERIFY_IS_NOT_NULL(pResult); + VERIFY_SUCCEEDED(pResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); + + // Get PSV part. + hlsl::DxilContainerHeader *pHeader; + hlsl::DxilPartIterator pPartIter(nullptr, 0); + pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer(); + pPartIter = + std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader), + hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation)); + VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter); + + const DxilPartHeader *pPSVPart = (const DxilPartHeader *)(*pPartIter); + SimplePSV PSV(pPSVPart); + + // Update PSV. + PSV.SigPatchConstOrPrim[0].InterpolationMode = 20; + memset(PSV.InputToPCOutputTable.data(), 0, + PSV.InputToPCOutputTable.size() * sizeof(uint32_t)); + memset(PSV.ViewIDPCOutputMask.data(), 0, + PSV.ViewIDPCOutputMask.size() * sizeof(uint32_t)); + + // Run validation again. + CComPtr pUpdatedResult; + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult)); + // Make sure the validation was fail. + VERIFY_IS_NOT_NULL(pUpdatedResult); + VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status)); + VERIFY_FAILED(status); + + CheckOperationResultMsgs( + pUpdatedResult, + {"error: DXIL container mismatch for 'SigPatchConstantOrPrimElement' " + "between 'PSV0' part:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 0 1 2 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 3", + " Rows: 3", + " Cols: 1", + " SemanticKind: TessFactor", + " InterpolationMode: 20", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 0 1 2 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 3", + " Rows: 3", + " Cols: 1", + " SemanticKind: TessFactor", + " InterpolationMode: 0", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'ViewIDState' between 'PSV0' " + "part:('Outputs affected by ViewID as a bitmask for stream 0:", + " ViewID influencing Outputs[0] : 8 9 10 ", + "PCOutputs affected by ViewID as a bitmask:", + " ViewID influencing PCOutputs : None", + "Outputs affected by inputs as a table of bitmasks for stream 0:", + "Inputs contributing to computation of Outputs[0]:", + " Inputs[0] influencing Outputs[0] : 0 ", + " Inputs[1] influencing Outputs[0] : 1 ", + " Inputs[2] influencing Outputs[0] : 2 ", + " Inputs[3] influencing Outputs[0] : 3 ", + " Inputs[4] influencing Outputs[0] : 4 ", + " Inputs[5] influencing Outputs[0] : 5 ", + " Inputs[6] influencing Outputs[0] : None", + " Inputs[7] influencing Outputs[0] : None", + " Inputs[8] influencing Outputs[0] : 8 ", + " Inputs[9] influencing Outputs[0] : 9 ", + " Inputs[10] influencing Outputs[0] : 10 ", + " Inputs[11] influencing Outputs[0] : None", + "Patch constant outputs affected by inputs as a table of bitmasks:", + "Inputs contributing to computation of PatchConstantOutputs:", + " Inputs[0] influencing PatchConstantOutputs : None", + " Inputs[1] influencing PatchConstantOutputs : None", + " Inputs[2] influencing PatchConstantOutputs : None", + " Inputs[3] influencing PatchConstantOutputs : None", + " Inputs[4] influencing PatchConstantOutputs : None", + " Inputs[5] influencing PatchConstantOutputs : None", + " Inputs[6] influencing PatchConstantOutputs : None", + " Inputs[7] influencing PatchConstantOutputs : None", + " Inputs[8] influencing PatchConstantOutputs : None", + " Inputs[9] influencing PatchConstantOutputs : None", + " Inputs[10] influencing PatchConstantOutputs : None", + " Inputs[11] influencing PatchConstantOutputs : None", + "') and DXIL module:('Outputs affected by ViewID as a bitmask for " + "stream 0:", + " ViewID influencing Outputs[0] : 8 9 10 ", + "PCOutputs affected by ViewID as a bitmask:", + " ViewID influencing PCOutputs : 12 ", + "Outputs affected by inputs as a table of bitmasks for stream 0:", + "Inputs contributing to computation of Outputs[0]:", + " Inputs[0] influencing Outputs[0] : 0 ", + " Inputs[1] influencing Outputs[0] : 1 ", + " Inputs[2] influencing Outputs[0] : 2 ", + " Inputs[3] influencing Outputs[0] : 3 ", + " Inputs[4] influencing Outputs[0] : 4 ", + " Inputs[5] influencing Outputs[0] : 5 ", + " Inputs[6] influencing Outputs[0] : None", + " Inputs[7] influencing Outputs[0] : None", + " Inputs[8] influencing Outputs[0] : 8 ", + " Inputs[9] influencing Outputs[0] : 9 ", + " Inputs[10] influencing Outputs[0] : 10 ", + " Inputs[11] influencing Outputs[0] : None", + "Patch constant outputs affected by inputs as a table of bitmasks:", + "Inputs contributing to computation of PatchConstantOutputs:", + " Inputs[0] influencing PatchConstantOutputs : 3 ", + " Inputs[1] influencing PatchConstantOutputs : None", + " Inputs[2] influencing PatchConstantOutputs : None", + " Inputs[3] influencing PatchConstantOutputs : None", + " Inputs[4] influencing PatchConstantOutputs : None", + " Inputs[5] influencing PatchConstantOutputs : None", + " Inputs[6] influencing PatchConstantOutputs : None", + " Inputs[7] influencing PatchConstantOutputs : None", + " Inputs[8] influencing PatchConstantOutputs : None", + " Inputs[9] influencing PatchConstantOutputs : None", + " Inputs[10] influencing PatchConstantOutputs : None", + " Inputs[11] influencing PatchConstantOutputs : None", + "')", + "error: Container part 'Pipeline State Validation' does not match " + "expected for module.", + "Validation failed."}, + /*maySucceedAnyway*/ false, /*bRegex*/ false); +} + +TEST_F(ValidationTest, PSVContentValidationDS) { + if (!m_ver.m_InternalValidator) + if (m_ver.SkipDxilVersion(1, 8)) + return; + + CComPtr pProgram; + CompileFile(L"..\\DXC\\dumpPSV_DS.hlsl", "ds_6_8", &pProgram); + + CComPtr pValidator; + CComPtr pResult; + unsigned Flags = 0; + VERIFY_SUCCEEDED( + m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator)); + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pResult)); + // Make sure the validation was successful. + HRESULT status; + VERIFY_IS_NOT_NULL(pResult); + VERIFY_SUCCEEDED(pResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); + + // Get PSV part. + hlsl::DxilContainerHeader *pHeader; + hlsl::DxilPartIterator pPartIter(nullptr, 0); + pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer(); + pPartIter = + std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader), + hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation)); + VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter); + + const DxilPartHeader *pPSVPart = (const DxilPartHeader *)(*pPartIter); + SimplePSV PSV(pPSVPart); + + // Update PSV. + PSV.SigPatchConstOrPrim[0].InterpolationMode = 20; + memset(PSV.PCInputToOutputTable.data(), 0, + PSV.PCInputToOutputTable.size() * sizeof(uint32_t)); + + // Run validation again. + CComPtr pUpdatedResult; + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult)); + // Make sure the validation was fail. + VERIFY_IS_NOT_NULL(pUpdatedResult); + VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status)); + VERIFY_FAILED(status); + + CheckOperationResultMsgs( + pUpdatedResult, + {"error: DXIL container mismatch for 'SigPatchConstantOrPrimElement' " + "between 'PSV0' part:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 0 1 2 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 3", + " Rows: 3", + " Cols: 1", + " SemanticKind: TessFactor", + " InterpolationMode: 20", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "') and DXIL module:('PSVSignatureElement:", + " SemanticName: ", + " SemanticIndex: 0 1 2 ", + " IsAllocated: 1", + " StartRow: 0", + " StartCol: 3", + " Rows: 3", + " Cols: 1", + " SemanticKind: TessFactor", + " InterpolationMode: 0", + " OutputStream: 0", + " ComponentType: 3", + " DynamicIndexMask: 0", + "')", + "error: DXIL container mismatch for 'ViewIDState' between 'PSV0' " + "part:('Outputs affected by inputs as a table of bitmasks for stream " + "0:", + "Inputs contributing to computation of Outputs[0]:", + " Inputs[0] influencing Outputs[0] : 0 ", + " Inputs[1] influencing Outputs[0] : 1 ", + " Inputs[2] influencing Outputs[0] : 2 ", + " Inputs[3] influencing Outputs[0] : 3 ", + " Inputs[4] influencing Outputs[0] : 4 ", + " Inputs[5] influencing Outputs[0] : 5 ", + " Inputs[6] influencing Outputs[0] : None", + " Inputs[7] influencing Outputs[0] : None", + " Inputs[8] influencing Outputs[0] : 8 ", + " Inputs[9] influencing Outputs[0] : 9 ", + " Inputs[10] influencing Outputs[0] : 10 ", + " Inputs[11] influencing Outputs[0] : None", + " Inputs[12] influencing Outputs[0] : None", + " Inputs[13] influencing Outputs[0] : None", + " Inputs[14] influencing Outputs[0] : None", + " Inputs[15] influencing Outputs[0] : None", + "Outputs affected by patch constant inputs as a table of bitmasks:", + "PatchConstantInputs contributing to computation of Outputs:", + " PatchConstantInputs[0] influencing Outputs : None", + " PatchConstantInputs[1] influencing Outputs : None", + " PatchConstantInputs[2] influencing Outputs : None", + " PatchConstantInputs[3] influencing Outputs : None", + " PatchConstantInputs[4] influencing Outputs : None", + " PatchConstantInputs[5] influencing Outputs : None", + " PatchConstantInputs[6] influencing Outputs : None", + " PatchConstantInputs[7] influencing Outputs : None", + " PatchConstantInputs[8] influencing Outputs : None", + " PatchConstantInputs[9] influencing Outputs : None", + " PatchConstantInputs[10] influencing Outputs : None", + " PatchConstantInputs[11] influencing Outputs : None", + " PatchConstantInputs[12] influencing Outputs : None", + " PatchConstantInputs[13] influencing Outputs : None", + " PatchConstantInputs[14] influencing Outputs : None", + " PatchConstantInputs[15] influencing Outputs : None", + "') and DXIL module:('Outputs affected by inputs as a table of " + "bitmasks for stream 0:", + "Inputs contributing to computation of Outputs[0]:", + " Inputs[0] influencing Outputs[0] : 0 ", + " Inputs[1] influencing Outputs[0] : 1 ", + " Inputs[2] influencing Outputs[0] : 2 ", + " Inputs[3] influencing Outputs[0] : 3 ", + " Inputs[4] influencing Outputs[0] : 4 ", + " Inputs[5] influencing Outputs[0] : 5 ", + " Inputs[6] influencing Outputs[0] : None", + " Inputs[7] influencing Outputs[0] : None", + " Inputs[8] influencing Outputs[0] : 8 ", + " Inputs[9] influencing Outputs[0] : 9 ", + " Inputs[10] influencing Outputs[0] : 10 ", + " Inputs[11] influencing Outputs[0] : None", + " Inputs[12] influencing Outputs[0] : None", + " Inputs[13] influencing Outputs[0] : None", + " Inputs[14] influencing Outputs[0] : None", + " Inputs[15] influencing Outputs[0] : None", + "Outputs affected by patch constant inputs as a table of bitmasks:", + "PatchConstantInputs contributing to computation of Outputs:", + " PatchConstantInputs[0] influencing Outputs : None", + " PatchConstantInputs[1] influencing Outputs : None", + " PatchConstantInputs[2] influencing Outputs : None", + " PatchConstantInputs[3] influencing Outputs : 4 5 ", + " PatchConstantInputs[4] influencing Outputs : None", + " PatchConstantInputs[5] influencing Outputs : None", + " PatchConstantInputs[6] influencing Outputs : None", + " PatchConstantInputs[7] influencing Outputs : 0 1 2 3 ", + " PatchConstantInputs[8] influencing Outputs : None", + " PatchConstantInputs[9] influencing Outputs : None", + " PatchConstantInputs[10] influencing Outputs : None", + " PatchConstantInputs[11] influencing Outputs : None", + " PatchConstantInputs[12] influencing Outputs : 8 9 10 ", + " PatchConstantInputs[13] influencing Outputs : None", + " PatchConstantInputs[14] influencing Outputs : None", + " PatchConstantInputs[15] influencing Outputs : None", + "')", + "error: Container part 'Pipeline State Validation' does not match " + "expected for module.", + "Validation failed."}, + /*maySucceedAnyway*/ false, /*bRegex*/ false); +} + +TEST_F(ValidationTest, PSVContentValidationGS) { + if (!m_ver.m_InternalValidator) + if (m_ver.SkipDxilVersion(1, 8)) + return; + + CComPtr pProgram; + CompileFile(L"..\\DXC\\dumpPSV_GS.hlsl", "gs_6_8", &pProgram); + + CComPtr pValidator; + CComPtr pResult; + unsigned Flags = 0; + VERIFY_SUCCEEDED( + m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator)); + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pResult)); + // Make sure the validation was successful. + HRESULT status; + VERIFY_IS_NOT_NULL(pResult); + VERIFY_SUCCEEDED(pResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); + + // Get PSV part. + hlsl::DxilContainerHeader *pHeader; + hlsl::DxilPartIterator pPartIter(nullptr, 0); + pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer(); + pPartIter = + std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader), + hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation)); + VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter); + + const DxilPartHeader *pPSVPart = (const DxilPartHeader *)(*pPartIter); + SimplePSV PSV(pPSVPart); + // Update PSV. + PSV.PSVInfo->MaxVertexCount = 2; + + // Run validation again. + CComPtr pUpdatedResult; + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult)); + // Make sure the validation was fail. + VERIFY_IS_NOT_NULL(pUpdatedResult); + VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status)); + VERIFY_FAILED(status); + + CheckOperationResultMsgs( + pUpdatedResult, + {"error: DXIL container mismatch for 'PSVRuntimeInfo' between 'PSV0' " + "part:('PSVRuntimeInfo:", + " Geometry Shader", + " InputPrimitive=point", + " OutputTopology=triangle", + " OutputStreamMask=1", + " OutputPositionPresent=1", + " MinimumExpectedWaveLaneCount: 0", + " MaximumExpectedWaveLaneCount: 4294967295", + " UsesViewID: false", + " SigInputElements: 3", + " SigOutputElements: 3", + " SigPatchConstOrPrimElements: 0", + " SigInputVectors: 3", + " SigOutputVectors[0]: 3", + " SigOutputVectors[1]: 0", + " SigOutputVectors[2]: 0", + " SigOutputVectors[3]: 0", + " EntryFunctionName: main", + "') and DXIL module:('PSVRuntimeInfo:", + " Geometry Shader", + " InputPrimitive=point", + " OutputTopology=triangle", + " OutputStreamMask=1", + " OutputPositionPresent=1", + " MinimumExpectedWaveLaneCount: 0", + " MaximumExpectedWaveLaneCount: 4294967295", + " UsesViewID: false", + " SigInputElements: 3", + " SigOutputElements: 3", + " SigPatchConstOrPrimElements: 0", + " SigInputVectors: 3", + " SigOutputVectors[0]: 3", + " SigOutputVectors[1]: 0", + " SigOutputVectors[2]: 0", + " SigOutputVectors[3]: 0", + " EntryFunctionName: main", + "')", + "error: Container part 'Pipeline State Validation' does not match " + "expected for module.", + "Validation failed."}, + /*maySucceedAnyway*/ false, /*bRegex*/ false); +} + +TEST_F(ValidationTest, PSVContentValidationPS) { + if (!m_ver.m_InternalValidator) + if (m_ver.SkipDxilVersion(1, 8)) + return; + + CComPtr pProgram; + CompileFile(L"..\\DXC\\dumpPSV_PS.hlsl", "ps_6_8", &pProgram); + + CComPtr pValidator; + CComPtr pResult; + unsigned Flags = 0; + VERIFY_SUCCEEDED( + m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator)); + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pResult)); + // Make sure the validation was successful. + HRESULT status; + VERIFY_IS_NOT_NULL(pResult); + VERIFY_SUCCEEDED(pResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); + + // Get PSV part. + hlsl::DxilContainerHeader *pHeader; + hlsl::DxilPartIterator pPartIter(nullptr, 0); + pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer(); + pPartIter = + std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader), + hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation)); + VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter); + + const DxilPartHeader *pPSVPart = (const DxilPartHeader *)(*pPartIter); + SimplePSV PSV(pPSVPart); + + // Update PSV. + PSV.PSVInfo->PS.DepthOutput = 1; + + // Run validation again. + CComPtr pUpdatedResult; + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult)); + // Make sure the validation was fail. + VERIFY_IS_NOT_NULL(pUpdatedResult); + VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status)); + VERIFY_FAILED(status); + + CheckOperationResultMsgs( + pUpdatedResult, + {"error: DXIL container mismatch for 'PSVRuntimeInfo' between 'PSV0' " + "part:('PSVRuntimeInfo:", + " Pixel Shader", + " DepthOutput=0", + " SampleFrequency=1", + " MinimumExpectedWaveLaneCount: 0", + " MaximumExpectedWaveLaneCount: 4294967295", + " UsesViewID: false", + " SigInputElements: 2", + " SigOutputElements: 1", + " SigPatchConstOrPrimElements: 0", + " SigInputVectors: 2", + " SigOutputVectors[0]: 1", + " SigOutputVectors[1]: 0", + " SigOutputVectors[2]: 0", + " SigOutputVectors[3]: 0", + " EntryFunctionName: main", + "') and DXIL module:('PSVRuntimeInfo:", + " Pixel Shader", + " DepthOutput=1", + " SampleFrequency=1", + " MinimumExpectedWaveLaneCount: 0", + " MaximumExpectedWaveLaneCount: 4294967295", + " UsesViewID: false", + " SigInputElements: 2", + " SigOutputElements: 1", + " SigPatchConstOrPrimElements: 0", + " SigInputVectors: 2", + " SigOutputVectors[0]: 1", + " SigOutputVectors[1]: 0", + " SigOutputVectors[2]: 0", + " SigOutputVectors[3]: 0", + " EntryFunctionName: main", + "')", + "error: Container part 'Pipeline State Validation' does not match " + "expected for module.", + "Validation failed."}, + /*maySucceedAnyway*/ false, /*bRegex*/ false); +} + +TEST_F(ValidationTest, PSVContentValidationCS) { + if (!m_ver.m_InternalValidator) + if (m_ver.SkipDxilVersion(1, 8)) + return; + + CComPtr pProgram; + CompileFile(L"..\\DXC\\dumpPSV_CS.hlsl", "cs_6_8", &pProgram); + + CComPtr pValidator; + CComPtr pResult; + unsigned Flags = 0; + VERIFY_SUCCEEDED( + m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator)); + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pResult)); + // Make sure the validation was successful. + HRESULT status; + VERIFY_IS_NOT_NULL(pResult); + VERIFY_SUCCEEDED(pResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); + + // Get PSV part. + hlsl::DxilContainerHeader *pHeader; + hlsl::DxilPartIterator pPartIter(nullptr, 0); + pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer(); + pPartIter = + std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader), + hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation)); + VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter); + + const DxilPartHeader *pPSVPart = (const DxilPartHeader *)(*pPartIter); + SimplePSV PSV(pPSVPart); + // Update PSV. + PSV.PSVInfo->NumThreadsX = 1; + + // Run validation again. + CComPtr pUpdatedResult; + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult)); + // Make sure the validation was fail. + VERIFY_IS_NOT_NULL(pUpdatedResult); + VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status)); + VERIFY_FAILED(status); + + CheckOperationResultMsgs( + pUpdatedResult, + {"error: DXIL container mismatch for 'PSVRuntimeInfo' between 'PSV0' " + "part:('PSVRuntimeInfo:", + " Compute Shader", + " NumThreads=(128,1,1)", + " MinimumExpectedWaveLaneCount: 0", + " MaximumExpectedWaveLaneCount: 4294967295", + " UsesViewID: false", + " SigInputElements: 0", + " SigOutputElements: 0", + " SigPatchConstOrPrimElements: 0", + " SigInputVectors: 0", + " SigOutputVectors[0]: 0", + " SigOutputVectors[1]: 0", + " SigOutputVectors[2]: 0", + " SigOutputVectors[3]: 0", + " EntryFunctionName: main", + "') and DXIL module:('PSVRuntimeInfo:", + " Compute Shader", + " NumThreads=(1,1,1)", + " MinimumExpectedWaveLaneCount: 0", + " MaximumExpectedWaveLaneCount: 4294967295", + " UsesViewID: false", + " SigInputElements: 0", + " SigOutputElements: 0", + " SigPatchConstOrPrimElements: 0", + " SigInputVectors: 0", + " SigOutputVectors[0]: 0", + " SigOutputVectors[1]: 0", + " SigOutputVectors[2]: 0", + " SigOutputVectors[3]: 0", + " EntryFunctionName: main", + "')", + "error: Container part 'Pipeline State Validation' does not match " + "expected for module.", + "Validation failed."}, + /*maySucceedAnyway*/ false, /*bRegex*/ false); +} + +TEST_F(ValidationTest, PSVContentValidationMS) { + if (!m_ver.m_InternalValidator) + if (m_ver.SkipDxilVersion(1, 8)) + return; + + CComPtr pProgram; + CompileFile(L"..\\DXC\\dumpPSV_MS.hlsl", "ms_6_8", &pProgram); + + CComPtr pValidator; + CComPtr pResult; + unsigned Flags = 0; + VERIFY_SUCCEEDED( + m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator)); + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pResult)); + // Make sure the validation was successful. + HRESULT status; + VERIFY_IS_NOT_NULL(pResult); + VERIFY_SUCCEEDED(pResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); + + // Get PSV part. + hlsl::DxilContainerHeader *pHeader; + hlsl::DxilPartIterator pPartIter(nullptr, 0); + pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer(); + pPartIter = + std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader), + hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation)); + VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter); + + const DxilPartHeader *pPSVPart = (const DxilPartHeader *)(*pPartIter); + SimplePSV PSV(pPSVPart); + // Update PSV. + memset(PSV.ViewIDOutputMask[0].data(), 0, + PSV.ViewIDOutputMask[0].size() * sizeof(uint32_t)); + memset(PSV.ViewIDPCOutputMask.data(), 0, + PSV.ViewIDPCOutputMask.size() * sizeof(uint32_t)); + + // Run validation again. + CComPtr pUpdatedResult; + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult)); + // Make sure the validation was fail. + VERIFY_IS_NOT_NULL(pUpdatedResult); + VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status)); + VERIFY_FAILED(status); + + CheckOperationResultMsgs( + pUpdatedResult, + {"error: DXIL container mismatch for 'ViewIDState' between 'PSV0' " + "part:('Outputs affected by ViewID as a bitmask for stream 0:", + " ViewID influencing Outputs[0] : None", + "PCOutputs affected by ViewID as a bitmask:", + " ViewID influencing PCOutputs : None", + "Outputs affected by inputs as a table of bitmasks for stream 0:", + "Inputs contributing to computation of Outputs[0]: None", + "') and DXIL module:('Outputs affected by ViewID as a bitmask for " + "stream 0:", + " ViewID influencing Outputs[0] : 0 1 2 3 4 8 12 16 ", + "PCOutputs affected by ViewID as a bitmask:", + " ViewID influencing PCOutputs : 3 ", + "Outputs affected by inputs as a table of bitmasks for stream 0:", + "Inputs contributing to computation of Outputs[0]: None", "')", + "error: Container part 'Pipeline State Validation' does not match " + "expected for module.", + "Validation failed."}, + /*maySucceedAnyway*/ false, /*bRegex*/ false); +} + +TEST_F(ValidationTest, PSVContentValidationAS) { + if (!m_ver.m_InternalValidator) + if (m_ver.SkipDxilVersion(1, 8)) + return; + + CComPtr pProgram; + CompileFile(L"..\\DXC\\dumpPSV_AS.hlsl", "as_6_8", &pProgram); + + CComPtr pValidator; + CComPtr pResult; + unsigned Flags = 0; + VERIFY_SUCCEEDED( + m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator)); + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pResult)); + // Make sure the validation was successful. + HRESULT status; + VERIFY_IS_NOT_NULL(pResult); + VERIFY_SUCCEEDED(pResult->GetStatus(&status)); + VERIFY_SUCCEEDED(status); + + // Get PSV part. + hlsl::DxilContainerHeader *pHeader; + hlsl::DxilPartIterator pPartIter(nullptr, 0); + pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer(); + pPartIter = + std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader), + hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation)); + VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter); + + const DxilPartHeader *pPSVPart = (const DxilPartHeader *)(*pPartIter); + SimplePSV PSV(pPSVPart); + + // Update PSV. + PSV.PSVInfo->AS.PayloadSizeInBytes = 0; + + // Run validation again. + CComPtr pUpdatedResult; + VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult)); + // Make sure the validation was fail. + VERIFY_IS_NOT_NULL(pUpdatedResult); + VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status)); + VERIFY_FAILED(status); + + CheckOperationResultMsgs( + pUpdatedResult, + {"error: DXIL container mismatch for 'PSVRuntimeInfo' between 'PSV0' " + "part:('PSVRuntimeInfo:", + " Amplification Shader", + " NumThreads=(32,1,1)", + " MinimumExpectedWaveLaneCount: 0", + " MaximumExpectedWaveLaneCount: 4294967295", + " UsesViewID: false", + " SigInputElements: 0", + " SigOutputElements: 0", + " SigPatchConstOrPrimElements: 0", + " SigInputVectors: 0", + " SigOutputVectors[0]: 0", + " SigOutputVectors[1]: 0", + " SigOutputVectors[2]: 0", + " SigOutputVectors[3]: 0", + " EntryFunctionName: main", + "') and DXIL module:('PSVRuntimeInfo:", + " Amplification Shader", + " NumThreads=(32,1,1)", + " MinimumExpectedWaveLaneCount: 0", + " MaximumExpectedWaveLaneCount: 4294967295", + " UsesViewID: false", + " SigInputElements: 0", + " SigOutputElements: 0", + " SigPatchConstOrPrimElements: 0", + " SigInputVectors: 0", + " SigOutputVectors[0]: 0", + " SigOutputVectors[1]: 0", + " SigOutputVectors[2]: 0", + " SigOutputVectors[3]: 0", + " EntryFunctionName: main", + "')", + "error: Container part 'Pipeline State Validation' does not match " + "expected for module.", + "Validation failed."}, + /*maySucceedAnyway*/ false, /*bRegex*/ false); +} diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index 35343fe31..69d1e4293 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -6923,7 +6923,16 @@ class db_dxil(object): "Root Signature in DXIL Container must be compatible with shader", "Root Signature in DXIL container is not compatible with shader.", ) - + self.add_valrule_msg( + "Container.ContentMatches", + "DXIL Container Content must match Module", + "DXIL container mismatch for '%0' between '%1' part:('%2') and DXIL module:('%3')", + ) + self.add_valrule_msg( + "Container.ContentInvalid", + "DXIL Container Content is well-formed", + "In '%0', '%1' is not well-formed", + ) self.add_valrule("Meta.Required", "Required metadata missing.") self.add_valrule_msg( "Meta.ComputeWithNode",