spirv-val: Add Vulkan Execution Scope checks (#4183)

* spirv-val: Add Vulkan Execution Scope checks
This commit is contained in:
sfricke-samsung 2021-03-17 07:00:11 -07:00 committed by GitHub
parent 8866fd7ae2
commit c040bd3ae5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 110 additions and 24 deletions

View File

@ -105,21 +105,53 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _,
} }
} }
// If OpControlBarrier is used in fragment, vertex, tessellation evaluation, // OpControlBarrier must only use Subgroup execution scope for a subset of
// or geometry stages, the execution Scope must be Subgroup. // execution models.
if (opcode == SpvOpControlBarrier && value != SpvScopeSubgroup) { if (opcode == SpvOpControlBarrier && value != SpvScopeSubgroup) {
std::string errorVUID = _.VkErrorID(4682);
_.function(inst->function()->id()) _.function(inst->function()->id())
->RegisterExecutionModelLimitation([](SpvExecutionModel model, ->RegisterExecutionModelLimitation([errorVUID](
SpvExecutionModel model,
std::string* message) { std::string* message) {
if (model == SpvExecutionModelFragment || if (model == SpvExecutionModelFragment ||
model == SpvExecutionModelVertex || model == SpvExecutionModelVertex ||
model == SpvExecutionModelGeometry || model == SpvExecutionModelGeometry ||
model == SpvExecutionModelTessellationEvaluation) { model == SpvExecutionModelTessellationEvaluation ||
model == SpvExecutionModelRayGenerationKHR ||
model == SpvExecutionModelIntersectionKHR ||
model == SpvExecutionModelAnyHitKHR ||
model == SpvExecutionModelClosestHitKHR ||
model == SpvExecutionModelMissKHR) {
if (message) { if (message) {
*message = *message =
"in Vulkan evironment, OpControlBarrier execution scope " errorVUID +
"must be Subgroup for Fragment, Vertex, Geometry and " "in Vulkan environment, OpControlBarrier execution scope "
"TessellationEvaluation execution models"; "must be Subgroup for Fragment, Vertex, Geometry, "
"TessellationEvaluation, RayGeneration, Intersection, "
"AnyHit, ClosestHit, and Miss execution models";
}
return false;
}
return true;
});
}
// Only subset of execution models support Workgroup.
if (value == SpvScopeWorkgroup) {
std::string errorVUID = _.VkErrorID(4637);
_.function(inst->function()->id())
->RegisterExecutionModelLimitation(
[errorVUID](SpvExecutionModel model, std::string* message) {
if (model != SpvExecutionModelTaskNV &&
model != SpvExecutionModelMeshNV &&
model != SpvExecutionModelTessellationControl &&
model != SpvExecutionModelGLCompute) {
if (message) {
*message =
errorVUID +
"in Vulkan environment, Workgroup execution scope is "
"only for TaskNV, MeshNV, TessellationControl, and "
"GLCompute execution models";
} }
return false; return false;
} }
@ -131,7 +163,7 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _,
// Scope for execution must be limited to Workgroup or Subgroup // Scope for execution must be limited to Workgroup or Subgroup
if (value != SpvScopeWorkgroup && value != SpvScopeSubgroup) { if (value != SpvScopeWorkgroup && value != SpvScopeSubgroup) {
return _.diag(SPV_ERROR_INVALID_DATA, inst) return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< spvOpcodeString(opcode) << _.VkErrorID(4636) << spvOpcodeString(opcode)
<< ": in Vulkan environment Execution Scope is limited to " << ": in Vulkan environment Execution Scope is limited to "
<< "Workgroup and Subgroup"; << "Workgroup and Subgroup";
} }

View File

@ -1680,6 +1680,10 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-StandaloneSpirv-None-04634); return VUID_WRAP(VUID-StandaloneSpirv-None-04634);
case 4635: case 4635:
return VUID_WRAP(VUID-StandaloneSpirv-None-04635); return VUID_WRAP(VUID-StandaloneSpirv-None-04635);
case 4636:
return VUID_WRAP(VUID-StandaloneSpirv-None-04636);
case 4637:
return VUID_WRAP(VUID-StandaloneSpirv-None-04637);
case 4638: case 4638:
return VUID_WRAP(VUID-StandaloneSpirv-None-04638); return VUID_WRAP(VUID-StandaloneSpirv-None-04638);
case 4639: case 4639:
@ -1720,6 +1724,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675); return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675);
case 4677: case 4677:
return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677); return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677);
case 4682:
return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04682);
case 4683: case 4683:
return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-04683); return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-04683);
case 4685: case 4685:

