[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
This commit is contained in:
Xiang Li 2024-09-19 07:24:28 -07:00 коммит произвёл GitHub
Родитель e1bb926f63
Коммит 5155b0934c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
9 изменённых файлов: 2121 добавлений и 152 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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;

Просмотреть файл

@ -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);
}
}

Просмотреть файл

@ -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 <memory>
#include <unordered_set>
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 <typename T>
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 <typename Ty> 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<unsigned int> 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<unsigned int> 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<DxilPartWriter> pWriter(NewPSVWriter(DM, PSVVersion));
CComPtr<AbstractMemoryStream> 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<PSVSignatureElement0>(
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<uint32_t> &SemanticIndexVec = SE.GetSemanticIndexVec();
llvm::ArrayRef<uint32_t> 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<uint8_t>(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 <typename T>
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<uint8_t>(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<uint8_t>(SM->GetKind()),
DM.GetEntryFunctionName().c_str(), "");
OS.flush();
std::string Str1;
raw_string_ostream OS1(Str1);
PSV.PrintPSVRuntimeInfo(OS1, static_cast<uint8_t>(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<uint8_t>(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<DxilPartWriter> 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,

Просмотреть файл

@ -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);

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

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