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",