View File

@ -345,6 +345,8 @@ OpControlBarrier %device %workgroup %none
CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-None-04636"));
EXPECT_THAT(getDiagnosticString(), EXPECT_THAT(getDiagnosticString(),
HasSubstr("ControlBarrier: in Vulkan environment Execution Scope " HasSubstr("ControlBarrier: in Vulkan environment Execution Scope "
"is limited to Workgroup and Subgroup")); "is limited to Workgroup and Subgroup"));
@ -388,9 +390,10 @@ OpControlBarrier %subgroup %cross_device %none
"cannot be CrossDevice")); "cannot be CrossDevice"));
} }
TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeFailure) { TEST_F(ValidateBarriers,
OpControlBarrierVulkan1p1WorkgroupNonComputeMemoryFailure) {
const std::string body = R"( const std::string body = R"(
OpControlBarrier %workgroup %workgroup %acquire OpControlBarrier %subgroup %workgroup %acquire
)"; )";
CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1); CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1);
@ -402,7 +405,23 @@ OpControlBarrier %workgroup %workgroup %acquire
"and GLCompute execution model")); "and GLCompute execution model"));
} }
TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeSuccess) { TEST_F(ValidateBarriers,
OpControlBarrierVulkan1p1WorkgroupNonComputeExecutionFailure) {
const std::string body = R"(
OpControlBarrier %workgroup %subgroup %acquire
)";
CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-None-04637"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("in Vulkan environment, Workgroup execution scope is "
"only for TaskNV, MeshNV, TessellationControl, and "
"GLCompute execution models"));
}
TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupComputeSuccess) {
const std::string body = R"( const std::string body = R"(
OpControlBarrier %workgroup %workgroup %acquire OpControlBarrier %workgroup %workgroup %acquire
)"; )";
@ -411,6 +430,15 @@ OpControlBarrier %workgroup %workgroup %acquire
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
} }
TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeSuccess) {
const std::string body = R"(
OpControlBarrier %subgroup %subgroup %acquire
)";
CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
}
TEST_F(ValidateBarriers, OpControlBarrierVulkanInvocationSuccess) { TEST_F(ValidateBarriers, OpControlBarrierVulkanInvocationSuccess) {
const std::string body = R"( const std::string body = R"(
OpControlBarrier %workgroup %invocation %none OpControlBarrier %workgroup %invocation %none
@ -483,9 +511,13 @@ OpControlBarrier %workgroup %workgroup %acquire_release
SPV_ENV_VULKAN_1_1); SPV_ENV_VULKAN_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(), EXPECT_THAT(getDiagnosticString(),
HasSubstr("OpControlBarrier execution scope must be Subgroup for " AnyVUID("VUID-StandaloneSpirv-OpControlBarrier-04682"));
"Fragment, Vertex, Geometry and TessellationEvaluation " EXPECT_THAT(
"execution models")); getDiagnosticString(),
HasSubstr(
"OpControlBarrier execution scope must be Subgroup for Fragment, "
"Vertex, Geometry, TessellationEvaluation, RayGeneration, "
"Intersection, AnyHit, ClosestHit, and Miss execution models"));
} }
TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionFragment1p0) { TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionFragment1p0) {
@ -521,9 +553,13 @@ OpControlBarrier %workgroup %workgroup %acquire_release
SPV_ENV_VULKAN_1_1); SPV_ENV_VULKAN_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(), EXPECT_THAT(getDiagnosticString(),
HasSubstr("OpControlBarrier execution scope must be Subgroup for " AnyVUID("VUID-StandaloneSpirv-OpControlBarrier-04682"));
"Fragment, Vertex, Geometry and TessellationEvaluation " EXPECT_THAT(
"execution models")); getDiagnosticString(),
HasSubstr(
"OpControlBarrier execution scope must be Subgroup for Fragment, "
"Vertex, Geometry, TessellationEvaluation, RayGeneration, "
"Intersection, AnyHit, ClosestHit, and Miss execution models"));
} }
TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionVertex1p0) { TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionVertex1p0) {
@ -561,9 +597,13 @@ OpControlBarrier %workgroup %workgroup %acquire_release
SPV_ENV_VULKAN_1_1); SPV_ENV_VULKAN_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(), EXPECT_THAT(getDiagnosticString(),
HasSubstr("OpControlBarrier execution scope must be Subgroup for " AnyVUID("VUID-StandaloneSpirv-OpControlBarrier-04682"));
"Fragment, Vertex, Geometry and TessellationEvaluation " EXPECT_THAT(
"execution models")); getDiagnosticString(),
HasSubstr(
"OpControlBarrier execution scope must be Subgroup for Fragment, "
"Vertex, Geometry, TessellationEvaluation, RayGeneration, "
"Intersection, AnyHit, ClosestHit, and Miss execution models"));
} }
TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionGeometry1p0) { TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionGeometry1p0) {
@ -604,9 +644,13 @@ OpControlBarrier %workgroup %workgroup %acquire_release
SPV_ENV_VULKAN_1_1); SPV_ENV_VULKAN_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(), EXPECT_THAT(getDiagnosticString(),
HasSubstr("OpControlBarrier execution scope must be Subgroup for " AnyVUID("VUID-StandaloneSpirv-OpControlBarrier-04682"));
"Fragment, Vertex, Geometry and TessellationEvaluation " EXPECT_THAT(
"execution models")); getDiagnosticString(),
HasSubstr(
"OpControlBarrier execution scope must be Subgroup for Fragment, "
"Vertex, Geometry, TessellationEvaluation, RayGeneration, "
"Intersection, AnyHit, ClosestHit, and Miss execution models"));
} }
TEST_F(ValidateBarriers, TEST_F(ValidateBarriers,
@ -1487,6 +1531,8 @@ TEST_F(ValidateBarriers, OpControlBarrierShaderCallRayGenFailure) {
SPV_ENV_VULKAN_1_1); SPV_ENV_VULKAN_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-None-04636"));
EXPECT_THAT(getDiagnosticString(), EXPECT_THAT(getDiagnosticString(),
HasSubstr("in Vulkan environment Execution Scope is limited to " HasSubstr("in Vulkan environment Execution Scope is limited to "
"Workgroup and Subgroup")); "Workgroup and Subgroup"));

View File

@ -4991,6 +4991,8 @@ TEST_F(ValidateDecorations, UniformDecorationWithScopeIdV14VulkanEnv) {
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1_SPIRV_1_4); CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1_SPIRV_1_4);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, EXPECT_EQ(SPV_ERROR_INVALID_DATA,
ValidateInstructions(SPV_ENV_VULKAN_1_1_SPIRV_1_4)); ValidateInstructions(SPV_ENV_VULKAN_1_1_SPIRV_1_4));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-None-04636"));
EXPECT_THAT(getDiagnosticString(), EXPECT_THAT(getDiagnosticString(),
HasSubstr(": in Vulkan environment Execution Scope is limited to " HasSubstr(": in Vulkan environment Execution Scope is limited to "
"Workgroup and Subgroup")); "Workgroup and Subgroup"));