@@ -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