|
@@ -12,6 +12,10 @@
|
|
|
#include <vector>
|
|
|
#include <string>
|
|
|
#include <algorithm>
|
|
|
+
|
|
|
+#include "llvm/ADT/StringRef.h"
|
|
|
+#include "llvm/Support/Regex.h"
|
|
|
+
|
|
|
#include <atlbase.h>
|
|
|
|
|
|
#include "WexTestClass.h"
|
|
@@ -117,6 +121,28 @@ public:
|
|
|
TEST_METHOD(StructBitCast)
|
|
|
TEST_METHOD(MultiDimArray)
|
|
|
|
|
|
+ TEST_METHOD(ClipCullMaxComponents)
|
|
|
+ TEST_METHOD(ClipCullMaxRows)
|
|
|
+ TEST_METHOD(DuplicateSysValue)
|
|
|
+ TEST_METHOD(SemTargetMax)
|
|
|
+ TEST_METHOD(SemTargetIndexMatchesRow)
|
|
|
+ TEST_METHOD(SemTargetCol0)
|
|
|
+ TEST_METHOD(SemIndexMax)
|
|
|
+ TEST_METHOD(SemTessFactorIndexMax)
|
|
|
+ TEST_METHOD(SemInsideTessFactorIndexMax)
|
|
|
+ TEST_METHOD(SemShouldBeAllocated)
|
|
|
+ TEST_METHOD(SemShouldNotBeAllocated)
|
|
|
+ TEST_METHOD(SemComponentOrder)
|
|
|
+ TEST_METHOD(SemComponentOrder2)
|
|
|
+ TEST_METHOD(SemComponentOrder3)
|
|
|
+ TEST_METHOD(SemIndexConflictArbSV)
|
|
|
+ TEST_METHOD(SemIndexConflictTessfactors)
|
|
|
+ TEST_METHOD(SemIndexConflictTessfactors2)
|
|
|
+ TEST_METHOD(SemRowOutOfRange)
|
|
|
+ TEST_METHOD(SemPackOverlap)
|
|
|
+ TEST_METHOD(SemPackOverlap2)
|
|
|
+ TEST_METHOD(SemMultiDepth)
|
|
|
+
|
|
|
TEST_METHOD(WhenInstrDisallowedThenFail);
|
|
|
TEST_METHOD(WhenDepthNotFloatThenFail);
|
|
|
TEST_METHOD(BarrierFail);
|
|
@@ -166,7 +192,8 @@ public:
|
|
|
}
|
|
|
|
|
|
bool CheckOperationResultMsg(IDxcOperationResult *pResult,
|
|
|
- const char *pErrorMsg, bool maySucceedAnyway) {
|
|
|
+ const char *pErrorMsg, bool maySucceedAnyway,
|
|
|
+ bool bRegex) {
|
|
|
HRESULT status;
|
|
|
VERIFY_SUCCEEDED(pResult->GetStatus(&status));
|
|
|
if (pErrorMsg == nullptr) {
|
|
@@ -179,15 +206,22 @@ public:
|
|
|
//VERIFY_FAILED(status);
|
|
|
CComPtr<IDxcBlobEncoding> text;
|
|
|
VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&text));
|
|
|
- const char *pStart = (const char *)text->GetBufferPointer();
|
|
|
- const char *pEnd = pStart + text->GetBufferSize();
|
|
|
- const char *pMatch = std::search(pStart, pEnd, pErrorMsg, pErrorMsg + strlen(pErrorMsg));
|
|
|
- VERIFY_ARE_NOT_EQUAL(pEnd, pMatch);
|
|
|
+ if (bRegex) {
|
|
|
+ llvm::Regex RE(pErrorMsg);
|
|
|
+ std::string reErrors;
|
|
|
+ VERIFY_IS_TRUE(RE.isValid(reErrors));
|
|
|
+ VERIFY_IS_TRUE(RE.match(llvm::StringRef((const char *)text->GetBufferPointer(), text->GetBufferSize())));
|
|
|
+ } else {
|
|
|
+ const char *pStart = (const char *)text->GetBufferPointer();
|
|
|
+ const char *pEnd = pStart + text->GetBufferSize();
|
|
|
+ const char *pMatch = std::search(pStart, pEnd, pErrorMsg, pErrorMsg + strlen(pErrorMsg));
|
|
|
+ VERIFY_ARE_NOT_EQUAL(pEnd, pMatch);
|
|
|
+ }
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- void CheckValidationMsg(IDxcBlob *pBlob, const char *pErrorMsg) {
|
|
|
+ void CheckValidationMsg(IDxcBlob *pBlob, const char *pErrorMsg, bool bRegex = false) {
|
|
|
CComPtr<IDxcValidator> pValidator;
|
|
|
CComPtr<IDxcOperationResult> pResult;
|
|
|
|
|
@@ -198,10 +232,10 @@ public:
|
|
|
VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator));
|
|
|
VERIFY_SUCCEEDED(pValidator->Validate(pBlob, DxcValidatorFlags_Default, &pResult));
|
|
|
|
|
|
- CheckOperationResultMsg(pResult, pErrorMsg, false);
|
|
|
+ CheckOperationResultMsg(pResult, pErrorMsg, false, bRegex);
|
|
|
}
|
|
|
|
|
|
- void CheckValidationMsg(const char *pBlob, size_t blobSize, const char *pErrorMsg) {
|
|
|
+ void CheckValidationMsg(const char *pBlob, size_t blobSize, const char *pErrorMsg, bool bRegex = false) {
|
|
|
if (!m_dllSupport.IsEnabled()) {
|
|
|
VERIFY_SUCCEEDED(m_dllSupport.Initialize());
|
|
|
}
|
|
@@ -209,7 +243,7 @@ public:
|
|
|
CComPtr<IDxcBlobEncoding> pBlobEncoding; // Encoding doesn't actually matter, it's binary.
|
|
|
VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
|
|
|
VERIFY_SUCCEEDED(pLibrary->CreateBlobWithEncodingFromPinned((LPBYTE)pBlob, blobSize, CP_UTF8, &pBlobEncoding));
|
|
|
- CheckValidationMsg(pBlobEncoding, pErrorMsg);
|
|
|
+ CheckValidationMsg(pBlobEncoding, pErrorMsg, bRegex);
|
|
|
}
|
|
|
|
|
|
void CompileSource(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
|
|
@@ -247,7 +281,7 @@ public:
|
|
|
|
|
|
void RewriteAssemblyCheckMsg(LPCSTR pSource, LPCSTR pShaderModel,
|
|
|
LPCSTR pLookFor, LPCSTR pReplacement,
|
|
|
- LPCSTR pErrorMsg) {
|
|
|
+ LPCSTR pErrorMsg, bool bRegex = false) {
|
|
|
CComPtr<IDxcBlob> pText;
|
|
|
CComPtr<IDxcBlobEncoding> pSourceBlob;
|
|
|
|
|
@@ -257,7 +291,7 @@ public:
|
|
|
|
|
|
Utf8ToBlob(m_dllSupport, pSource, &pSourceBlob);
|
|
|
|
|
|
- RewriteAssemblyToText(pSourceBlob, pShaderModel, pLookFor, pReplacement, &pText);
|
|
|
+ RewriteAssemblyToText(pSourceBlob, pShaderModel, pLookFor, pReplacement, &pText, bRegex);
|
|
|
|
|
|
CComPtr<IDxcAssembler> pAssembler;
|
|
|
CComPtr<IDxcOperationResult> pAssembleResult;
|
|
@@ -265,42 +299,52 @@ public:
|
|
|
m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
|
|
|
VERIFY_SUCCEEDED(pAssembler->AssembleToContainer(pText, &pAssembleResult));
|
|
|
|
|
|
- if (!CheckOperationResultMsg(pAssembleResult, pErrorMsg, true)) {
|
|
|
+ if (!CheckOperationResultMsg(pAssembleResult, pErrorMsg, true, bRegex)) {
|
|
|
// Assembly succeeded, try validation.
|
|
|
CComPtr<IDxcBlob> pBlob;
|
|
|
VERIFY_SUCCEEDED(pAssembleResult->GetResult(&pBlob));
|
|
|
- CheckValidationMsg(pBlob, pErrorMsg);
|
|
|
+ CheckValidationMsg(pBlob, pErrorMsg, bRegex);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void RewriteAssemblyToText(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
|
|
|
LPCSTR pLookFor, LPCSTR pReplacement,
|
|
|
- IDxcBlob **pBlob) {
|
|
|
+ IDxcBlob **pBlob, bool bRegex = false) {
|
|
|
CComPtr<IDxcBlob> pProgram;
|
|
|
std::string disassembly;
|
|
|
CompileSource(pSource, pShaderModel, &pProgram);
|
|
|
DisassembleProgram(pProgram, &disassembly);
|
|
|
if (pLookFor && *pLookFor) {
|
|
|
- bool found = false;
|
|
|
- size_t pos = 0;
|
|
|
- size_t lookForLen = strlen(pLookFor);
|
|
|
- size_t replaceLen = strlen(pReplacement);
|
|
|
- for (;;) {
|
|
|
- pos = disassembly.find(pLookFor, pos);
|
|
|
- if (pos == std::string::npos)
|
|
|
- break;
|
|
|
- found = true; // at least once
|
|
|
- disassembly.replace(pos, lookForLen, pReplacement);
|
|
|
- pos += replaceLen;
|
|
|
+ if (bRegex) {
|
|
|
+ llvm::Regex RE(pLookFor);
|
|
|
+ std::string reErrors;
|
|
|
+ VERIFY_IS_TRUE(RE.isValid(reErrors));
|
|
|
+ std::string replaced = RE.sub(pReplacement, disassembly, &reErrors);
|
|
|
+ VERIFY_ARE_NOT_EQUAL(disassembly, replaced);
|
|
|
+ VERIFY_IS_TRUE(reErrors.empty());
|
|
|
+ disassembly = std::move(replaced);
|
|
|
+ } else {
|
|
|
+ bool found = false;
|
|
|
+ size_t pos = 0;
|
|
|
+ size_t lookForLen = strlen(pLookFor);
|
|
|
+ size_t replaceLen = strlen(pReplacement);
|
|
|
+ for (;;) {
|
|
|
+ pos = disassembly.find(pLookFor, pos);
|
|
|
+ if (pos == std::string::npos)
|
|
|
+ break;
|
|
|
+ found = true; // at least once
|
|
|
+ disassembly.replace(pos, lookForLen, pReplacement);
|
|
|
+ pos += replaceLen;
|
|
|
+ }
|
|
|
+ VERIFY_IS_TRUE(found);
|
|
|
}
|
|
|
- VERIFY_IS_TRUE(found);
|
|
|
}
|
|
|
Utf8ToBlob(m_dllSupport, disassembly.c_str(), pBlob);
|
|
|
}
|
|
|
|
|
|
void RewriteAssemblyCheckMsg(LPCWSTR name, LPCSTR pShaderModel,
|
|
|
LPCSTR pLookFor, LPCSTR pReplacement,
|
|
|
- LPCSTR pErrorMsg) {
|
|
|
+ LPCSTR pErrorMsg, bool bRegex = false) {
|
|
|
std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(name);
|
|
|
CComPtr<IDxcLibrary> pLibrary;
|
|
|
CComPtr<IDxcBlobEncoding> pSource;
|
|
@@ -321,11 +365,11 @@ public:
|
|
|
m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
|
|
|
VERIFY_SUCCEEDED(pAssembler->AssembleToContainer(pText, &pAssembleResult));
|
|
|
|
|
|
- if (!CheckOperationResultMsg(pAssembleResult, pErrorMsg, true)) {
|
|
|
+ if (!CheckOperationResultMsg(pAssembleResult, pErrorMsg, true, bRegex)) {
|
|
|
// Assembly succeeded, try validation.
|
|
|
CComPtr<IDxcBlob> pBlob;
|
|
|
VERIFY_SUCCEEDED(pAssembleResult->GetResult(&pBlob));
|
|
|
- CheckValidationMsg(pBlob, pErrorMsg);
|
|
|
+ CheckValidationMsg(pBlob, pErrorMsg, bRegex);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
@@ -540,7 +584,7 @@ TEST_F(ValidationTest, SignatureStreamIDForNonGS) {
|
|
|
L"..\\CodeGenHLSL\\abs1.hlsl", "ps_6_0",
|
|
|
", i8 0, i32 1, i8 4, i32 0, i8 0, null}",
|
|
|
", i8 0, i32 1, i8 4, i32 0, i8 0, !19}\n!19 = !{i32 0, i32 1}",
|
|
|
- "expect StreamID for none GS between 0, got 1");
|
|
|
+ "Stream index (1) must between 0 and 0");
|
|
|
}
|
|
|
|
|
|
TEST_F(ValidationTest, TypedUAVStoreFullMask0) {
|
|
@@ -1085,4 +1129,527 @@ HSPerVertexData main( const uint id : SV_OutputControlPointID,\
|
|
|
"opcode 'OutputControlPointID' should only used in 'hull function'");
|
|
|
}
|
|
|
|
|
|
+TEST_F(ValidationTest, ClipCullMaxComponents) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+struct VSOut { \
|
|
|
+ float3 clip0 : SV_ClipDistance; \
|
|
|
+ float3 clip1 : SV_ClipDistance1; \
|
|
|
+ float cull0 : SV_CullDistance; \
|
|
|
+ float cull1 : SV_CullDistance1; \
|
|
|
+ float cull2 : CullDistance2; \
|
|
|
+}; \
|
|
|
+VSOut main() { \
|
|
|
+ VSOut Out; \
|
|
|
+ Out.clip0 = 0.1; \
|
|
|
+ Out.clip1 = 0.2; \
|
|
|
+ Out.cull0 = 0.3; \
|
|
|
+ Out.cull1 = 0.4; \
|
|
|
+ Out.cull2 = 0.5; \
|
|
|
+ return Out; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "vs_6_0",
|
|
|
+ "!{i32 4, !\"CullDistance\", i8 9, i8 0,",
|
|
|
+ "!{i32 4, !\"SV_CullDistance\", i8 9, i8 7,",
|
|
|
+ "ClipDistance and CullDistance use more than the maximum of 8 components combined.");
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, ClipCullMaxRows) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+struct VSOut { \
|
|
|
+ float3 clip0 : SV_ClipDistance; \
|
|
|
+ float3 clip1 : SV_ClipDistance1; \
|
|
|
+ float2 cull0 : CullDistance; \
|
|
|
+}; \
|
|
|
+VSOut main() { \
|
|
|
+ VSOut Out; \
|
|
|
+ Out.clip0 = 0.1; \
|
|
|
+ Out.clip1 = 0.2; \
|
|
|
+ Out.cull0 = 0.3; \
|
|
|
+ return Out; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "vs_6_0",
|
|
|
+ "!{i32 2, !\"CullDistance\", i8 9, i8 0,",
|
|
|
+ "!{i32 2, !\"SV_CullDistance\", i8 9, i8 7,",
|
|
|
+ "ClipDistance and CullDistance occupy more than the maximum of 2 rows combined.");
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, DuplicateSysValue) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+float4 main(uint vid : SV_VertexID, uint iid : SV_InstanceID) : SV_Position { \
|
|
|
+ return (float4)0 + vid + iid; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "vs_6_0",
|
|
|
+ "!{i32 1, !\"SV_InstanceID\", i8 5, i8 2,",
|
|
|
+ "!{i32 1, !\"\", i8 5, i8 1,",
|
|
|
+ //"System value SV_VertexID appears more than once in the same signature.");
|
|
|
+ "Semantic 'SV_VertexID' overlap at 0");
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemTargetMax) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+float4 main(float4 col : COLOR) : SV_Target7 { return col; } \
|
|
|
+ ",
|
|
|
+ "ps_6_0",
|
|
|
+ "!{i32 0, !\"SV_Target\", i8 9, i8 16, ![0-9]+, i8 0, i32 1, i8 4, i32 7, i8 0, null}",
|
|
|
+ "!{i32 0, !\"SV_Target\", i8 9, i8 16, !101, i8 0, i32 1, i8 4, i32 8, i8 0, null}\n!101 = !{i32 8}",
|
|
|
+ "SV_Target semantic index exceeds maximum \\(7\\)",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemTargetIndexMatchesRow) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+float4 main(float4 col : COLOR) : SV_Target7 { return col; } \
|
|
|
+ ",
|
|
|
+ "ps_6_0",
|
|
|
+ "!{i32 0, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 4, i32 7, i8 0, null}",
|
|
|
+ "!{i32 0, !\"SV_Target\", i8 9, i8 16, !\\1, i8 0, i32 1, i8 4, i32 6, i8 0, null}",
|
|
|
+ "SV_Target semantic index must match packed row location",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemTargetCol0) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+float3 main(float4 col : COLOR) : SV_Target7 { return col.xyz; } \
|
|
|
+ ",
|
|
|
+ "ps_6_0",
|
|
|
+ "!{i32 0, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 3, i32 7, i8 0, null}",
|
|
|
+ "!{i32 0, !\"SV_Target\", i8 9, i8 16, !\\1, i8 0, i32 1, i8 3, i32 7, i8 1, null}",
|
|
|
+ "SV_Target packed location must start at column 0",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemIndexMax) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+float4 main(uint vid : SV_VertexID, uint iid : SV_InstanceID) : SV_Position { \
|
|
|
+ return (float4)0 + vid + iid; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "vs_6_0",
|
|
|
+ "!{i32 0, !\"SV_VertexID\", i8 5, i8 1, ![0-9]+, i8 0, i32 1, i8 1, i32 0, i8 0, null}",
|
|
|
+ "!{i32 0, !\"SV_VertexID\", i8 5, i8 1, !101, i8 0, i32 1, i8 1, i32 0, i8 0, null}\n!101 = !{i32 1}",
|
|
|
+ "SV_VertexID semantic index exceeds maximum \\(0\\)",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemTessFactorIndexMax) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+struct Vertex { \
|
|
|
+ float4 pos : SV_Position; \
|
|
|
+}; \
|
|
|
+struct PatchConstant { \
|
|
|
+ float edges[ 3 ] : SV_TessFactor; \
|
|
|
+ float inside : SV_InsideTessFactor; \
|
|
|
+}; \
|
|
|
+PatchConstant PCMain( InputPatch<Vertex, 3> patch) { \
|
|
|
+ PatchConstant PC; \
|
|
|
+ PC.edges = (float[3])patch[1].pos.xyz; \
|
|
|
+ PC.inside = patch[1].pos.w; \
|
|
|
+ return PC; \
|
|
|
+} \
|
|
|
+[domain(\"tri\")] \
|
|
|
+[partitioning(\"fractional_odd\")] \
|
|
|
+[outputtopology(\"triangle_cw\")] \
|
|
|
+[patchconstantfunc(\"PCMain\")] \
|
|
|
+[outputcontrolpoints(3)] \
|
|
|
+Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 3 > patch) { \
|
|
|
+ Vertex Out = patch[id]; \
|
|
|
+ Out.pos.w += 0.25; \
|
|
|
+ return Out; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "hs_6_0",
|
|
|
+ "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, ![0-9]+, i8 0, i32 3, i8 1, i32 0, i8 3, null}",
|
|
|
+ "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !101, i8 0, i32 2, i8 1, i32 0, i8 3, null}\n!101 = !{i32 0, i32 1}",
|
|
|
+ "TessFactor rows, columns \\(2, 1\\) invalid for domain Tri. Expected 3 rows and 1 column.",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemInsideTessFactorIndexMax) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+struct Vertex { \
|
|
|
+ float4 pos : SV_Position; \
|
|
|
+}; \
|
|
|
+struct PatchConstant { \
|
|
|
+ float edges[ 3 ] : SV_TessFactor; \
|
|
|
+ float inside : SV_InsideTessFactor; \
|
|
|
+}; \
|
|
|
+PatchConstant PCMain( InputPatch<Vertex, 3> patch) { \
|
|
|
+ PatchConstant PC; \
|
|
|
+ PC.edges = (float[3])patch[1].pos.xyz; \
|
|
|
+ PC.inside = patch[1].pos.w; \
|
|
|
+ return PC; \
|
|
|
+} \
|
|
|
+[domain(\"tri\")] \
|
|
|
+[partitioning(\"fractional_odd\")] \
|
|
|
+[outputtopology(\"triangle_cw\")] \
|
|
|
+[patchconstantfunc(\"PCMain\")] \
|
|
|
+[outputcontrolpoints(3)] \
|
|
|
+Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 3 > patch) { \
|
|
|
+ Vertex Out = patch[id]; \
|
|
|
+ Out.pos.w += 0.25; \
|
|
|
+ return Out; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "hs_6_0",
|
|
|
+ "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !([0-9]+), i8 0, i32 1, i8 1, i32 3, i8 0, null}",
|
|
|
+ "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !\\1, i8 0, i32 2, i8 1, i32 3, i8 0, null}",
|
|
|
+ "InsideTessFactor rows, columns \\(2, 1\\) invalid for domain Tri. Expected 1 rows and 1 column.",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemShouldBeAllocated) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+struct Vertex { \
|
|
|
+ float4 pos : SV_Position; \
|
|
|
+}; \
|
|
|
+struct PatchConstant { \
|
|
|
+ float edges[ 3 ] : SV_TessFactor; \
|
|
|
+ float inside : SV_InsideTessFactor; \
|
|
|
+}; \
|
|
|
+PatchConstant PCMain( InputPatch<Vertex, 3> patch) { \
|
|
|
+ PatchConstant PC; \
|
|
|
+ PC.edges = (float[3])patch[1].pos.xyz; \
|
|
|
+ PC.inside = patch[1].pos.w; \
|
|
|
+ return PC; \
|
|
|
+} \
|
|
|
+[domain(\"tri\")] \
|
|
|
+[partitioning(\"fractional_odd\")] \
|
|
|
+[outputtopology(\"triangle_cw\")] \
|
|
|
+[patchconstantfunc(\"PCMain\")] \
|
|
|
+[outputcontrolpoints(3)] \
|
|
|
+Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 3 > patch) { \
|
|
|
+ Vertex Out = patch[id]; \
|
|
|
+ Out.pos.w += 0.25; \
|
|
|
+ return Out; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "hs_6_0",
|
|
|
+ "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 3, null}",
|
|
|
+ "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !\\1, i8 0, i32 3, i8 1, i32 -1, i8 -1, null}",
|
|
|
+ "PatchConstant Semantic 'SV_TessFactor' should have a valid packing location",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemShouldNotBeAllocated) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+float4 main(float4 col : COLOR, out uint coverage : SV_Coverage) : SV_Target7 { coverage = 7; return col; } \
|
|
|
+ ",
|
|
|
+ "ps_6_0",
|
|
|
+ "!\"SV_Coverage\", i8 5, i8 14, !([0-9]+), i8 0, i32 1, i8 1, i32 -1, i8 -1, null}",
|
|
|
+ "!\"SV_Coverage\", i8 5, i8 14, !\\1, i8 0, i32 1, i8 1, i32 2, i8 0, null}",
|
|
|
+ "Output Semantic 'SV_Coverage' should have a packing location of -1",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemComponentOrder) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+void main( \
|
|
|
+ float2 f2in : f2in, \
|
|
|
+ float3 f3in : f3in, \
|
|
|
+ uint vid : SV_VertexID, \
|
|
|
+ uint iid : SV_InstanceID, \
|
|
|
+ out float4 pos : SV_Position, \
|
|
|
+ out float2 f2out : f2out, \
|
|
|
+ out float3 f3out : f3out, \
|
|
|
+ out float2 ClipDistance : SV_ClipDistance, \
|
|
|
+ out float CullDistance : SV_CullDistance) \
|
|
|
+{ \
|
|
|
+ pos = float4(f3in, f2in.x); \
|
|
|
+ ClipDistance = f2in.x; \
|
|
|
+ CullDistance = f2in.y; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "vs_6_0",
|
|
|
+
|
|
|
+ "= !{i32 1, !\"f2out\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 2, i32 2, i8 0, null}\n"
|
|
|
+ "!([0-9]+) = !{i32 2, !\"f3out\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 3, i32 1, i8 0, null}\n"
|
|
|
+ "!([0-9]+) = !{i32 3, !\"SV_ClipDistance\", i8 9, i8 6, !([0-9]+), i8 2, i32 1, i8 2, i32 3, i8 0, null}\n"
|
|
|
+ "!([0-9]+) = !{i32 4, !\"SV_CullDistance\", i8 9, i8 7, !([0-9]+), i8 2, i32 1, i8 1, i32 3, i8 2, null}\n",
|
|
|
+
|
|
|
+ "= !{i32 1, !\"f2out\", i8 9, i8 0, !\\1, i8 2, i32 1, i8 2, i32 2, i8 2, null}\n"
|
|
|
+ "!\\2 = !{i32 2, !\"f3out\", i8 9, i8 0, !\\3, i8 2, i32 1, i8 3, i32 1, i8 1, null}\n"
|
|
|
+ "!\\4 = !{i32 3, !\"SV_ClipDistance\", i8 9, i8 6, !\\5, i8 2, i32 1, i8 2, i32 2, i8 0, null}\n"
|
|
|
+ "!\\6 = !{i32 4, !\"SV_CullDistance\", i8 9, i8 7, !\\7, i8 2, i32 1, i8 1, i32 1, i8 0, null}\n",
|
|
|
+
|
|
|
+ "signature element SV_ClipDistance at location \\(2,0\\) size \\(1,2\\) violates component ordering rule \\(arb < sv < sgv\\).\n"
|
|
|
+ "signature element SV_CullDistance at location \\(1,0\\) size \\(1,1\\) violates component ordering rule \\(arb < sv < sgv\\).",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemComponentOrder2) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+float4 main( \
|
|
|
+ float4 col : Color, \
|
|
|
+ uint2 val : Value, \
|
|
|
+ uint pid : SV_PrimitiveID, \
|
|
|
+ bool ff : SV_IsFrontFace) : SV_Target \
|
|
|
+{ \
|
|
|
+ return col; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "ps_6_0",
|
|
|
+
|
|
|
+ "= !{i32 1, !\"Value\", i8 5, i8 0, !([0-9]+), i8 1, i32 1, i8 2, i32 1, i8 0, null}\n"
|
|
|
+ "!([0-9]+) = !{i32 2, !\"SV_PrimitiveID\", i8 5, i8 10, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 2, null}\n"
|
|
|
+ "!([0-9]+) = !{i32 3, !\"SV_IsFrontFace\", i8 1, i8 13, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 3, null}\n",
|
|
|
+
|
|
|
+ "= !{i32 1, !\"Value\", i8 5, i8 0, !\\1, i8 1, i32 1, i8 2, i32 1, i8 2, null}\n"
|
|
|
+ "!\\2 = !{i32 2, !\"SV_PrimitiveID\", i8 5, i8 10, !\\3, i8 1, i32 1, i8 1, i32 1, i8 0, null}\n"
|
|
|
+ "!\\4 = !{i32 3, !\"SV_IsFrontFace\", i8 1, i8 13, !\\5, i8 1, i32 1, i8 1, i32 1, i8 1, null}\n",
|
|
|
+
|
|
|
+ "signature element SV_PrimitiveID at location \\(1,0\\) size \\(1,1\\) violates component ordering rule \\(arb < sv < sgv\\).\n"
|
|
|
+ "signature element SV_IsFrontFace at location \\(1,1\\) size \\(1,1\\) violates component ordering rule \\(arb < sv < sgv\\).",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemComponentOrder3) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+float4 main( \
|
|
|
+ float4 col : Color, \
|
|
|
+ uint val : Value, \
|
|
|
+ uint pid : SV_PrimitiveID, \
|
|
|
+ bool ff : SV_IsFrontFace, \
|
|
|
+ uint vpid : ViewPortArrayIndex) : SV_Target \
|
|
|
+{ \
|
|
|
+ return col; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "ps_6_0",
|
|
|
+
|
|
|
+ "= !{i32 1, !\"Value\", i8 5, i8 0, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 0, null}\n"
|
|
|
+ "!([0-9]+) = !{i32 2, !\"SV_PrimitiveID\", i8 5, i8 10, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 2, null}\n"
|
|
|
+ "!([0-9]+) = !{i32 3, !\"SV_IsFrontFace\", i8 1, i8 13, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 3, null}\n"
|
|
|
+ "!([0-9]+) = !{i32 4, !\"ViewPortArrayIndex\", i8 5, i8 0, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 1, null}\n",
|
|
|
+
|
|
|
+ "= !{i32 1, !\"Value\", i8 5, i8 0, !\\1, i8 1, i32 1, i8 1, i32 1, i8 1, null}\n"
|
|
|
+ "!\\2 = !{i32 2, !\"SV_PrimitiveID\", i8 5, i8 10, !\\3, i8 1, i32 1, i8 1, i32 1, i8 0, null}\n"
|
|
|
+ "!\\4 = !{i32 3, !\"SV_IsFrontFace\", i8 1, i8 13, !\\5, i8 1, i32 1, i8 1, i32 1, i8 2, null}\n"
|
|
|
+ "!\\6 = !{i32 4, !\"ViewPortArrayIndex\", i8 5, i8 0, !\\7, i8 1, i32 1, i8 1, i32 1, i8 3, null}\n",
|
|
|
+
|
|
|
+ "signature element SV_PrimitiveID at location \\(1,0\\) size \\(1,1\\) violates component ordering rule \\(arb < sv < sgv\\).\n"
|
|
|
+ "signature element ViewPortArrayIndex at location \\(1,3\\) size \\(1,1\\) violates component ordering rule \\(arb < sv < sgv\\).",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemIndexConflictArbSV) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+void main( \
|
|
|
+ float4 inpos : Position, \
|
|
|
+ uint iid : SV_InstanceID, \
|
|
|
+ out float4 pos : SV_Position, \
|
|
|
+ out uint id[2] : Array, \
|
|
|
+ out uint vpid : SV_ViewPortArrayIndex, \
|
|
|
+ out float2 ClipDistance : SV_ClipDistance, \
|
|
|
+ out float CullDistance : SV_CullDistance) \
|
|
|
+{ \
|
|
|
+ pos = inpos; \
|
|
|
+ ClipDistance = inpos.x; \
|
|
|
+ CullDistance = inpos.y; \
|
|
|
+ vpid = iid; \
|
|
|
+ id[0] = iid; \
|
|
|
+ id[1] = iid + 1; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "vs_6_0",
|
|
|
+
|
|
|
+ "!{i32 2, !\"SV_ViewportArrayIndex\", i8 5, i8 5, !([0-9]+), i8 1, i32 1, i8 1, i32 3, i8 0, null}",
|
|
|
+ "!{i32 2, !\"SV_ViewportArrayIndex\", i8 5, i8 5, !\\1, i8 1, i32 1, i8 1, i32 1, i8 3, null}",
|
|
|
+
|
|
|
+ "signature element SV_ViewportArrayIndex at location \\(1,3\\) size \\(1,1\\) has an indexing conflict with another signature element packed into the same row.",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemIndexConflictTessfactors) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+struct Vertex { \
|
|
|
+ float4 pos : SV_Position; \
|
|
|
+}; \
|
|
|
+struct PatchConstant { \
|
|
|
+ float edges[ 4 ] : SV_TessFactor; \
|
|
|
+ float inside[ 2 ] : SV_InsideTessFactor; \
|
|
|
+}; \
|
|
|
+PatchConstant PCMain( InputPatch<Vertex, 4> patch) { \
|
|
|
+ PatchConstant PC; \
|
|
|
+ PC.edges = (float[4])patch[1].pos; \
|
|
|
+ PC.inside = (float[2])patch[1].pos.xy; \
|
|
|
+ return PC; \
|
|
|
+} \
|
|
|
+[domain(\"quad\")] \
|
|
|
+[partitioning(\"fractional_odd\")] \
|
|
|
+[outputtopology(\"triangle_cw\")] \
|
|
|
+[patchconstantfunc(\"PCMain\")] \
|
|
|
+[outputcontrolpoints(4)] \
|
|
|
+Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) { \
|
|
|
+ Vertex Out = patch[id]; \
|
|
|
+ Out.pos.w += 0.25; \
|
|
|
+ return Out; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "hs_6_0",
|
|
|
+ //!{i32 0, !"SV_TessFactor", i8 9, i8 25, !23, i8 0, i32 4, i8 1, i32 0, i8 3, null}
|
|
|
+ "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !([0-9]+), i8 0, i32 2, i8 1, i32 4, i8 3, null}",
|
|
|
+ "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !\\1, i8 0, i32 2, i8 1, i32 0, i8 2, null}",
|
|
|
+ "signature element SV_InsideTessFactor at location \\(0,2\\) size \\(2,1\\) has an indexing conflict with another signature element packed into the same row.",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemIndexConflictTessfactors2) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+struct Vertex { \
|
|
|
+ float4 pos : SV_Position; \
|
|
|
+}; \
|
|
|
+struct PatchConstant { \
|
|
|
+ float edges[ 4 ] : SV_TessFactor; \
|
|
|
+ float inside[ 2 ] : SV_InsideTessFactor; \
|
|
|
+ float arb [ 3 ] : Arb; \
|
|
|
+}; \
|
|
|
+PatchConstant PCMain( InputPatch<Vertex, 4> patch) { \
|
|
|
+ PatchConstant PC; \
|
|
|
+ PC.edges = (float[4])patch[1].pos; \
|
|
|
+ PC.inside = (float[2])patch[1].pos.xy; \
|
|
|
+ PC.arb[0] = 1; PC.arb[1] = 2; PC.arb[2] = 3; \
|
|
|
+ return PC; \
|
|
|
+} \
|
|
|
+[domain(\"quad\")] \
|
|
|
+[partitioning(\"fractional_odd\")] \
|
|
|
+[outputtopology(\"triangle_cw\")] \
|
|
|
+[patchconstantfunc(\"PCMain\")] \
|
|
|
+[outputcontrolpoints(4)] \
|
|
|
+Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) { \
|
|
|
+ Vertex Out = patch[id]; \
|
|
|
+ Out.pos.w += 0.25; \
|
|
|
+ return Out; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "hs_6_0",
|
|
|
+ "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, null}",
|
|
|
+ "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 2, i8 0, null}",
|
|
|
+ "signature element Arb at location \\(2,0\\) size \\(3,1\\) has an indexing conflict with another signature element packed into the same row.",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemRowOutOfRange) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+struct Vertex { \
|
|
|
+ float4 pos : SV_Position; \
|
|
|
+}; \
|
|
|
+struct PatchConstant { \
|
|
|
+ float edges[ 4 ] : SV_TessFactor; \
|
|
|
+ float inside[ 2 ] : SV_InsideTessFactor; \
|
|
|
+ float arb [ 3 ] : Arb; \
|
|
|
+}; \
|
|
|
+PatchConstant PCMain( InputPatch<Vertex, 4> patch) { \
|
|
|
+ PatchConstant PC; \
|
|
|
+ PC.edges = (float[4])patch[1].pos; \
|
|
|
+ PC.inside = (float[2])patch[1].pos.xy; \
|
|
|
+ PC.arb[0] = 1; PC.arb[1] = 2; PC.arb[2] = 3; \
|
|
|
+ return PC; \
|
|
|
+} \
|
|
|
+[domain(\"quad\")] \
|
|
|
+[partitioning(\"fractional_odd\")] \
|
|
|
+[outputtopology(\"triangle_cw\")] \
|
|
|
+[patchconstantfunc(\"PCMain\")] \
|
|
|
+[outputcontrolpoints(4)] \
|
|
|
+Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) { \
|
|
|
+ Vertex Out = patch[id]; \
|
|
|
+ Out.pos.w += 0.25; \
|
|
|
+ return Out; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "hs_6_0",
|
|
|
+ "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, null}",
|
|
|
+ "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 31, i8 0, null}",
|
|
|
+ "signature element Arb at location \\(31,0\\) size \\(3,1\\) is out of range.",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemPackOverlap) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+struct Vertex { \
|
|
|
+ float4 pos : SV_Position; \
|
|
|
+}; \
|
|
|
+struct PatchConstant { \
|
|
|
+ float edges[ 4 ] : SV_TessFactor; \
|
|
|
+ float inside[ 2 ] : SV_InsideTessFactor; \
|
|
|
+ float arb [ 3 ] : Arb; \
|
|
|
+}; \
|
|
|
+PatchConstant PCMain( InputPatch<Vertex, 4> patch) { \
|
|
|
+ PatchConstant PC; \
|
|
|
+ PC.edges = (float[4])patch[1].pos; \
|
|
|
+ PC.inside = (float[2])patch[1].pos.xy; \
|
|
|
+ PC.arb[0] = 1; PC.arb[1] = 2; PC.arb[2] = 3; \
|
|
|
+ return PC; \
|
|
|
+} \
|
|
|
+[domain(\"quad\")] \
|
|
|
+[partitioning(\"fractional_odd\")] \
|
|
|
+[outputtopology(\"triangle_cw\")] \
|
|
|
+[patchconstantfunc(\"PCMain\")] \
|
|
|
+[outputcontrolpoints(4)] \
|
|
|
+Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) { \
|
|
|
+ Vertex Out = patch[id]; \
|
|
|
+ Out.pos.w += 0.25; \
|
|
|
+ return Out; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "hs_6_0",
|
|
|
+ "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, null}",
|
|
|
+ "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 1, i8 3, null}",
|
|
|
+ "signature element Arb at location \\(1,3\\) size \\(3,1\\) overlaps another signature element.",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemPackOverlap2) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+void main( \
|
|
|
+ float4 inpos : Position, \
|
|
|
+ uint iid : SV_InstanceID, \
|
|
|
+ out float4 pos : SV_Position, \
|
|
|
+ out uint id[2] : Array, \
|
|
|
+ out uint3 value : Value, \
|
|
|
+ out float2 ClipDistance : SV_ClipDistance, \
|
|
|
+ out float CullDistance : SV_CullDistance) \
|
|
|
+{ \
|
|
|
+ pos = inpos; \
|
|
|
+ ClipDistance = inpos.x; \
|
|
|
+ CullDistance = inpos.y; \
|
|
|
+ value = iid; \
|
|
|
+ id[0] = iid; \
|
|
|
+ id[1] = iid + 1; \
|
|
|
+} \
|
|
|
+ ",
|
|
|
+ "vs_6_0",
|
|
|
+
|
|
|
+ "!{i32 1, !\"Array\", i8 5, i8 0, !([0-9]+), i8 1, i32 2, i8 1, i32 1, i8 0, null}\n"
|
|
|
+ "!([0-9]+) = !{i32 2, !\"Value\", i8 5, i8 0, !([0-9]+), i8 1, i32 1, i8 3, i32 1, i8 1, null}",
|
|
|
+
|
|
|
+ "!{i32 1, !\"Array\", i8 5, i8 0, !\\1, i8 1, i32 2, i8 1, i32 1, i8 1, null}\n"
|
|
|
+ "!\\2 = !{i32 2, !\"Value\", i8 5, i8 0, !\\3, i8 1, i32 1, i8 3, i32 2, i8 0, null}",
|
|
|
+
|
|
|
+ "signature element Value at location \\(2,0\\) size \\(1,3\\) overlaps another signature element.",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ValidationTest, SemMultiDepth) {
|
|
|
+ RewriteAssemblyCheckMsg(" \
|
|
|
+float4 main(float4 f4 : Input, out float d0 : SV_Depth, out float d1 : SV_Target1) : SV_Target \
|
|
|
+{ d0 = f4.z; d1 = f4.w; return f4; } \
|
|
|
+ ",
|
|
|
+ "ps_6_0",
|
|
|
+
|
|
|
+ "!{i32 1, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 1, i32 1, i8 0, null}\n"
|
|
|
+ "!([0-9]+) = !{i32 2, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 4, i32 0, i8 0, null}",
|
|
|
+
|
|
|
+ "!{i32 1, !\"SV_DepthGreaterEqual\", i8 9, i8 19, !\\3, i8 0, i32 1, i8 1, i32 -1, i8 -1, null}\n"
|
|
|
+ "!\\2 = !{i32 2, !\"SV_Target\", i8 9, i8 16, !\\3, i8 0, i32 1, i8 4, i32 0, i8 0, null}",
|
|
|
+
|
|
|
+ "Pixel Shader only allows one type of depth semantic to be declared",
|
|
|
+ /*bRegex*/true);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
// TODO: reject non-zero padding
|