@@ -99,6 +99,10 @@ CodeGenerator GetInMainCodeGenerator(const char* const built_in,
99
99
generator.before_types_ += built_in;
100
100
generator.before_types_ += "\n";
101
101
102
+ if (strncmp(built_in, "TessLevel", 9) == 0) {
103
+ generator.before_types_ += "OpMemberDecorate %built_in_type 0 Patch\n";
104
+ }
105
+
102
106
std::ostringstream after_types;
103
107
104
108
after_types << "%built_in_type = OpTypeStruct " << data_type << "\n";
@@ -258,6 +262,10 @@ CodeGenerator GetInFunctionCodeGenerator(const char* const built_in,
258
262
generator.before_types_ += built_in;
259
263
generator.before_types_ += "\n";
260
264
265
+ if (strncmp(built_in, "TessLevel", 9) == 0) {
266
+ generator.before_types_ += "OpMemberDecorate %built_in_type 0 Patch\n";
267
+ }
268
+
261
269
std::ostringstream after_types;
262
270
after_types << "%built_in_type = OpTypeStruct " << data_type << "\n";
263
271
if (InitializerRequired(storage_class)) {
@@ -395,6 +403,11 @@ CodeGenerator GetVariableCodeGenerator(const char* const built_in,
395
403
generator.before_types_ = "OpDecorate %built_in_var BuiltIn ";
396
404
generator.before_types_ += built_in;
397
405
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
+
398
411
if ((0 == std::strcmp(storage_class, "Input")) &&
399
412
(0 == std::strcmp(execution_model, "Fragment"))) {
400
413
// ensure any needed input types that might require Flat
@@ -6550,6 +6563,50 @@ TEST_F(ValidateBuiltIns, BadVulkanBuiltinPrimitiveIdFragmentWithRayTracing) {
6550
6563
AnyVUID("VUID-PrimitiveId-PrimitiveId-04333"));
6551
6564
}
6552
6565
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
+
6553
6610
} // namespace
6554
6611
} // namespace val
6555
6612
} // namespace spvtools
0 commit comments