Skip to content

Commit 3abad50

Browse files
spirv-val: Add Patch Decoration check (KhronosGroup#6219)
1 parent 8cf1bf9 commit 3abad50

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

source/val/validate_builtins.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2692,6 +2692,13 @@ spv_result_t BuiltInsValidator::ValidateTessLevelOuterAtDefinition(
26922692
})) {
26932693
return error;
26942694
}
2695+
2696+
if (!_.HasDecoration(inst.id(), spv::Decoration::Patch)) {
2697+
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2698+
<< _.VkErrorID(10880)
2699+
<< "BuiltIn TessLevelOuter variable needs to also have a Patch "
2700+
"decoration.";
2701+
}
26952702
}
26962703

26972704
// Seed at reference checks with this built-in.
@@ -2706,13 +2713,20 @@ spv_result_t BuiltInsValidator::ValidateTessLevelInnerAtDefinition(
27062713
[this, &inst](const std::string& message) -> spv_result_t {
27072714
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
27082715
<< _.VkErrorID(4397)
2709-
<< "According to the Vulkan spec BuiltIn TessLevelOuter "
2716+
<< "According to the Vulkan spec BuiltIn TessLevelInner "
27102717
"variable needs to be a 2-component 32-bit float "
27112718
"array. "
27122719
<< message;
27132720
})) {
27142721
return error;
27152722
}
2723+
2724+
if (!_.HasDecoration(inst.id(), spv::Decoration::Patch)) {
2725+
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2726+
<< _.VkErrorID(10880)
2727+
<< "BuiltIn TessLevelInner variable needs to also have a Patch "
2728+
"decoration.";
2729+
}
27162730
}
27172731

27182732
// Seed at reference checks with this built-in.

source/val/validation_state.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2698,6 +2698,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
26982698
case 10824:
26992699
// This use to be a standalone, but maintenance9 will set allow_vulkan_32_bit_bitwise now
27002700
return VUID_WRAP(VUID-RuntimeSpirv-None-10824);
2701+
case 10880:
2702+
return VUID_WRAP(VUID-StandaloneSpirv-TessLevelInner-10880);
27012703
default:
27022704
return ""; // unknown id
27032705
}

test/val/val_builtins_test.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ CodeGenerator GetInMainCodeGenerator(const char* const built_in,
9999
generator.before_types_ += built_in;
100100
generator.before_types_ += "\n";
101101

102+
if (strncmp(built_in, "TessLevel", 9) == 0) {
103+
generator.before_types_ += "OpMemberDecorate %built_in_type 0 Patch\n";
104+
}
105+
102106
std::ostringstream after_types;
103107

104108
after_types << "%built_in_type = OpTypeStruct " << data_type << "\n";
@@ -258,6 +262,10 @@ CodeGenerator GetInFunctionCodeGenerator(const char* const built_in,
258262
generator.before_types_ += built_in;
259263
generator.before_types_ += "\n";
260264

265+
if (strncmp(built_in, "TessLevel", 9) == 0) {
266+
generator.before_types_ += "OpMemberDecorate %built_in_type 0 Patch\n";
267+
}
268+
261269
std::ostringstream after_types;
262270
after_types << "%built_in_type = OpTypeStruct " << data_type << "\n";
263271
if (InitializerRequired(storage_class)) {
@@ -395,6 +403,11 @@ CodeGenerator GetVariableCodeGenerator(const char* const built_in,
395403
generator.before_types_ = "OpDecorate %built_in_var BuiltIn ";
396404
generator.before_types_ += built_in;
397405
generator.before_types_ += "\n";
406+
407+
if (strncmp(built_in, "TessLevel", 9) == 0) {
408+
generator.before_types_ += "OpDecorate %built_in_var Patch\n";
409+
}
410+
398411
if ((0 == std::strcmp(storage_class, "Input")) &&
399412
(0 == std::strcmp(execution_model, "Fragment"))) {
400413
// ensure any needed input types that might require Flat
@@ -6550,6 +6563,50 @@ TEST_F(ValidateBuiltIns, BadVulkanBuiltinPrimitiveIdFragmentWithRayTracing) {
65506563
AnyVUID("VUID-PrimitiveId-PrimitiveId-04333"));
65516564
}
65526565

6566+
TEST_F(ValidateBuiltIns, TessellationMissingPatch) {
6567+
const std::string spirv = R"(
6568+
OpCapability Tessellation
6569+
OpMemoryModel Logical GLSL450
6570+
OpEntryPoint TessellationControl %main "main" %gl_TessLevelInner %gl_TessLevelOuter
6571+
OpExecutionMode %main OutputVertices 3
6572+
OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
6573+
OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
6574+
OpDecorate %gl_TessLevelOuter Patch
6575+
%void = OpTypeVoid
6576+
%4 = OpTypeFunction %void
6577+
%float = OpTypeFloat 32
6578+
%uint = OpTypeInt 32 0
6579+
%uint_2 = OpConstant %uint 2
6580+
%_arr_float_uint_2 = OpTypeArray %float %uint_2
6581+
%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2
6582+
%gl_TessLevelInner = OpVariable %_ptr_Output__arr_float_uint_2 Output
6583+
%int = OpTypeInt 32 1
6584+
%int_0 = OpConstant %int 0
6585+
%float_1 = OpConstant %float 1
6586+
%_ptr_Output_float = OpTypePointer Output %float
6587+
%uint_4 = OpConstant %uint 4
6588+
%_arr_float_uint_4 = OpTypeArray %float %uint_4
6589+
%_ptr_Output__arr_float_uint_4 = OpTypePointer Output %_arr_float_uint_4
6590+
%gl_TessLevelOuter = OpVariable %_ptr_Output__arr_float_uint_4 Output
6591+
%main = OpFunction %void None %4
6592+
%6 = OpLabel
6593+
%17 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %int_0
6594+
OpStore %17 %float_1
6595+
%22 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_0
6596+
OpStore %22 %float_1
6597+
OpReturn
6598+
OpFunctionEnd
6599+
)";
6600+
6601+
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
6602+
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
6603+
EXPECT_THAT(getDiagnosticString(),
6604+
HasSubstr("BuiltIn TessLevelInner variable needs to also have a "
6605+
"Patch decoration"));
6606+
EXPECT_THAT(getDiagnosticString(),
6607+
AnyVUID("VUID-StandaloneSpirv-TessLevelInner-10880"));
6608+
}
6609+
65536610
} // namespace
65546611
} // namespace val
65556612
} // namespace spvtools

0 commit comments

Comments
 (0)