[Validator] Check size of PSV. (#6924)
Check size of PSV part matches the PSVVersion. Updated DxilPipelineStateValidation::ReadOrWrite to read based on initInfo.PSVVersion. And return fail when size mismatch in RWMode::Read. Fixes #6817
This commit is contained in:
Родитель
b05313c384
Коммит
9221570027
|
@ -23,6 +23,7 @@ Place release notes for the upcoming release below this line and remove this lin
|
|||
|
||||
- The incomplete WaveMatrix implementation has been removed.
|
||||
- DXIL Validator Hash is open sourced.
|
||||
- DXIL container validation for PSV0 part allows any content ordering inside string and semantic index tables.
|
||||
|
||||
### Version 1.8.2407
|
||||
|
||||
|
|
|
@ -226,7 +226,8 @@ struct PSVStringTable {
|
|||
PSVStringTable() : Table(nullptr), Size(0) {}
|
||||
PSVStringTable(const char *table, uint32_t size) : Table(table), Size(size) {}
|
||||
const char *Get(uint32_t offset) const {
|
||||
assert(offset < Size && Table && Table[Size - 1] == '\0');
|
||||
if (!(offset < Size && Table && Table[Size - 1] == '\0'))
|
||||
return nullptr;
|
||||
return Table + offset;
|
||||
}
|
||||
};
|
||||
|
@ -344,7 +345,8 @@ struct PSVSemanticIndexTable {
|
|||
PSVSemanticIndexTable(const uint32_t *table, uint32_t entries)
|
||||
: Table(table), Entries(entries) {}
|
||||
const uint32_t *Get(uint32_t offset) const {
|
||||
assert(offset < Entries && Table);
|
||||
if (!(offset < Entries && Table))
|
||||
return nullptr;
|
||||
return Table + offset;
|
||||
}
|
||||
};
|
||||
|
@ -638,7 +640,8 @@ public:
|
|||
_T *GetRecord(void *pRecords, uint32_t recordSize, uint32_t numRecords,
|
||||
uint32_t index) const {
|
||||
if (pRecords && index < numRecords && sizeof(_T) <= recordSize) {
|
||||
assert((size_t)index * (size_t)recordSize <= UINT_MAX);
|
||||
if (!((size_t)index * (size_t)recordSize <= UINT_MAX))
|
||||
return nullptr;
|
||||
return reinterpret_cast<_T *>(reinterpret_cast<uint8_t *>(pRecords) +
|
||||
(index * recordSize));
|
||||
}
|
||||
|
@ -1126,6 +1129,10 @@ void InitPSVSignatureElement(PSVSignatureElement0 &E,
|
|||
const DxilSignatureElement &SE,
|
||||
bool i1ToUnknownCompat);
|
||||
|
||||
// Setup PSVInitInfo with DxilModule.
|
||||
// Note that the StringTable and PSVSemanticIndexTable are not done.
|
||||
void SetupPSVInitInfo(PSVInitInfo &InitInfo, const DxilModule &DM);
|
||||
|
||||
// Setup shader properties for PSVRuntimeInfo* with DxilModule.
|
||||
void SetShaderProps(PSVRuntimeInfo0 *pInfo, const DxilModule &DM);
|
||||
void SetShaderProps(PSVRuntimeInfo1 *pInfo1, const DxilModule &DM);
|
||||
|
|
|
@ -738,30 +738,14 @@ public:
|
|||
DxilPSVWriter(const DxilModule &mod, uint32_t PSVVersion = UINT_MAX)
|
||||
: m_Module(mod), m_PSVInitInfo(PSVVersion) {
|
||||
m_Module.GetValidatorVersion(m_ValMajor, m_ValMinor);
|
||||
// Constraint PSVVersion based on validator version
|
||||
uint32_t PSVVersionConstraint = hlsl::GetPSVVersion(m_ValMajor, m_ValMinor);
|
||||
if (PSVVersion > PSVVersionConstraint)
|
||||
m_PSVInitInfo.PSVVersion = PSVVersionConstraint;
|
||||
hlsl::SetupPSVInitInfo(m_PSVInitInfo, m_Module);
|
||||
|
||||
const ShaderModel *SM = m_Module.GetShaderModel();
|
||||
UINT uCBuffers = m_Module.GetCBuffers().size();
|
||||
UINT uSamplers = m_Module.GetSamplers().size();
|
||||
UINT uSRVs = m_Module.GetSRVs().size();
|
||||
UINT uUAVs = m_Module.GetUAVs().size();
|
||||
m_PSVInitInfo.ResourceCount = uCBuffers + uSamplers + uSRVs + uUAVs;
|
||||
// TODO: for >= 6.2 version, create more efficient structure
|
||||
if (m_PSVInitInfo.PSVVersion > 0) {
|
||||
m_PSVInitInfo.ShaderStage = (PSVShaderKind)SM->GetKind();
|
||||
// Copy Dxil Signatures
|
||||
m_StringBuffer.push_back('\0'); // For empty semantic name (system value)
|
||||
m_PSVInitInfo.SigInputElements =
|
||||
m_Module.GetInputSignature().GetElements().size();
|
||||
m_SigInputElements.resize(m_PSVInitInfo.SigInputElements);
|
||||
m_PSVInitInfo.SigOutputElements =
|
||||
m_Module.GetOutputSignature().GetElements().size();
|
||||
m_SigOutputElements.resize(m_PSVInitInfo.SigOutputElements);
|
||||
m_PSVInitInfo.SigPatchConstOrPrimElements =
|
||||
m_Module.GetPatchConstOrPrimSignature().GetElements().size();
|
||||
m_SigPatchConstOrPrimElements.resize(
|
||||
m_PSVInitInfo.SigPatchConstOrPrimElements);
|
||||
uint32_t i = 0;
|
||||
|
@ -791,20 +775,6 @@ public:
|
|||
m_PSVInitInfo.StringTable.Size = m_StringBuffer.size();
|
||||
m_PSVInitInfo.SemanticIndexTable.Table = m_SemanticIndexBuffer.data();
|
||||
m_PSVInitInfo.SemanticIndexTable.Entries = m_SemanticIndexBuffer.size();
|
||||
// Set up ViewID and signature dependency info
|
||||
m_PSVInitInfo.UsesViewID =
|
||||
m_Module.m_ShaderFlags.GetViewID() ? true : false;
|
||||
m_PSVInitInfo.SigInputVectors =
|
||||
m_Module.GetInputSignature().NumVectorsUsed(0);
|
||||
for (unsigned streamIndex = 0; streamIndex < 4; streamIndex++) {
|
||||
m_PSVInitInfo.SigOutputVectors[streamIndex] =
|
||||
m_Module.GetOutputSignature().NumVectorsUsed(streamIndex);
|
||||
}
|
||||
m_PSVInitInfo.SigPatchConstOrPrimVectors = 0;
|
||||
if (SM->IsHS() || SM->IsDS() || SM->IsMS()) {
|
||||
m_PSVInitInfo.SigPatchConstOrPrimVectors =
|
||||
m_Module.GetPatchConstOrPrimSignature().NumVectorsUsed(0);
|
||||
}
|
||||
}
|
||||
if (!m_PSV.InitNew(m_PSVInitInfo, nullptr, &m_PSVBufferSize)) {
|
||||
DXASSERT(false, "PSV InitNew failed computing size!");
|
||||
|
|
|
@ -110,6 +110,43 @@ void hlsl::InitPSVSignatureElement(PSVSignatureElement0 &E,
|
|||
E.DynamicMaskAndStream |= (SE.GetDynIdxCompMask()) & 0xF;
|
||||
}
|
||||
|
||||
void hlsl::SetupPSVInitInfo(PSVInitInfo &InitInfo, const DxilModule &DM) {
|
||||
// Constraint PSVVersion based on validator version
|
||||
unsigned ValMajor, ValMinor;
|
||||
DM.GetValidatorVersion(ValMajor, ValMinor);
|
||||
unsigned PSVVersionConstraint = hlsl::GetPSVVersion(ValMajor, ValMinor);
|
||||
if (InitInfo.PSVVersion > PSVVersionConstraint)
|
||||
InitInfo.PSVVersion = PSVVersionConstraint;
|
||||
|
||||
const ShaderModel *SM = DM.GetShaderModel();
|
||||
uint32_t uCBuffers = DM.GetCBuffers().size();
|
||||
uint32_t uSamplers = DM.GetSamplers().size();
|
||||
uint32_t uSRVs = DM.GetSRVs().size();
|
||||
uint32_t uUAVs = DM.GetUAVs().size();
|
||||
InitInfo.ResourceCount = uCBuffers + uSamplers + uSRVs + uUAVs;
|
||||
|
||||
if (InitInfo.PSVVersion > 0) {
|
||||
InitInfo.ShaderStage = (PSVShaderKind)SM->GetKind();
|
||||
InitInfo.SigInputElements = DM.GetInputSignature().GetElements().size();
|
||||
InitInfo.SigPatchConstOrPrimElements =
|
||||
DM.GetPatchConstOrPrimSignature().GetElements().size();
|
||||
InitInfo.SigOutputElements = DM.GetOutputSignature().GetElements().size();
|
||||
|
||||
// Set up ViewID and signature dependency info
|
||||
InitInfo.UsesViewID = DM.m_ShaderFlags.GetViewID() ? true : false;
|
||||
InitInfo.SigInputVectors = DM.GetInputSignature().NumVectorsUsed(0);
|
||||
for (unsigned streamIndex = 0; streamIndex < 4; streamIndex++) {
|
||||
InitInfo.SigOutputVectors[streamIndex] =
|
||||
DM.GetOutputSignature().NumVectorsUsed(streamIndex);
|
||||
}
|
||||
InitInfo.SigPatchConstOrPrimVectors = 0;
|
||||
if (SM->IsHS() || SM->IsDS() || SM->IsMS()) {
|
||||
InitInfo.SigPatchConstOrPrimVectors =
|
||||
DM.GetPatchConstOrPrimSignature().NumVectorsUsed(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hlsl::SetShaderProps(PSVRuntimeInfo0 *pInfo, const DxilModule &DM) {
|
||||
const ShaderModel *SM = DM.GetShaderModel();
|
||||
pInfo->MinimumExpectedWaveLaneCount = 0;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "dxc/DXIL/DxilUtil.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/IR/DiagnosticPrinter.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
|
@ -33,6 +34,7 @@
|
|||
#include "DxilValidationUtils.h"
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace llvm;
|
||||
|
@ -79,17 +81,95 @@ static void emitDxilDiag(LLVMContext &Ctx, const char *str) {
|
|||
hlsl::dxilutil::EmitErrorOnContext(Ctx, str);
|
||||
}
|
||||
|
||||
class StringTableVerifier {
|
||||
std::unordered_map<unsigned, unsigned> OffsetToUseCountMap;
|
||||
const PSVStringTable &Table;
|
||||
|
||||
public:
|
||||
StringTableVerifier(const PSVStringTable &Table) : Table(Table) {
|
||||
unsigned Start = 0;
|
||||
for (unsigned i = 0; i < Table.Size; ++i) {
|
||||
char ch = Table.Table[i];
|
||||
if (ch == '\0') {
|
||||
OffsetToUseCountMap[Start] = 0;
|
||||
Start = i + 1;
|
||||
}
|
||||
}
|
||||
if (Table.Size >= 4) {
|
||||
// Remove the '\0's at the end of the table added for padding.
|
||||
for (unsigned i = Table.Size - 1; i > Table.Size - 4; --i) {
|
||||
if (Table.Table[i] != '\0')
|
||||
break;
|
||||
OffsetToUseCountMap.erase(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool MarkUse(unsigned Offset) {
|
||||
auto it = OffsetToUseCountMap.find(Offset);
|
||||
if (it != OffsetToUseCountMap.end())
|
||||
it->second++;
|
||||
return Offset < Table.Size;
|
||||
}
|
||||
void Verify(ValidationContext &ValCtx) {
|
||||
for (auto [Offset, UseCount] : OffsetToUseCountMap) {
|
||||
if (UseCount != 0)
|
||||
continue;
|
||||
// DXC will always add a null-terminated string at the beginning of the
|
||||
// StringTable. It is OK if it is not used.
|
||||
if (Offset == 0 && Table.Table[0] == '\0')
|
||||
continue;
|
||||
|
||||
ValCtx.EmitFormatError(ValidationRule::ContainerUnusedItemInTable,
|
||||
{"StringTable", Table.Get(Offset)});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SemanticIndexTableVerifier {
|
||||
const PSVSemanticIndexTable &Table;
|
||||
llvm::BitVector UseMask;
|
||||
|
||||
public:
|
||||
SemanticIndexTableVerifier(const PSVSemanticIndexTable &Table)
|
||||
: Table(Table), UseMask(Table.Entries, false) {}
|
||||
bool MarkUse(unsigned Offset, unsigned Size) {
|
||||
if (Table.Table == nullptr)
|
||||
return false;
|
||||
if (Offset > Table.Entries)
|
||||
return false;
|
||||
if ((Offset + Size) > Table.Entries)
|
||||
return false;
|
||||
for (unsigned i = Offset; i < (Offset + Size); ++i) {
|
||||
UseMask[i] = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void Verify(ValidationContext &ValCtx) {
|
||||
for (unsigned i = 0; i < Table.Entries; i++) {
|
||||
if (UseMask[i])
|
||||
continue;
|
||||
|
||||
ValCtx.EmitFormatError(ValidationRule::ContainerUnusedItemInTable,
|
||||
{"SemanticIndexTable", std::to_string(i)});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class PSVContentVerifier {
|
||||
DxilModule &DM;
|
||||
DxilPipelineStateValidation &PSV;
|
||||
ValidationContext &ValCtx;
|
||||
bool PSVContentValid = true;
|
||||
StringTableVerifier StrTableVerifier;
|
||||
SemanticIndexTableVerifier IndexTableVerifier;
|
||||
|
||||
public:
|
||||
PSVContentVerifier(DxilPipelineStateValidation &PSV, DxilModule &DM,
|
||||
ValidationContext &ValCtx)
|
||||
: DM(DM), PSV(PSV), ValCtx(ValCtx) {}
|
||||
void Verify();
|
||||
: DM(DM), PSV(PSV), ValCtx(ValCtx),
|
||||
StrTableVerifier(PSV.GetStringTable()),
|
||||
IndexTableVerifier(PSV.GetSemanticIndexTable()) {}
|
||||
void Verify(unsigned ValMajor, unsigned ValMinor, unsigned PSVVersion);
|
||||
|
||||
private:
|
||||
void VerifySignatures(unsigned ValMajor, unsigned ValMinor);
|
||||
|
@ -113,7 +193,8 @@ private:
|
|||
PSVContentValid = false;
|
||||
}
|
||||
void EmitInvalidError(StringRef Name) {
|
||||
ValCtx.EmitFormatError(ValidationRule::ContainerContentInvalid, {Name});
|
||||
ValCtx.EmitFormatError(ValidationRule::ContainerContentInvalid,
|
||||
{"PSV0 part", Name});
|
||||
PSVContentValid = false;
|
||||
}
|
||||
template <typename Ty> static std::string GetDump(const Ty &T) {
|
||||
|
@ -226,6 +307,17 @@ void PSVContentVerifier::VerifySignatureElement(
|
|||
const DxilSignatureElement &SE, PSVSignatureElement0 *PSVSE0,
|
||||
const PSVStringTable &StrTab, const PSVSemanticIndexTable &IndexTab,
|
||||
std::string Name, bool i1ToUnknownCompat) {
|
||||
bool InvalidTableAccess = false;
|
||||
if (!StrTableVerifier.MarkUse(PSVSE0->SemanticName)) {
|
||||
EmitInvalidError("SemanticName");
|
||||
InvalidTableAccess = true;
|
||||
}
|
||||
if (!IndexTableVerifier.MarkUse(PSVSE0->SemanticIndexes, PSVSE0->Rows)) {
|
||||
EmitInvalidError("SemanticIndex");
|
||||
InvalidTableAccess = true;
|
||||
}
|
||||
if (InvalidTableAccess)
|
||||
return;
|
||||
// Find the signature element in the set.
|
||||
PSVSignatureElement0 ModulePSVSE0;
|
||||
InitPSVSignatureElement(ModulePSVSE0, SE, i1ToUnknownCompat);
|
||||
|
@ -368,18 +460,9 @@ void PSVContentVerifier::VerifyEntryProperties(const ShaderModel *SM,
|
|||
}
|
||||
}
|
||||
|
||||
void PSVContentVerifier::Verify() {
|
||||
unsigned ValMajor, ValMinor;
|
||||
DM.GetValidatorVersion(ValMajor, ValMinor);
|
||||
unsigned PSVVersion = hlsl::GetPSVVersion(ValMajor, ValMinor);
|
||||
|
||||
void PSVContentVerifier::Verify(unsigned ValMajor, unsigned ValMinor,
|
||||
unsigned PSVVersion) {
|
||||
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()) {
|
||||
|
@ -421,11 +504,19 @@ void PSVContentVerifier::Verify() {
|
|||
}
|
||||
// PSV2 only added NumThreadsX/Y/Z which verified in VerifyEntryProperties.
|
||||
if (PSVVersion > 2) {
|
||||
if (DM.GetEntryFunctionName() != PSV.GetEntryFunctionName())
|
||||
EmitMismatchError("EntryFunctionName", PSV.GetEntryFunctionName(),
|
||||
DM.GetEntryFunctionName());
|
||||
PSVRuntimeInfo3 *PSV3 = PSV.GetPSVRuntimeInfo3();
|
||||
if (!StrTableVerifier.MarkUse(PSV3->EntryFunctionName)) {
|
||||
EmitInvalidError("EntryFunctionName");
|
||||
} else {
|
||||
if (DM.GetEntryFunctionName() != PSV.GetEntryFunctionName())
|
||||
EmitMismatchError("EntryFunctionName", PSV.GetEntryFunctionName(),
|
||||
DM.GetEntryFunctionName());
|
||||
}
|
||||
}
|
||||
|
||||
StrTableVerifier.Verify(ValCtx);
|
||||
IndexTableVerifier.Verify(ValCtx);
|
||||
|
||||
if (!PSVContentValid)
|
||||
ValCtx.EmitFormatError(ValidationRule::ContainerPartMatches,
|
||||
{"Pipeline State Validation"});
|
||||
|
@ -507,16 +598,204 @@ bool VerifySignatureMatches(llvm::Module *pModule, DXIL::SignatureKind SigKind,
|
|||
return !ValCtx.Failed;
|
||||
}
|
||||
|
||||
struct SimplePSV {
|
||||
uint32_t PSVRuntimeInfoSize = 0;
|
||||
uint32_t PSVNumResources = 0;
|
||||
uint32_t PSVResourceBindInfoSize = 0;
|
||||
uint32_t StringTableSize = 0;
|
||||
const char *StringTable = nullptr;
|
||||
uint32_t SemanticIndexTableEntries = 0;
|
||||
const uint32_t *SemanticIndexTable = nullptr;
|
||||
uint32_t PSVSignatureElementSize = 0;
|
||||
const PSVRuntimeInfo1 *RuntimeInfo1 = nullptr;
|
||||
bool IsValid = true;
|
||||
SimplePSV(const void *pPSVData, uint32_t PSVSize) {
|
||||
|
||||
#define INCREMENT_POS(Size) \
|
||||
Offset += Size; \
|
||||
if (Offset > PSVSize) { \
|
||||
IsValid = false; \
|
||||
return; \
|
||||
}
|
||||
|
||||
uint32_t Offset = 0;
|
||||
PSVRuntimeInfoSize = GetUint32AtOffset(pPSVData, 0);
|
||||
INCREMENT_POS(4);
|
||||
if (PSVRuntimeInfoSize >= sizeof(PSVRuntimeInfo1))
|
||||
RuntimeInfo1 =
|
||||
(const PSVRuntimeInfo1 *)(GetPtrAtOffset(pPSVData, Offset));
|
||||
INCREMENT_POS(PSVRuntimeInfoSize);
|
||||
|
||||
PSVNumResources = GetUint32AtOffset(pPSVData, Offset);
|
||||
INCREMENT_POS(4);
|
||||
if (PSVNumResources > 0) {
|
||||
PSVResourceBindInfoSize = GetUint32AtOffset(pPSVData, Offset);
|
||||
// Increase the offset for the resource bind info size.
|
||||
INCREMENT_POS(4);
|
||||
// Increase the offset for the resource bind info.
|
||||
INCREMENT_POS(PSVNumResources * PSVResourceBindInfoSize);
|
||||
}
|
||||
if (RuntimeInfo1) {
|
||||
StringTableSize = GetUint32AtOffset(pPSVData, Offset);
|
||||
INCREMENT_POS(4);
|
||||
// Make sure StringTableSize is aligned to 4 bytes.
|
||||
if ((StringTableSize & 3) != 0) {
|
||||
IsValid = false;
|
||||
return;
|
||||
}
|
||||
if (StringTableSize) {
|
||||
StringTable = GetPtrAtOffset(pPSVData, Offset);
|
||||
INCREMENT_POS(StringTableSize);
|
||||
}
|
||||
SemanticIndexTableEntries = GetUint32AtOffset(pPSVData, Offset);
|
||||
INCREMENT_POS(4);
|
||||
if (SemanticIndexTableEntries) {
|
||||
SemanticIndexTable =
|
||||
(const uint32_t *)(GetPtrAtOffset(pPSVData, Offset));
|
||||
INCREMENT_POS(SemanticIndexTableEntries * 4);
|
||||
}
|
||||
if (RuntimeInfo1->SigInputElements || RuntimeInfo1->SigOutputElements ||
|
||||
RuntimeInfo1->SigPatchConstOrPrimElements) {
|
||||
PSVSignatureElementSize = GetUint32AtOffset(pPSVData, Offset);
|
||||
INCREMENT_POS(4);
|
||||
uint32_t PSVNumSignatures = RuntimeInfo1->SigInputElements +
|
||||
RuntimeInfo1->SigOutputElements +
|
||||
RuntimeInfo1->SigPatchConstOrPrimElements;
|
||||
INCREMENT_POS(PSVNumSignatures * PSVSignatureElementSize);
|
||||
}
|
||||
if (RuntimeInfo1->UsesViewID) {
|
||||
for (unsigned i = 0; i < DXIL::kNumOutputStreams; i++) {
|
||||
uint32_t SigOutputVectors = RuntimeInfo1->SigOutputVectors[i];
|
||||
if (SigOutputVectors == 0)
|
||||
continue;
|
||||
uint32_t MaskSizeInBytes =
|
||||
sizeof(uint32_t) *
|
||||
PSVComputeMaskDwordsFromVectors(SigOutputVectors);
|
||||
INCREMENT_POS(MaskSizeInBytes);
|
||||
}
|
||||
if ((RuntimeInfo1->ShaderStage == (unsigned)DXIL::ShaderKind::Hull ||
|
||||
RuntimeInfo1->ShaderStage == (unsigned)DXIL::ShaderKind::Mesh) &&
|
||||
RuntimeInfo1->SigPatchConstOrPrimVectors) {
|
||||
uint32_t MaskSizeInBytes =
|
||||
sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(
|
||||
RuntimeInfo1->SigPatchConstOrPrimVectors);
|
||||
INCREMENT_POS(MaskSizeInBytes);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < DXIL::kNumOutputStreams; i++) {
|
||||
uint32_t SigOutputVectors = RuntimeInfo1->SigOutputVectors[i];
|
||||
if (SigOutputVectors == 0)
|
||||
continue;
|
||||
uint32_t TableSizeInBytes =
|
||||
sizeof(uint32_t) *
|
||||
PSVComputeInputOutputTableDwords(RuntimeInfo1->SigInputVectors,
|
||||
SigOutputVectors);
|
||||
INCREMENT_POS(TableSizeInBytes);
|
||||
}
|
||||
|
||||
if ((RuntimeInfo1->ShaderStage == (unsigned)DXIL::ShaderKind::Hull ||
|
||||
RuntimeInfo1->ShaderStage == (unsigned)DXIL::ShaderKind::Mesh) &&
|
||||
RuntimeInfo1->SigPatchConstOrPrimVectors &&
|
||||
RuntimeInfo1->SigInputVectors) {
|
||||
uint32_t TableSizeInBytes =
|
||||
sizeof(uint32_t) * PSVComputeInputOutputTableDwords(
|
||||
RuntimeInfo1->SigInputVectors,
|
||||
RuntimeInfo1->SigPatchConstOrPrimVectors);
|
||||
INCREMENT_POS(TableSizeInBytes);
|
||||
}
|
||||
|
||||
if (RuntimeInfo1->ShaderStage == (unsigned)DXIL::ShaderKind::Domain &&
|
||||
RuntimeInfo1->SigOutputVectors[0] &&
|
||||
RuntimeInfo1->SigPatchConstOrPrimVectors) {
|
||||
uint32_t TableSizeInBytes =
|
||||
sizeof(uint32_t) * PSVComputeInputOutputTableDwords(
|
||||
RuntimeInfo1->SigPatchConstOrPrimVectors,
|
||||
RuntimeInfo1->SigOutputVectors[0]);
|
||||
INCREMENT_POS(TableSizeInBytes);
|
||||
}
|
||||
}
|
||||
IsValid = PSVSize == Offset;
|
||||
#undef INCREMENT_POS
|
||||
}
|
||||
bool ValidatePSVInit(PSVInitInfo PSVInfo, ValidationContext &ValCtx) {
|
||||
if (PSVRuntimeInfoSize != PSVInfo.RuntimeInfoSize()) {
|
||||
ValCtx.EmitFormatError(ValidationRule::ContainerContentMatches,
|
||||
{"PSVRuntimeInfoSize", "PSV0",
|
||||
std::to_string(PSVRuntimeInfoSize),
|
||||
std::to_string(PSVInfo.RuntimeInfoSize())});
|
||||
return false;
|
||||
}
|
||||
if (PSVNumResources &&
|
||||
PSVResourceBindInfoSize != PSVInfo.ResourceBindInfoSize()) {
|
||||
ValCtx.EmitFormatError(ValidationRule::ContainerContentMatches,
|
||||
{"PSVResourceBindInfoSize", "PSV0",
|
||||
std::to_string(PSVResourceBindInfoSize),
|
||||
std::to_string(PSVInfo.ResourceBindInfoSize())});
|
||||
return false;
|
||||
}
|
||||
if (RuntimeInfo1 &&
|
||||
(RuntimeInfo1->SigInputElements || RuntimeInfo1->SigOutputElements ||
|
||||
RuntimeInfo1->SigPatchConstOrPrimElements) &&
|
||||
PSVSignatureElementSize != PSVInfo.SignatureElementSize()) {
|
||||
ValCtx.EmitFormatError(ValidationRule::ContainerContentMatches,
|
||||
{"PSVSignatureElementSize", "PSV0",
|
||||
std::to_string(PSVSignatureElementSize),
|
||||
std::to_string(PSVInfo.SignatureElementSize())});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const char *GetPtrAtOffset(const void *BasePtr, uint32_t Offset) const {
|
||||
return (const char *)BasePtr + Offset;
|
||||
}
|
||||
uint32_t GetUint32AtOffset(const void *BasePtr, uint32_t Offset) const {
|
||||
return *(const uint32_t *)GetPtrAtOffset(BasePtr, Offset);
|
||||
}
|
||||
};
|
||||
|
||||
static void VerifyPSVMatches(ValidationContext &ValCtx, const void *pPSVData,
|
||||
uint32_t PSVSize) {
|
||||
// SimplePSV.IsValid indicates whether the part is well-formed so that we may
|
||||
// proceed with more detailed validation.
|
||||
SimplePSV SimplePSV(pPSVData, PSVSize);
|
||||
if (!SimplePSV.IsValid) {
|
||||
ValCtx.EmitFormatError(ValidationRule::ContainerContentInvalid,
|
||||
{"DxilContainer", "PSV0 part"});
|
||||
return;
|
||||
}
|
||||
// The PSVVersion determines the size of record structures that should be
|
||||
// used when writing PSV0 data, and is based on the validator version in the
|
||||
// module.
|
||||
unsigned ValMajor, ValMinor;
|
||||
ValCtx.DxilMod.GetValidatorVersion(ValMajor, ValMinor);
|
||||
unsigned PSVVersion = hlsl::GetPSVVersion(ValMajor, ValMinor);
|
||||
// PSVInfo is used to compute the expected record size of the PSV0 part of the
|
||||
// container. It uses facts from the module.
|
||||
PSVInitInfo PSVInfo(PSVVersion);
|
||||
hlsl::SetupPSVInitInfo(PSVInfo, ValCtx.DxilMod);
|
||||
// ValidatePSVInit checks that record sizes match expected for PSVVersion.
|
||||
if (!SimplePSV.ValidatePSVInit(PSVInfo, ValCtx))
|
||||
return;
|
||||
// Ensure that the string table data is null-terminated.
|
||||
if (SimplePSV.StringTable &&
|
||||
SimplePSV.StringTable[SimplePSV.StringTableSize - 1] != '\0') {
|
||||
ValCtx.EmitFormatError(ValidationRule::ContainerContentInvalid,
|
||||
{"PSV part StringTable"});
|
||||
return;
|
||||
}
|
||||
|
||||
DxilPipelineStateValidation PSV;
|
||||
if (!PSV.InitFromPSV0(pPSVData, PSVSize)) {
|
||||
ValCtx.EmitFormatError(ValidationRule::ContainerPartMatches,
|
||||
{"Pipeline State Validation"});
|
||||
return;
|
||||
}
|
||||
|
||||
PSVContentVerifier Verifier(PSV, ValCtx.DxilMod, ValCtx);
|
||||
Verifier.Verify();
|
||||
Verifier.Verify(ValMajor, ValMinor, PSVVersion);
|
||||
}
|
||||
|
||||
static void VerifyFeatureInfoMatches(ValidationContext &ValCtx,
|
||||
|
|
|
@ -321,6 +321,9 @@ public:
|
|||
TEST_METHOD(PSVContentValidationCS)
|
||||
TEST_METHOD(PSVContentValidationMS)
|
||||
TEST_METHOD(PSVContentValidationAS)
|
||||
TEST_METHOD(WrongPSVSize)
|
||||
TEST_METHOD(WrongPSVSizeOnZeros)
|
||||
TEST_METHOD(WrongPSVVersion)
|
||||
|
||||
dxc::DxcDllSupport m_dllSupport;
|
||||
VersionSupportInfo m_ver;
|
||||
|
@ -427,6 +430,18 @@ public:
|
|||
pResultBlob);
|
||||
}
|
||||
|
||||
bool CompileFile(LPCWSTR fileName, LPCSTR pShaderModel, LPCWSTR *pArguments,
|
||||
UINT32 argCount, IDxcBlob **pResultBlob) {
|
||||
std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(fileName);
|
||||
CComPtr<IDxcLibrary> pLibrary;
|
||||
CComPtr<IDxcBlobEncoding> pSource;
|
||||
VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
|
||||
VERIFY_SUCCEEDED(
|
||||
pLibrary->CreateBlobFromFile(fullPath.c_str(), nullptr, &pSource));
|
||||
return CompileSource(pSource, pShaderModel, pArguments, argCount, nullptr,
|
||||
0, pResultBlob);
|
||||
}
|
||||
|
||||
bool CompileSource(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
|
||||
IDxcBlob **pResultBlob) {
|
||||
return CompileSource(pSource, pShaderModel, nullptr, 0, nullptr, 0,
|
||||
|
@ -4636,7 +4651,7 @@ TEST_F(ValidationTest, PSVStringTableReorder) {
|
|||
" ComponentType: 3",
|
||||
" DynamicIndexMask: 0",
|
||||
"') and DXIL module:('PSVSignatureElement:",
|
||||
" SemanticName: ",
|
||||
" SemanticName: A",
|
||||
" SemanticIndex: 0 ",
|
||||
" IsAllocated: 1",
|
||||
" StartRow: 0",
|
||||
|
@ -4664,7 +4679,7 @@ TEST_F(ValidationTest, PSVStringTableReorder) {
|
|||
" ComponentType: 3",
|
||||
" DynamicIndexMask: 0",
|
||||
"') and DXIL module:('PSVSignatureElement:",
|
||||
" SemanticName: ",
|
||||
" SemanticName: B",
|
||||
" SemanticIndex: 0 ",
|
||||
" IsAllocated: 1",
|
||||
" StartRow: 0",
|
||||
|
@ -4679,6 +4694,8 @@ TEST_F(ValidationTest, PSVStringTableReorder) {
|
|||
"')",
|
||||
"error: DXIL container mismatch for 'EntryFunctionName' between 'PSV0' "
|
||||
"part:('ain') and DXIL module:('main')",
|
||||
"error: In 'StringTable', 'A' is not used",
|
||||
"error: In 'StringTable', 'main' is not used",
|
||||
"error: Container part 'Pipeline State Validation' does not match "
|
||||
"expected for module.",
|
||||
"Validation failed."},
|
||||
|
@ -4697,6 +4714,25 @@ TEST_F(ValidationTest, PSVStringTableReorder) {
|
|||
VERIFY_IS_NOT_NULL(pUpdatedResult);
|
||||
VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status));
|
||||
VERIFY_SUCCEEDED(status);
|
||||
|
||||
// Create unused name in String table.
|
||||
PSVInfo->EntryFunctionName = UINT32_MAX;
|
||||
|
||||
// Run validation again.
|
||||
CComPtr<IDxcOperationResult> pUpdatedTableResult2;
|
||||
VERIFY_SUCCEEDED(
|
||||
pValidator->Validate(pProgram, Flags, &pUpdatedTableResult2));
|
||||
// Make sure the validation was fail.
|
||||
VERIFY_IS_NOT_NULL(pUpdatedTableResult2);
|
||||
VERIFY_SUCCEEDED(pUpdatedTableResult2->GetStatus(&status));
|
||||
VERIFY_FAILED(status);
|
||||
CheckOperationResultMsgs(
|
||||
pUpdatedTableResult2,
|
||||
{
|
||||
"In 'PSV0 part', 'EntryFunctionName' is not well-formed",
|
||||
"error: In 'StringTable', 'main' is not used",
|
||||
},
|
||||
/*maySucceedAnyway*/ false, /*bRegex*/ false);
|
||||
}
|
||||
|
||||
class SemanticIndexRotator {
|
||||
|
@ -4715,6 +4751,10 @@ public:
|
|||
SignatureElements[i].SemanticIndexes =
|
||||
SignatureElements[i].SemanticIndexes - 1;
|
||||
}
|
||||
void Clear(unsigned Index) {
|
||||
for (unsigned i = 0; i < SignatureElements.size(); ++i)
|
||||
SignatureElements[i].SemanticIndexes = Index;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ValidationTest, PSVSemanticIndexTableReorder) {
|
||||
|
@ -5043,6 +5083,31 @@ TEST_F(ValidationTest, PSVSemanticIndexTableReorder) {
|
|||
VERIFY_IS_NOT_NULL(pUpdatedResult);
|
||||
VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status));
|
||||
VERIFY_SUCCEEDED(status);
|
||||
|
||||
// Clear SemanticIndexes.
|
||||
InputRotator.Clear(UINT32_MAX);
|
||||
OutputRotator.Clear(UINT32_MAX);
|
||||
PatchConstOrPrimRotator.Clear(UINT32_MAX);
|
||||
|
||||
// Run validation again.
|
||||
CComPtr<IDxcOperationResult> pUpdatedResult2;
|
||||
VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult2));
|
||||
// Make sure the validation was successful.
|
||||
VERIFY_IS_NOT_NULL(pUpdatedResult2);
|
||||
VERIFY_SUCCEEDED(pUpdatedResult2->GetStatus(&status));
|
||||
VERIFY_FAILED(status);
|
||||
|
||||
CheckOperationResultMsgs(
|
||||
pUpdatedResult2,
|
||||
{"error: In 'PSV0 part', 'SemanticIndex' is not well-formed",
|
||||
"error: In 'SemanticIndexTable', '0' is not used",
|
||||
"error: In 'SemanticIndexTable', '2' is not used",
|
||||
"error: In 'SemanticIndexTable', '3' is not used",
|
||||
"error: In 'SemanticIndexTable', '4' is not used",
|
||||
"error: Container part 'Pipeline State Validation' "
|
||||
"does not match expected for module.",
|
||||
"Validation failed."},
|
||||
/*maySucceedAnyway*/ false, /*bRegex*/ false);
|
||||
}
|
||||
|
||||
struct SimplePSV {
|
||||
|
@ -6034,3 +6099,400 @@ TEST_F(ValidationTest, PSVContentValidationAS) {
|
|||
"Validation failed."},
|
||||
/*maySucceedAnyway*/ false, /*bRegex*/ false);
|
||||
}
|
||||
|
||||
struct SimpleContainer {
|
||||
hlsl::DxilContainerHeader *Header;
|
||||
std::vector<uint32_t> PartOffsets;
|
||||
std::vector<const DxilPartHeader *> PartHeaders;
|
||||
SimpleContainer(void *Ptr) {
|
||||
Header = (hlsl::DxilContainerHeader *)Ptr;
|
||||
hlsl::DxilPartIterator pPartIter(nullptr, 0);
|
||||
pPartIter = hlsl::begin(Header);
|
||||
for (unsigned i = 0; i < Header->PartCount; ++i) {
|
||||
VERIFY_IS_TRUE(pPartIter != hlsl::end(Header));
|
||||
PartOffsets.push_back(
|
||||
(uint32_t)((const char *)(*pPartIter) - (const char *)Header));
|
||||
PartHeaders.push_back((const DxilPartHeader *)(*pPartIter));
|
||||
++pPartIter;
|
||||
}
|
||||
VERIFY_ARE_EQUAL(pPartIter, hlsl::end(Header));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ValidationTest, WrongPSVSize) {
|
||||
if (!m_ver.m_InternalValidator)
|
||||
if (m_ver.SkipDxilVersion(1, 8))
|
||||
return;
|
||||
|
||||
CComPtr<IDxcBlob> pProgram;
|
||||
CompileFile(L"..\\DXC\\dumpPSV_AS.hlsl", "as_6_8", &pProgram);
|
||||
|
||||
CComPtr<IDxcValidator> pValidator;
|
||||
CComPtr<IDxcOperationResult> 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);
|
||||
|
||||
hlsl::DxilContainerHeader *pHeader;
|
||||
hlsl::DxilPartIterator pPartIter(nullptr, 0);
|
||||
pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer();
|
||||
// Make sure the PSV part exists.
|
||||
pPartIter =
|
||||
std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader),
|
||||
hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation));
|
||||
VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter);
|
||||
|
||||
// Create a new Blob which is 16 bytes larger than the original one.
|
||||
std::vector<char> pProgram2Data(pProgram->GetBufferSize() + 16, 0);
|
||||
// Copy data from the original blob part by part.
|
||||
// Copy all parts to program2.
|
||||
SimpleContainer Container(pProgram->GetBufferPointer());
|
||||
uint32_t PartOffsetsSize = pHeader->PartCount * sizeof(uint32_t);
|
||||
uint32_t Offset = sizeof(hlsl::DxilContainerHeader) + PartOffsetsSize;
|
||||
std::vector<uint32_t> PartOffsets;
|
||||
const uint32_t ExtraSize = 16;
|
||||
// copy all parts to program2.
|
||||
for (unsigned i = 0; i < pHeader->PartCount; ++i) {
|
||||
PartOffsets.emplace_back(Offset);
|
||||
const DxilPartHeader *pPartHeader = Container.PartHeaders[i];
|
||||
|
||||
// Copy part header.
|
||||
memcpy(pProgram2Data.data() + Offset, pPartHeader, sizeof(DxilPartHeader));
|
||||
Offset += sizeof(DxilPartHeader);
|
||||
|
||||
// Copy part content.
|
||||
uint32_t *PartPtr =
|
||||
const_cast<uint32_t *>((const uint32_t *)GetDxilPartData(pPartHeader));
|
||||
memcpy(pProgram2Data.data() + Offset, PartPtr, pPartHeader->PartSize);
|
||||
|
||||
Offset += pPartHeader->PartSize;
|
||||
|
||||
if (pPartHeader->PartFourCC == hlsl::DFCC_PipelineStateValidation) {
|
||||
// Update the size of PSV part.
|
||||
DxilPartHeader *pPSVPartHeader =
|
||||
(DxilPartHeader *)(pProgram2Data.data() + PartOffsets.back());
|
||||
pPSVPartHeader->PartSize += ExtraSize;
|
||||
Offset += ExtraSize;
|
||||
}
|
||||
}
|
||||
// Copy header.
|
||||
pHeader->ContainerSizeInBytes += ExtraSize;
|
||||
memcpy(pProgram2Data.data(), pHeader, sizeof(hlsl::DxilContainerHeader));
|
||||
// Copy partOffsets.
|
||||
memcpy(pProgram2Data.data() + sizeof(hlsl::DxilContainerHeader),
|
||||
PartOffsets.data(), PartOffsetsSize);
|
||||
|
||||
// Create a new Blob from pProgram2Data.
|
||||
CComPtr<IDxcBlobEncoding> pProgram2;
|
||||
CComPtr<IDxcLibrary> pLibrary;
|
||||
VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
|
||||
VERIFY_SUCCEEDED(pLibrary->CreateBlobWithEncodingFromPinned(
|
||||
pProgram2Data.data(), pProgram2Data.size(), CP_UTF8, &pProgram2));
|
||||
|
||||
// Run validation on updated container.
|
||||
CComPtr<IDxcOperationResult> pUpdatedResult;
|
||||
VERIFY_SUCCEEDED(pValidator->Validate(pProgram2, Flags, &pUpdatedResult));
|
||||
// Make sure the validation was fail.
|
||||
VERIFY_IS_NOT_NULL(pUpdatedResult);
|
||||
VERIFY_SUCCEEDED(pUpdatedResult->GetStatus(&status));
|
||||
VERIFY_FAILED(status);
|
||||
|
||||
CheckOperationResultMsgs(
|
||||
pUpdatedResult, {"In 'DxilContainer', 'PSV0 part' is not well-formed"},
|
||||
/*maySucceedAnyway*/ false, /*bRegex*/ false);
|
||||
}
|
||||
|
||||
TEST_F(ValidationTest, WrongPSVSizeOnZeros) {
|
||||
if (!m_ver.m_InternalValidator)
|
||||
if (m_ver.SkipDxilVersion(1, 8))
|
||||
return;
|
||||
|
||||
CComPtr<IDxcBlob> pProgram;
|
||||
CompileFile(L"..\\DXC\\dumpPSV_PS.hlsl", "ps_6_8", &pProgram);
|
||||
|
||||
CComPtr<IDxcValidator> pValidator;
|
||||
CComPtr<IDxcOperationResult> 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);
|
||||
|
||||
hlsl::DxilContainerHeader *pHeader;
|
||||
hlsl::DxilPartIterator pPartIter(nullptr, 0);
|
||||
pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer();
|
||||
// Make sure the PSV part exists.
|
||||
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<PSVRuntimeInfo3 *>((const PSVRuntimeInfo3 *)PSVPtr);
|
||||
VERIFY_ARE_EQUAL(2u, PSVInfo->SigInputElements);
|
||||
PSVPtr += PSVRuntimeInfo_size / 4;
|
||||
uint32_t *ResourceCountPtr = const_cast<uint32_t *>(PSVPtr++);
|
||||
uint32_t ResourceCount = *ResourceCountPtr;
|
||||
VERIFY_ARE_NOT_EQUAL(0u, ResourceCount);
|
||||
uint32_t ResourceBindingsSize = *(PSVPtr++);
|
||||
PSVPtr += (ResourceCount * ResourceBindingsSize) / 4;
|
||||
uint32_t *StringTableSizePtr = const_cast<uint32_t *>(PSVPtr++);
|
||||
uint32_t StringTableSize = *StringTableSizePtr;
|
||||
// Skip string table.
|
||||
PSVPtr += StringTableSize / 4;
|
||||
uint32_t *SemanticIndexTableEntriesPtr = const_cast<uint32_t *>(PSVPtr++);
|
||||
uint32_t SemanticIndexTableEntries = *SemanticIndexTableEntriesPtr;
|
||||
|
||||
*SemanticIndexTableEntriesPtr = 0;
|
||||
|
||||
// Run validation on updated container.
|
||||
CComPtr<IDxcOperationResult> pUpdatedResult1;
|
||||
VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult1));
|
||||
// Make sure the validation was fail.
|
||||
VERIFY_IS_NOT_NULL(pUpdatedResult1);
|
||||
VERIFY_SUCCEEDED(pUpdatedResult1->GetStatus(&status));
|
||||
VERIFY_FAILED(status);
|
||||
|
||||
CheckOperationResultMsgs(
|
||||
pUpdatedResult1, {"In 'DxilContainer', 'PSV0 part' is not well-formed"},
|
||||
/*maySucceedAnyway*/ false, /*bRegex*/ false);
|
||||
|
||||
*SemanticIndexTableEntriesPtr = SemanticIndexTableEntries;
|
||||
*StringTableSizePtr = 0;
|
||||
|
||||
// Run validation on updated container.
|
||||
CComPtr<IDxcOperationResult> pUpdatedResult2;
|
||||
VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult2));
|
||||
// Make sure the validation was fail.
|
||||
VERIFY_IS_NOT_NULL(pUpdatedResult2);
|
||||
VERIFY_SUCCEEDED(pUpdatedResult2->GetStatus(&status));
|
||||
VERIFY_FAILED(status);
|
||||
|
||||
CheckOperationResultMsgs(
|
||||
pUpdatedResult2, {"In 'DxilContainer', 'PSV0 part' is not well-formed"},
|
||||
/*maySucceedAnyway*/ false, /*bRegex*/ false);
|
||||
|
||||
*StringTableSizePtr = StringTableSize;
|
||||
*ResourceCountPtr = 0;
|
||||
|
||||
// Run validation on updated container.
|
||||
CComPtr<IDxcOperationResult> pUpdatedResult3;
|
||||
VERIFY_SUCCEEDED(pValidator->Validate(pProgram, Flags, &pUpdatedResult3));
|
||||
// Make sure the validation was fail.
|
||||
VERIFY_IS_NOT_NULL(pUpdatedResult3);
|
||||
VERIFY_SUCCEEDED(pUpdatedResult3->GetStatus(&status));
|
||||
VERIFY_FAILED(status);
|
||||
|
||||
CheckOperationResultMsgs(
|
||||
pUpdatedResult3, {"In 'DxilContainer', 'PSV0 part' is not well-formed"},
|
||||
/*maySucceedAnyway*/ false, /*bRegex*/ false);
|
||||
*ResourceCountPtr = ResourceCount;
|
||||
}
|
||||
|
||||
TEST_F(ValidationTest, WrongPSVVersion) {
|
||||
if (!m_ver.m_InternalValidator)
|
||||
if (m_ver.SkipDxilVersion(1, 8))
|
||||
return;
|
||||
|
||||
CComPtr<IDxcBlob> pProgram60;
|
||||
std::vector<LPCWSTR> args;
|
||||
args.emplace_back(L"-validator-version");
|
||||
args.emplace_back(L"1.0");
|
||||
CompileFile(L"..\\DXC\\dumpPSV_CS.hlsl", "cs_6_0", args.data(), args.size(),
|
||||
&pProgram60);
|
||||
|
||||
CComPtr<IDxcValidator> pValidator;
|
||||
CComPtr<IDxcOperationResult> pResult;
|
||||
unsigned Flags = DxcValidatorFlags_InPlaceEdit;
|
||||
VERIFY_SUCCEEDED(
|
||||
m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator));
|
||||
VERIFY_SUCCEEDED(pValidator->Validate(pProgram60, Flags, &pResult));
|
||||
// Make sure the validation was successful.
|
||||
HRESULT status;
|
||||
VERIFY_IS_NOT_NULL(pResult);
|
||||
VERIFY_SUCCEEDED(pResult->GetStatus(&status));
|
||||
VERIFY_SUCCEEDED(status);
|
||||
|
||||
hlsl::DxilContainerHeader *pHeader60;
|
||||
hlsl::DxilPartIterator pPartIter(nullptr, 0);
|
||||
pHeader60 = (hlsl::DxilContainerHeader *)pProgram60->GetBufferPointer();
|
||||
// Make sure the PSV part exists.
|
||||
pPartIter =
|
||||
std::find_if(hlsl::begin(pHeader60), hlsl::end(pHeader60),
|
||||
hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation));
|
||||
VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader60), pPartIter);
|
||||
|
||||
CComPtr<IDxcBlob> pProgram68;
|
||||
|
||||
CompileFile(L"..\\DXC\\dumpPSV_CS.hlsl", "cs_6_8", &pProgram68);
|
||||
CComPtr<IDxcOperationResult> pResult2;
|
||||
VERIFY_SUCCEEDED(pValidator->Validate(pProgram68, Flags, &pResult2));
|
||||
// Make sure the validation was successful.
|
||||
VERIFY_IS_NOT_NULL(pResult);
|
||||
VERIFY_SUCCEEDED(pResult->GetStatus(&status));
|
||||
VERIFY_SUCCEEDED(status);
|
||||
|
||||
hlsl::DxilContainerHeader *pHeader68;
|
||||
pHeader68 = (hlsl::DxilContainerHeader *)pProgram68->GetBufferPointer();
|
||||
// Make sure the PSV part exists.
|
||||
pPartIter =
|
||||
std::find_if(hlsl::begin(pHeader68), hlsl::end(pHeader68),
|
||||
hlsl::DxilPartIsType(hlsl::DFCC_PipelineStateValidation));
|
||||
VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader68), pPartIter);
|
||||
|
||||
// Switch the PSV part between 6.0 to 6.8.
|
||||
SimpleContainer Container60(pProgram60->GetBufferPointer());
|
||||
SimpleContainer Container68(pProgram68->GetBufferPointer());
|
||||
uint32_t Container60WithPSV68Size = sizeof(hlsl::DxilContainerHeader) +
|
||||
pHeader60->PartCount * sizeof(uint32_t);
|
||||
uint32_t Container68WithPSV60Size = sizeof(hlsl::DxilContainerHeader) +
|
||||
pHeader60->PartCount * sizeof(uint32_t);
|
||||
unsigned Container68PartSkipped = 0;
|
||||
for (unsigned i = 0; i < pHeader60->PartCount; ++i) {
|
||||
const DxilPartHeader *pPartHeader60 = Container60.PartHeaders[i];
|
||||
const DxilPartHeader *pPartHeader68 =
|
||||
Container68.PartHeaders[i + Container68PartSkipped];
|
||||
if (pPartHeader68->PartFourCC == hlsl::DFCC_ShaderHash) {
|
||||
Container68PartSkipped++;
|
||||
pPartHeader68 = Container68.PartHeaders[i + Container68PartSkipped];
|
||||
}
|
||||
|
||||
VERIFY_ARE_EQUAL(pPartHeader60->PartFourCC, pPartHeader68->PartFourCC);
|
||||
Container60WithPSV68Size += sizeof(DxilPartHeader);
|
||||
Container68WithPSV60Size += sizeof(DxilPartHeader);
|
||||
if (pPartHeader60->PartFourCC == hlsl::DFCC_PipelineStateValidation) {
|
||||
Container60WithPSV68Size += pPartHeader68->PartSize;
|
||||
Container68WithPSV60Size += pPartHeader60->PartSize;
|
||||
} else {
|
||||
Container60WithPSV68Size += pPartHeader60->PartSize;
|
||||
Container68WithPSV60Size += pPartHeader68->PartSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Create mixed container.
|
||||
std::vector<char> pProgram60WithPSV68Data(Container60WithPSV68Size, 0);
|
||||
std::vector<char> pProgram68WithPSV60Data(Container68WithPSV60Size, 0);
|
||||
|
||||
uint32_t PartOffsetsSize = pHeader60->PartCount * sizeof(uint32_t);
|
||||
uint32_t Offset60 = sizeof(hlsl::DxilContainerHeader) + PartOffsetsSize;
|
||||
std::vector<uint32_t> PartOffsets60;
|
||||
uint32_t Offset68 = sizeof(hlsl::DxilContainerHeader) + PartOffsetsSize;
|
||||
std::vector<uint32_t> PartOffsets68;
|
||||
Container68PartSkipped = 0;
|
||||
for (unsigned i = 0; i < pHeader60->PartCount; ++i) {
|
||||
PartOffsets60.emplace_back(Offset60);
|
||||
PartOffsets68.emplace_back(Offset68);
|
||||
|
||||
const DxilPartHeader *pPartHeader60 = Container60.PartHeaders[i];
|
||||
const DxilPartHeader *pPartHeader68 =
|
||||
Container68.PartHeaders[i + Container68PartSkipped];
|
||||
if (pPartHeader68->PartFourCC == hlsl::DFCC_ShaderHash) {
|
||||
Container68PartSkipped++;
|
||||
pPartHeader68 = Container68.PartHeaders[i + Container68PartSkipped];
|
||||
}
|
||||
|
||||
if (pPartHeader60->PartFourCC == hlsl::DFCC_PipelineStateValidation) {
|
||||
// Copy PSV part from 6.8 to 6.0.
|
||||
memcpy(pProgram60WithPSV68Data.data() + Offset60, pPartHeader68,
|
||||
sizeof(DxilPartHeader));
|
||||
Offset60 += sizeof(DxilPartHeader);
|
||||
memcpy(pProgram60WithPSV68Data.data() + Offset60,
|
||||
GetDxilPartData(pPartHeader68), pPartHeader68->PartSize);
|
||||
Offset60 += pPartHeader68->PartSize;
|
||||
// Copy PSV part from 6.0 to 6.8.
|
||||
memcpy(pProgram68WithPSV60Data.data() + Offset68, pPartHeader60,
|
||||
sizeof(DxilPartHeader));
|
||||
Offset68 += sizeof(DxilPartHeader);
|
||||
memcpy(pProgram68WithPSV60Data.data() + Offset68,
|
||||
GetDxilPartData(pPartHeader60), pPartHeader60->PartSize);
|
||||
|
||||
Offset68 += pPartHeader60->PartSize;
|
||||
} else {
|
||||
// Copy PSV part from 6.0 to 6.0.
|
||||
memcpy(pProgram60WithPSV68Data.data() + Offset60, pPartHeader60,
|
||||
sizeof(DxilPartHeader));
|
||||
Offset60 += sizeof(DxilPartHeader);
|
||||
memcpy(pProgram60WithPSV68Data.data() + Offset60,
|
||||
GetDxilPartData(pPartHeader60), pPartHeader60->PartSize);
|
||||
Offset60 += pPartHeader60->PartSize;
|
||||
// Copy PSV part from 6.8 to 6.8.
|
||||
memcpy(pProgram68WithPSV60Data.data() + Offset68, pPartHeader68,
|
||||
sizeof(DxilPartHeader));
|
||||
Offset68 += sizeof(DxilPartHeader);
|
||||
memcpy(pProgram68WithPSV60Data.data() + Offset68,
|
||||
GetDxilPartData(pPartHeader68), pPartHeader68->PartSize);
|
||||
Offset68 += pPartHeader68->PartSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy header.
|
||||
VERIFY_ARE_EQUAL(Container60WithPSV68Size, Offset60);
|
||||
pHeader60->ContainerSizeInBytes = Container60WithPSV68Size;
|
||||
memcpy(pProgram60WithPSV68Data.data(), pHeader60,
|
||||
sizeof(hlsl::DxilContainerHeader));
|
||||
VERIFY_ARE_EQUAL(Container68WithPSV60Size, Offset68);
|
||||
pHeader68->ContainerSizeInBytes = Container68WithPSV60Size;
|
||||
pHeader68->PartCount -= Container68PartSkipped;
|
||||
memcpy(pProgram68WithPSV60Data.data(), pHeader68,
|
||||
sizeof(hlsl::DxilContainerHeader));
|
||||
// Copy partOffsets.
|
||||
memcpy(pProgram60WithPSV68Data.data() + sizeof(hlsl::DxilContainerHeader),
|
||||
PartOffsets60.data(), PartOffsetsSize);
|
||||
memcpy(pProgram68WithPSV60Data.data() + sizeof(hlsl::DxilContainerHeader),
|
||||
PartOffsets68.data(), PartOffsetsSize);
|
||||
|
||||
// Create a new Blob.
|
||||
CComPtr<IDxcBlobEncoding> pProgram60WithPSV68;
|
||||
CComPtr<IDxcLibrary> pLibrary;
|
||||
VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
|
||||
VERIFY_SUCCEEDED(pLibrary->CreateBlobWithEncodingFromPinned(
|
||||
pProgram60WithPSV68Data.data(), pProgram60WithPSV68Data.size(), CP_UTF8,
|
||||
&pProgram60WithPSV68));
|
||||
|
||||
// Run validation on new containers.
|
||||
CComPtr<IDxcOperationResult> p60WithPSV68Result;
|
||||
VERIFY_SUCCEEDED(
|
||||
pValidator->Validate(pProgram60WithPSV68, Flags, &p60WithPSV68Result));
|
||||
// Make sure the validation was fail.
|
||||
VERIFY_IS_NOT_NULL(p60WithPSV68Result);
|
||||
VERIFY_SUCCEEDED(p60WithPSV68Result->GetStatus(&status));
|
||||
VERIFY_FAILED(status);
|
||||
CheckOperationResultMsgs(
|
||||
p60WithPSV68Result,
|
||||
{"DXIL container mismatch for 'PSVRuntimeInfoSize' between 'PSV0' "
|
||||
"part:('52') and DXIL module:('24')"},
|
||||
/*maySucceedAnyway*/ false, /*bRegex*/ false);
|
||||
|
||||
// Create a new Blob.
|
||||
CComPtr<IDxcBlobEncoding> pProgram68WithPSV60;
|
||||
VERIFY_SUCCEEDED(pLibrary->CreateBlobWithEncodingFromPinned(
|
||||
pProgram68WithPSV60Data.data(), pProgram68WithPSV60Data.size(), CP_UTF8,
|
||||
&pProgram68WithPSV60));
|
||||
CComPtr<IDxcOperationResult> p68WithPSV60Result;
|
||||
VERIFY_SUCCEEDED(
|
||||
pValidator->Validate(pProgram68WithPSV60, Flags, &p68WithPSV60Result));
|
||||
// Make sure the validation was fail.
|
||||
VERIFY_IS_NOT_NULL(p68WithPSV60Result);
|
||||
VERIFY_SUCCEEDED(p68WithPSV60Result->GetStatus(&status));
|
||||
VERIFY_FAILED(status);
|
||||
CheckOperationResultMsgs(
|
||||
p68WithPSV60Result,
|
||||
{"DXIL container mismatch for 'PSVRuntimeInfoSize' between 'PSV0' "
|
||||
"part:('24') and DXIL module:('52')"},
|
||||
/*maySucceedAnyway*/ false, /*bRegex*/ false);
|
||||
}
|
||||
|
|
|
@ -6933,6 +6933,11 @@ class db_dxil(object):
|
|||
"DXIL Container Content is well-formed",
|
||||
"In '%0', '%1' is not well-formed",
|
||||
)
|
||||
self.add_valrule_msg(
|
||||
"Container.UnusedItemInTable",
|
||||
"Items in Table must be used",
|
||||
"In '%0', '%1' is not used",
|
||||
)
|
||||
self.add_valrule("Meta.Required", "Required metadata missing.")
|
||||
self.add_valrule_msg(
|
||||
"Meta.ComputeWithNode",
|
||||
|
|
Загрузка…
Ссылка в новой задаче