spirv-val: Add Vulkan Memory Scope VUs (#4106)
* Fix test using Fragment execution
diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp
index 636d54c..a92f7fd 100644
--- a/source/val/validate_scopes.cpp
+++ b/source/val/validate_scopes.cpp
@@ -190,7 +190,7 @@
if (spvIsVulkanEnv(_.context()->target_env)) {
if (value == SpvScopeCrossDevice) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
+ << _.VkErrorID(4638) << spvOpcodeString(opcode)
<< ": in Vulkan environment, Memory Scope cannot be CrossDevice";
}
// Vulkan 1.0 specifc rules
@@ -198,7 +198,7 @@
value != SpvScopeDevice && value != SpvScopeWorkgroup &&
value != SpvScopeInvocation) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
+ << _.VkErrorID(4638) << spvOpcodeString(opcode)
<< ": in Vulkan 1.0 environment Memory Scope is limited to "
<< "Device, Workgroup and Invocation";
}
@@ -209,15 +209,16 @@
value != SpvScopeSubgroup && value != SpvScopeInvocation &&
value != SpvScopeShaderCallKHR) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
- << spvOpcodeString(opcode)
+ << _.VkErrorID(4638) << spvOpcodeString(opcode)
<< ": in Vulkan 1.1 and 1.2 environment Memory Scope is limited "
<< "to Device, Workgroup, Invocation, and ShaderCall";
}
if (value == SpvScopeShaderCallKHR) {
+ std::string errorVUID = _.VkErrorID(4640);
_.function(inst->function()->id())
->RegisterExecutionModelLimitation(
- [](SpvExecutionModel model, std::string* message) {
+ [errorVUID](SpvExecutionModel model, std::string* message) {
if (model != SpvExecutionModelRayGenerationKHR &&
model != SpvExecutionModelIntersectionKHR &&
model != SpvExecutionModelAnyHitKHR &&
@@ -226,6 +227,7 @@
model != SpvExecutionModelCallableKHR) {
if (message) {
*message =
+ errorVUID +
"ShaderCallKHR Memory Scope requires a ray tracing "
"execution model";
}
@@ -234,6 +236,25 @@
return true;
});
}
+
+ if (value == SpvScopeWorkgroup) {
+ std::string errorVUID = _.VkErrorID(4639);
+ _.function(inst->function()->id())
+ ->RegisterExecutionModelLimitation(
+ [errorVUID](SpvExecutionModel model, std::string* message) {
+ if (model != SpvExecutionModelGLCompute &&
+ model != SpvExecutionModelTaskNV &&
+ model != SpvExecutionModelMeshNV) {
+ if (message) {
+ *message = errorVUID +
+ "Workgroup Memory Scope is limited to MeshNV, "
+ "TaskNV, and GLCompute execution model";
+ }
+ return false;
+ }
+ return true;
+ });
+ }
}
// TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments.
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index 367506e..92b51c7 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -1652,6 +1652,12 @@
return VUID_WRAP(VUID-StandaloneSpirv-None-04633);
case 4635:
return VUID_WRAP(VUID-StandaloneSpirv-None-04635);
+ case 4638:
+ return VUID_WRAP(VUID-StandaloneSpirv-None-04638);
+ case 4639:
+ return VUID_WRAP(VUID-StandaloneSpirv-None-04639);
+ case 4640:
+ return VUID_WRAP(VUID-StandaloneSpirv-None-04640);
case 4642:
return VUID_WRAP(VUID-StandaloneSpirv-None-04642);
case 4649:
diff --git a/test/val/val_atomics_test.cpp b/test/val/val_atomics_test.cpp
index 8a79e45..c7e36f5 100644
--- a/test/val/val_atomics_test.cpp
+++ b/test/val/val_atomics_test.cpp
@@ -30,16 +30,16 @@
std::string GenerateShaderCodeImpl(
const std::string& body, const std::string& capabilities_and_extensions,
- const std::string& definitions, const std::string& memory_model) {
+ const std::string& definitions, const std::string& memory_model,
+ const std::string& execution) {
std::ostringstream ss;
ss << R"(
OpCapability Shader
)";
ss << capabilities_and_extensions;
ss << "OpMemoryModel Logical " << memory_model << "\n";
+ ss << execution;
ss << R"(
-OpEntryPoint Fragment %main "main"
-OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%func = OpTypeFunction %void
%bool = OpTypeBool
@@ -96,6 +96,10 @@
const std::string& body,
const std::string& capabilities_and_extensions = "",
const std::string& memory_model = "GLSL450") {
+ const std::string execution = R"(
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+)";
const std::string defintions = R"(
%u64 = OpTypeInt 64 0
%s64 = OpTypeInt 64 1
@@ -110,7 +114,32 @@
)";
return GenerateShaderCodeImpl(
body, "OpCapability Int64\n" + capabilities_and_extensions, defintions,
- memory_model);
+ memory_model, execution);
+}
+
+std::string GenerateShaderComputeCode(
+ const std::string& body,
+ const std::string& capabilities_and_extensions = "",
+ const std::string& memory_model = "GLSL450") {
+ const std::string execution = R"(
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 32 1 1
+)";
+ const std::string defintions = R"(
+%u64 = OpTypeInt 64 0
+%s64 = OpTypeInt 64 1
+
+%u64_1 = OpConstant %u64 1
+%s64_1 = OpConstant %s64 1
+
+%u64_ptr = OpTypePointer Workgroup %u64
+%s64_ptr = OpTypePointer Workgroup %s64
+%u64_var = OpVariable %u64_ptr Workgroup
+%s64_var = OpVariable %s64_ptr Workgroup
+)";
+ return GenerateShaderCodeImpl(
+ body, "OpCapability Int64\n" + capabilities_and_extensions, defintions,
+ memory_model, execution);
}
std::string GenerateKernelCode(
@@ -217,7 +246,7 @@
%val2 = OpAtomicLoad %u32 %u32_var %workgroup %acquire
)";
- CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
+ CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
@@ -341,7 +370,7 @@
%val2 = OpAtomicLoad %f32 %f32_var %workgroup %acquire
)";
- CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
+ CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
@@ -369,8 +398,9 @@
%val2 = OpAtomicLoad %u64 %u64_var %workgroup %acquire
)";
- CompileSuccessfully(GenerateShaderCode(body, "OpCapability Int64Atomics\n"),
- SPV_ENV_VULKAN_1_0);
+ CompileSuccessfully(
+ GenerateShaderComputeCode(body, "OpCapability Int64Atomics\n"),
+ SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
@@ -380,7 +410,7 @@
%val2 = OpAtomicLoad %u64 %u64_var %workgroup %acquire
)";
- CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
+ CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("64-bit atomics require the Int64Atomics capability"));
diff --git a/test/val/val_barriers_test.cpp b/test/val/val_barriers_test.cpp
index 579ec69..9a4beba 100644
--- a/test/val/val_barriers_test.cpp
+++ b/test/val/val_barriers_test.cpp
@@ -121,6 +121,15 @@
execution_model, memory_model);
}
+std::string GenerateVulkanVertexShaderCode(
+ const std::string& body,
+ const std::string& capabilities_and_extensions = "",
+ const std::string& execution_model = "Vertex") {
+ const std::string memory_model = "OpMemoryModel Logical GLSL450";
+ return GenerateShaderCodeImpl(body, capabilities_and_extensions, "",
+ execution_model, memory_model);
+}
+
std::string GenerateKernelCode(
const std::string& body,
const std::string& capabilities_and_extensions = "") {
@@ -348,6 +357,8 @@
CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-None-04638"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("ControlBarrier: in Vulkan 1.0 environment Memory Scope is "
@@ -371,10 +382,35 @@
CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-None-04638"));
+ EXPECT_THAT(getDiagnosticString(),
HasSubstr("ControlBarrier: in Vulkan environment, Memory Scope "
"cannot be CrossDevice"));
}
+TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeFailure) {
+ const std::string body = R"(
+OpControlBarrier %workgroup %workgroup %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-04639"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Workgroup Memory Scope is limited to MeshNV, TaskNV, "
+ "and GLCompute execution model"));
+}
+
+TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeSuccess) {
+ const std::string body = R"(
+OpControlBarrier %workgroup %workgroup %acquire
+)";
+
+ CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+}
+
TEST_F(ValidateBarriers, OpControlBarrierAcquireAndRelease) {
const std::string body = R"(
OpControlBarrier %device %device %acquire_and_release_uniform
@@ -647,6 +683,8 @@
CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-None-04638"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("MemoryBarrier: in Vulkan 1.0 environment Memory Scope is "
@@ -1397,6 +1435,8 @@
SPV_ENV_VULKAN_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-None-04640"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(