1 // Copyright (c) 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Validation tests for decorations
16
17 #include <string>
18 #include <vector>
19
20 #include "gmock/gmock.h"
21 #include "source/val/decoration.h"
22 #include "test/unit_spirv.h"
23 #include "test/val/val_fixtures.h"
24
25 namespace spvtools {
26 namespace val {
27 namespace {
28
29 using ::testing::Eq;
30 using ::testing::HasSubstr;
31
32 using ValidateDecorations = spvtest::ValidateBase<bool>;
33
TEST_F(ValidateDecorations,ValidateOpDecorateRegistration)34 TEST_F(ValidateDecorations, ValidateOpDecorateRegistration) {
35 std::string spirv = R"(
36 OpCapability Shader
37 OpCapability Linkage
38 OpMemoryModel Logical GLSL450
39 OpDecorate %1 ArrayStride 4
40 OpDecorate %1 RelaxedPrecision
41 %2 = OpTypeFloat 32
42 %1 = OpTypeRuntimeArray %2
43 ; Since %1 is used first in Decoration, it gets id 1.
44 )";
45 const uint32_t id = 1;
46 CompileSuccessfully(spirv);
47 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
48 // Must have 2 decorations.
49 EXPECT_THAT(
50 vstate_->id_decorations(id),
51 Eq(std::vector<Decoration>{Decoration(SpvDecorationArrayStride, {4}),
52 Decoration(SpvDecorationRelaxedPrecision)}));
53 }
54
TEST_F(ValidateDecorations,ValidateOpMemberDecorateRegistration)55 TEST_F(ValidateDecorations, ValidateOpMemberDecorateRegistration) {
56 std::string spirv = R"(
57 OpCapability Shader
58 OpCapability Linkage
59 OpMemoryModel Logical GLSL450
60 OpDecorate %_arr_double_uint_6 ArrayStride 4
61 OpMemberDecorate %_struct_115 2 NonReadable
62 OpMemberDecorate %_struct_115 2 Offset 2
63 OpDecorate %_struct_115 BufferBlock
64 %float = OpTypeFloat 32
65 %uint = OpTypeInt 32 0
66 %uint_6 = OpConstant %uint 6
67 %_arr_double_uint_6 = OpTypeArray %float %uint_6
68 %_struct_115 = OpTypeStruct %float %float %_arr_double_uint_6
69 )";
70 CompileSuccessfully(spirv);
71 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
72
73 // The array must have 1 decoration.
74 const uint32_t arr_id = 1;
75 EXPECT_THAT(
76 vstate_->id_decorations(arr_id),
77 Eq(std::vector<Decoration>{Decoration(SpvDecorationArrayStride, {4})}));
78
79 // The struct must have 3 decorations.
80 const uint32_t struct_id = 2;
81 EXPECT_THAT(
82 vstate_->id_decorations(struct_id),
83 Eq(std::vector<Decoration>{Decoration(SpvDecorationNonReadable, {}, 2),
84 Decoration(SpvDecorationOffset, {2}, 2),
85 Decoration(SpvDecorationBufferBlock)}));
86 }
87
TEST_F(ValidateDecorations,ValidateOpMemberDecorateOutOfBound)88 TEST_F(ValidateDecorations, ValidateOpMemberDecorateOutOfBound) {
89 std::string spirv = R"(
90 OpCapability Shader
91 OpMemoryModel Logical GLSL450
92 OpEntryPoint Fragment %1 "Main"
93 OpExecutionMode %1 OriginUpperLeft
94 OpMemberDecorate %_struct_2 1 RelaxedPrecision
95 %void = OpTypeVoid
96 %4 = OpTypeFunction %void
97 %float = OpTypeFloat 32
98 %_struct_2 = OpTypeStruct %float
99 %1 = OpFunction %void None %4
100 %6 = OpLabel
101 OpReturn
102 OpFunctionEnd
103 )";
104 CompileSuccessfully(spirv);
105 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
106 EXPECT_THAT(getDiagnosticString(),
107 HasSubstr("Index 1 provided in OpMemberDecorate for struct <id> "
108 "2[%_struct_2] is out of bounds. The structure has 1 "
109 "members. Largest valid index is 0."));
110 }
111
TEST_F(ValidateDecorations,ValidateGroupDecorateRegistration)112 TEST_F(ValidateDecorations, ValidateGroupDecorateRegistration) {
113 std::string spirv = R"(
114 OpCapability Shader
115 OpCapability Linkage
116 OpMemoryModel Logical GLSL450
117 OpDecorate %1 DescriptorSet 0
118 OpDecorate %1 NonWritable
119 OpDecorate %1 Restrict
120 %1 = OpDecorationGroup
121 OpGroupDecorate %1 %2 %3
122 OpGroupDecorate %1 %4
123 %float = OpTypeFloat 32
124 %_runtimearr_float = OpTypeRuntimeArray %float
125 %_struct_9 = OpTypeStruct %_runtimearr_float
126 %_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
127 %2 = OpVariable %_ptr_Uniform__struct_9 Uniform
128 %_struct_10 = OpTypeStruct %_runtimearr_float
129 %_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10
130 %3 = OpVariable %_ptr_Uniform__struct_10 Uniform
131 %_struct_11 = OpTypeStruct %_runtimearr_float
132 %_ptr_Uniform__struct_11 = OpTypePointer Uniform %_struct_11
133 %4 = OpVariable %_ptr_Uniform__struct_11 Uniform
134 )";
135 CompileSuccessfully(spirv);
136 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
137
138 // Decoration group has 3 decorations.
139 auto expected_decorations = std::vector<Decoration>{
140 Decoration(SpvDecorationDescriptorSet, {0}),
141 Decoration(SpvDecorationNonWritable), Decoration(SpvDecorationRestrict)};
142
143 // Decoration group is applied to id 1, 2, 3, and 4. Note that id 1 (which is
144 // the decoration group id) also has all the decorations.
145 EXPECT_THAT(vstate_->id_decorations(1), Eq(expected_decorations));
146 EXPECT_THAT(vstate_->id_decorations(2), Eq(expected_decorations));
147 EXPECT_THAT(vstate_->id_decorations(3), Eq(expected_decorations));
148 EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations));
149 }
150
TEST_F(ValidateDecorations,WebGPUOpDecorationGroupBad)151 TEST_F(ValidateDecorations, WebGPUOpDecorationGroupBad) {
152 std::string spirv = R"(
153 OpCapability Shader
154 OpCapability VulkanMemoryModelKHR
155 OpExtension "SPV_KHR_vulkan_memory_model"
156 OpMemoryModel Logical VulkanKHR
157 OpDecorate %1 DescriptorSet 0
158 OpDecorate %1 NonWritable
159 OpDecorate %1 Restrict
160 %1 = OpDecorationGroup
161 OpGroupDecorate %1 %2 %3
162 OpGroupDecorate %1 %4
163 %float = OpTypeFloat 32
164 %_runtimearr_float = OpTypeRuntimeArray %float
165 %_struct_9 = OpTypeStruct %_runtimearr_float
166 %_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
167 %2 = OpVariable %_ptr_Uniform__struct_9 Uniform
168 %_struct_10 = OpTypeStruct %_runtimearr_float
169 %_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10
170 %3 = OpVariable %_ptr_Uniform__struct_10 Uniform
171 %_struct_11 = OpTypeStruct %_runtimearr_float
172 %_ptr_Uniform__struct_11 = OpTypePointer Uniform %_struct_11
173 %4 = OpVariable %_ptr_Uniform__struct_11 Uniform
174 )";
175 CompileSuccessfully(spirv);
176 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0));
177 EXPECT_THAT(getDiagnosticString(),
178 HasSubstr("OpDecorationGroup is not allowed in the WebGPU "
179 "execution environment.\n %1 = OpDecorationGroup\n"));
180 }
181
182 // For WebGPU, OpGroupDecorate does not have a test case, because it requires
183 // being preceded by OpDecorationGroup, which will cause a validation error.
184
185 // For WebGPU, OpGroupMemberDecorate does not have a test case, because it
186 // requires being preceded by OpDecorationGroup, which will cause a validation
187 // error.
188
TEST_F(ValidateDecorations,ValidateGroupMemberDecorateRegistration)189 TEST_F(ValidateDecorations, ValidateGroupMemberDecorateRegistration) {
190 std::string spirv = R"(
191 OpCapability Shader
192 OpCapability Linkage
193 OpMemoryModel Logical GLSL450
194 OpDecorate %1 Offset 3
195 %1 = OpDecorationGroup
196 OpGroupMemberDecorate %1 %_struct_1 3 %_struct_2 3 %_struct_3 3
197 %float = OpTypeFloat 32
198 %_runtimearr = OpTypeRuntimeArray %float
199 %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
200 %_struct_2 = OpTypeStruct %float %float %float %_runtimearr
201 %_struct_3 = OpTypeStruct %float %float %float %_runtimearr
202 )";
203 CompileSuccessfully(spirv);
204 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
205 // Decoration group has 1 decoration.
206 auto expected_decorations =
207 std::vector<Decoration>{Decoration(SpvDecorationOffset, {3}, 3)};
208
209 // Decoration group is applied to id 2, 3, and 4.
210 EXPECT_THAT(vstate_->id_decorations(2), Eq(expected_decorations));
211 EXPECT_THAT(vstate_->id_decorations(3), Eq(expected_decorations));
212 EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations));
213 }
214
TEST_F(ValidateDecorations,LinkageImportUsedForInitializedVariableBad)215 TEST_F(ValidateDecorations, LinkageImportUsedForInitializedVariableBad) {
216 std::string spirv = R"(
217 OpCapability Shader
218 OpCapability Linkage
219 OpMemoryModel Logical GLSL450
220 OpDecorate %target LinkageAttributes "link_ptr" Import
221 %float = OpTypeFloat 32
222 %_ptr_float = OpTypePointer Uniform %float
223 %zero = OpConstantNull %float
224 %target = OpVariable %_ptr_float Uniform %zero
225 )";
226 CompileSuccessfully(spirv);
227 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
228 EXPECT_THAT(getDiagnosticString(),
229 HasSubstr("A module-scope OpVariable with initialization value "
230 "cannot be marked with the Import Linkage Type."));
231 }
TEST_F(ValidateDecorations,LinkageExportUsedForInitializedVariableGood)232 TEST_F(ValidateDecorations, LinkageExportUsedForInitializedVariableGood) {
233 std::string spirv = R"(
234 OpCapability Shader
235 OpCapability Linkage
236 OpMemoryModel Logical GLSL450
237 OpDecorate %target LinkageAttributes "link_ptr" Export
238 %float = OpTypeFloat 32
239 %_ptr_float = OpTypePointer Uniform %float
240 %zero = OpConstantNull %float
241 %target = OpVariable %_ptr_float Uniform %zero
242 )";
243 CompileSuccessfully(spirv);
244 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
245 }
246
TEST_F(ValidateDecorations,StructAllMembersHaveBuiltInDecorationsGood)247 TEST_F(ValidateDecorations, StructAllMembersHaveBuiltInDecorationsGood) {
248 std::string spirv = R"(
249 OpCapability Shader
250 OpCapability Linkage
251 OpMemoryModel Logical GLSL450
252 OpMemberDecorate %_struct_1 0 BuiltIn Position
253 OpMemberDecorate %_struct_1 1 BuiltIn Position
254 OpMemberDecorate %_struct_1 2 BuiltIn Position
255 OpMemberDecorate %_struct_1 3 BuiltIn Position
256 %float = OpTypeFloat 32
257 %_runtimearr = OpTypeRuntimeArray %float
258 %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
259 )";
260 CompileSuccessfully(spirv);
261 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
262 }
263
TEST_F(ValidateDecorations,MixedBuiltInDecorationsBad)264 TEST_F(ValidateDecorations, MixedBuiltInDecorationsBad) {
265 std::string spirv = R"(
266 OpCapability Shader
267 OpCapability Linkage
268 OpMemoryModel Logical GLSL450
269 OpMemberDecorate %_struct_1 0 BuiltIn Position
270 OpMemberDecorate %_struct_1 1 BuiltIn Position
271 %float = OpTypeFloat 32
272 %_runtimearr = OpTypeRuntimeArray %float
273 %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
274 )";
275 CompileSuccessfully(spirv);
276 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
277 EXPECT_THAT(
278 getDiagnosticString(),
279 HasSubstr("When BuiltIn decoration is applied to a structure-type "
280 "member, all members of that structure type must also be "
281 "decorated with BuiltIn (No allowed mixing of built-in "
282 "variables and non-built-in variables within a single "
283 "structure). Structure id 1 does not meet this requirement."));
284 }
285
TEST_F(ValidateDecorations,StructContainsBuiltInStructBad)286 TEST_F(ValidateDecorations, StructContainsBuiltInStructBad) {
287 std::string spirv = R"(
288 OpCapability Shader
289 OpCapability Linkage
290 OpMemoryModel Logical GLSL450
291 OpMemberDecorate %_struct_1 0 BuiltIn Position
292 OpMemberDecorate %_struct_1 1 BuiltIn Position
293 OpMemberDecorate %_struct_1 2 BuiltIn Position
294 OpMemberDecorate %_struct_1 3 BuiltIn Position
295 %float = OpTypeFloat 32
296 %_runtimearr = OpTypeRuntimeArray %float
297 %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
298 %_struct_2 = OpTypeStruct %_struct_1
299 )";
300 CompileSuccessfully(spirv);
301 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
302 EXPECT_THAT(getDiagnosticString(),
303 HasSubstr("Structure <id> 1[%_struct_1] contains members with "
304 "BuiltIn decoration. Therefore this structure may not "
305 "be contained as a member of another structure type. "
306 "Structure <id> 4[%_struct_4] contains structure <id> "
307 "1[%_struct_1]."));
308 }
309
TEST_F(ValidateDecorations,StructContainsNonBuiltInStructGood)310 TEST_F(ValidateDecorations, StructContainsNonBuiltInStructGood) {
311 std::string spirv = R"(
312 OpCapability Shader
313 OpCapability Linkage
314 OpMemoryModel Logical GLSL450
315 %float = OpTypeFloat 32
316 %_struct_1 = OpTypeStruct %float
317 %_struct_2 = OpTypeStruct %_struct_1
318 )";
319 CompileSuccessfully(spirv);
320 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
321 }
322
TEST_F(ValidateDecorations,MultipleBuiltInObjectsConsumedByOpEntryPointBad)323 TEST_F(ValidateDecorations, MultipleBuiltInObjectsConsumedByOpEntryPointBad) {
324 std::string spirv = R"(
325 OpCapability Shader
326 OpCapability Geometry
327 OpMemoryModel Logical GLSL450
328 OpEntryPoint Geometry %main "main" %in_1 %in_2
329 OpExecutionMode %main InputPoints
330 OpExecutionMode %main OutputPoints
331 OpMemberDecorate %struct_1 0 BuiltIn InvocationId
332 OpMemberDecorate %struct_2 0 BuiltIn Position
333 %int = OpTypeInt 32 1
334 %void = OpTypeVoid
335 %func = OpTypeFunction %void
336 %float = OpTypeFloat 32
337 %struct_1 = OpTypeStruct %int
338 %struct_2 = OpTypeStruct %float
339 %ptr_builtin_1 = OpTypePointer Input %struct_1
340 %ptr_builtin_2 = OpTypePointer Input %struct_2
341 %in_1 = OpVariable %ptr_builtin_1 Input
342 %in_2 = OpVariable %ptr_builtin_2 Input
343 %main = OpFunction %void None %func
344 %5 = OpLabel
345 OpReturn
346 OpFunctionEnd
347 )";
348 CompileSuccessfully(spirv);
349 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
350 EXPECT_THAT(getDiagnosticString(),
351 HasSubstr("There must be at most one object per Storage Class "
352 "that can contain a structure type containing members "
353 "decorated with BuiltIn, consumed per entry-point."));
354 }
355
TEST_F(ValidateDecorations,OneBuiltInObjectPerStorageClassConsumedByOpEntryPointGood)356 TEST_F(ValidateDecorations,
357 OneBuiltInObjectPerStorageClassConsumedByOpEntryPointGood) {
358 std::string spirv = R"(
359 OpCapability Shader
360 OpCapability Geometry
361 OpMemoryModel Logical GLSL450
362 OpEntryPoint Geometry %main "main" %in_1 %out_1
363 OpExecutionMode %main InputPoints
364 OpExecutionMode %main OutputPoints
365 OpMemberDecorate %struct_1 0 BuiltIn InvocationId
366 OpMemberDecorate %struct_2 0 BuiltIn Position
367 %int = OpTypeInt 32 1
368 %void = OpTypeVoid
369 %func = OpTypeFunction %void
370 %float = OpTypeFloat 32
371 %struct_1 = OpTypeStruct %int
372 %struct_2 = OpTypeStruct %float
373 %ptr_builtin_1 = OpTypePointer Input %struct_1
374 %ptr_builtin_2 = OpTypePointer Output %struct_2
375 %in_1 = OpVariable %ptr_builtin_1 Input
376 %out_1 = OpVariable %ptr_builtin_2 Output
377 %main = OpFunction %void None %func
378 %5 = OpLabel
379 OpReturn
380 OpFunctionEnd
381 )";
382 CompileSuccessfully(spirv);
383 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
384 }
385
TEST_F(ValidateDecorations,NoBuiltInObjectsConsumedByOpEntryPointGood)386 TEST_F(ValidateDecorations, NoBuiltInObjectsConsumedByOpEntryPointGood) {
387 std::string spirv = R"(
388 OpCapability Shader
389 OpCapability Geometry
390 OpMemoryModel Logical GLSL450
391 OpEntryPoint Geometry %main "main" %in_1 %out_1
392 OpExecutionMode %main InputPoints
393 OpExecutionMode %main OutputPoints
394 %int = OpTypeInt 32 1
395 %void = OpTypeVoid
396 %func = OpTypeFunction %void
397 %float = OpTypeFloat 32
398 %struct_1 = OpTypeStruct %int
399 %struct_2 = OpTypeStruct %float
400 %ptr_builtin_1 = OpTypePointer Input %struct_1
401 %ptr_builtin_2 = OpTypePointer Output %struct_2
402 %in_1 = OpVariable %ptr_builtin_1 Input
403 %out_1 = OpVariable %ptr_builtin_2 Output
404 %main = OpFunction %void None %func
405 %5 = OpLabel
406 OpReturn
407 OpFunctionEnd
408 )";
409 CompileSuccessfully(spirv);
410 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
411 }
412
TEST_F(ValidateDecorations,EntryPointFunctionHasLinkageAttributeBad)413 TEST_F(ValidateDecorations, EntryPointFunctionHasLinkageAttributeBad) {
414 std::string spirv = R"(
415 OpCapability Shader
416 OpCapability Linkage
417 OpMemoryModel Logical GLSL450
418 OpEntryPoint GLCompute %main "main"
419 OpDecorate %main LinkageAttributes "import_main" Import
420 %1 = OpTypeVoid
421 %2 = OpTypeFunction %1
422 %main = OpFunction %1 None %2
423 %4 = OpLabel
424 OpReturn
425 OpFunctionEnd
426 )";
427 CompileSuccessfully(spirv.c_str());
428 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
429 EXPECT_THAT(
430 getDiagnosticString(),
431 HasSubstr("The LinkageAttributes Decoration (Linkage name: import_main) "
432 "cannot be applied to function id 1 because it is targeted by "
433 "an OpEntryPoint instruction."));
434 }
435
TEST_F(ValidateDecorations,FunctionDeclarationWithoutImportLinkageBad)436 TEST_F(ValidateDecorations, FunctionDeclarationWithoutImportLinkageBad) {
437 std::string spirv = R"(
438 OpCapability Shader
439 OpCapability Linkage
440 OpMemoryModel Logical GLSL450
441 %void = OpTypeVoid
442 %func = OpTypeFunction %void
443 %main = OpFunction %void None %func
444 OpFunctionEnd
445 )";
446 CompileSuccessfully(spirv);
447 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
448 EXPECT_THAT(
449 getDiagnosticString(),
450 HasSubstr("Function declaration (id 3) must have a LinkageAttributes "
451 "decoration with the Import Linkage type."));
452 }
453
TEST_F(ValidateDecorations,FunctionDeclarationWithImportLinkageGood)454 TEST_F(ValidateDecorations, FunctionDeclarationWithImportLinkageGood) {
455 std::string spirv = R"(
456 OpCapability Shader
457 OpCapability Linkage
458 OpMemoryModel Logical GLSL450
459 OpDecorate %main LinkageAttributes "link_fn" Import
460 %void = OpTypeVoid
461 %func = OpTypeFunction %void
462 %main = OpFunction %void None %func
463 OpFunctionEnd
464 )";
465 CompileSuccessfully(spirv);
466 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
467 }
468
TEST_F(ValidateDecorations,FunctionDeclarationWithExportLinkageBad)469 TEST_F(ValidateDecorations, FunctionDeclarationWithExportLinkageBad) {
470 std::string spirv = R"(
471 OpCapability Shader
472 OpCapability Linkage
473 OpMemoryModel Logical GLSL450
474 OpDecorate %main LinkageAttributes "link_fn" Export
475 %void = OpTypeVoid
476 %func = OpTypeFunction %void
477 %main = OpFunction %void None %func
478 OpFunctionEnd
479 )";
480 CompileSuccessfully(spirv);
481 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
482 EXPECT_THAT(
483 getDiagnosticString(),
484 HasSubstr("Function declaration (id 1) must have a LinkageAttributes "
485 "decoration with the Import Linkage type."));
486 }
487
TEST_F(ValidateDecorations,FunctionDefinitionWithImportLinkageBad)488 TEST_F(ValidateDecorations, FunctionDefinitionWithImportLinkageBad) {
489 std::string spirv = R"(
490 OpCapability Shader
491 OpCapability Linkage
492 OpMemoryModel Logical GLSL450
493 OpDecorate %main LinkageAttributes "link_fn" Import
494 %void = OpTypeVoid
495 %func = OpTypeFunction %void
496 %main = OpFunction %void None %func
497 %label = OpLabel
498 OpReturn
499 OpFunctionEnd
500 )";
501 CompileSuccessfully(spirv);
502 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
503 EXPECT_THAT(getDiagnosticString(),
504 HasSubstr("Function definition (id 1) may not be decorated with "
505 "Import Linkage type."));
506 }
507
TEST_F(ValidateDecorations,FunctionDefinitionWithoutImportLinkageGood)508 TEST_F(ValidateDecorations, FunctionDefinitionWithoutImportLinkageGood) {
509 std::string spirv = R"(
510 OpCapability Shader
511 OpCapability Linkage
512 OpMemoryModel Logical GLSL450
513 %void = OpTypeVoid
514 %func = OpTypeFunction %void
515 %main = OpFunction %void None %func
516 %label = OpLabel
517 OpReturn
518 OpFunctionEnd
519 )";
520 CompileSuccessfully(spirv);
521 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
522 }
523
TEST_F(ValidateDecorations,BuiltinVariablesGoodVulkan)524 TEST_F(ValidateDecorations, BuiltinVariablesGoodVulkan) {
525 const spv_target_env env = SPV_ENV_VULKAN_1_0;
526 std::string spirv = R"(
527 OpCapability Shader
528 OpMemoryModel Logical GLSL450
529 OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
530 OpExecutionMode %main OriginUpperLeft
531 OpSource HLSL 500
532 OpDecorate %gl_FragCoord BuiltIn FragCoord
533 OpDecorate %_entryPointOutput Location 0
534 %void = OpTypeVoid
535 %3 = OpTypeFunction %void
536 %float = OpTypeFloat 32
537 %v4float = OpTypeVector %float 4
538 %float_0 = OpConstant %float 0
539 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
540 %_ptr_Input_v4float = OpTypePointer Input %v4float
541 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
542 %_ptr_Output_v4float = OpTypePointer Output %v4float
543 %_entryPointOutput = OpVariable %_ptr_Output_v4float Output
544 %main = OpFunction %void None %3
545 %5 = OpLabel
546 OpStore %_entryPointOutput %14
547 OpReturn
548 OpFunctionEnd
549 )";
550
551 CompileSuccessfully(spirv, env);
552 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
553 }
554
TEST_F(ValidateDecorations,BuiltinVariablesWithLocationDecorationVulkan)555 TEST_F(ValidateDecorations, BuiltinVariablesWithLocationDecorationVulkan) {
556 const spv_target_env env = SPV_ENV_VULKAN_1_0;
557 std::string spirv = R"(
558 OpCapability Shader
559 OpMemoryModel Logical GLSL450
560 OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
561 OpExecutionMode %main OriginUpperLeft
562 OpSource HLSL 500
563 OpDecorate %gl_FragCoord BuiltIn FragCoord
564 OpDecorate %gl_FragCoord Location 0
565 OpDecorate %_entryPointOutput Location 0
566 %void = OpTypeVoid
567 %3 = OpTypeFunction %void
568 %float = OpTypeFloat 32
569 %v4float = OpTypeVector %float 4
570 %float_0 = OpConstant %float 0
571 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
572 %_ptr_Input_v4float = OpTypePointer Input %v4float
573 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
574 %_ptr_Output_v4float = OpTypePointer Output %v4float
575 %_entryPointOutput = OpVariable %_ptr_Output_v4float Output
576 %main = OpFunction %void None %3
577 %5 = OpLabel
578 OpStore %_entryPointOutput %14
579 OpReturn
580 OpFunctionEnd
581 )";
582
583 CompileSuccessfully(spirv, env);
584 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
585 EXPECT_THAT(getDiagnosticString(),
586 HasSubstr("A BuiltIn variable (id 2) cannot have any Location or "
587 "Component decorations"));
588 }
TEST_F(ValidateDecorations,BuiltinVariablesWithComponentDecorationVulkan)589 TEST_F(ValidateDecorations, BuiltinVariablesWithComponentDecorationVulkan) {
590 const spv_target_env env = SPV_ENV_VULKAN_1_0;
591 std::string spirv = R"(
592 OpCapability Shader
593 OpMemoryModel Logical GLSL450
594 OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
595 OpExecutionMode %main OriginUpperLeft
596 OpSource HLSL 500
597 OpDecorate %gl_FragCoord BuiltIn FragCoord
598 OpDecorate %gl_FragCoord Component 0
599 OpDecorate %_entryPointOutput Location 0
600 %void = OpTypeVoid
601 %3 = OpTypeFunction %void
602 %float = OpTypeFloat 32
603 %v4float = OpTypeVector %float 4
604 %float_0 = OpConstant %float 0
605 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
606 %_ptr_Input_v4float = OpTypePointer Input %v4float
607 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
608 %_ptr_Output_v4float = OpTypePointer Output %v4float
609 %_entryPointOutput = OpVariable %_ptr_Output_v4float Output
610 %main = OpFunction %void None %3
611 %5 = OpLabel
612 OpStore %_entryPointOutput %14
613 OpReturn
614 OpFunctionEnd
615 )";
616
617 CompileSuccessfully(spirv, env);
618 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
619 EXPECT_THAT(getDiagnosticString(),
620 HasSubstr("A BuiltIn variable (id 2) cannot have any Location or "
621 "Component decorations"));
622 }
623
624 // #version 440
625 // #extension GL_EXT_nonuniform_qualifier : enable
626 // layout(binding = 1) uniform sampler2D s2d[];
627 // layout(location = 0) in nonuniformEXT int i;
628 // void main()
629 // {
630 // vec4 v = texture(s2d[i], vec2(0.3));
631 // }
TEST_F(ValidateDecorations,RuntimeArrayOfDescriptorSetsIsAllowed)632 TEST_F(ValidateDecorations, RuntimeArrayOfDescriptorSetsIsAllowed) {
633 const spv_target_env env = SPV_ENV_VULKAN_1_0;
634 std::string spirv = R"(
635 OpCapability Shader
636 OpCapability ShaderNonUniformEXT
637 OpCapability RuntimeDescriptorArrayEXT
638 OpCapability SampledImageArrayNonUniformIndexingEXT
639 OpExtension "SPV_EXT_descriptor_indexing"
640 %1 = OpExtInstImport "GLSL.std.450"
641 OpMemoryModel Logical GLSL450
642 OpEntryPoint Vertex %main "main" %i
643 OpSource GLSL 440
644 OpSourceExtension "GL_EXT_nonuniform_qualifier"
645 OpName %main "main"
646 OpName %v "v"
647 OpName %s2d "s2d"
648 OpName %i "i"
649 OpDecorate %s2d DescriptorSet 0
650 OpDecorate %s2d Binding 1
651 OpDecorate %i Location 0
652 OpDecorate %i NonUniformEXT
653 OpDecorate %18 NonUniformEXT
654 OpDecorate %21 NonUniformEXT
655 %void = OpTypeVoid
656 %3 = OpTypeFunction %void
657 %float = OpTypeFloat 32
658 %v4float = OpTypeVector %float 4
659 %_ptr_Function_v4float = OpTypePointer Function %v4float
660 %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
661 %11 = OpTypeSampledImage %10
662 %_runtimearr_11 = OpTypeRuntimeArray %11
663 %_ptr_Uniform__runtimearr_11 = OpTypePointer Uniform %_runtimearr_11
664 %s2d = OpVariable %_ptr_Uniform__runtimearr_11 Uniform
665 %int = OpTypeInt 32 1
666 %_ptr_Input_int = OpTypePointer Input %int
667 %i = OpVariable %_ptr_Input_int Input
668 %_ptr_Uniform_11 = OpTypePointer Uniform %11
669 %v2float = OpTypeVector %float 2
670 %float_0_300000012 = OpConstant %float 0.300000012
671 %24 = OpConstantComposite %v2float %float_0_300000012 %float_0_300000012
672 %float_0 = OpConstant %float 0
673 %main = OpFunction %void None %3
674 %5 = OpLabel
675 %v = OpVariable %_ptr_Function_v4float Function
676 %18 = OpLoad %int %i
677 %20 = OpAccessChain %_ptr_Uniform_11 %s2d %18
678 %21 = OpLoad %11 %20
679 %26 = OpImageSampleExplicitLod %v4float %21 %24 Lod %float_0
680 OpStore %v %26
681 OpReturn
682 OpFunctionEnd
683 )";
684 CompileSuccessfully(spirv, env);
685 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
686 }
687
TEST_F(ValidateDecorations,BlockMissingOffsetBad)688 TEST_F(ValidateDecorations, BlockMissingOffsetBad) {
689 std::string spirv = R"(
690 OpCapability Shader
691 %1 = OpExtInstImport "GLSL.std.450"
692 OpMemoryModel Logical GLSL450
693 OpEntryPoint GLCompute %main "main"
694 OpExecutionMode %main LocalSize 1 1 1
695 OpSource GLSL 430
696 OpDecorate %Output Block
697 %void = OpTypeVoid
698 %3 = OpTypeFunction %void
699 %float = OpTypeFloat 32
700 %Output = OpTypeStruct %float
701 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
702 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
703 %main = OpFunction %void None %3
704 %5 = OpLabel
705 OpReturn
706 OpFunctionEnd
707 )";
708
709 CompileSuccessfully(spirv);
710 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
711 EXPECT_THAT(getDiagnosticString(),
712 HasSubstr("must be explicitly laid out with Offset decorations"));
713 }
714
TEST_F(ValidateDecorations,BufferBlockMissingOffsetBad)715 TEST_F(ValidateDecorations, BufferBlockMissingOffsetBad) {
716 std::string spirv = R"(
717 OpCapability Shader
718 %1 = OpExtInstImport "GLSL.std.450"
719 OpMemoryModel Logical GLSL450
720 OpEntryPoint GLCompute %main "main"
721 OpExecutionMode %main LocalSize 1 1 1
722 OpSource GLSL 430
723 OpDecorate %Output BufferBlock
724 %void = OpTypeVoid
725 %3 = OpTypeFunction %void
726 %float = OpTypeFloat 32
727 %Output = OpTypeStruct %float
728 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
729 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
730 %main = OpFunction %void None %3
731 %5 = OpLabel
732 OpReturn
733 OpFunctionEnd
734 )";
735
736 CompileSuccessfully(spirv);
737 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
738 EXPECT_THAT(getDiagnosticString(),
739 HasSubstr("must be explicitly laid out with Offset decorations"));
740 }
741
TEST_F(ValidateDecorations,BlockNestedStructMissingOffsetBad)742 TEST_F(ValidateDecorations, BlockNestedStructMissingOffsetBad) {
743 std::string spirv = R"(
744 OpCapability Shader
745 %1 = OpExtInstImport "GLSL.std.450"
746 OpMemoryModel Logical GLSL450
747 OpEntryPoint GLCompute %main "main"
748 OpExecutionMode %main LocalSize 1 1 1
749 OpSource GLSL 430
750 OpMemberDecorate %S 0 Offset 0
751 OpMemberDecorate %Output 0 Offset 0
752 OpMemberDecorate %Output 1 Offset 16
753 OpMemberDecorate %Output 2 Offset 32
754 OpDecorate %Output Block
755 %void = OpTypeVoid
756 %3 = OpTypeFunction %void
757 %float = OpTypeFloat 32
758 %v4float = OpTypeVector %float 4
759 %v3float = OpTypeVector %float 3
760 %int = OpTypeInt 32 1
761 %S = OpTypeStruct %v3float %int
762 %Output = OpTypeStruct %float %v4float %S
763 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
764 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
765 %main = OpFunction %void None %3
766 %5 = OpLabel
767 OpReturn
768 OpFunctionEnd
769 )";
770
771 CompileSuccessfully(spirv);
772 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
773 EXPECT_THAT(getDiagnosticString(),
774 HasSubstr("must be explicitly laid out with Offset decorations"));
775 }
776
TEST_F(ValidateDecorations,BufferBlockNestedStructMissingOffsetBad)777 TEST_F(ValidateDecorations, BufferBlockNestedStructMissingOffsetBad) {
778 std::string spirv = R"(
779 OpCapability Shader
780 %1 = OpExtInstImport "GLSL.std.450"
781 OpMemoryModel Logical GLSL450
782 OpEntryPoint GLCompute %main "main"
783 OpExecutionMode %main LocalSize 1 1 1
784 OpSource GLSL 430
785 OpMemberDecorate %S 0 Offset 0
786 OpMemberDecorate %Output 0 Offset 0
787 OpMemberDecorate %Output 1 Offset 16
788 OpMemberDecorate %Output 2 Offset 32
789 OpDecorate %Output BufferBlock
790 %void = OpTypeVoid
791 %3 = OpTypeFunction %void
792 %float = OpTypeFloat 32
793 %v4float = OpTypeVector %float 4
794 %v3float = OpTypeVector %float 3
795 %int = OpTypeInt 32 1
796 %S = OpTypeStruct %v3float %int
797 %Output = OpTypeStruct %float %v4float %S
798 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
799 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
800 %main = OpFunction %void None %3
801 %5 = OpLabel
802 OpReturn
803 OpFunctionEnd
804 )";
805
806 CompileSuccessfully(spirv);
807 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
808 EXPECT_THAT(getDiagnosticString(),
809 HasSubstr("must be explicitly laid out with Offset decorations"));
810 }
811
TEST_F(ValidateDecorations,BlockGLSLSharedBad)812 TEST_F(ValidateDecorations, BlockGLSLSharedBad) {
813 std::string spirv = R"(
814 OpCapability Shader
815 %1 = OpExtInstImport "GLSL.std.450"
816 OpMemoryModel Logical GLSL450
817 OpEntryPoint GLCompute %main "main"
818 OpExecutionMode %main LocalSize 1 1 1
819 OpSource GLSL 430
820 OpDecorate %Output Block
821 OpDecorate %Output GLSLShared
822 OpMemberDecorate %Output 0 Offset 0
823 %void = OpTypeVoid
824 %3 = OpTypeFunction %void
825 %float = OpTypeFloat 32
826 %Output = OpTypeStruct %float
827 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
828 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
829 %main = OpFunction %void None %3
830 %5 = OpLabel
831 OpReturn
832 OpFunctionEnd
833 )";
834
835 CompileSuccessfully(spirv);
836 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
837 EXPECT_THAT(getDiagnosticString(),
838 HasSubstr("must not use GLSLShared decoration"));
839 }
840
TEST_F(ValidateDecorations,BufferBlockGLSLSharedBad)841 TEST_F(ValidateDecorations, BufferBlockGLSLSharedBad) {
842 std::string spirv = R"(
843 OpCapability Shader
844 %1 = OpExtInstImport "GLSL.std.450"
845 OpMemoryModel Logical GLSL450
846 OpEntryPoint GLCompute %main "main"
847 OpExecutionMode %main LocalSize 1 1 1
848 OpSource GLSL 430
849 OpDecorate %Output BufferBlock
850 OpDecorate %Output GLSLShared
851 OpMemberDecorate %Output 0 Offset 0
852 %void = OpTypeVoid
853 %3 = OpTypeFunction %void
854 %float = OpTypeFloat 32
855 %Output = OpTypeStruct %float
856 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
857 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
858 %main = OpFunction %void None %3
859 %5 = OpLabel
860 OpReturn
861 OpFunctionEnd
862 )";
863
864 CompileSuccessfully(spirv);
865 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
866 EXPECT_THAT(getDiagnosticString(),
867 HasSubstr("must not use GLSLShared decoration"));
868 }
869
TEST_F(ValidateDecorations,BlockNestedStructGLSLSharedBad)870 TEST_F(ValidateDecorations, BlockNestedStructGLSLSharedBad) {
871 std::string spirv = R"(
872 OpCapability Shader
873 %1 = OpExtInstImport "GLSL.std.450"
874 OpMemoryModel Logical GLSL450
875 OpEntryPoint GLCompute %main "main"
876 OpExecutionMode %main LocalSize 1 1 1
877 OpSource GLSL 430
878 OpMemberDecorate %S 0 Offset 0
879 OpDecorate %S GLSLShared
880 OpMemberDecorate %Output 0 Offset 0
881 OpMemberDecorate %Output 1 Offset 16
882 OpMemberDecorate %Output 2 Offset 32
883 OpDecorate %Output Block
884 %void = OpTypeVoid
885 %3 = OpTypeFunction %void
886 %float = OpTypeFloat 32
887 %v4float = OpTypeVector %float 4
888 %int = OpTypeInt 32 1
889 %S = OpTypeStruct %int
890 %Output = OpTypeStruct %float %v4float %S
891 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
892 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
893 %main = OpFunction %void None %3
894 %5 = OpLabel
895 OpReturn
896 OpFunctionEnd
897 )";
898
899 CompileSuccessfully(spirv);
900 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
901 EXPECT_THAT(getDiagnosticString(),
902 HasSubstr("must not use GLSLShared decoration"));
903 }
904
TEST_F(ValidateDecorations,BufferBlockNestedStructGLSLSharedBad)905 TEST_F(ValidateDecorations, BufferBlockNestedStructGLSLSharedBad) {
906 std::string spirv = R"(
907 OpCapability Shader
908 %1 = OpExtInstImport "GLSL.std.450"
909 OpMemoryModel Logical GLSL450
910 OpEntryPoint GLCompute %main "main"
911 OpExecutionMode %main LocalSize 1 1 1
912 OpSource GLSL 430
913 OpMemberDecorate %S 0 Offset 0
914 OpDecorate %S GLSLShared
915 OpMemberDecorate %Output 0 Offset 0
916 OpMemberDecorate %Output 1 Offset 16
917 OpMemberDecorate %Output 2 Offset 32
918 OpDecorate %Output BufferBlock
919 %void = OpTypeVoid
920 %3 = OpTypeFunction %void
921 %float = OpTypeFloat 32
922 %v4float = OpTypeVector %float 4
923 %int = OpTypeInt 32 1
924 %S = OpTypeStruct %int
925 %Output = OpTypeStruct %float %v4float %S
926 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
927 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
928 %main = OpFunction %void None %3
929 %5 = OpLabel
930 OpReturn
931 OpFunctionEnd
932 )";
933
934 CompileSuccessfully(spirv);
935 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
936 EXPECT_THAT(getDiagnosticString(),
937 HasSubstr("must not use GLSLShared decoration"));
938 }
939
TEST_F(ValidateDecorations,BlockGLSLPackedBad)940 TEST_F(ValidateDecorations, BlockGLSLPackedBad) {
941 std::string spirv = R"(
942 OpCapability Shader
943 %1 = OpExtInstImport "GLSL.std.450"
944 OpMemoryModel Logical GLSL450
945 OpEntryPoint GLCompute %main "main"
946 OpExecutionMode %main LocalSize 1 1 1
947 OpSource GLSL 430
948 OpDecorate %Output Block
949 OpDecorate %Output GLSLPacked
950 OpMemberDecorate %Output 0 Offset 0
951 %void = OpTypeVoid
952 %3 = OpTypeFunction %void
953 %float = OpTypeFloat 32
954 %Output = OpTypeStruct %float
955 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
956 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
957 %main = OpFunction %void None %3
958 %5 = OpLabel
959 OpReturn
960 OpFunctionEnd
961 )";
962
963 CompileSuccessfully(spirv);
964 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
965 EXPECT_THAT(getDiagnosticString(),
966 HasSubstr("must not use GLSLPacked decoration"));
967 }
968
TEST_F(ValidateDecorations,BufferBlockGLSLPackedBad)969 TEST_F(ValidateDecorations, BufferBlockGLSLPackedBad) {
970 std::string spirv = R"(
971 OpCapability Shader
972 %1 = OpExtInstImport "GLSL.std.450"
973 OpMemoryModel Logical GLSL450
974 OpEntryPoint GLCompute %main "main"
975 OpExecutionMode %main LocalSize 1 1 1
976 OpSource GLSL 430
977 OpDecorate %Output BufferBlock
978 OpDecorate %Output GLSLPacked
979 OpMemberDecorate %Output 0 Offset 0
980 %void = OpTypeVoid
981 %3 = OpTypeFunction %void
982 %float = OpTypeFloat 32
983 %Output = OpTypeStruct %float
984 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
985 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
986 %main = OpFunction %void None %3
987 %5 = OpLabel
988 OpReturn
989 OpFunctionEnd
990 )";
991
992 CompileSuccessfully(spirv);
993 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
994 EXPECT_THAT(getDiagnosticString(),
995 HasSubstr("must not use GLSLPacked decoration"));
996 }
997
TEST_F(ValidateDecorations,BlockNestedStructGLSLPackedBad)998 TEST_F(ValidateDecorations, BlockNestedStructGLSLPackedBad) {
999 std::string spirv = R"(
1000 OpCapability Shader
1001 %1 = OpExtInstImport "GLSL.std.450"
1002 OpMemoryModel Logical GLSL450
1003 OpEntryPoint GLCompute %main "main"
1004 OpExecutionMode %main LocalSize 1 1 1
1005 OpSource GLSL 430
1006 OpMemberDecorate %S 0 Offset 0
1007 OpDecorate %S GLSLPacked
1008 OpMemberDecorate %Output 0 Offset 0
1009 OpMemberDecorate %Output 1 Offset 16
1010 OpMemberDecorate %Output 2 Offset 32
1011 OpDecorate %Output Block
1012 %void = OpTypeVoid
1013 %3 = OpTypeFunction %void
1014 %float = OpTypeFloat 32
1015 %v4float = OpTypeVector %float 4
1016 %int = OpTypeInt 32 1
1017 %S = OpTypeStruct %int
1018 %Output = OpTypeStruct %float %v4float %S
1019 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1020 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1021 %main = OpFunction %void None %3
1022 %5 = OpLabel
1023 OpReturn
1024 OpFunctionEnd
1025 )";
1026
1027 CompileSuccessfully(spirv);
1028 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1029 EXPECT_THAT(getDiagnosticString(),
1030 HasSubstr("must not use GLSLPacked decoration"));
1031 }
1032
TEST_F(ValidateDecorations,BufferBlockNestedStructGLSLPackedBad)1033 TEST_F(ValidateDecorations, BufferBlockNestedStructGLSLPackedBad) {
1034 std::string spirv = R"(
1035 OpCapability Shader
1036 %1 = OpExtInstImport "GLSL.std.450"
1037 OpMemoryModel Logical GLSL450
1038 OpEntryPoint GLCompute %main "main"
1039 OpExecutionMode %main LocalSize 1 1 1
1040 OpSource GLSL 430
1041 OpMemberDecorate %S 0 Offset 0
1042 OpDecorate %S GLSLPacked
1043 OpMemberDecorate %Output 0 Offset 0
1044 OpMemberDecorate %Output 1 Offset 16
1045 OpMemberDecorate %Output 2 Offset 32
1046 OpDecorate %Output BufferBlock
1047 %void = OpTypeVoid
1048 %3 = OpTypeFunction %void
1049 %float = OpTypeFloat 32
1050 %v4float = OpTypeVector %float 4
1051 %int = OpTypeInt 32 1
1052 %S = OpTypeStruct %int
1053 %Output = OpTypeStruct %float %v4float %S
1054 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1055 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1056 %main = OpFunction %void None %3
1057 %5 = OpLabel
1058 OpReturn
1059 OpFunctionEnd
1060 )";
1061
1062 CompileSuccessfully(spirv);
1063 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1064 EXPECT_THAT(getDiagnosticString(),
1065 HasSubstr("must not use GLSLPacked decoration"));
1066 }
1067
TEST_F(ValidateDecorations,BlockMissingArrayStrideBad)1068 TEST_F(ValidateDecorations, BlockMissingArrayStrideBad) {
1069 std::string spirv = R"(
1070 OpCapability Shader
1071 %1 = OpExtInstImport "GLSL.std.450"
1072 OpMemoryModel Logical GLSL450
1073 OpEntryPoint GLCompute %main "main"
1074 OpExecutionMode %main LocalSize 1 1 1
1075 OpSource GLSL 430
1076 OpDecorate %Output Block
1077 OpMemberDecorate %Output 0 Offset 0
1078 %void = OpTypeVoid
1079 %3 = OpTypeFunction %void
1080 %float = OpTypeFloat 32
1081 %int = OpTypeInt 32 1
1082 %int_3 = OpConstant %int 3
1083 %array = OpTypeArray %float %int_3
1084 %Output = OpTypeStruct %array
1085 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1086 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1087 %main = OpFunction %void None %3
1088 %5 = OpLabel
1089 OpReturn
1090 OpFunctionEnd
1091 )";
1092
1093 CompileSuccessfully(spirv);
1094 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1095 EXPECT_THAT(
1096 getDiagnosticString(),
1097 HasSubstr("must be explicitly laid out with ArrayStride decorations"));
1098 }
1099
TEST_F(ValidateDecorations,BufferBlockMissingArrayStrideBad)1100 TEST_F(ValidateDecorations, BufferBlockMissingArrayStrideBad) {
1101 std::string spirv = R"(
1102 OpCapability Shader
1103 %1 = OpExtInstImport "GLSL.std.450"
1104 OpMemoryModel Logical GLSL450
1105 OpEntryPoint GLCompute %main "main"
1106 OpExecutionMode %main LocalSize 1 1 1
1107 OpSource GLSL 430
1108 OpDecorate %Output BufferBlock
1109 OpMemberDecorate %Output 0 Offset 0
1110 %void = OpTypeVoid
1111 %3 = OpTypeFunction %void
1112 %float = OpTypeFloat 32
1113 %int = OpTypeInt 32 1
1114 %int_3 = OpConstant %int 3
1115 %array = OpTypeArray %float %int_3
1116 %Output = OpTypeStruct %array
1117 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1118 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1119 %main = OpFunction %void None %3
1120 %5 = OpLabel
1121 OpReturn
1122 OpFunctionEnd
1123 )";
1124
1125 CompileSuccessfully(spirv);
1126 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1127 EXPECT_THAT(
1128 getDiagnosticString(),
1129 HasSubstr("must be explicitly laid out with ArrayStride decorations"));
1130 }
1131
TEST_F(ValidateDecorations,BlockNestedStructMissingArrayStrideBad)1132 TEST_F(ValidateDecorations, BlockNestedStructMissingArrayStrideBad) {
1133 std::string spirv = R"(
1134 OpCapability Shader
1135 %1 = OpExtInstImport "GLSL.std.450"
1136 OpMemoryModel Logical GLSL450
1137 OpEntryPoint GLCompute %main "main"
1138 OpExecutionMode %main LocalSize 1 1 1
1139 OpSource GLSL 430
1140 OpMemberDecorate %S 0 Offset 0
1141 OpMemberDecorate %Output 0 Offset 0
1142 OpMemberDecorate %Output 1 Offset 16
1143 OpMemberDecorate %Output 2 Offset 32
1144 OpDecorate %Output Block
1145 %void = OpTypeVoid
1146 %3 = OpTypeFunction %void
1147 %float = OpTypeFloat 32
1148 %v4float = OpTypeVector %float 4
1149 %int = OpTypeInt 32 1
1150 %int_3 = OpConstant %int 3
1151 %array = OpTypeArray %float %int_3
1152 %S = OpTypeStruct %array
1153 %Output = OpTypeStruct %float %v4float %S
1154 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1155 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1156 %main = OpFunction %void None %3
1157 %5 = OpLabel
1158 OpReturn
1159 OpFunctionEnd
1160 )";
1161
1162 CompileSuccessfully(spirv);
1163 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1164 EXPECT_THAT(
1165 getDiagnosticString(),
1166 HasSubstr("must be explicitly laid out with ArrayStride decorations"));
1167 }
1168
TEST_F(ValidateDecorations,BufferBlockNestedStructMissingArrayStrideBad)1169 TEST_F(ValidateDecorations, BufferBlockNestedStructMissingArrayStrideBad) {
1170 std::string spirv = R"(
1171 OpCapability Shader
1172 %1 = OpExtInstImport "GLSL.std.450"
1173 OpMemoryModel Logical GLSL450
1174 OpEntryPoint GLCompute %main "main"
1175 OpExecutionMode %main LocalSize 1 1 1
1176 OpSource GLSL 430
1177 OpMemberDecorate %S 0 Offset 0
1178 OpMemberDecorate %Output 0 Offset 0
1179 OpMemberDecorate %Output 1 Offset 16
1180 OpMemberDecorate %Output 2 Offset 32
1181 OpDecorate %Output BufferBlock
1182 %void = OpTypeVoid
1183 %3 = OpTypeFunction %void
1184 %float = OpTypeFloat 32
1185 %v4float = OpTypeVector %float 4
1186 %int = OpTypeInt 32 1
1187 %int_3 = OpConstant %int 3
1188 %array = OpTypeArray %float %int_3
1189 %S = OpTypeStruct %array
1190 %Output = OpTypeStruct %float %v4float %S
1191 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1192 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1193 %main = OpFunction %void None %3
1194 %5 = OpLabel
1195 OpReturn
1196 OpFunctionEnd
1197 )";
1198
1199 CompileSuccessfully(spirv);
1200 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1201 EXPECT_THAT(
1202 getDiagnosticString(),
1203 HasSubstr("must be explicitly laid out with ArrayStride decorations"));
1204 }
1205
TEST_F(ValidateDecorations,BlockMissingMatrixStrideBad)1206 TEST_F(ValidateDecorations, BlockMissingMatrixStrideBad) {
1207 std::string spirv = R"(
1208 OpCapability Shader
1209 %1 = OpExtInstImport "GLSL.std.450"
1210 OpMemoryModel Logical GLSL450
1211 OpEntryPoint GLCompute %main "main"
1212 OpExecutionMode %main LocalSize 1 1 1
1213 OpSource GLSL 430
1214 OpDecorate %Output Block
1215 OpMemberDecorate %Output 0 Offset 0
1216 %void = OpTypeVoid
1217 %3 = OpTypeFunction %void
1218 %float = OpTypeFloat 32
1219 %v3float = OpTypeVector %float 3
1220 %matrix = OpTypeMatrix %v3float 4
1221 %Output = OpTypeStruct %matrix
1222 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1223 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1224 %main = OpFunction %void None %3
1225 %5 = OpLabel
1226 OpReturn
1227 OpFunctionEnd
1228 )";
1229
1230 CompileSuccessfully(spirv);
1231 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1232 EXPECT_THAT(
1233 getDiagnosticString(),
1234 HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1235 }
1236
TEST_F(ValidateDecorations,BufferBlockMissingMatrixStrideBad)1237 TEST_F(ValidateDecorations, BufferBlockMissingMatrixStrideBad) {
1238 std::string spirv = R"(
1239 OpCapability Shader
1240 %1 = OpExtInstImport "GLSL.std.450"
1241 OpMemoryModel Logical GLSL450
1242 OpEntryPoint GLCompute %main "main"
1243 OpExecutionMode %main LocalSize 1 1 1
1244 OpSource GLSL 430
1245 OpDecorate %Output BufferBlock
1246 OpMemberDecorate %Output 0 Offset 0
1247 %void = OpTypeVoid
1248 %3 = OpTypeFunction %void
1249 %float = OpTypeFloat 32
1250 %v3float = OpTypeVector %float 3
1251 %matrix = OpTypeMatrix %v3float 4
1252 %Output = OpTypeStruct %matrix
1253 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1254 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1255 %main = OpFunction %void None %3
1256 %5 = OpLabel
1257 OpReturn
1258 OpFunctionEnd
1259 )";
1260
1261 CompileSuccessfully(spirv);
1262 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1263 EXPECT_THAT(
1264 getDiagnosticString(),
1265 HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1266 }
1267
TEST_F(ValidateDecorations,BlockMissingMatrixStrideArrayBad)1268 TEST_F(ValidateDecorations, BlockMissingMatrixStrideArrayBad) {
1269 std::string spirv = R"(
1270 OpCapability Shader
1271 %1 = OpExtInstImport "GLSL.std.450"
1272 OpMemoryModel Logical GLSL450
1273 OpEntryPoint GLCompute %main "main"
1274 OpExecutionMode %main LocalSize 1 1 1
1275 OpSource GLSL 430
1276 OpDecorate %Output Block
1277 OpMemberDecorate %Output 0 Offset 0
1278 %void = OpTypeVoid
1279 %3 = OpTypeFunction %void
1280 %float = OpTypeFloat 32
1281 %v3float = OpTypeVector %float 3
1282 %matrix = OpTypeMatrix %v3float 4
1283 %int = OpTypeInt 32 1
1284 %int_3 = OpConstant %int 3
1285 %array = OpTypeArray %matrix %int_3
1286 %Output = OpTypeStruct %matrix
1287 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1288 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1289 %main = OpFunction %void None %3
1290 %5 = OpLabel
1291 OpReturn
1292 OpFunctionEnd
1293 )";
1294
1295 CompileSuccessfully(spirv);
1296 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1297 EXPECT_THAT(
1298 getDiagnosticString(),
1299 HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1300 }
1301
TEST_F(ValidateDecorations,BufferBlockMissingMatrixStrideArrayBad)1302 TEST_F(ValidateDecorations, BufferBlockMissingMatrixStrideArrayBad) {
1303 std::string spirv = R"(
1304 OpCapability Shader
1305 %1 = OpExtInstImport "GLSL.std.450"
1306 OpMemoryModel Logical GLSL450
1307 OpEntryPoint GLCompute %main "main"
1308 OpExecutionMode %main LocalSize 1 1 1
1309 OpSource GLSL 430
1310 OpDecorate %Output BufferBlock
1311 OpMemberDecorate %Output 0 Offset 0
1312 %void = OpTypeVoid
1313 %3 = OpTypeFunction %void
1314 %float = OpTypeFloat 32
1315 %v3float = OpTypeVector %float 3
1316 %matrix = OpTypeMatrix %v3float 4
1317 %int = OpTypeInt 32 1
1318 %int_3 = OpConstant %int 3
1319 %array = OpTypeArray %matrix %int_3
1320 %Output = OpTypeStruct %matrix
1321 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1322 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1323 %main = OpFunction %void None %3
1324 %5 = OpLabel
1325 OpReturn
1326 OpFunctionEnd
1327 )";
1328
1329 CompileSuccessfully(spirv);
1330 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1331 EXPECT_THAT(
1332 getDiagnosticString(),
1333 HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1334 }
1335
TEST_F(ValidateDecorations,BlockNestedStructMissingMatrixStrideBad)1336 TEST_F(ValidateDecorations, BlockNestedStructMissingMatrixStrideBad) {
1337 std::string spirv = R"(
1338 OpCapability Shader
1339 %1 = OpExtInstImport "GLSL.std.450"
1340 OpMemoryModel Logical GLSL450
1341 OpEntryPoint GLCompute %main "main"
1342 OpExecutionMode %main LocalSize 1 1 1
1343 OpSource GLSL 430
1344 OpMemberDecorate %S 0 Offset 0
1345 OpMemberDecorate %Output 0 Offset 0
1346 OpMemberDecorate %Output 1 Offset 16
1347 OpMemberDecorate %Output 2 Offset 32
1348 OpDecorate %Output Block
1349 %void = OpTypeVoid
1350 %3 = OpTypeFunction %void
1351 %float = OpTypeFloat 32
1352 %v3float = OpTypeVector %float 3
1353 %v4float = OpTypeVector %float 4
1354 %matrix = OpTypeMatrix %v3float 4
1355 %S = OpTypeStruct %matrix
1356 %Output = OpTypeStruct %float %v4float %S
1357 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1358 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1359 %main = OpFunction %void None %3
1360 %5 = OpLabel
1361 OpReturn
1362 OpFunctionEnd
1363 )";
1364
1365 CompileSuccessfully(spirv);
1366 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1367 EXPECT_THAT(
1368 getDiagnosticString(),
1369 HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1370 }
1371
TEST_F(ValidateDecorations,BufferBlockNestedStructMissingMatrixStrideBad)1372 TEST_F(ValidateDecorations, BufferBlockNestedStructMissingMatrixStrideBad) {
1373 std::string spirv = R"(
1374 OpCapability Shader
1375 %1 = OpExtInstImport "GLSL.std.450"
1376 OpMemoryModel Logical GLSL450
1377 OpEntryPoint GLCompute %main "main"
1378 OpExecutionMode %main LocalSize 1 1 1
1379 OpSource GLSL 430
1380 OpMemberDecorate %S 0 Offset 0
1381 OpMemberDecorate %Output 0 Offset 0
1382 OpMemberDecorate %Output 1 Offset 16
1383 OpMemberDecorate %Output 2 Offset 32
1384 OpDecorate %Output BufferBlock
1385 %void = OpTypeVoid
1386 %3 = OpTypeFunction %void
1387 %float = OpTypeFloat 32
1388 %v3float = OpTypeVector %float 3
1389 %v4float = OpTypeVector %float 4
1390 %matrix = OpTypeMatrix %v3float 4
1391 %S = OpTypeStruct %matrix
1392 %Output = OpTypeStruct %float %v4float %S
1393 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1394 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1395 %main = OpFunction %void None %3
1396 %5 = OpLabel
1397 OpReturn
1398 OpFunctionEnd
1399 )";
1400
1401 CompileSuccessfully(spirv);
1402 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1403 EXPECT_THAT(
1404 getDiagnosticString(),
1405 HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1406 }
1407
TEST_F(ValidateDecorations,BlockStandardUniformBufferLayout)1408 TEST_F(ValidateDecorations, BlockStandardUniformBufferLayout) {
1409 std::string spirv = R"(
1410 OpCapability Shader
1411 %1 = OpExtInstImport "GLSL.std.450"
1412 OpMemoryModel Logical GLSL450
1413 OpEntryPoint GLCompute %main "main"
1414 OpExecutionMode %main LocalSize 1 1 1
1415 OpSource GLSL 430
1416 OpMemberDecorate %F 0 Offset 0
1417 OpMemberDecorate %F 1 Offset 8
1418 OpDecorate %_arr_float_uint_2 ArrayStride 16
1419 OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
1420 OpMemberDecorate %O 0 Offset 0
1421 OpMemberDecorate %O 1 Offset 16
1422 OpMemberDecorate %O 2 Offset 32
1423 OpMemberDecorate %O 3 Offset 64
1424 OpMemberDecorate %O 4 ColMajor
1425 OpMemberDecorate %O 4 Offset 80
1426 OpMemberDecorate %O 4 MatrixStride 16
1427 OpDecorate %_arr_O_uint_2 ArrayStride 176
1428 OpMemberDecorate %Output 0 Offset 0
1429 OpMemberDecorate %Output 1 Offset 8
1430 OpMemberDecorate %Output 2 Offset 16
1431 OpMemberDecorate %Output 3 Offset 32
1432 OpMemberDecorate %Output 4 Offset 48
1433 OpMemberDecorate %Output 5 Offset 64
1434 OpMemberDecorate %Output 6 ColMajor
1435 OpMemberDecorate %Output 6 Offset 96
1436 OpMemberDecorate %Output 6 MatrixStride 16
1437 OpMemberDecorate %Output 7 Offset 128
1438 OpDecorate %Output Block
1439 %void = OpTypeVoid
1440 %3 = OpTypeFunction %void
1441 %float = OpTypeFloat 32
1442 %v2float = OpTypeVector %float 2
1443 %v3float = OpTypeVector %float 3
1444 %int = OpTypeInt 32 1
1445 %uint = OpTypeInt 32 0
1446 %v2uint = OpTypeVector %uint 2
1447 %F = OpTypeStruct %int %v2uint
1448 %uint_2 = OpConstant %uint 2
1449 %_arr_float_uint_2 = OpTypeArray %float %uint_2
1450 %mat2v3float = OpTypeMatrix %v3float 2
1451 %v3uint = OpTypeVector %uint 3
1452 %mat3v3float = OpTypeMatrix %v3float 3
1453 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
1454 %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
1455 %_arr_O_uint_2 = OpTypeArray %O %uint_2
1456 %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
1457 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1458 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1459 %main = OpFunction %void None %3
1460 %5 = OpLabel
1461 OpReturn
1462 OpFunctionEnd
1463 )";
1464
1465 CompileSuccessfully(spirv);
1466 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
1467 }
1468
TEST_F(ValidateDecorations,BlockLayoutPermitsTightVec3ScalarPackingGood)1469 TEST_F(ValidateDecorations, BlockLayoutPermitsTightVec3ScalarPackingGood) {
1470 // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
1471 std::string spirv = R"(
1472 OpCapability Shader
1473 OpMemoryModel Logical GLSL450
1474 OpEntryPoint Vertex %main "main"
1475 OpSource GLSL 450
1476 OpMemberDecorate %S 0 Offset 0
1477 OpMemberDecorate %S 1 Offset 12
1478 OpDecorate %S Block
1479 OpDecorate %B DescriptorSet 0
1480 OpDecorate %B Binding 0
1481 %void = OpTypeVoid
1482 %3 = OpTypeFunction %void
1483 %float = OpTypeFloat 32
1484 %v3float = OpTypeVector %float 3
1485 %S = OpTypeStruct %v3float %float
1486 %_ptr_Uniform_S = OpTypePointer Uniform %S
1487 %B = OpVariable %_ptr_Uniform_S Uniform
1488 %main = OpFunction %void None %3
1489 %5 = OpLabel
1490 OpReturn
1491 OpFunctionEnd
1492 )";
1493
1494 CompileSuccessfully(spirv);
1495 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
1496 << getDiagnosticString();
1497 }
1498
TEST_F(ValidateDecorations,BlockLayoutForbidsTightScalarVec3PackingBad)1499 TEST_F(ValidateDecorations, BlockLayoutForbidsTightScalarVec3PackingBad) {
1500 // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
1501 std::string spirv = R"(
1502 OpCapability Shader
1503 OpMemoryModel Logical GLSL450
1504 OpEntryPoint Vertex %main "main"
1505 OpSource GLSL 450
1506 OpMemberDecorate %S 0 Offset 0
1507 OpMemberDecorate %S 1 Offset 4
1508 OpDecorate %S Block
1509 OpDecorate %B DescriptorSet 0
1510 OpDecorate %B Binding 0
1511 %void = OpTypeVoid
1512 %3 = OpTypeFunction %void
1513 %float = OpTypeFloat 32
1514 %v3float = OpTypeVector %float 3
1515 %S = OpTypeStruct %float %v3float
1516 %_ptr_Uniform_S = OpTypePointer Uniform %S
1517 %B = OpVariable %_ptr_Uniform_S Uniform
1518 %main = OpFunction %void None %3
1519 %5 = OpLabel
1520 OpReturn
1521 OpFunctionEnd
1522 )";
1523
1524 CompileSuccessfully(spirv);
1525 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1526 EXPECT_THAT(
1527 getDiagnosticString(),
1528 HasSubstr("Structure id 2 decorated as Block for variable in Uniform "
1529 "storage class must follow standard uniform buffer layout "
1530 "rules: member 1 at offset 4 is not aligned to 16"));
1531 }
1532
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingWithRelaxedLayoutGood)1533 TEST_F(ValidateDecorations,
1534 BlockLayoutPermitsTightScalarVec3PackingWithRelaxedLayoutGood) {
1535 // Same as previous test, but with explicit option to relax block layout.
1536 std::string spirv = R"(
1537 OpCapability Shader
1538 OpMemoryModel Logical GLSL450
1539 OpEntryPoint Vertex %main "main"
1540 OpSource GLSL 450
1541 OpMemberDecorate %S 0 Offset 0
1542 OpMemberDecorate %S 1 Offset 4
1543 OpDecorate %S Block
1544 OpDecorate %B DescriptorSet 0
1545 OpDecorate %B Binding 0
1546 %void = OpTypeVoid
1547 %3 = OpTypeFunction %void
1548 %float = OpTypeFloat 32
1549 %v3float = OpTypeVector %float 3
1550 %S = OpTypeStruct %float %v3float
1551 %_ptr_Uniform_S = OpTypePointer Uniform %S
1552 %B = OpVariable %_ptr_Uniform_S Uniform
1553 %main = OpFunction %void None %3
1554 %5 = OpLabel
1555 OpReturn
1556 OpFunctionEnd
1557 )";
1558
1559 CompileSuccessfully(spirv);
1560 spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
1561 EXPECT_EQ(SPV_SUCCESS,
1562 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1563 EXPECT_THAT(getDiagnosticString(), Eq(""));
1564 }
1565
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingBadOffsetWithRelaxedLayoutBad)1566 TEST_F(ValidateDecorations,
1567 BlockLayoutPermitsTightScalarVec3PackingBadOffsetWithRelaxedLayoutBad) {
1568 // Same as previous test, but with the vector not aligned to its scalar
1569 // element. Use offset 5 instead of a multiple of 4.
1570 std::string spirv = R"(
1571 OpCapability Shader
1572 OpMemoryModel Logical GLSL450
1573 OpEntryPoint Vertex %main "main"
1574 OpSource GLSL 450
1575 OpMemberDecorate %S 0 Offset 0
1576 OpMemberDecorate %S 1 Offset 5
1577 OpDecorate %S Block
1578 OpDecorate %B DescriptorSet 0
1579 OpDecorate %B Binding 0
1580 %void = OpTypeVoid
1581 %3 = OpTypeFunction %void
1582 %float = OpTypeFloat 32
1583 %v3float = OpTypeVector %float 3
1584 %S = OpTypeStruct %float %v3float
1585 %_ptr_Uniform_S = OpTypePointer Uniform %S
1586 %B = OpVariable %_ptr_Uniform_S Uniform
1587 %main = OpFunction %void None %3
1588 %5 = OpLabel
1589 OpReturn
1590 OpFunctionEnd
1591 )";
1592
1593 CompileSuccessfully(spirv);
1594 spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
1595 EXPECT_EQ(SPV_ERROR_INVALID_ID,
1596 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1597 EXPECT_THAT(
1598 getDiagnosticString(),
1599 HasSubstr(
1600 "Structure id 2 decorated as Block for variable in Uniform storage "
1601 "class must follow relaxed uniform buffer layout rules: member 1 at "
1602 "offset 5 is not aligned to scalar element size 4"));
1603 }
1604
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingWithVulkan1_1Good)1605 TEST_F(ValidateDecorations,
1606 BlockLayoutPermitsTightScalarVec3PackingWithVulkan1_1Good) {
1607 // Same as previous test, but with Vulkan 1.1. Vulkan 1.1 included
1608 // VK_KHR_relaxed_block_layout in core.
1609 std::string spirv = R"(
1610 OpCapability Shader
1611 OpMemoryModel Logical GLSL450
1612 OpEntryPoint Vertex %main "main"
1613 OpSource GLSL 450
1614 OpMemberDecorate %S 0 Offset 0
1615 OpMemberDecorate %S 1 Offset 4
1616 OpDecorate %S Block
1617 OpDecorate %B DescriptorSet 0
1618 OpDecorate %B Binding 0
1619 %void = OpTypeVoid
1620 %3 = OpTypeFunction %void
1621 %float = OpTypeFloat 32
1622 %v3float = OpTypeVector %float 3
1623 %S = OpTypeStruct %float %v3float
1624 %_ptr_Uniform_S = OpTypePointer Uniform %S
1625 %B = OpVariable %_ptr_Uniform_S Uniform
1626 %main = OpFunction %void None %3
1627 %5 = OpLabel
1628 OpReturn
1629 OpFunctionEnd
1630 )";
1631
1632 CompileSuccessfully(spirv);
1633 EXPECT_EQ(SPV_SUCCESS,
1634 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
1635 EXPECT_THAT(getDiagnosticString(), Eq(""));
1636 }
1637
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingWithScalarLayoutGood)1638 TEST_F(ValidateDecorations,
1639 BlockLayoutPermitsTightScalarVec3PackingWithScalarLayoutGood) {
1640 // Same as previous test, but with scalar block layout.
1641 std::string spirv = R"(
1642 OpCapability Shader
1643 OpMemoryModel Logical GLSL450
1644 OpEntryPoint Vertex %main "main"
1645 OpSource GLSL 450
1646 OpMemberDecorate %S 0 Offset 0
1647 OpMemberDecorate %S 1 Offset 4
1648 OpDecorate %S Block
1649 OpDecorate %B DescriptorSet 0
1650 OpDecorate %B Binding 0
1651 %void = OpTypeVoid
1652 %3 = OpTypeFunction %void
1653 %float = OpTypeFloat 32
1654 %v3float = OpTypeVector %float 3
1655 %S = OpTypeStruct %float %v3float
1656 %_ptr_Uniform_S = OpTypePointer Uniform %S
1657 %B = OpVariable %_ptr_Uniform_S Uniform
1658 %main = OpFunction %void None %3
1659 %5 = OpLabel
1660 OpReturn
1661 OpFunctionEnd
1662 )";
1663
1664 CompileSuccessfully(spirv);
1665 spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1666 EXPECT_EQ(SPV_SUCCESS,
1667 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1668 EXPECT_THAT(getDiagnosticString(), Eq(""));
1669 }
1670
TEST_F(ValidateDecorations,BlockLayoutPermitsScalarAlignedArrayWithScalarLayoutGood)1671 TEST_F(ValidateDecorations,
1672 BlockLayoutPermitsScalarAlignedArrayWithScalarLayoutGood) {
1673 // The array at offset 4 is ok with scalar block layout.
1674 std::string spirv = R"(
1675 OpCapability Shader
1676 OpMemoryModel Logical GLSL450
1677 OpEntryPoint Vertex %main "main"
1678 OpSource GLSL 450
1679 OpMemberDecorate %S 0 Offset 0
1680 OpMemberDecorate %S 1 Offset 4
1681 OpDecorate %S Block
1682 OpDecorate %B DescriptorSet 0
1683 OpDecorate %B Binding 0
1684 OpDecorate %arr_float ArrayStride 4
1685 %void = OpTypeVoid
1686 %3 = OpTypeFunction %void
1687 %uint = OpTypeInt 32 0
1688 %uint_3 = OpConstant %uint 3
1689 %float = OpTypeFloat 32
1690 %arr_float = OpTypeArray %float %uint_3
1691 %S = OpTypeStruct %float %arr_float
1692 %_ptr_Uniform_S = OpTypePointer Uniform %S
1693 %B = OpVariable %_ptr_Uniform_S Uniform
1694 %main = OpFunction %void None %3
1695 %5 = OpLabel
1696 OpReturn
1697 OpFunctionEnd
1698 )";
1699
1700 CompileSuccessfully(spirv);
1701 spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1702 EXPECT_EQ(SPV_SUCCESS,
1703 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1704 EXPECT_THAT(getDiagnosticString(), Eq(""));
1705 }
1706
TEST_F(ValidateDecorations,BlockLayoutPermitsScalarAlignedArrayOfVec3WithScalarLayoutGood)1707 TEST_F(ValidateDecorations,
1708 BlockLayoutPermitsScalarAlignedArrayOfVec3WithScalarLayoutGood) {
1709 // The array at offset 4 is ok with scalar block layout, even though
1710 // its elements are vec3.
1711 // This is the same as the previous case, but the array elements are vec3
1712 // instead of float.
1713 std::string spirv = R"(
1714 OpCapability Shader
1715 OpMemoryModel Logical GLSL450
1716 OpEntryPoint Vertex %main "main"
1717 OpSource GLSL 450
1718 OpMemberDecorate %S 0 Offset 0
1719 OpMemberDecorate %S 1 Offset 4
1720 OpDecorate %S Block
1721 OpDecorate %B DescriptorSet 0
1722 OpDecorate %B Binding 0
1723 OpDecorate %arr_vec3 ArrayStride 12
1724 %void = OpTypeVoid
1725 %3 = OpTypeFunction %void
1726 %uint = OpTypeInt 32 0
1727 %uint_3 = OpConstant %uint 3
1728 %float = OpTypeFloat 32
1729 %vec3 = OpTypeVector %float 3
1730 %arr_vec3 = OpTypeArray %vec3 %uint_3
1731 %S = OpTypeStruct %float %arr_vec3
1732 %_ptr_Uniform_S = OpTypePointer Uniform %S
1733 %B = OpVariable %_ptr_Uniform_S Uniform
1734 %main = OpFunction %void None %3
1735 %5 = OpLabel
1736 OpReturn
1737 OpFunctionEnd
1738 )";
1739
1740 CompileSuccessfully(spirv);
1741 spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1742 EXPECT_EQ(SPV_SUCCESS,
1743 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1744 EXPECT_THAT(getDiagnosticString(), Eq(""));
1745 }
1746
TEST_F(ValidateDecorations,BlockLayoutPermitsScalarAlignedStructWithScalarLayoutGood)1747 TEST_F(ValidateDecorations,
1748 BlockLayoutPermitsScalarAlignedStructWithScalarLayoutGood) {
1749 // Scalar block layout permits the struct at offset 4, even though
1750 // it contains a vector with base alignment 8 and scalar alignment 4.
1751 std::string spirv = R"(
1752 OpCapability Shader
1753 OpMemoryModel Logical GLSL450
1754 OpEntryPoint Vertex %main "main"
1755 OpSource GLSL 450
1756 OpMemberDecorate %S 0 Offset 0
1757 OpMemberDecorate %S 1 Offset 4
1758 OpMemberDecorate %st 0 Offset 0
1759 OpMemberDecorate %st 1 Offset 8
1760 OpDecorate %S Block
1761 OpDecorate %B DescriptorSet 0
1762 OpDecorate %B Binding 0
1763 %void = OpTypeVoid
1764 %3 = OpTypeFunction %void
1765 %float = OpTypeFloat 32
1766 %vec2 = OpTypeVector %float 2
1767 %st = OpTypeStruct %vec2 %float
1768 %S = OpTypeStruct %float %st
1769 %_ptr_Uniform_S = OpTypePointer Uniform %S
1770 %B = OpVariable %_ptr_Uniform_S Uniform
1771 %main = OpFunction %void None %3
1772 %5 = OpLabel
1773 OpReturn
1774 OpFunctionEnd
1775 )";
1776
1777 CompileSuccessfully(spirv);
1778 spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1779 EXPECT_EQ(SPV_SUCCESS,
1780 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1781 EXPECT_THAT(getDiagnosticString(), Eq(""));
1782 }
1783
TEST_F(ValidateDecorations,BlockLayoutPermitsFieldsInBaseAlignmentPaddingAtEndOfStructWithScalarLayoutGood)1784 TEST_F(
1785 ValidateDecorations,
1786 BlockLayoutPermitsFieldsInBaseAlignmentPaddingAtEndOfStructWithScalarLayoutGood) {
1787 // Scalar block layout permits fields in what would normally be the padding at
1788 // the end of a struct.
1789 std::string spirv = R"(
1790 OpCapability Shader
1791 OpCapability Float64
1792 OpMemoryModel Logical GLSL450
1793 OpEntryPoint Vertex %main "main"
1794 OpSource GLSL 450
1795 OpMemberDecorate %st 0 Offset 0
1796 OpMemberDecorate %st 1 Offset 8
1797 OpMemberDecorate %S 0 Offset 0
1798 OpMemberDecorate %S 1 Offset 12
1799 OpDecorate %S Block
1800 OpDecorate %B DescriptorSet 0
1801 OpDecorate %B Binding 0
1802 %void = OpTypeVoid
1803 %3 = OpTypeFunction %void
1804 %float = OpTypeFloat 32
1805 %double = OpTypeFloat 64
1806 %st = OpTypeStruct %double %float
1807 %S = OpTypeStruct %st %float
1808 %_ptr_Uniform_S = OpTypePointer Uniform %S
1809 %B = OpVariable %_ptr_Uniform_S Uniform
1810 %main = OpFunction %void None %3
1811 %5 = OpLabel
1812 OpReturn
1813 OpFunctionEnd
1814 )";
1815
1816 CompileSuccessfully(spirv);
1817 spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1818 EXPECT_EQ(SPV_SUCCESS,
1819 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1820 EXPECT_THAT(getDiagnosticString(), Eq(""));
1821 }
1822
TEST_F(ValidateDecorations,BlockLayoutPermitsStraddlingVectorWithScalarLayoutOverrideRelaxBlockLayoutGood)1823 TEST_F(
1824 ValidateDecorations,
1825 BlockLayoutPermitsStraddlingVectorWithScalarLayoutOverrideRelaxBlockLayoutGood) {
1826 // Same as previous, but set relaxed block layout first. Scalar layout always
1827 // wins.
1828 std::string spirv = R"(
1829 OpCapability Shader
1830 OpMemoryModel Logical GLSL450
1831 OpEntryPoint Vertex %main "main"
1832 OpSource GLSL 450
1833 OpMemberDecorate %S 0 Offset 0
1834 OpMemberDecorate %S 1 Offset 4
1835 OpDecorate %S Block
1836 OpDecorate %B DescriptorSet 0
1837 OpDecorate %B Binding 0
1838 %void = OpTypeVoid
1839 %3 = OpTypeFunction %void
1840 %float = OpTypeFloat 32
1841 %vec4 = OpTypeVector %float 4
1842 %S = OpTypeStruct %float %vec4
1843 %_ptr_Uniform_S = OpTypePointer Uniform %S
1844 %B = OpVariable %_ptr_Uniform_S Uniform
1845 %main = OpFunction %void None %3
1846 %5 = OpLabel
1847 OpReturn
1848 OpFunctionEnd
1849 )";
1850
1851 CompileSuccessfully(spirv);
1852 spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
1853 spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1854 EXPECT_EQ(SPV_SUCCESS,
1855 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1856 EXPECT_THAT(getDiagnosticString(), Eq(""));
1857 }
1858
TEST_F(ValidateDecorations,BlockLayoutPermitsStraddlingVectorWithRelaxedLayoutOverridenByScalarBlockLayoutGood)1859 TEST_F(
1860 ValidateDecorations,
1861 BlockLayoutPermitsStraddlingVectorWithRelaxedLayoutOverridenByScalarBlockLayoutGood) {
1862 // Same as previous, but set scalar block layout first. Scalar layout always
1863 // wins.
1864 std::string spirv = R"(
1865 OpCapability Shader
1866 OpMemoryModel Logical GLSL450
1867 OpEntryPoint Vertex %main "main"
1868 OpSource GLSL 450
1869 OpMemberDecorate %S 0 Offset 0
1870 OpMemberDecorate %S 1 Offset 4
1871 OpDecorate %S Block
1872 OpDecorate %B DescriptorSet 0
1873 OpDecorate %B Binding 0
1874 %void = OpTypeVoid
1875 %3 = OpTypeFunction %void
1876 %float = OpTypeFloat 32
1877 %vec4 = OpTypeVector %float 4
1878 %S = OpTypeStruct %float %vec4
1879 %_ptr_Uniform_S = OpTypePointer Uniform %S
1880 %B = OpVariable %_ptr_Uniform_S Uniform
1881 %main = OpFunction %void None %3
1882 %5 = OpLabel
1883 OpReturn
1884 OpFunctionEnd
1885 )";
1886
1887 CompileSuccessfully(spirv);
1888 spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1889 spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
1890 EXPECT_EQ(SPV_SUCCESS,
1891 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1892 EXPECT_THAT(getDiagnosticString(), Eq(""));
1893 }
1894
TEST_F(ValidateDecorations,BufferBlock16bitStandardStorageBufferLayout)1895 TEST_F(ValidateDecorations, BufferBlock16bitStandardStorageBufferLayout) {
1896 std::string spirv = R"(
1897 OpCapability Shader
1898 OpCapability StorageUniform16
1899 OpExtension "SPV_KHR_16bit_storage"
1900 OpMemoryModel Logical GLSL450
1901 OpEntryPoint GLCompute %main "main"
1902 OpExecutionMode %main LocalSize 1 1 1
1903 OpDecorate %f32arr ArrayStride 4
1904 OpDecorate %f16arr ArrayStride 2
1905 OpMemberDecorate %SSBO32 0 Offset 0
1906 OpMemberDecorate %SSBO16 0 Offset 0
1907 OpDecorate %SSBO32 BufferBlock
1908 OpDecorate %SSBO16 BufferBlock
1909 %void = OpTypeVoid
1910 %voidf = OpTypeFunction %void
1911 %u32 = OpTypeInt 32 0
1912 %i32 = OpTypeInt 32 1
1913 %f32 = OpTypeFloat 32
1914 %uvec3 = OpTypeVector %u32 3
1915 %c_i32_32 = OpConstant %i32 32
1916 %c_i32_128 = OpConstant %i32 128
1917 %f32arr = OpTypeArray %f32 %c_i32_128
1918 %f16 = OpTypeFloat 16
1919 %f16arr = OpTypeArray %f16 %c_i32_128
1920 %SSBO32 = OpTypeStruct %f32arr
1921 %SSBO16 = OpTypeStruct %f16arr
1922 %_ptr_Uniform_SSBO32 = OpTypePointer Uniform %SSBO32
1923 %varSSBO32 = OpVariable %_ptr_Uniform_SSBO32 Uniform
1924 %_ptr_Uniform_SSBO16 = OpTypePointer Uniform %SSBO16
1925 %varSSBO16 = OpVariable %_ptr_Uniform_SSBO16 Uniform
1926 %main = OpFunction %void None %voidf
1927 %label = OpLabel
1928 OpReturn
1929 OpFunctionEnd
1930 )";
1931
1932 CompileSuccessfully(spirv);
1933 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
1934 }
1935
TEST_F(ValidateDecorations,BlockArrayBaseAlignmentGood)1936 TEST_F(ValidateDecorations, BlockArrayBaseAlignmentGood) {
1937 // For uniform buffer, Array base alignment is 16, and ArrayStride
1938 // must be a multiple of 16.
1939 std::string spirv = R"(
1940 OpCapability Shader
1941 OpMemoryModel Logical GLSL450
1942 OpEntryPoint Vertex %main "main"
1943 OpSource GLSL 450
1944 OpDecorate %_arr_float_uint_2 ArrayStride 16
1945 OpMemberDecorate %S 0 Offset 0
1946 OpMemberDecorate %S 1 Offset 16
1947 OpDecorate %S Block
1948 %void = OpTypeVoid
1949 %3 = OpTypeFunction %void
1950 %float = OpTypeFloat 32
1951 %v2float = OpTypeVector %float 2
1952 %uint = OpTypeInt 32 0
1953 %uint_2 = OpConstant %uint 2
1954 %_arr_float_uint_2 = OpTypeArray %float %uint_2
1955 %S = OpTypeStruct %v2float %_arr_float_uint_2
1956 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
1957 %u = OpVariable %_ptr_PushConstant_S PushConstant
1958 %main = OpFunction %void None %3
1959 %5 = OpLabel
1960 OpReturn
1961 OpFunctionEnd
1962 )";
1963
1964 CompileSuccessfully(spirv);
1965 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
1966 << getDiagnosticString();
1967 }
1968
TEST_F(ValidateDecorations,BlockArrayBadAlignmentBad)1969 TEST_F(ValidateDecorations, BlockArrayBadAlignmentBad) {
1970 // For uniform buffer, Array base alignment is 16.
1971 std::string spirv = R"(
1972 OpCapability Shader
1973 OpMemoryModel Logical GLSL450
1974 OpEntryPoint Vertex %main "main"
1975 OpSource GLSL 450
1976 OpDecorate %_arr_float_uint_2 ArrayStride 16
1977 OpMemberDecorate %S 0 Offset 0
1978 OpMemberDecorate %S 1 Offset 8
1979 OpDecorate %S Block
1980 %void = OpTypeVoid
1981 %3 = OpTypeFunction %void
1982 %float = OpTypeFloat 32
1983 %v2float = OpTypeVector %float 2
1984 %uint = OpTypeInt 32 0
1985 %uint_2 = OpConstant %uint 2
1986 %_arr_float_uint_2 = OpTypeArray %float %uint_2
1987 %S = OpTypeStruct %v2float %_arr_float_uint_2
1988 %_ptr_Uniform_S = OpTypePointer Uniform %S
1989 %u = OpVariable %_ptr_Uniform_S Uniform
1990 %main = OpFunction %void None %3
1991 %5 = OpLabel
1992 OpReturn
1993 OpFunctionEnd
1994 )";
1995
1996 CompileSuccessfully(spirv);
1997 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1998 EXPECT_THAT(
1999 getDiagnosticString(),
2000 HasSubstr(
2001 "Structure id 3 decorated as Block for variable in Uniform "
2002 "storage class must follow standard uniform buffer layout rules: "
2003 "member 1 at offset 8 is not aligned to 16"));
2004 }
2005
TEST_F(ValidateDecorations,BlockArrayBadAlignmentWithRelaxedLayoutStillBad)2006 TEST_F(ValidateDecorations, BlockArrayBadAlignmentWithRelaxedLayoutStillBad) {
2007 // For uniform buffer, Array base alignment is 16, and ArrayStride
2008 // must be a multiple of 16. This case uses relaxed block layout. Relaxed
2009 // layout only relaxes rules for vector alignment, not array alignment.
2010 std::string spirv = R"(
2011 OpCapability Shader
2012 OpMemoryModel Logical GLSL450
2013 OpEntryPoint Vertex %main "main"
2014 OpSource GLSL 450
2015 OpDecorate %_arr_float_uint_2 ArrayStride 16
2016 OpDecorate %u DescriptorSet 0
2017 OpDecorate %u Binding 0
2018 OpMemberDecorate %S 0 Offset 0
2019 OpMemberDecorate %S 1 Offset 8
2020 OpDecorate %S Block
2021 %void = OpTypeVoid
2022 %3 = OpTypeFunction %void
2023 %float = OpTypeFloat 32
2024 %v2float = OpTypeVector %float 2
2025 %uint = OpTypeInt 32 0
2026 %uint_2 = OpConstant %uint 2
2027 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2028 %S = OpTypeStruct %v2float %_arr_float_uint_2
2029 %_ptr_Uniform_S = OpTypePointer Uniform %S
2030 %u = OpVariable %_ptr_Uniform_S Uniform
2031 %main = OpFunction %void None %3
2032 %5 = OpLabel
2033 OpReturn
2034 OpFunctionEnd
2035 )";
2036
2037 CompileSuccessfully(spirv);
2038 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2039 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
2040 spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
2041 EXPECT_THAT(
2042 getDiagnosticString(),
2043 HasSubstr(
2044 "Structure id 4 decorated as Block for variable in Uniform "
2045 "storage class must follow standard uniform buffer layout rules: "
2046 "member 1 at offset 8 is not aligned to 16"));
2047 }
2048
TEST_F(ValidateDecorations,BlockArrayBadAlignmentWithVulkan1_1StillBad)2049 TEST_F(ValidateDecorations, BlockArrayBadAlignmentWithVulkan1_1StillBad) {
2050 // Same as previous test, but with Vulkan 1.1, which includes
2051 // VK_KHR_relaxed_block_layout in core.
2052 std::string spirv = R"(
2053 OpCapability Shader
2054 OpMemoryModel Logical GLSL450
2055 OpEntryPoint Vertex %main "main"
2056 OpSource GLSL 450
2057 OpDecorate %_arr_float_uint_2 ArrayStride 16
2058 OpDecorate %u DescriptorSet 0
2059 OpDecorate %u Binding 0
2060 OpMemberDecorate %S 0 Offset 0
2061 OpMemberDecorate %S 1 Offset 8
2062 OpDecorate %S Block
2063 %void = OpTypeVoid
2064 %3 = OpTypeFunction %void
2065 %float = OpTypeFloat 32
2066 %v2float = OpTypeVector %float 2
2067 %uint = OpTypeInt 32 0
2068 %uint_2 = OpConstant %uint 2
2069 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2070 %S = OpTypeStruct %v2float %_arr_float_uint_2
2071 %_ptr_Uniform_S = OpTypePointer Uniform %S
2072 %u = OpVariable %_ptr_Uniform_S Uniform
2073 %main = OpFunction %void None %3
2074 %5 = OpLabel
2075 OpReturn
2076 OpFunctionEnd
2077 )";
2078
2079 CompileSuccessfully(spirv);
2080 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2081 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2082 EXPECT_THAT(
2083 getDiagnosticString(),
2084 HasSubstr(
2085 "Structure id 4 decorated as Block for variable in Uniform "
2086 "storage class must follow relaxed uniform buffer layout rules: "
2087 "member 1 at offset 8 is not aligned to 16"));
2088 }
2089
TEST_F(ValidateDecorations,PushConstantArrayBaseAlignmentGood)2090 TEST_F(ValidateDecorations, PushConstantArrayBaseAlignmentGood) {
2091 // Tests https://github.com/KhronosGroup/SPIRV-Tools/issues/1664
2092 // From GLSL vertex shader:
2093 // #version 450
2094 // layout(push_constant) uniform S { vec2 v; float arr[2]; } u;
2095 // void main() { }
2096
2097 std::string spirv = R"(
2098 OpCapability Shader
2099 OpMemoryModel Logical GLSL450
2100 OpEntryPoint Vertex %main "main"
2101 OpSource GLSL 450
2102 OpDecorate %_arr_float_uint_2 ArrayStride 4
2103 OpMemberDecorate %S 0 Offset 0
2104 OpMemberDecorate %S 1 Offset 8
2105 OpDecorate %S Block
2106 %void = OpTypeVoid
2107 %3 = OpTypeFunction %void
2108 %float = OpTypeFloat 32
2109 %v2float = OpTypeVector %float 2
2110 %uint = OpTypeInt 32 0
2111 %uint_2 = OpConstant %uint 2
2112 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2113 %S = OpTypeStruct %v2float %_arr_float_uint_2
2114 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
2115 %u = OpVariable %_ptr_PushConstant_S PushConstant
2116 %main = OpFunction %void None %3
2117 %5 = OpLabel
2118 OpReturn
2119 OpFunctionEnd
2120 )";
2121
2122 CompileSuccessfully(spirv);
2123 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2124 << getDiagnosticString();
2125 }
2126
TEST_F(ValidateDecorations,PushConstantArrayBadAlignmentBad)2127 TEST_F(ValidateDecorations, PushConstantArrayBadAlignmentBad) {
2128 // Like the previous test, but with offset 7 instead of 8.
2129 std::string spirv = R"(
2130 OpCapability Shader
2131 OpMemoryModel Logical GLSL450
2132 OpEntryPoint Vertex %main "main"
2133 OpSource GLSL 450
2134 OpDecorate %_arr_float_uint_2 ArrayStride 4
2135 OpMemberDecorate %S 0 Offset 0
2136 OpMemberDecorate %S 1 Offset 7
2137 OpDecorate %S Block
2138 %void = OpTypeVoid
2139 %3 = OpTypeFunction %void
2140 %float = OpTypeFloat 32
2141 %v2float = OpTypeVector %float 2
2142 %uint = OpTypeInt 32 0
2143 %uint_2 = OpConstant %uint 2
2144 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2145 %S = OpTypeStruct %v2float %_arr_float_uint_2
2146 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
2147 %u = OpVariable %_ptr_PushConstant_S PushConstant
2148 %main = OpFunction %void None %3
2149 %5 = OpLabel
2150 OpReturn
2151 OpFunctionEnd
2152 )";
2153
2154 CompileSuccessfully(spirv);
2155 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
2156 EXPECT_THAT(
2157 getDiagnosticString(),
2158 HasSubstr(
2159 "Structure id 3 decorated as Block for variable in PushConstant "
2160 "storage class must follow standard storage buffer layout rules: "
2161 "member 1 at offset 7 is not aligned to 4"));
2162 }
2163
TEST_F(ValidateDecorations,PushConstantLayoutPermitsTightVec3ScalarPackingGood)2164 TEST_F(ValidateDecorations,
2165 PushConstantLayoutPermitsTightVec3ScalarPackingGood) {
2166 // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
2167 std::string spirv = R"(
2168 OpCapability Shader
2169 OpMemoryModel Logical GLSL450
2170 OpEntryPoint Vertex %main "main"
2171 OpSource GLSL 450
2172 OpMemberDecorate %S 0 Offset 0
2173 OpMemberDecorate %S 1 Offset 12
2174 OpDecorate %S Block
2175 %void = OpTypeVoid
2176 %3 = OpTypeFunction %void
2177 %float = OpTypeFloat 32
2178 %v3float = OpTypeVector %float 3
2179 %S = OpTypeStruct %v3float %float
2180 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
2181 %B = OpVariable %_ptr_PushConstant_S PushConstant
2182 %main = OpFunction %void None %3
2183 %5 = OpLabel
2184 OpReturn
2185 OpFunctionEnd
2186 )";
2187
2188 CompileSuccessfully(spirv);
2189 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2190 << getDiagnosticString();
2191 }
2192
TEST_F(ValidateDecorations,PushConstantLayoutForbidsTightScalarVec3PackingBad)2193 TEST_F(ValidateDecorations,
2194 PushConstantLayoutForbidsTightScalarVec3PackingBad) {
2195 // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
2196 std::string spirv = R"(
2197 OpCapability Shader
2198 OpMemoryModel Logical GLSL450
2199 OpEntryPoint Vertex %main "main"
2200 OpSource GLSL 450
2201 OpMemberDecorate %S 0 Offset 0
2202 OpMemberDecorate %S 1 Offset 4
2203 OpDecorate %S Block
2204 %void = OpTypeVoid
2205 %3 = OpTypeFunction %void
2206 %float = OpTypeFloat 32
2207 %v3float = OpTypeVector %float 3
2208 %S = OpTypeStruct %float %v3float
2209 %_ptr_Uniform_S = OpTypePointer PushConstant %S
2210 %B = OpVariable %_ptr_Uniform_S PushConstant
2211 %main = OpFunction %void None %3
2212 %5 = OpLabel
2213 OpReturn
2214 OpFunctionEnd
2215 )";
2216
2217 CompileSuccessfully(spirv);
2218 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
2219 EXPECT_THAT(
2220 getDiagnosticString(),
2221 HasSubstr(
2222 "Structure id 2 decorated as Block for variable in PushConstant "
2223 "storage class must follow standard storage buffer layout "
2224 "rules: member 1 at offset 4 is not aligned to 16"));
2225 }
2226
TEST_F(ValidateDecorations,PushConstantMissingBlockGood)2227 TEST_F(ValidateDecorations, PushConstantMissingBlockGood) {
2228 std::string spirv = R"(
2229 OpCapability Shader
2230 OpMemoryModel Logical GLSL450
2231 OpEntryPoint Fragment %1 "main"
2232 OpExecutionMode %1 OriginUpperLeft
2233
2234 OpMemberDecorate %struct 0 Offset 0
2235
2236 %void = OpTypeVoid
2237 %voidfn = OpTypeFunction %void
2238 %float = OpTypeFloat 32
2239 %struct = OpTypeStruct %float
2240 %ptr = OpTypePointer PushConstant %struct
2241 %pc = OpVariable %ptr PushConstant
2242
2243 %1 = OpFunction %void None %voidfn
2244 %label = OpLabel
2245 OpReturn
2246 OpFunctionEnd
2247 )";
2248
2249 CompileSuccessfully(spirv);
2250 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2251 << getDiagnosticString();
2252 }
2253
TEST_F(ValidateDecorations,VulkanPushConstantMissingBlockBad)2254 TEST_F(ValidateDecorations, VulkanPushConstantMissingBlockBad) {
2255 std::string spirv = R"(
2256 OpCapability Shader
2257 OpMemoryModel Logical GLSL450
2258 OpEntryPoint Fragment %1 "main"
2259 OpExecutionMode %1 OriginUpperLeft
2260
2261 OpMemberDecorate %struct 0 Offset 0
2262
2263 %void = OpTypeVoid
2264 %voidfn = OpTypeFunction %void
2265 %float = OpTypeFloat 32
2266 %struct = OpTypeStruct %float
2267 %ptr = OpTypePointer PushConstant %struct
2268 %pc = OpVariable %ptr PushConstant
2269
2270 %1 = OpFunction %void None %voidfn
2271 %label = OpLabel
2272 OpReturn
2273 OpFunctionEnd
2274 )";
2275
2276 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2277 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2278 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2279 EXPECT_THAT(getDiagnosticString(),
2280 HasSubstr("PushConstant id '2' is missing Block decoration.\n"
2281 "From Vulkan spec, section 14.5.1:\n"
2282 "Such variables must be identified with a Block "
2283 "decoration"));
2284 }
2285
TEST_F(ValidateDecorations,MultiplePushConstantsSingleEntryPointGood)2286 TEST_F(ValidateDecorations, MultiplePushConstantsSingleEntryPointGood) {
2287 std::string spirv = R"(
2288 OpCapability Shader
2289 OpMemoryModel Logical GLSL450
2290 OpEntryPoint Fragment %1 "main"
2291 OpExecutionMode %1 OriginUpperLeft
2292
2293 OpDecorate %struct Block
2294 OpMemberDecorate %struct 0 Offset 0
2295
2296 %void = OpTypeVoid
2297 %voidfn = OpTypeFunction %void
2298 %float = OpTypeFloat 32
2299 %int = OpTypeInt 32 0
2300 %int_0 = OpConstant %int 0
2301 %struct = OpTypeStruct %float
2302 %ptr = OpTypePointer PushConstant %struct
2303 %ptr_float = OpTypePointer PushConstant %float
2304 %pc1 = OpVariable %ptr PushConstant
2305 %pc2 = OpVariable %ptr PushConstant
2306
2307 %1 = OpFunction %void None %voidfn
2308 %label = OpLabel
2309 %2 = OpAccessChain %ptr_float %pc1 %int_0
2310 %3 = OpLoad %float %2
2311 %4 = OpAccessChain %ptr_float %pc2 %int_0
2312 %5 = OpLoad %float %4
2313 OpReturn
2314 OpFunctionEnd
2315 )";
2316
2317 CompileSuccessfully(spirv);
2318 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2319 << getDiagnosticString();
2320 }
2321
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsDifferentEntryPointGood)2322 TEST_F(ValidateDecorations,
2323 VulkanMultiplePushConstantsDifferentEntryPointGood) {
2324 std::string spirv = R"(
2325 OpCapability Shader
2326 OpMemoryModel Logical GLSL450
2327 OpEntryPoint Vertex %1 "func1"
2328 OpEntryPoint Fragment %2 "func2"
2329 OpExecutionMode %2 OriginUpperLeft
2330
2331 OpDecorate %struct Block
2332 OpMemberDecorate %struct 0 Offset 0
2333
2334 %void = OpTypeVoid
2335 %voidfn = OpTypeFunction %void
2336 %float = OpTypeFloat 32
2337 %int = OpTypeInt 32 0
2338 %int_0 = OpConstant %int 0
2339 %struct = OpTypeStruct %float
2340 %ptr = OpTypePointer PushConstant %struct
2341 %ptr_float = OpTypePointer PushConstant %float
2342 %pc1 = OpVariable %ptr PushConstant
2343 %pc2 = OpVariable %ptr PushConstant
2344
2345 %1 = OpFunction %void None %voidfn
2346 %label1 = OpLabel
2347 %3 = OpAccessChain %ptr_float %pc1 %int_0
2348 %4 = OpLoad %float %3
2349 OpReturn
2350 OpFunctionEnd
2351
2352 %2 = OpFunction %void None %voidfn
2353 %label2 = OpLabel
2354 %5 = OpAccessChain %ptr_float %pc2 %int_0
2355 %6 = OpLoad %float %5
2356 OpReturn
2357 OpFunctionEnd
2358 )";
2359
2360 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2361 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
2362 << getDiagnosticString();
2363 }
2364
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsUnusedSingleEntryPointGood)2365 TEST_F(ValidateDecorations,
2366 VulkanMultiplePushConstantsUnusedSingleEntryPointGood) {
2367 std::string spirv = R"(
2368 OpCapability Shader
2369 OpMemoryModel Logical GLSL450
2370 OpEntryPoint Fragment %1 "main"
2371 OpExecutionMode %1 OriginUpperLeft
2372
2373 OpDecorate %struct Block
2374 OpMemberDecorate %struct 0 Offset 0
2375
2376 %void = OpTypeVoid
2377 %voidfn = OpTypeFunction %void
2378 %float = OpTypeFloat 32
2379 %int = OpTypeInt 32 0
2380 %int_0 = OpConstant %int 0
2381 %struct = OpTypeStruct %float
2382 %ptr = OpTypePointer PushConstant %struct
2383 %ptr_float = OpTypePointer PushConstant %float
2384 %pc1 = OpVariable %ptr PushConstant
2385 %pc2 = OpVariable %ptr PushConstant
2386
2387 %1 = OpFunction %void None %voidfn
2388 %label = OpLabel
2389 OpReturn
2390 OpFunctionEnd
2391 )";
2392
2393 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2394 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
2395 << getDiagnosticString();
2396 }
2397
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsSingleEntryPointBad)2398 TEST_F(ValidateDecorations, VulkanMultiplePushConstantsSingleEntryPointBad) {
2399 std::string spirv = R"(
2400 OpCapability Shader
2401 OpMemoryModel Logical GLSL450
2402 OpEntryPoint Fragment %1 "main"
2403 OpExecutionMode %1 OriginUpperLeft
2404
2405 OpDecorate %struct Block
2406 OpMemberDecorate %struct 0 Offset 0
2407
2408 %void = OpTypeVoid
2409 %voidfn = OpTypeFunction %void
2410 %float = OpTypeFloat 32
2411 %int = OpTypeInt 32 0
2412 %int_0 = OpConstant %int 0
2413 %struct = OpTypeStruct %float
2414 %ptr = OpTypePointer PushConstant %struct
2415 %ptr_float = OpTypePointer PushConstant %float
2416 %pc1 = OpVariable %ptr PushConstant
2417 %pc2 = OpVariable %ptr PushConstant
2418
2419 %1 = OpFunction %void None %voidfn
2420 %label = OpLabel
2421 %2 = OpAccessChain %ptr_float %pc1 %int_0
2422 %3 = OpLoad %float %2
2423 %4 = OpAccessChain %ptr_float %pc2 %int_0
2424 %5 = OpLoad %float %4
2425 OpReturn
2426 OpFunctionEnd
2427 )";
2428
2429 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2430 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2431 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2432 EXPECT_THAT(
2433 getDiagnosticString(),
2434 HasSubstr(
2435 "Entry point id '1' uses more than one PushConstant interface.\n"
2436 "From Vulkan spec, section 14.5.1:\n"
2437 "There must be no more than one push constant block "
2438 "statically used per shader entry point."));
2439 }
2440
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsDifferentEntryPointSubFunctionGood)2441 TEST_F(ValidateDecorations,
2442 VulkanMultiplePushConstantsDifferentEntryPointSubFunctionGood) {
2443 std::string spirv = R"(
2444 OpCapability Shader
2445 OpMemoryModel Logical GLSL450
2446 OpEntryPoint Vertex %1 "func1"
2447 OpEntryPoint Fragment %2 "func2"
2448 OpExecutionMode %2 OriginUpperLeft
2449
2450 OpDecorate %struct Block
2451 OpMemberDecorate %struct 0 Offset 0
2452
2453 %void = OpTypeVoid
2454 %voidfn = OpTypeFunction %void
2455 %float = OpTypeFloat 32
2456 %int = OpTypeInt 32 0
2457 %int_0 = OpConstant %int 0
2458 %struct = OpTypeStruct %float
2459 %ptr = OpTypePointer PushConstant %struct
2460 %ptr_float = OpTypePointer PushConstant %float
2461 %pc1 = OpVariable %ptr PushConstant
2462 %pc2 = OpVariable %ptr PushConstant
2463
2464 %sub1 = OpFunction %void None %voidfn
2465 %label_sub1 = OpLabel
2466 %3 = OpAccessChain %ptr_float %pc1 %int_0
2467 %4 = OpLoad %float %3
2468 OpReturn
2469 OpFunctionEnd
2470
2471 %sub2 = OpFunction %void None %voidfn
2472 %label_sub2 = OpLabel
2473 %5 = OpAccessChain %ptr_float %pc2 %int_0
2474 %6 = OpLoad %float %5
2475 OpReturn
2476 OpFunctionEnd
2477
2478 %1 = OpFunction %void None %voidfn
2479 %label1 = OpLabel
2480 %call1 = OpFunctionCall %void %sub1
2481 OpReturn
2482 OpFunctionEnd
2483
2484 %2 = OpFunction %void None %voidfn
2485 %label2 = OpLabel
2486 %call2 = OpFunctionCall %void %sub2
2487 OpReturn
2488 OpFunctionEnd
2489 )";
2490
2491 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2492 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
2493 << getDiagnosticString();
2494 }
2495
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsSingleEntryPointSubFunctionBad)2496 TEST_F(ValidateDecorations,
2497 VulkanMultiplePushConstantsSingleEntryPointSubFunctionBad) {
2498 std::string spirv = R"(
2499 OpCapability Shader
2500 OpMemoryModel Logical GLSL450
2501 OpEntryPoint Fragment %1 "main"
2502 OpExecutionMode %1 OriginUpperLeft
2503
2504 OpDecorate %struct Block
2505 OpMemberDecorate %struct 0 Offset 0
2506
2507 %void = OpTypeVoid
2508 %voidfn = OpTypeFunction %void
2509 %float = OpTypeFloat 32
2510 %int = OpTypeInt 32 0
2511 %int_0 = OpConstant %int 0
2512 %struct = OpTypeStruct %float
2513 %ptr = OpTypePointer PushConstant %struct
2514 %ptr_float = OpTypePointer PushConstant %float
2515 %pc1 = OpVariable %ptr PushConstant
2516 %pc2 = OpVariable %ptr PushConstant
2517
2518 %sub1 = OpFunction %void None %voidfn
2519 %label_sub1 = OpLabel
2520 %3 = OpAccessChain %ptr_float %pc1 %int_0
2521 %4 = OpLoad %float %3
2522 OpReturn
2523 OpFunctionEnd
2524
2525 %sub2 = OpFunction %void None %voidfn
2526 %label_sub2 = OpLabel
2527 %5 = OpAccessChain %ptr_float %pc2 %int_0
2528 %6 = OpLoad %float %5
2529 OpReturn
2530 OpFunctionEnd
2531
2532 %1 = OpFunction %void None %voidfn
2533 %label1 = OpLabel
2534 %call1 = OpFunctionCall %void %sub1
2535 %call2 = OpFunctionCall %void %sub2
2536 OpReturn
2537 OpFunctionEnd
2538 )";
2539
2540 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2541 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2542 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2543 EXPECT_THAT(
2544 getDiagnosticString(),
2545 HasSubstr(
2546 "Entry point id '1' uses more than one PushConstant interface.\n"
2547 "From Vulkan spec, section 14.5.1:\n"
2548 "There must be no more than one push constant block "
2549 "statically used per shader entry point."));
2550 }
2551
TEST_F(ValidateDecorations,VulkanUniformMissingDescriptorSetBad)2552 TEST_F(ValidateDecorations, VulkanUniformMissingDescriptorSetBad) {
2553 std::string spirv = R"(
2554 OpCapability Shader
2555 OpMemoryModel Logical GLSL450
2556 OpEntryPoint Fragment %1 "main"
2557 OpExecutionMode %1 OriginUpperLeft
2558
2559 OpDecorate %struct Block
2560 OpMemberDecorate %struct 0 Offset 0
2561 OpDecorate %var Binding 0
2562
2563 %void = OpTypeVoid
2564 %voidfn = OpTypeFunction %void
2565 %float = OpTypeFloat 32
2566 %struct = OpTypeStruct %float
2567 %ptr = OpTypePointer Uniform %struct
2568 %ptr_float = OpTypePointer Uniform %float
2569 %var = OpVariable %ptr Uniform
2570 %int = OpTypeInt 32 0
2571 %int_0 = OpConstant %int 0
2572
2573 %1 = OpFunction %void None %voidfn
2574 %label = OpLabel
2575 %2 = OpAccessChain %ptr_float %var %int_0
2576 %3 = OpLoad %float %2
2577 OpReturn
2578 OpFunctionEnd
2579 )";
2580
2581 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2582 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2583 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2584 EXPECT_THAT(getDiagnosticString(),
2585 HasSubstr("Uniform id '3' is missing DescriptorSet decoration.\n"
2586 "From Vulkan spec, section 14.5.2:\n"
2587 "These variables must have DescriptorSet and Binding "
2588 "decorations specified"));
2589 }
2590
TEST_F(ValidateDecorations,VulkanUniformMissingBindingBad)2591 TEST_F(ValidateDecorations, VulkanUniformMissingBindingBad) {
2592 std::string spirv = R"(
2593 OpCapability Shader
2594 OpMemoryModel Logical GLSL450
2595 OpEntryPoint Fragment %1 "main"
2596 OpExecutionMode %1 OriginUpperLeft
2597
2598 OpDecorate %struct Block
2599 OpMemberDecorate %struct 0 Offset 0
2600 OpDecorate %var DescriptorSet 0
2601
2602 %void = OpTypeVoid
2603 %voidfn = OpTypeFunction %void
2604 %float = OpTypeFloat 32
2605 %struct = OpTypeStruct %float
2606 %ptr = OpTypePointer Uniform %struct
2607 %ptr_float = OpTypePointer Uniform %float
2608 %var = OpVariable %ptr Uniform
2609 %int = OpTypeInt 32 0
2610 %int_0 = OpConstant %int 0
2611
2612 %1 = OpFunction %void None %voidfn
2613 %label = OpLabel
2614 %2 = OpAccessChain %ptr_float %var %int_0
2615 %3 = OpLoad %float %2
2616 OpReturn
2617 OpFunctionEnd
2618 )";
2619
2620 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2621 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2622 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2623 EXPECT_THAT(getDiagnosticString(),
2624 HasSubstr("Uniform id '3' is missing Binding decoration.\n"
2625 "From Vulkan spec, section 14.5.2:\n"
2626 "These variables must have DescriptorSet and Binding "
2627 "decorations specified"));
2628 }
2629
TEST_F(ValidateDecorations,VulkanUniformConstantMissingDescriptorSetBad)2630 TEST_F(ValidateDecorations, VulkanUniformConstantMissingDescriptorSetBad) {
2631 std::string spirv = R"(
2632 OpCapability Shader
2633 OpMemoryModel Logical GLSL450
2634 OpEntryPoint Fragment %1 "main"
2635 OpExecutionMode %1 OriginUpperLeft
2636
2637 OpDecorate %var Binding 0
2638
2639 %void = OpTypeVoid
2640 %voidfn = OpTypeFunction %void
2641 %sampler = OpTypeSampler
2642 %ptr = OpTypePointer UniformConstant %sampler
2643 %var = OpVariable %ptr UniformConstant
2644
2645 %1 = OpFunction %void None %voidfn
2646 %label = OpLabel
2647 %2 = OpLoad %sampler %var
2648 OpReturn
2649 OpFunctionEnd
2650 )";
2651
2652 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2653 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2654 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2655 EXPECT_THAT(
2656 getDiagnosticString(),
2657 HasSubstr("UniformConstant id '2' is missing DescriptorSet decoration.\n"
2658 "From Vulkan spec, section 14.5.2:\n"
2659 "These variables must have DescriptorSet and Binding "
2660 "decorations specified"));
2661 }
2662
TEST_F(ValidateDecorations,VulkanUniformConstantMissingBindingBad)2663 TEST_F(ValidateDecorations, VulkanUniformConstantMissingBindingBad) {
2664 std::string spirv = R"(
2665 OpCapability Shader
2666 OpMemoryModel Logical GLSL450
2667 OpEntryPoint Fragment %1 "main"
2668 OpExecutionMode %1 OriginUpperLeft
2669
2670 OpDecorate %var DescriptorSet 0
2671
2672 %void = OpTypeVoid
2673 %voidfn = OpTypeFunction %void
2674 %sampler = OpTypeSampler
2675 %ptr = OpTypePointer UniformConstant %sampler
2676 %var = OpVariable %ptr UniformConstant
2677
2678 %1 = OpFunction %void None %voidfn
2679 %label = OpLabel
2680 %2 = OpLoad %sampler %var
2681 OpReturn
2682 OpFunctionEnd
2683 )";
2684
2685 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2686 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2687 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2688 EXPECT_THAT(
2689 getDiagnosticString(),
2690 HasSubstr("UniformConstant id '2' is missing Binding decoration.\n"
2691 "From Vulkan spec, section 14.5.2:\n"
2692 "These variables must have DescriptorSet and Binding "
2693 "decorations specified"));
2694 }
2695
TEST_F(ValidateDecorations,VulkanStorageBufferMissingDescriptorSetBad)2696 TEST_F(ValidateDecorations, VulkanStorageBufferMissingDescriptorSetBad) {
2697 std::string spirv = R"(
2698 OpCapability Shader
2699 OpExtension "SPV_KHR_storage_buffer_storage_class"
2700 OpMemoryModel Logical GLSL450
2701 OpEntryPoint Fragment %1 "main"
2702 OpExecutionMode %1 OriginUpperLeft
2703
2704 OpDecorate %struct Block
2705 OpDecorate %var Binding 0
2706
2707 %void = OpTypeVoid
2708 %voidfn = OpTypeFunction %void
2709 %float = OpTypeFloat 32
2710 %struct = OpTypeStruct %float
2711 %ptr = OpTypePointer StorageBuffer %struct
2712 %var = OpVariable %ptr StorageBuffer
2713 %ptr_float = OpTypePointer StorageBuffer %float
2714 %int = OpTypeInt 32 0
2715 %int_0 = OpConstant %int 0
2716
2717 %1 = OpFunction %void None %voidfn
2718 %label = OpLabel
2719 %2 = OpAccessChain %ptr_float %var %int_0
2720 %3 = OpLoad %float %2
2721 OpReturn
2722 OpFunctionEnd
2723 )";
2724
2725 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2726 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2727 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2728 EXPECT_THAT(
2729 getDiagnosticString(),
2730 HasSubstr("StorageBuffer id '3' is missing DescriptorSet decoration.\n"
2731 "From Vulkan spec, section 14.5.2:\n"
2732 "These variables must have DescriptorSet and Binding "
2733 "decorations specified"));
2734 }
2735
TEST_F(ValidateDecorations,VulkanStorageBufferMissingBindingBad)2736 TEST_F(ValidateDecorations, VulkanStorageBufferMissingBindingBad) {
2737 std::string spirv = R"(
2738 OpCapability Shader
2739 OpExtension "SPV_KHR_storage_buffer_storage_class"
2740 OpMemoryModel Logical GLSL450
2741 OpEntryPoint Fragment %1 "main"
2742 OpExecutionMode %1 OriginUpperLeft
2743
2744 OpDecorate %struct Block
2745 OpDecorate %var DescriptorSet 0
2746
2747 %void = OpTypeVoid
2748 %voidfn = OpTypeFunction %void
2749 %float = OpTypeFloat 32
2750 %struct = OpTypeStruct %float
2751 %ptr = OpTypePointer StorageBuffer %struct
2752 %var = OpVariable %ptr StorageBuffer
2753 %ptr_float = OpTypePointer StorageBuffer %float
2754 %int = OpTypeInt 32 0
2755 %int_0 = OpConstant %int 0
2756
2757 %1 = OpFunction %void None %voidfn
2758 %label = OpLabel
2759 %2 = OpAccessChain %ptr_float %var %int_0
2760 %3 = OpLoad %float %2
2761 OpReturn
2762 OpFunctionEnd
2763 )";
2764
2765 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2766 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2767 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2768 EXPECT_THAT(getDiagnosticString(),
2769 HasSubstr("StorageBuffer id '3' is missing Binding decoration.\n"
2770 "From Vulkan spec, section 14.5.2:\n"
2771 "These variables must have DescriptorSet and Binding "
2772 "decorations specified"));
2773 }
2774
TEST_F(ValidateDecorations,VulkanStorageBufferMissingDescriptorSetSubFunctionBad)2775 TEST_F(ValidateDecorations,
2776 VulkanStorageBufferMissingDescriptorSetSubFunctionBad) {
2777 std::string spirv = R"(
2778 OpCapability Shader
2779 OpExtension "SPV_KHR_storage_buffer_storage_class"
2780 OpMemoryModel Logical GLSL450
2781 OpEntryPoint Fragment %1 "main"
2782 OpExecutionMode %1 OriginUpperLeft
2783
2784 OpDecorate %struct Block
2785 OpDecorate %var Binding 0
2786
2787 %void = OpTypeVoid
2788 %voidfn = OpTypeFunction %void
2789 %float = OpTypeFloat 32
2790 %struct = OpTypeStruct %float
2791 %ptr = OpTypePointer StorageBuffer %struct
2792 %var = OpVariable %ptr StorageBuffer
2793 %ptr_float = OpTypePointer StorageBuffer %float
2794 %int = OpTypeInt 32 0
2795 %int_0 = OpConstant %int 0
2796
2797 %1 = OpFunction %void None %voidfn
2798 %label = OpLabel
2799 %call = OpFunctionCall %void %2
2800 OpReturn
2801 OpFunctionEnd
2802 %2 = OpFunction %void None %voidfn
2803 %label2 = OpLabel
2804 %3 = OpAccessChain %ptr_float %var %int_0
2805 %4 = OpLoad %float %3
2806 OpReturn
2807 OpFunctionEnd
2808 )";
2809
2810 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2811 EXPECT_EQ(SPV_ERROR_INVALID_ID,
2812 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2813 EXPECT_THAT(
2814 getDiagnosticString(),
2815 HasSubstr("StorageBuffer id '3' is missing DescriptorSet decoration.\n"
2816 "From Vulkan spec, section 14.5.2:\n"
2817 "These variables must have DescriptorSet and Binding "
2818 "decorations specified"));
2819 }
2820
TEST_F(ValidateDecorations,VulkanStorageBufferMissingDescriptorAndBindingUnusedGood)2821 TEST_F(ValidateDecorations,
2822 VulkanStorageBufferMissingDescriptorAndBindingUnusedGood) {
2823 std::string spirv = R"(
2824 OpCapability Shader
2825 OpExtension "SPV_KHR_storage_buffer_storage_class"
2826 OpMemoryModel Logical GLSL450
2827 OpEntryPoint Fragment %1 "main"
2828 OpExecutionMode %1 OriginUpperLeft
2829
2830 OpDecorate %struct BufferBlock
2831
2832 %void = OpTypeVoid
2833 %voidfn = OpTypeFunction %void
2834 %float = OpTypeFloat 32
2835 %struct = OpTypeStruct %float
2836 %ptr = OpTypePointer StorageBuffer %struct
2837 %var = OpVariable %ptr StorageBuffer
2838
2839 %1 = OpFunction %void None %voidfn
2840 %label = OpLabel
2841 OpReturn
2842 OpFunctionEnd
2843 )";
2844
2845 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2846 EXPECT_EQ(SPV_SUCCESS,
2847 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2848 }
2849
TEST_F(ValidateDecorations,UniformMissingDescriptorSetGood)2850 TEST_F(ValidateDecorations, UniformMissingDescriptorSetGood) {
2851 std::string spirv = R"(
2852 OpCapability Shader
2853 OpMemoryModel Logical GLSL450
2854 OpEntryPoint Fragment %1 "main"
2855 OpExecutionMode %1 OriginUpperLeft
2856
2857 OpDecorate %struct Block
2858 OpMemberDecorate %struct 0 Offset 0
2859 OpDecorate %var Binding 0
2860
2861 %void = OpTypeVoid
2862 %voidfn = OpTypeFunction %void
2863 %float = OpTypeFloat 32
2864 %struct = OpTypeStruct %float
2865 %ptr = OpTypePointer Uniform %struct
2866 %var = OpVariable %ptr Uniform
2867
2868 %1 = OpFunction %void None %voidfn
2869 %label = OpLabel
2870 OpReturn
2871 OpFunctionEnd
2872 )";
2873
2874 CompileSuccessfully(spirv);
2875 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2876 << getDiagnosticString();
2877 }
2878
TEST_F(ValidateDecorations,UniformMissingBindingGood)2879 TEST_F(ValidateDecorations, UniformMissingBindingGood) {
2880 std::string spirv = R"(
2881 OpCapability Shader
2882 OpMemoryModel Logical GLSL450
2883 OpEntryPoint Fragment %1 "main"
2884 OpExecutionMode %1 OriginUpperLeft
2885
2886 OpDecorate %struct Block
2887 OpMemberDecorate %struct 0 Offset 0
2888 OpDecorate %var DescriptorSet 0
2889
2890 %void = OpTypeVoid
2891 %voidfn = OpTypeFunction %void
2892 %float = OpTypeFloat 32
2893 %struct = OpTypeStruct %float
2894 %ptr = OpTypePointer Uniform %struct
2895 %var = OpVariable %ptr Uniform
2896
2897 %1 = OpFunction %void None %voidfn
2898 %label = OpLabel
2899 OpReturn
2900 OpFunctionEnd
2901 )";
2902
2903 CompileSuccessfully(spirv);
2904 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2905 << getDiagnosticString();
2906 }
2907
TEST_F(ValidateDecorations,UniformConstantMissingDescriptorSetGood)2908 TEST_F(ValidateDecorations, UniformConstantMissingDescriptorSetGood) {
2909 std::string spirv = R"(
2910 OpCapability Shader
2911 OpMemoryModel Logical GLSL450
2912 OpEntryPoint Fragment %1 "main"
2913 OpExecutionMode %1 OriginUpperLeft
2914
2915 OpDecorate %var Binding 0
2916
2917 %void = OpTypeVoid
2918 %voidfn = OpTypeFunction %void
2919 %sampler = OpTypeSampler
2920 %ptr = OpTypePointer UniformConstant %sampler
2921 %var = OpVariable %ptr UniformConstant
2922
2923 %1 = OpFunction %void None %voidfn
2924 %label = OpLabel
2925 OpReturn
2926 OpFunctionEnd
2927 )";
2928
2929 CompileSuccessfully(spirv);
2930 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2931 << getDiagnosticString();
2932 }
2933
TEST_F(ValidateDecorations,UniformConstantMissingBindingGood)2934 TEST_F(ValidateDecorations, UniformConstantMissingBindingGood) {
2935 std::string spirv = R"(
2936 OpCapability Shader
2937 OpMemoryModel Logical GLSL450
2938 OpEntryPoint Fragment %1 "main"
2939 OpExecutionMode %1 OriginUpperLeft
2940
2941 OpDecorate %var DescriptorSet 0
2942
2943 %void = OpTypeVoid
2944 %voidfn = OpTypeFunction %void
2945 %sampler = OpTypeSampler
2946 %ptr = OpTypePointer UniformConstant %sampler
2947 %var = OpVariable %ptr UniformConstant
2948
2949 %1 = OpFunction %void None %voidfn
2950 %label = OpLabel
2951 OpReturn
2952 OpFunctionEnd
2953 )";
2954
2955 CompileSuccessfully(spirv);
2956 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2957 << getDiagnosticString();
2958 }
2959
TEST_F(ValidateDecorations,StorageBufferMissingDescriptorSetGood)2960 TEST_F(ValidateDecorations, StorageBufferMissingDescriptorSetGood) {
2961 std::string spirv = R"(
2962 OpCapability Shader
2963 OpExtension "SPV_KHR_storage_buffer_storage_class"
2964 OpMemoryModel Logical GLSL450
2965 OpEntryPoint Fragment %1 "main"
2966 OpExecutionMode %1 OriginUpperLeft
2967
2968 OpDecorate %struct BufferBlock
2969 OpDecorate %var Binding 0
2970
2971 %void = OpTypeVoid
2972 %voidfn = OpTypeFunction %void
2973 %float = OpTypeFloat 32
2974 %struct = OpTypeStruct %float
2975 %ptr = OpTypePointer StorageBuffer %struct
2976 %var = OpVariable %ptr StorageBuffer
2977
2978 %1 = OpFunction %void None %voidfn
2979 %label = OpLabel
2980 OpReturn
2981 OpFunctionEnd
2982 )";
2983
2984 CompileSuccessfully(spirv);
2985 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2986 << getDiagnosticString();
2987 }
2988
TEST_F(ValidateDecorations,StorageBufferMissingBindingGood)2989 TEST_F(ValidateDecorations, StorageBufferMissingBindingGood) {
2990 std::string spirv = R"(
2991 OpCapability Shader
2992 OpExtension "SPV_KHR_storage_buffer_storage_class"
2993 OpMemoryModel Logical GLSL450
2994 OpEntryPoint Fragment %1 "main"
2995 OpExecutionMode %1 OriginUpperLeft
2996
2997 OpDecorate %struct BufferBlock
2998 OpDecorate %var DescriptorSet 0
2999
3000 %void = OpTypeVoid
3001 %voidfn = OpTypeFunction %void
3002 %float = OpTypeFloat 32
3003 %struct = OpTypeStruct %float
3004 %ptr = OpTypePointer StorageBuffer %struct
3005 %var = OpVariable %ptr StorageBuffer
3006
3007 %1 = OpFunction %void None %voidfn
3008 %label = OpLabel
3009 OpReturn
3010 OpFunctionEnd
3011 )";
3012
3013 CompileSuccessfully(spirv);
3014 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3015 << getDiagnosticString();
3016 }
3017
TEST_F(ValidateDecorations,StorageBufferStorageClassArrayBaseAlignmentGood)3018 TEST_F(ValidateDecorations, StorageBufferStorageClassArrayBaseAlignmentGood) {
3019 // Spot check buffer rules when using StorageBuffer storage class with Block
3020 // decoration.
3021 std::string spirv = R"(
3022 OpCapability Shader
3023 OpExtension "SPV_KHR_storage_buffer_storage_class"
3024 OpMemoryModel Logical GLSL450
3025 OpEntryPoint Vertex %main "main"
3026 OpSource GLSL 450
3027 OpDecorate %_arr_float_uint_2 ArrayStride 4
3028 OpMemberDecorate %S 0 Offset 0
3029 OpMemberDecorate %S 1 Offset 8
3030 OpDecorate %S Block
3031 OpDecorate %u DescriptorSet 0
3032 OpDecorate %u Binding 0
3033 %void = OpTypeVoid
3034 %3 = OpTypeFunction %void
3035 %float = OpTypeFloat 32
3036 %v2float = OpTypeVector %float 2
3037 %uint = OpTypeInt 32 0
3038 %uint_2 = OpConstant %uint 2
3039 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3040 %S = OpTypeStruct %v2float %_arr_float_uint_2
3041 %_ptr_Uniform_S = OpTypePointer StorageBuffer %S
3042 %u = OpVariable %_ptr_Uniform_S StorageBuffer
3043 %main = OpFunction %void None %3
3044 %5 = OpLabel
3045 OpReturn
3046 OpFunctionEnd
3047 )";
3048
3049 CompileSuccessfully(spirv);
3050 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3051 << getDiagnosticString();
3052 }
3053
TEST_F(ValidateDecorations,StorageBufferStorageClassArrayBadAlignmentBad)3054 TEST_F(ValidateDecorations, StorageBufferStorageClassArrayBadAlignmentBad) {
3055 // Like the previous test, but with offset 7.
3056 std::string spirv = R"(
3057 OpCapability Shader
3058 OpExtension "SPV_KHR_storage_buffer_storage_class"
3059 OpMemoryModel Logical GLSL450
3060 OpEntryPoint Vertex %main "main"
3061 OpSource GLSL 450
3062 OpDecorate %_arr_float_uint_2 ArrayStride 4
3063 OpMemberDecorate %S 0 Offset 0
3064 OpMemberDecorate %S 1 Offset 7
3065 OpDecorate %S Block
3066 OpDecorate %u DescriptorSet 0
3067 OpDecorate %u Binding 0
3068 %void = OpTypeVoid
3069 %3 = OpTypeFunction %void
3070 %float = OpTypeFloat 32
3071 %v2float = OpTypeVector %float 2
3072 %uint = OpTypeInt 32 0
3073 %uint_2 = OpConstant %uint 2
3074 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3075 %S = OpTypeStruct %v2float %_arr_float_uint_2
3076 %_ptr_Uniform_S = OpTypePointer StorageBuffer %S
3077 %u = OpVariable %_ptr_Uniform_S StorageBuffer
3078 %main = OpFunction %void None %3
3079 %5 = OpLabel
3080 OpReturn
3081 OpFunctionEnd
3082 )";
3083
3084 CompileSuccessfully(spirv);
3085 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3086 EXPECT_THAT(
3087 getDiagnosticString(),
3088 HasSubstr(
3089 "Structure id 3 decorated as Block for variable in StorageBuffer "
3090 "storage class must follow standard storage buffer layout rules: "
3091 "member 1 at offset 7 is not aligned to 4"));
3092 }
3093
TEST_F(ValidateDecorations,BufferBlockStandardStorageBufferLayout)3094 TEST_F(ValidateDecorations, BufferBlockStandardStorageBufferLayout) {
3095 std::string spirv = R"(
3096 OpCapability Shader
3097 %1 = OpExtInstImport "GLSL.std.450"
3098 OpMemoryModel Logical GLSL450
3099 OpEntryPoint GLCompute %main "main"
3100 OpExecutionMode %main LocalSize 1 1 1
3101 OpSource GLSL 430
3102 OpMemberDecorate %F 0 Offset 0
3103 OpMemberDecorate %F 1 Offset 8
3104 OpDecorate %_arr_float_uint_2 ArrayStride 4
3105 OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
3106 OpMemberDecorate %O 0 Offset 0
3107 OpMemberDecorate %O 1 Offset 16
3108 OpMemberDecorate %O 2 Offset 24
3109 OpMemberDecorate %O 3 Offset 32
3110 OpMemberDecorate %O 4 ColMajor
3111 OpMemberDecorate %O 4 Offset 48
3112 OpMemberDecorate %O 4 MatrixStride 16
3113 OpDecorate %_arr_O_uint_2 ArrayStride 144
3114 OpMemberDecorate %Output 0 Offset 0
3115 OpMemberDecorate %Output 1 Offset 8
3116 OpMemberDecorate %Output 2 Offset 16
3117 OpMemberDecorate %Output 3 Offset 32
3118 OpMemberDecorate %Output 4 Offset 48
3119 OpMemberDecorate %Output 5 Offset 52
3120 OpMemberDecorate %Output 6 ColMajor
3121 OpMemberDecorate %Output 6 Offset 64
3122 OpMemberDecorate %Output 6 MatrixStride 16
3123 OpMemberDecorate %Output 7 Offset 96
3124 OpDecorate %Output BufferBlock
3125 %void = OpTypeVoid
3126 %3 = OpTypeFunction %void
3127 %float = OpTypeFloat 32
3128 %v2float = OpTypeVector %float 2
3129 %v3float = OpTypeVector %float 3
3130 %int = OpTypeInt 32 1
3131 %uint = OpTypeInt 32 0
3132 %v2uint = OpTypeVector %uint 2
3133 %F = OpTypeStruct %int %v2uint
3134 %uint_2 = OpConstant %uint 2
3135 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3136 %mat2v3float = OpTypeMatrix %v3float 2
3137 %v3uint = OpTypeVector %uint 3
3138 %mat3v3float = OpTypeMatrix %v3float 3
3139 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3140 %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3141 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3142 %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3143 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3144 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3145 %main = OpFunction %void None %3
3146 %5 = OpLabel
3147 OpReturn
3148 OpFunctionEnd
3149 )";
3150
3151 CompileSuccessfully(spirv);
3152 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
3153 }
3154
TEST_F(ValidateDecorations,StorageBufferLayoutPermitsTightVec3ScalarPackingGood)3155 TEST_F(ValidateDecorations,
3156 StorageBufferLayoutPermitsTightVec3ScalarPackingGood) {
3157 // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
3158 std::string spirv = R"(
3159 OpCapability Shader
3160 OpExtension "SPV_KHR_storage_buffer_storage_class"
3161 OpMemoryModel Logical GLSL450
3162 OpEntryPoint Vertex %main "main"
3163 OpSource GLSL 450
3164 OpMemberDecorate %S 0 Offset 0
3165 OpMemberDecorate %S 1 Offset 12
3166 OpDecorate %S Block
3167 OpDecorate %B DescriptorSet 0
3168 OpDecorate %B Binding 0
3169 %void = OpTypeVoid
3170 %3 = OpTypeFunction %void
3171 %float = OpTypeFloat 32
3172 %v3float = OpTypeVector %float 3
3173 %S = OpTypeStruct %v3float %float
3174 %_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
3175 %B = OpVariable %_ptr_StorageBuffer_S StorageBuffer
3176 %main = OpFunction %void None %3
3177 %5 = OpLabel
3178 OpReturn
3179 OpFunctionEnd
3180 )";
3181
3182 CompileSuccessfully(spirv);
3183 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3184 << getDiagnosticString();
3185 }
3186
TEST_F(ValidateDecorations,StorageBufferLayoutForbidsTightScalarVec3PackingBad)3187 TEST_F(ValidateDecorations,
3188 StorageBufferLayoutForbidsTightScalarVec3PackingBad) {
3189 // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
3190 std::string spirv = R"(
3191 OpCapability Shader
3192 OpExtension "SPV_KHR_storage_buffer_storage_class"
3193 OpMemoryModel Logical GLSL450
3194 OpEntryPoint Vertex %main "main"
3195 OpSource GLSL 450
3196 OpMemberDecorate %S 0 Offset 0
3197 OpMemberDecorate %S 1 Offset 4
3198 OpDecorate %S Block
3199 OpDecorate %B DescriptorSet 0
3200 OpDecorate %B Binding 0
3201 %void = OpTypeVoid
3202 %3 = OpTypeFunction %void
3203 %float = OpTypeFloat 32
3204 %v3float = OpTypeVector %float 3
3205 %S = OpTypeStruct %float %v3float
3206 %_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
3207 %B = OpVariable %_ptr_StorageBuffer_S StorageBuffer
3208 %main = OpFunction %void None %3
3209 %5 = OpLabel
3210 OpReturn
3211 OpFunctionEnd
3212 )";
3213
3214 CompileSuccessfully(spirv);
3215 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3216 EXPECT_THAT(
3217 getDiagnosticString(),
3218 HasSubstr(
3219 "Structure id 2 decorated as Block for variable in StorageBuffer "
3220 "storage class must follow standard storage buffer layout "
3221 "rules: member 1 at offset 4 is not aligned to 16"));
3222 }
3223
TEST_F(ValidateDecorations,BlockStandardUniformBufferLayoutIncorrectOffset0Bad)3224 TEST_F(ValidateDecorations,
3225 BlockStandardUniformBufferLayoutIncorrectOffset0Bad) {
3226 std::string spirv = R"(
3227 OpCapability Shader
3228 %1 = OpExtInstImport "GLSL.std.450"
3229 OpMemoryModel Logical GLSL450
3230 OpEntryPoint GLCompute %main "main"
3231 OpExecutionMode %main LocalSize 1 1 1
3232 OpSource GLSL 430
3233 OpMemberDecorate %F 0 Offset 0
3234 OpMemberDecorate %F 1 Offset 8
3235 OpDecorate %_arr_float_uint_2 ArrayStride 16
3236 OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
3237 OpMemberDecorate %O 0 Offset 0
3238 OpMemberDecorate %O 1 Offset 16
3239 OpMemberDecorate %O 2 Offset 24
3240 OpMemberDecorate %O 3 Offset 33
3241 OpMemberDecorate %O 4 ColMajor
3242 OpMemberDecorate %O 4 Offset 80
3243 OpMemberDecorate %O 4 MatrixStride 16
3244 OpDecorate %_arr_O_uint_2 ArrayStride 176
3245 OpMemberDecorate %Output 0 Offset 0
3246 OpMemberDecorate %Output 1 Offset 8
3247 OpMemberDecorate %Output 2 Offset 16
3248 OpMemberDecorate %Output 3 Offset 32
3249 OpMemberDecorate %Output 4 Offset 48
3250 OpMemberDecorate %Output 5 Offset 64
3251 OpMemberDecorate %Output 6 ColMajor
3252 OpMemberDecorate %Output 6 Offset 96
3253 OpMemberDecorate %Output 6 MatrixStride 16
3254 OpMemberDecorate %Output 7 Offset 128
3255 OpDecorate %Output Block
3256 %void = OpTypeVoid
3257 %3 = OpTypeFunction %void
3258 %float = OpTypeFloat 32
3259 %v2float = OpTypeVector %float 2
3260 %v3float = OpTypeVector %float 3
3261 %int = OpTypeInt 32 1
3262 %uint = OpTypeInt 32 0
3263 %v2uint = OpTypeVector %uint 2
3264 %F = OpTypeStruct %int %v2uint
3265 %uint_2 = OpConstant %uint 2
3266 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3267 %mat2v3float = OpTypeMatrix %v3float 2
3268 %v3uint = OpTypeVector %uint 3
3269 %mat3v3float = OpTypeMatrix %v3float 3
3270 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3271 %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3272 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3273 %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3274 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3275 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3276 %main = OpFunction %void None %3
3277 %5 = OpLabel
3278 OpReturn
3279 OpFunctionEnd
3280 )";
3281
3282 CompileSuccessfully(spirv);
3283 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3284 EXPECT_THAT(
3285 getDiagnosticString(),
3286 HasSubstr("Structure id 6 decorated as Block for variable in Uniform "
3287 "storage class must follow standard uniform buffer layout "
3288 "rules: member 2 at offset 24 is not aligned to 16"));
3289 }
3290
TEST_F(ValidateDecorations,BlockStandardUniformBufferLayoutIncorrectOffset1Bad)3291 TEST_F(ValidateDecorations,
3292 BlockStandardUniformBufferLayoutIncorrectOffset1Bad) {
3293 std::string spirv = R"(
3294 OpCapability Shader
3295 %1 = OpExtInstImport "GLSL.std.450"
3296 OpMemoryModel Logical GLSL450
3297 OpEntryPoint GLCompute %main "main"
3298 OpExecutionMode %main LocalSize 1 1 1
3299 OpSource GLSL 430
3300 OpMemberDecorate %F 0 Offset 0
3301 OpMemberDecorate %F 1 Offset 8
3302 OpDecorate %_arr_float_uint_2 ArrayStride 16
3303 OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
3304 OpMemberDecorate %O 0 Offset 0
3305 OpMemberDecorate %O 1 Offset 16
3306 OpMemberDecorate %O 2 Offset 32
3307 OpMemberDecorate %O 3 Offset 64
3308 OpMemberDecorate %O 4 ColMajor
3309 OpMemberDecorate %O 4 Offset 80
3310 OpMemberDecorate %O 4 MatrixStride 16
3311 OpDecorate %_arr_O_uint_2 ArrayStride 176
3312 OpMemberDecorate %Output 0 Offset 0
3313 OpMemberDecorate %Output 1 Offset 8
3314 OpMemberDecorate %Output 2 Offset 16
3315 OpMemberDecorate %Output 3 Offset 32
3316 OpMemberDecorate %Output 4 Offset 48
3317 OpMemberDecorate %Output 5 Offset 71
3318 OpMemberDecorate %Output 6 ColMajor
3319 OpMemberDecorate %Output 6 Offset 96
3320 OpMemberDecorate %Output 6 MatrixStride 16
3321 OpMemberDecorate %Output 7 Offset 128
3322 OpDecorate %Output Block
3323 %void = OpTypeVoid
3324 %3 = OpTypeFunction %void
3325 %float = OpTypeFloat 32
3326 %v2float = OpTypeVector %float 2
3327 %v3float = OpTypeVector %float 3
3328 %int = OpTypeInt 32 1
3329 %uint = OpTypeInt 32 0
3330 %v2uint = OpTypeVector %uint 2
3331 %F = OpTypeStruct %int %v2uint
3332 %uint_2 = OpConstant %uint 2
3333 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3334 %mat2v3float = OpTypeMatrix %v3float 2
3335 %v3uint = OpTypeVector %uint 3
3336 %mat3v3float = OpTypeMatrix %v3float 3
3337 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3338 %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3339 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3340 %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3341 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3342 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3343 %main = OpFunction %void None %3
3344 %5 = OpLabel
3345 OpReturn
3346 OpFunctionEnd
3347 )";
3348
3349 CompileSuccessfully(spirv);
3350 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3351 EXPECT_THAT(
3352 getDiagnosticString(),
3353 HasSubstr("Structure id 8 decorated as Block for variable in Uniform "
3354 "storage class must follow standard uniform buffer layout "
3355 "rules: member 5 at offset 71 is not aligned to 16"));
3356 }
3357
TEST_F(ValidateDecorations,BlockUniformBufferLayoutIncorrectArrayStrideBad)3358 TEST_F(ValidateDecorations, BlockUniformBufferLayoutIncorrectArrayStrideBad) {
3359 std::string spirv = R"(
3360 OpCapability Shader
3361 %1 = OpExtInstImport "GLSL.std.450"
3362 OpMemoryModel Logical GLSL450
3363 OpEntryPoint GLCompute %main "main"
3364 OpExecutionMode %main LocalSize 1 1 1
3365 OpSource GLSL 430
3366 OpMemberDecorate %F 0 Offset 0
3367 OpMemberDecorate %F 1 Offset 8
3368 OpDecorate %_arr_float_uint_2 ArrayStride 16
3369 OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 49
3370 OpMemberDecorate %O 0 Offset 0
3371 OpMemberDecorate %O 1 Offset 16
3372 OpMemberDecorate %O 2 Offset 32
3373 OpMemberDecorate %O 3 Offset 64
3374 OpMemberDecorate %O 4 ColMajor
3375 OpMemberDecorate %O 4 Offset 80
3376 OpMemberDecorate %O 4 MatrixStride 16
3377 OpDecorate %_arr_O_uint_2 ArrayStride 176
3378 OpMemberDecorate %Output 0 Offset 0
3379 OpMemberDecorate %Output 1 Offset 8
3380 OpMemberDecorate %Output 2 Offset 16
3381 OpMemberDecorate %Output 3 Offset 32
3382 OpMemberDecorate %Output 4 Offset 48
3383 OpMemberDecorate %Output 5 Offset 64
3384 OpMemberDecorate %Output 6 ColMajor
3385 OpMemberDecorate %Output 6 Offset 96
3386 OpMemberDecorate %Output 6 MatrixStride 16
3387 OpMemberDecorate %Output 7 Offset 128
3388 OpDecorate %Output Block
3389 %void = OpTypeVoid
3390 %3 = OpTypeFunction %void
3391 %float = OpTypeFloat 32
3392 %v2float = OpTypeVector %float 2
3393 %v3float = OpTypeVector %float 3
3394 %int = OpTypeInt 32 1
3395 %uint = OpTypeInt 32 0
3396 %v2uint = OpTypeVector %uint 2
3397 %F = OpTypeStruct %int %v2uint
3398 %uint_2 = OpConstant %uint 2
3399 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3400 %mat2v3float = OpTypeMatrix %v3float 2
3401 %v3uint = OpTypeVector %uint 3
3402 %mat3v3float = OpTypeMatrix %v3float 3
3403 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3404 %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3405 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3406 %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3407 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3408 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3409 %main = OpFunction %void None %3
3410 %5 = OpLabel
3411 OpReturn
3412 OpFunctionEnd
3413 )";
3414
3415 CompileSuccessfully(spirv);
3416 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3417 EXPECT_THAT(
3418 getDiagnosticString(),
3419 HasSubstr(
3420 "Structure id 6 decorated as Block for variable in Uniform storage "
3421 "class must follow standard uniform buffer layout rules: member 4 is "
3422 "an array with stride 49 not satisfying alignment to 16"));
3423 }
3424
TEST_F(ValidateDecorations,BufferBlockStandardStorageBufferLayoutImproperStraddleBad)3425 TEST_F(ValidateDecorations,
3426 BufferBlockStandardStorageBufferLayoutImproperStraddleBad) {
3427 std::string spirv = R"(
3428 OpCapability Shader
3429 %1 = OpExtInstImport "GLSL.std.450"
3430 OpMemoryModel Logical GLSL450
3431 OpEntryPoint GLCompute %main "main"
3432 OpExecutionMode %main LocalSize 1 1 1
3433 OpSource GLSL 430
3434 OpMemberDecorate %Output 0 Offset 0
3435 OpMemberDecorate %Output 1 Offset 8
3436 OpDecorate %Output BufferBlock
3437 %void = OpTypeVoid
3438 %3 = OpTypeFunction %void
3439 %float = OpTypeFloat 32
3440 %v3float = OpTypeVector %float 3
3441 %Output = OpTypeStruct %float %v3float
3442 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3443 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3444 %main = OpFunction %void None %3
3445 %5 = OpLabel
3446 OpReturn
3447 OpFunctionEnd
3448 )";
3449
3450 CompileSuccessfully(spirv);
3451 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3452 EXPECT_THAT(
3453 getDiagnosticString(),
3454 HasSubstr("Structure id 3 decorated as BufferBlock for variable in "
3455 "Uniform storage class must follow standard storage buffer "
3456 "layout rules: member 1 at offset 8 is not aligned to 16"));
3457 }
3458
TEST_F(ValidateDecorations,BlockUniformBufferLayoutOffsetInsideArrayPaddingBad)3459 TEST_F(ValidateDecorations,
3460 BlockUniformBufferLayoutOffsetInsideArrayPaddingBad) {
3461 // In this case the 2nd member fits entirely within the padding.
3462 std::string spirv = R"(
3463 OpCapability Shader
3464 %1 = OpExtInstImport "GLSL.std.450"
3465 OpMemoryModel Logical GLSL450
3466 OpEntryPoint GLCompute %main "main"
3467 OpExecutionMode %main LocalSize 1 1 1
3468 OpSource GLSL 430
3469 OpDecorate %_arr_float_uint_2 ArrayStride 16
3470 OpMemberDecorate %Output 0 Offset 0
3471 OpMemberDecorate %Output 1 Offset 20
3472 OpDecorate %Output Block
3473 %void = OpTypeVoid
3474 %3 = OpTypeFunction %void
3475 %float = OpTypeFloat 32
3476 %uint = OpTypeInt 32 0
3477 %v2uint = OpTypeVector %uint 2
3478 %uint_2 = OpConstant %uint 2
3479 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3480 %Output = OpTypeStruct %_arr_float_uint_2 %float
3481 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3482 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3483 %main = OpFunction %void None %3
3484 %5 = OpLabel
3485 OpReturn
3486 OpFunctionEnd
3487 )";
3488
3489 CompileSuccessfully(spirv);
3490 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3491 EXPECT_THAT(
3492 getDiagnosticString(),
3493 HasSubstr(
3494 "Structure id 4 decorated as Block for variable in Uniform storage "
3495 "class must follow standard uniform buffer layout rules: member 1 at "
3496 "offset 20 overlaps previous member ending at offset 31"));
3497 }
3498
TEST_F(ValidateDecorations,BlockUniformBufferLayoutOffsetInsideStructPaddingBad)3499 TEST_F(ValidateDecorations,
3500 BlockUniformBufferLayoutOffsetInsideStructPaddingBad) {
3501 // In this case the 2nd member fits entirely within the padding.
3502 std::string spirv = R"(
3503 OpCapability Shader
3504 OpMemoryModel Logical GLSL450
3505 OpEntryPoint GLCompute %1 "main"
3506 OpMemberDecorate %_struct_6 0 Offset 0
3507 OpMemberDecorate %_struct_2 0 Offset 0
3508 OpMemberDecorate %_struct_2 1 Offset 4
3509 OpDecorate %_struct_2 Block
3510 %void = OpTypeVoid
3511 %4 = OpTypeFunction %void
3512 %float = OpTypeFloat 32
3513 %_struct_6 = OpTypeStruct %float
3514 %_struct_2 = OpTypeStruct %_struct_6 %float
3515 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
3516 %8 = OpVariable %_ptr_Uniform__struct_2 Uniform
3517 %1 = OpFunction %void None %4
3518 %9 = OpLabel
3519 OpReturn
3520 OpFunctionEnd
3521 )";
3522
3523 CompileSuccessfully(spirv);
3524 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3525 EXPECT_THAT(
3526 getDiagnosticString(),
3527 HasSubstr(
3528 "Structure id 3 decorated as Block for variable in Uniform storage "
3529 "class must follow standard uniform buffer layout rules: member 1 at "
3530 "offset 4 overlaps previous member ending at offset 15"));
3531 }
3532
TEST_F(ValidateDecorations,BlockLayoutOffsetOutOfOrderGoodUniversal1_0)3533 TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodUniversal1_0) {
3534 std::string spirv = R"(
3535 OpCapability Shader
3536 %1 = OpExtInstImport "GLSL.std.450"
3537 OpMemoryModel Logical GLSL450
3538 OpEntryPoint GLCompute %main "main"
3539 OpExecutionMode %main LocalSize 1 1 1
3540 OpMemberDecorate %Outer 0 Offset 4
3541 OpMemberDecorate %Outer 1 Offset 0
3542 OpDecorate %Outer Block
3543 OpDecorate %O DescriptorSet 0
3544 OpDecorate %O Binding 0
3545 %void = OpTypeVoid
3546 %3 = OpTypeFunction %void
3547 %uint = OpTypeInt 32 0
3548 %Outer = OpTypeStruct %uint %uint
3549 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3550 %O = OpVariable %_ptr_Uniform_Outer Uniform
3551 %main = OpFunction %void None %3
3552 %5 = OpLabel
3553 OpReturn
3554 OpFunctionEnd
3555 )";
3556
3557 CompileSuccessfully(spirv);
3558 EXPECT_EQ(SPV_SUCCESS,
3559 ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_0));
3560 }
3561
TEST_F(ValidateDecorations,BlockLayoutOffsetOutOfOrderGoodOpenGL4_5)3562 TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodOpenGL4_5) {
3563 std::string spirv = R"(
3564 OpCapability Shader
3565 %1 = OpExtInstImport "GLSL.std.450"
3566 OpMemoryModel Logical GLSL450
3567 OpEntryPoint GLCompute %main "main"
3568 OpExecutionMode %main LocalSize 1 1 1
3569 OpMemberDecorate %Outer 0 Offset 4
3570 OpMemberDecorate %Outer 1 Offset 0
3571 OpDecorate %Outer Block
3572 OpDecorate %O DescriptorSet 0
3573 OpDecorate %O Binding 0
3574 %void = OpTypeVoid
3575 %3 = OpTypeFunction %void
3576 %uint = OpTypeInt 32 0
3577 %Outer = OpTypeStruct %uint %uint
3578 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3579 %O = OpVariable %_ptr_Uniform_Outer Uniform
3580 %main = OpFunction %void None %3
3581 %5 = OpLabel
3582 OpReturn
3583 OpFunctionEnd
3584 )";
3585
3586 CompileSuccessfully(spirv);
3587 EXPECT_EQ(SPV_SUCCESS,
3588 ValidateAndRetrieveValidationState(SPV_ENV_OPENGL_4_5));
3589 }
3590
TEST_F(ValidateDecorations,BlockLayoutOffsetOutOfOrderGoodVulkan1_1)3591 TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodVulkan1_1) {
3592 std::string spirv = R"(
3593 OpCapability Shader
3594 %1 = OpExtInstImport "GLSL.std.450"
3595 OpMemoryModel Logical GLSL450
3596 OpEntryPoint GLCompute %main "main"
3597 OpExecutionMode %main LocalSize 1 1 1
3598 OpMemberDecorate %Outer 0 Offset 4
3599 OpMemberDecorate %Outer 1 Offset 0
3600 OpDecorate %Outer Block
3601 OpDecorate %O DescriptorSet 0
3602 OpDecorate %O Binding 0
3603 %void = OpTypeVoid
3604 %3 = OpTypeFunction %void
3605 %uint = OpTypeInt 32 0
3606 %Outer = OpTypeStruct %uint %uint
3607 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3608 %O = OpVariable %_ptr_Uniform_Outer Uniform
3609 %main = OpFunction %void None %3
3610 %5 = OpLabel
3611 OpReturn
3612 OpFunctionEnd
3613 )";
3614
3615 CompileSuccessfully(spirv);
3616 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
3617 << getDiagnosticString();
3618 EXPECT_THAT(getDiagnosticString(), Eq(""));
3619 }
3620
TEST_F(ValidateDecorations,BlockLayoutOffsetOverlapBad)3621 TEST_F(ValidateDecorations, BlockLayoutOffsetOverlapBad) {
3622 std::string spirv = R"(
3623 OpCapability Shader
3624 %1 = OpExtInstImport "GLSL.std.450"
3625 OpMemoryModel Logical GLSL450
3626 OpEntryPoint GLCompute %main "main"
3627 OpExecutionMode %main LocalSize 1 1 1
3628 OpMemberDecorate %Outer 0 Offset 0
3629 OpMemberDecorate %Outer 1 Offset 16
3630 OpMemberDecorate %Inner 0 Offset 0
3631 OpMemberDecorate %Inner 1 Offset 16
3632 OpDecorate %Outer Block
3633 OpDecorate %O DescriptorSet 0
3634 OpDecorate %O Binding 0
3635 %void = OpTypeVoid
3636 %3 = OpTypeFunction %void
3637 %uint = OpTypeInt 32 0
3638 %Inner = OpTypeStruct %uint %uint
3639 %Outer = OpTypeStruct %Inner %uint
3640 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3641 %O = OpVariable %_ptr_Uniform_Outer Uniform
3642 %main = OpFunction %void None %3
3643 %5 = OpLabel
3644 OpReturn
3645 OpFunctionEnd
3646 )";
3647
3648 CompileSuccessfully(spirv);
3649 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3650 EXPECT_THAT(
3651 getDiagnosticString(),
3652 HasSubstr(
3653 "Structure id 3 decorated as Block for variable in Uniform storage "
3654 "class must follow standard uniform buffer layout rules: member 1 at "
3655 "offset 16 overlaps previous member ending at offset 31"));
3656 }
3657
TEST_F(ValidateDecorations,BufferBlockEmptyStruct)3658 TEST_F(ValidateDecorations, BufferBlockEmptyStruct) {
3659 std::string spirv = R"(
3660 OpCapability Shader
3661 %1 = OpExtInstImport "GLSL.std.450"
3662 OpMemoryModel Logical GLSL450
3663 OpEntryPoint GLCompute %main "main"
3664 OpExecutionMode %main LocalSize 1 1 1
3665 OpSource GLSL 430
3666 OpMemberDecorate %Output 0 Offset 0
3667 OpDecorate %Output BufferBlock
3668 %void = OpTypeVoid
3669 %3 = OpTypeFunction %void
3670 %S = OpTypeStruct
3671 %Output = OpTypeStruct %S
3672 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3673 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3674 %main = OpFunction %void None %3
3675 %5 = OpLabel
3676 OpReturn
3677 OpFunctionEnd
3678 )";
3679
3680 CompileSuccessfully(spirv);
3681 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
3682 }
3683
TEST_F(ValidateDecorations,RowMajorMatrixTightPackingGood)3684 TEST_F(ValidateDecorations, RowMajorMatrixTightPackingGood) {
3685 // Row major matrix rule:
3686 // A row-major matrix of C columns has a base alignment equal to
3687 // the base alignment of a vector of C matrix components.
3688 // Note: The "matrix component" is the scalar element type.
3689
3690 // The matrix has 3 columns and 2 rows (C=3, R=2).
3691 // So the base alignment of b is the same as a vector of 3 floats, which is 16
3692 // bytes. The matrix consists of two of these, and therefore occupies 2 x 16
3693 // bytes, or 32 bytes.
3694 //
3695 // So the offsets can be:
3696 // a -> 0
3697 // b -> 16
3698 // c -> 48
3699 // d -> 60 ; d fits at bytes 12-15 after offset of c. Tight (vec3;float)
3700 // packing
3701
3702 std::string spirv = R"(
3703 OpCapability Shader
3704 OpMemoryModel Logical GLSL450
3705 OpEntryPoint Vertex %1 "main"
3706 OpSource GLSL 450
3707 OpMemberDecorate %_struct_2 0 Offset 0
3708 OpMemberDecorate %_struct_2 1 RowMajor
3709 OpMemberDecorate %_struct_2 1 Offset 16
3710 OpMemberDecorate %_struct_2 1 MatrixStride 16
3711 OpMemberDecorate %_struct_2 2 Offset 48
3712 OpMemberDecorate %_struct_2 3 Offset 60
3713 OpDecorate %_struct_2 Block
3714 OpDecorate %3 DescriptorSet 0
3715 OpDecorate %3 Binding 0
3716 %void = OpTypeVoid
3717 %5 = OpTypeFunction %void
3718 %float = OpTypeFloat 32
3719 %v4float = OpTypeVector %float 4
3720 %v2float = OpTypeVector %float 2
3721 %mat3v2float = OpTypeMatrix %v2float 3
3722 %v3float = OpTypeVector %float 3
3723 %_struct_2 = OpTypeStruct %v4float %mat3v2float %v3float %float
3724 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
3725 %3 = OpVariable %_ptr_Uniform__struct_2 Uniform
3726 %1 = OpFunction %void None %5
3727 %12 = OpLabel
3728 OpReturn
3729 OpFunctionEnd
3730 )";
3731
3732 CompileSuccessfully(spirv);
3733 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3734 << getDiagnosticString();
3735 }
3736
TEST_F(ValidateDecorations,ArrayArrayRowMajorMatrixTightPackingGood)3737 TEST_F(ValidateDecorations, ArrayArrayRowMajorMatrixTightPackingGood) {
3738 // Like the previous case, but we have an array of arrays of matrices.
3739 // The RowMajor decoration goes on the struct member (surprisingly).
3740
3741 std::string spirv = R"(
3742 OpCapability Shader
3743 OpMemoryModel Logical GLSL450
3744 OpEntryPoint Vertex %1 "main"
3745 OpSource GLSL 450
3746 OpMemberDecorate %_struct_2 0 Offset 0
3747 OpMemberDecorate %_struct_2 1 RowMajor
3748 OpMemberDecorate %_struct_2 1 Offset 16
3749 OpMemberDecorate %_struct_2 1 MatrixStride 16
3750 OpMemberDecorate %_struct_2 2 Offset 80
3751 OpMemberDecorate %_struct_2 3 Offset 92
3752 OpDecorate %arr_mat ArrayStride 32
3753 OpDecorate %arr_arr_mat ArrayStride 32
3754 OpDecorate %_struct_2 Block
3755 OpDecorate %3 DescriptorSet 0
3756 OpDecorate %3 Binding 0
3757 %void = OpTypeVoid
3758 %5 = OpTypeFunction %void
3759 %float = OpTypeFloat 32
3760 %v4float = OpTypeVector %float 4
3761 %v2float = OpTypeVector %float 2
3762 %mat3v2float = OpTypeMatrix %v2float 3
3763 %uint = OpTypeInt 32 0
3764 %uint_1 = OpConstant %uint 1
3765 %uint_2 = OpConstant %uint 2
3766 %arr_mat = OpTypeArray %mat3v2float %uint_1
3767 %arr_arr_mat = OpTypeArray %arr_mat %uint_2
3768 %v3float = OpTypeVector %float 3
3769 %_struct_2 = OpTypeStruct %v4float %arr_arr_mat %v3float %float
3770 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
3771 %3 = OpVariable %_ptr_Uniform__struct_2 Uniform
3772 %1 = OpFunction %void None %5
3773 %12 = OpLabel
3774 OpReturn
3775 OpFunctionEnd
3776 )";
3777
3778 CompileSuccessfully(spirv);
3779 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3780 << getDiagnosticString();
3781 }
3782
TEST_F(ValidateDecorations,ArrayArrayRowMajorMatrixNextMemberOverlapsBad)3783 TEST_F(ValidateDecorations, ArrayArrayRowMajorMatrixNextMemberOverlapsBad) {
3784 // Like the previous case, but the offset of member 2 overlaps the matrix.
3785 std::string spirv = R"(
3786 OpCapability Shader
3787 OpMemoryModel Logical GLSL450
3788 OpEntryPoint Vertex %1 "main"
3789 OpSource GLSL 450
3790 OpMemberDecorate %_struct_2 0 Offset 0
3791 OpMemberDecorate %_struct_2 1 RowMajor
3792 OpMemberDecorate %_struct_2 1 Offset 16
3793 OpMemberDecorate %_struct_2 1 MatrixStride 16
3794 OpMemberDecorate %_struct_2 2 Offset 64
3795 OpMemberDecorate %_struct_2 3 Offset 92
3796 OpDecorate %arr_mat ArrayStride 32
3797 OpDecorate %arr_arr_mat ArrayStride 32
3798 OpDecorate %_struct_2 Block
3799 OpDecorate %3 DescriptorSet 0
3800 OpDecorate %3 Binding 0
3801 %void = OpTypeVoid
3802 %5 = OpTypeFunction %void
3803 %float = OpTypeFloat 32
3804 %v4float = OpTypeVector %float 4
3805 %v2float = OpTypeVector %float 2
3806 %mat3v2float = OpTypeMatrix %v2float 3
3807 %uint = OpTypeInt 32 0
3808 %uint_1 = OpConstant %uint 1
3809 %uint_2 = OpConstant %uint 2
3810 %arr_mat = OpTypeArray %mat3v2float %uint_1
3811 %arr_arr_mat = OpTypeArray %arr_mat %uint_2
3812 %v3float = OpTypeVector %float 3
3813 %_struct_2 = OpTypeStruct %v4float %arr_arr_mat %v3float %float
3814 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
3815 %3 = OpVariable %_ptr_Uniform__struct_2 Uniform
3816 %1 = OpFunction %void None %5
3817 %12 = OpLabel
3818 OpReturn
3819 OpFunctionEnd
3820 )";
3821
3822 CompileSuccessfully(spirv);
3823 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3824 EXPECT_THAT(
3825 getDiagnosticString(),
3826 HasSubstr(
3827 "Structure id 2 decorated as Block for variable in Uniform storage "
3828 "class must follow standard uniform buffer layout rules: member 2 at "
3829 "offset 64 overlaps previous member ending at offset 79"));
3830 }
3831
TEST_F(ValidateDecorations,StorageBufferArraySizeCalculationPackGood)3832 TEST_F(ValidateDecorations, StorageBufferArraySizeCalculationPackGood) {
3833 // Original GLSL
3834
3835 // #version 450
3836 // layout (set=0,binding=0) buffer S {
3837 // uvec3 arr[2][2]; // first 3 elements are 16 bytes, last is 12
3838 // uint i; // Can have offset 60 = 3x16 + 12
3839 // } B;
3840 // void main() {}
3841
3842 std::string spirv = R"(
3843 OpCapability Shader
3844 OpMemoryModel Logical GLSL450
3845 OpEntryPoint Vertex %1 "main"
3846 OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
3847 OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
3848 OpMemberDecorate %_struct_4 0 Offset 0
3849 OpMemberDecorate %_struct_4 1 Offset 60
3850 OpDecorate %_struct_4 BufferBlock
3851 OpDecorate %5 DescriptorSet 0
3852 OpDecorate %5 Binding 0
3853 %void = OpTypeVoid
3854 %7 = OpTypeFunction %void
3855 %uint = OpTypeInt 32 0
3856 %v3uint = OpTypeVector %uint 3
3857 %uint_2 = OpConstant %uint 2
3858 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
3859 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
3860 %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
3861 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
3862 %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
3863 %1 = OpFunction %void None %7
3864 %12 = OpLabel
3865 OpReturn
3866 OpFunctionEnd
3867 )";
3868
3869 CompileSuccessfully(spirv);
3870 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
3871 }
3872
TEST_F(ValidateDecorations,StorageBufferArraySizeCalculationPackBad)3873 TEST_F(ValidateDecorations, StorageBufferArraySizeCalculationPackBad) {
3874 // Like previous but, the offset of the second member is too small.
3875
3876 std::string spirv = R"(
3877 OpCapability Shader
3878 OpMemoryModel Logical GLSL450
3879 OpEntryPoint Vertex %1 "main"
3880 OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
3881 OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
3882 OpMemberDecorate %_struct_4 0 Offset 0
3883 OpMemberDecorate %_struct_4 1 Offset 56
3884 OpDecorate %_struct_4 BufferBlock
3885 OpDecorate %5 DescriptorSet 0
3886 OpDecorate %5 Binding 0
3887 %void = OpTypeVoid
3888 %7 = OpTypeFunction %void
3889 %uint = OpTypeInt 32 0
3890 %v3uint = OpTypeVector %uint 3
3891 %uint_2 = OpConstant %uint 2
3892 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
3893 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
3894 %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
3895 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
3896 %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
3897 %1 = OpFunction %void None %7
3898 %12 = OpLabel
3899 OpReturn
3900 OpFunctionEnd
3901 )";
3902
3903 CompileSuccessfully(spirv);
3904 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3905 EXPECT_THAT(getDiagnosticString(),
3906 HasSubstr("Structure id 4 decorated as BufferBlock for variable "
3907 "in Uniform storage class must follow standard storage "
3908 "buffer layout rules: member 1 at offset 56 overlaps "
3909 "previous member ending at offset 59"));
3910 }
3911
TEST_F(ValidateDecorations,UniformBufferArraySizeCalculationPackGood)3912 TEST_F(ValidateDecorations, UniformBufferArraySizeCalculationPackGood) {
3913 // Like the corresponding buffer block case, but the array padding must
3914 // count for the last element as well, and so the offset of the second
3915 // member must be at least 64.
3916 std::string spirv = R"(
3917 OpCapability Shader
3918 OpMemoryModel Logical GLSL450
3919 OpEntryPoint Vertex %1 "main"
3920 OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
3921 OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
3922 OpMemberDecorate %_struct_4 0 Offset 0
3923 OpMemberDecorate %_struct_4 1 Offset 64
3924 OpDecorate %_struct_4 Block
3925 OpDecorate %5 DescriptorSet 0
3926 OpDecorate %5 Binding 0
3927 %void = OpTypeVoid
3928 %7 = OpTypeFunction %void
3929 %uint = OpTypeInt 32 0
3930 %v3uint = OpTypeVector %uint 3
3931 %uint_2 = OpConstant %uint 2
3932 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
3933 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
3934 %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
3935 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
3936 %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
3937 %1 = OpFunction %void None %7
3938 %12 = OpLabel
3939 OpReturn
3940 OpFunctionEnd
3941 )";
3942
3943 CompileSuccessfully(spirv);
3944 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
3945 }
3946
TEST_F(ValidateDecorations,UniformBufferArraySizeCalculationPackBad)3947 TEST_F(ValidateDecorations, UniformBufferArraySizeCalculationPackBad) {
3948 // Like previous but, the offset of the second member is too small.
3949
3950 std::string spirv = R"(
3951 OpCapability Shader
3952 OpMemoryModel Logical GLSL450
3953 OpEntryPoint Vertex %1 "main"
3954 OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
3955 OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
3956 OpMemberDecorate %_struct_4 0 Offset 0
3957 OpMemberDecorate %_struct_4 1 Offset 60
3958 OpDecorate %_struct_4 Block
3959 OpDecorate %5 DescriptorSet 0
3960 OpDecorate %5 Binding 0
3961 %void = OpTypeVoid
3962 %7 = OpTypeFunction %void
3963 %uint = OpTypeInt 32 0
3964 %v3uint = OpTypeVector %uint 3
3965 %uint_2 = OpConstant %uint 2
3966 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
3967 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
3968 %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
3969 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
3970 %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
3971 %1 = OpFunction %void None %7
3972 %12 = OpLabel
3973 OpReturn
3974 OpFunctionEnd
3975 )";
3976
3977 CompileSuccessfully(spirv);
3978 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3979 EXPECT_THAT(
3980 getDiagnosticString(),
3981 HasSubstr(
3982 "Structure id 4 decorated as Block for variable in Uniform storage "
3983 "class must follow standard uniform buffer layout rules: member 1 at "
3984 "offset 60 overlaps previous member ending at offset 63"));
3985 }
3986
TEST_F(ValidateDecorations,LayoutNotCheckedWhenSkipBlockLayout)3987 TEST_F(ValidateDecorations, LayoutNotCheckedWhenSkipBlockLayout) {
3988 // Checks that block layout is not verified in skipping block layout mode.
3989 // Even for obviously wrong layout.
3990 std::string spirv = R"(
3991 OpCapability Shader
3992 OpMemoryModel Logical GLSL450
3993 OpEntryPoint Vertex %main "main"
3994 OpSource GLSL 450
3995 OpMemberDecorate %S 0 Offset 3 ; wrong alignment
3996 OpMemberDecorate %S 1 Offset 3 ; same offset as before!
3997 OpDecorate %S Block
3998 OpDecorate %B DescriptorSet 0
3999 OpDecorate %B Binding 0
4000 %void = OpTypeVoid
4001 %3 = OpTypeFunction %void
4002 %float = OpTypeFloat 32
4003 %v3float = OpTypeVector %float 3
4004 %S = OpTypeStruct %float %v3float
4005 %_ptr_Uniform_S = OpTypePointer Uniform %S
4006 %B = OpVariable %_ptr_Uniform_S Uniform
4007 %main = OpFunction %void None %3
4008 %5 = OpLabel
4009 OpReturn
4010 OpFunctionEnd
4011 )";
4012
4013 CompileSuccessfully(spirv);
4014 spvValidatorOptionsSetSkipBlockLayout(getValidatorOptions(), true);
4015 EXPECT_EQ(SPV_SUCCESS,
4016 ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
4017 EXPECT_THAT(getDiagnosticString(), Eq(""));
4018 }
4019
TEST_F(ValidateDecorations,EntryPointVariableWrongStorageClass)4020 TEST_F(ValidateDecorations, EntryPointVariableWrongStorageClass) {
4021 const std::string spirv = R"(
4022 OpCapability Shader
4023 OpMemoryModel Logical GLSL450
4024 OpEntryPoint Fragment %1 "func" %var
4025 OpExecutionMode %1 OriginUpperLeft
4026 %void = OpTypeVoid
4027 %int = OpTypeInt 32 0
4028 %ptr_int_Workgroup = OpTypePointer Workgroup %int
4029 %var = OpVariable %ptr_int_Workgroup Workgroup
4030 %func_ty = OpTypeFunction %void
4031 %1 = OpFunction %void None %func_ty
4032 %2 = OpLabel
4033 OpReturn
4034 OpFunctionEnd
4035 )";
4036
4037 CompileSuccessfully(spirv);
4038 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4039 EXPECT_THAT(getDiagnosticString(),
4040 HasSubstr("OpEntryPoint interfaces must be OpVariables with "
4041 "Storage Class of Input(1) or Output(3). Found Storage "
4042 "Class 4 for Entry Point id 1."));
4043 }
4044
TEST_F(ValidateDecorations,VulkanMemoryModelNonCoherent)4045 TEST_F(ValidateDecorations, VulkanMemoryModelNonCoherent) {
4046 const std::string spirv = R"(
4047 OpCapability Shader
4048 OpCapability VulkanMemoryModelKHR
4049 OpCapability Linkage
4050 OpExtension "SPV_KHR_vulkan_memory_model"
4051 OpExtension "SPV_KHR_storage_buffer_storage_class"
4052 OpMemoryModel Logical VulkanKHR
4053 OpDecorate %1 Coherent
4054 %2 = OpTypeInt 32 0
4055 %3 = OpTypePointer StorageBuffer %2
4056 %1 = OpVariable %3 StorageBuffer
4057 )";
4058
4059 CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4060 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4061 EXPECT_THAT(getDiagnosticString(),
4062 HasSubstr("Coherent decoration targeting 1[%1] is "
4063 "banned when using the Vulkan memory model."));
4064 }
4065
TEST_F(ValidateDecorations,VulkanMemoryModelNoCoherentMember)4066 TEST_F(ValidateDecorations, VulkanMemoryModelNoCoherentMember) {
4067 const std::string spirv = R"(
4068 OpCapability Shader
4069 OpCapability VulkanMemoryModelKHR
4070 OpCapability Linkage
4071 OpExtension "SPV_KHR_vulkan_memory_model"
4072 OpMemoryModel Logical VulkanKHR
4073 OpMemberDecorate %1 0 Coherent
4074 %2 = OpTypeInt 32 0
4075 %1 = OpTypeStruct %2 %2
4076 )";
4077
4078 CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4079 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4080 EXPECT_THAT(
4081 getDiagnosticString(),
4082 HasSubstr("Coherent decoration targeting 1[%_struct_1] (member index 0) "
4083 "is banned when using the Vulkan memory model."));
4084 }
4085
TEST_F(ValidateDecorations,VulkanMemoryModelNoVolatile)4086 TEST_F(ValidateDecorations, VulkanMemoryModelNoVolatile) {
4087 const std::string spirv = R"(
4088 OpCapability Shader
4089 OpCapability VulkanMemoryModelKHR
4090 OpCapability Linkage
4091 OpExtension "SPV_KHR_vulkan_memory_model"
4092 OpExtension "SPV_KHR_storage_buffer_storage_class"
4093 OpMemoryModel Logical VulkanKHR
4094 OpDecorate %1 Volatile
4095 %2 = OpTypeInt 32 0
4096 %3 = OpTypePointer StorageBuffer %2
4097 %1 = OpVariable %3 StorageBuffer
4098 )";
4099
4100 CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4101 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4102 EXPECT_THAT(getDiagnosticString(),
4103 HasSubstr("Volatile decoration targeting 1[%1] is banned when "
4104 "using the Vulkan memory model."));
4105 }
4106
TEST_F(ValidateDecorations,VulkanMemoryModelNoVolatileMember)4107 TEST_F(ValidateDecorations, VulkanMemoryModelNoVolatileMember) {
4108 const std::string spirv = R"(
4109 OpCapability Shader
4110 OpCapability VulkanMemoryModelKHR
4111 OpCapability Linkage
4112 OpExtension "SPV_KHR_vulkan_memory_model"
4113 OpMemoryModel Logical VulkanKHR
4114 OpMemberDecorate %1 1 Volatile
4115 %2 = OpTypeInt 32 0
4116 %1 = OpTypeStruct %2 %2
4117 )";
4118
4119 CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4120 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4121 EXPECT_THAT(getDiagnosticString(),
4122 HasSubstr("Volatile decoration targeting 1[%_struct_1] (member "
4123 "index 1) is banned when using the Vulkan memory "
4124 "model."));
4125 }
4126
TEST_F(ValidateDecorations,FPRoundingModeGood)4127 TEST_F(ValidateDecorations, FPRoundingModeGood) {
4128 std::string spirv = R"(
4129 OpCapability Shader
4130 OpCapability Linkage
4131 OpCapability StorageBuffer16BitAccess
4132 OpExtension "SPV_KHR_storage_buffer_storage_class"
4133 OpExtension "SPV_KHR_variable_pointers"
4134 OpExtension "SPV_KHR_16bit_storage"
4135 OpMemoryModel Logical GLSL450
4136 OpEntryPoint GLCompute %main "main"
4137 OpDecorate %_ FPRoundingMode RTE
4138 %half = OpTypeFloat 16
4139 %float = OpTypeFloat 32
4140 %float_1_25 = OpConstant %float 1.25
4141 %half_ptr = OpTypePointer StorageBuffer %half
4142 %half_ptr_var = OpVariable %half_ptr StorageBuffer
4143 %void = OpTypeVoid
4144 %func = OpTypeFunction %void
4145 %main = OpFunction %void None %func
4146 %main_entry = OpLabel
4147 %_ = OpFConvert %half %float_1_25
4148 OpStore %half_ptr_var %_
4149 OpReturn
4150 OpFunctionEnd
4151 )";
4152
4153 CompileSuccessfully(spirv);
4154 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4155 }
4156
TEST_F(ValidateDecorations,FPRoundingModeVectorGood)4157 TEST_F(ValidateDecorations, FPRoundingModeVectorGood) {
4158 std::string spirv = R"(
4159 OpCapability Shader
4160 OpCapability Linkage
4161 OpCapability StorageBuffer16BitAccess
4162 OpExtension "SPV_KHR_storage_buffer_storage_class"
4163 OpExtension "SPV_KHR_variable_pointers"
4164 OpExtension "SPV_KHR_16bit_storage"
4165 OpMemoryModel Logical GLSL450
4166 OpEntryPoint GLCompute %main "main"
4167 OpDecorate %_ FPRoundingMode RTE
4168 %half = OpTypeFloat 16
4169 %float = OpTypeFloat 32
4170 %v2half = OpTypeVector %half 2
4171 %v2float = OpTypeVector %float 2
4172 %float_1_25 = OpConstant %float 1.25
4173 %floats = OpConstantComposite %v2float %float_1_25 %float_1_25
4174 %halfs_ptr = OpTypePointer StorageBuffer %v2half
4175 %halfs_ptr_var = OpVariable %halfs_ptr StorageBuffer
4176 %void = OpTypeVoid
4177 %func = OpTypeFunction %void
4178 %main = OpFunction %void None %func
4179 %main_entry = OpLabel
4180 %_ = OpFConvert %v2half %floats
4181 OpStore %halfs_ptr_var %_
4182 OpReturn
4183 OpFunctionEnd
4184 )";
4185
4186 CompileSuccessfully(spirv);
4187 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4188 }
4189
TEST_F(ValidateDecorations,FPRoundingModeNotOpFConvert)4190 TEST_F(ValidateDecorations, FPRoundingModeNotOpFConvert) {
4191 std::string spirv = R"(
4192 OpCapability Shader
4193 OpCapability Linkage
4194 OpCapability StorageBuffer16BitAccess
4195 OpExtension "SPV_KHR_storage_buffer_storage_class"
4196 OpExtension "SPV_KHR_variable_pointers"
4197 OpExtension "SPV_KHR_16bit_storage"
4198 OpMemoryModel Logical GLSL450
4199 OpEntryPoint GLCompute %main "main"
4200 OpDecorate %_ FPRoundingMode RTE
4201 %short = OpTypeInt 16 1
4202 %int = OpTypeInt 32 1
4203 %int_17 = OpConstant %int 17
4204 %short_ptr = OpTypePointer StorageBuffer %short
4205 %short_ptr_var = OpVariable %short_ptr StorageBuffer
4206 %void = OpTypeVoid
4207 %func = OpTypeFunction %void
4208 %main = OpFunction %void None %func
4209 %main_entry = OpLabel
4210 %_ = OpSConvert %short %int_17
4211 OpStore %short_ptr_var %_
4212 OpReturn
4213 OpFunctionEnd
4214 )";
4215
4216 CompileSuccessfully(spirv);
4217 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4218 EXPECT_THAT(getDiagnosticString(),
4219 HasSubstr("FPRoundingMode decoration can be applied only to a "
4220 "width-only conversion instruction for floating-point "
4221 "object."));
4222 }
4223
TEST_F(ValidateDecorations,FPRoundingModeNoOpStoreGood)4224 TEST_F(ValidateDecorations, FPRoundingModeNoOpStoreGood) {
4225 std::string spirv = R"(
4226 OpCapability Shader
4227 OpCapability Linkage
4228 OpCapability StorageBuffer16BitAccess
4229 OpExtension "SPV_KHR_storage_buffer_storage_class"
4230 OpExtension "SPV_KHR_variable_pointers"
4231 OpExtension "SPV_KHR_16bit_storage"
4232 OpMemoryModel Logical GLSL450
4233 OpEntryPoint GLCompute %main "main"
4234 OpDecorate %_ FPRoundingMode RTE
4235 %half = OpTypeFloat 16
4236 %float = OpTypeFloat 32
4237 %float_1_25 = OpConstant %float 1.25
4238 %half_ptr = OpTypePointer StorageBuffer %half
4239 %half_ptr_var = OpVariable %half_ptr StorageBuffer
4240 %void = OpTypeVoid
4241 %func = OpTypeFunction %void
4242 %main = OpFunction %void None %func
4243 %main_entry = OpLabel
4244 %_ = OpFConvert %half %float_1_25
4245 OpReturn
4246 OpFunctionEnd
4247 )";
4248
4249 CompileSuccessfully(spirv);
4250 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4251 }
4252
TEST_F(ValidateDecorations,FPRoundingModeFConvert64to16Good)4253 TEST_F(ValidateDecorations, FPRoundingModeFConvert64to16Good) {
4254 std::string spirv = R"(
4255 OpCapability Shader
4256 OpCapability Linkage
4257 OpCapability StorageBuffer16BitAccess
4258 OpCapability Float64
4259 OpExtension "SPV_KHR_storage_buffer_storage_class"
4260 OpExtension "SPV_KHR_variable_pointers"
4261 OpExtension "SPV_KHR_16bit_storage"
4262 OpMemoryModel Logical GLSL450
4263 OpEntryPoint GLCompute %main "main"
4264 OpDecorate %_ FPRoundingMode RTE
4265 %half = OpTypeFloat 16
4266 %double = OpTypeFloat 64
4267 %double_1_25 = OpConstant %double 1.25
4268 %half_ptr = OpTypePointer StorageBuffer %half
4269 %half_ptr_var = OpVariable %half_ptr StorageBuffer
4270 %void = OpTypeVoid
4271 %func = OpTypeFunction %void
4272 %main = OpFunction %void None %func
4273 %main_entry = OpLabel
4274 %_ = OpFConvert %half %double_1_25
4275 OpStore %half_ptr_var %_
4276 OpReturn
4277 OpFunctionEnd
4278 )";
4279
4280 CompileSuccessfully(spirv);
4281 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4282 }
4283
TEST_F(ValidateDecorations,FPRoundingModeNotStoreInFloat16)4284 TEST_F(ValidateDecorations, FPRoundingModeNotStoreInFloat16) {
4285 std::string spirv = R"(
4286 OpCapability Shader
4287 OpCapability Linkage
4288 OpCapability StorageBuffer16BitAccess
4289 OpCapability Float64
4290 OpExtension "SPV_KHR_storage_buffer_storage_class"
4291 OpExtension "SPV_KHR_variable_pointers"
4292 OpExtension "SPV_KHR_16bit_storage"
4293 OpMemoryModel Logical GLSL450
4294 OpEntryPoint GLCompute %main "main"
4295 OpDecorate %_ FPRoundingMode RTE
4296 %float = OpTypeFloat 32
4297 %double = OpTypeFloat 64
4298 %double_1_25 = OpConstant %double 1.25
4299 %float_ptr = OpTypePointer StorageBuffer %float
4300 %float_ptr_var = OpVariable %float_ptr StorageBuffer
4301 %void = OpTypeVoid
4302 %func = OpTypeFunction %void
4303 %main = OpFunction %void None %func
4304 %main_entry = OpLabel
4305 %_ = OpFConvert %float %double_1_25
4306 OpStore %float_ptr_var %_
4307 OpReturn
4308 OpFunctionEnd
4309 )";
4310
4311 CompileSuccessfully(spirv);
4312 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4313 EXPECT_THAT(
4314 getDiagnosticString(),
4315 HasSubstr("FPRoundingMode decoration can be applied only to the "
4316 "Object operand of an OpStore storing through a "
4317 "pointer to a 16-bit floating-point scalar or vector object."));
4318 }
4319
TEST_F(ValidateDecorations,FPRoundingModeBadStorageClass)4320 TEST_F(ValidateDecorations, FPRoundingModeBadStorageClass) {
4321 std::string spirv = R"(
4322 OpCapability Shader
4323 OpCapability Linkage
4324 OpCapability StorageBuffer16BitAccess
4325 OpExtension "SPV_KHR_storage_buffer_storage_class"
4326 OpExtension "SPV_KHR_variable_pointers"
4327 OpExtension "SPV_KHR_16bit_storage"
4328 OpMemoryModel Logical GLSL450
4329 OpEntryPoint GLCompute %main "main"
4330 OpDecorate %_ FPRoundingMode RTE
4331 %half = OpTypeFloat 16
4332 %float = OpTypeFloat 32
4333 %float_1_25 = OpConstant %float 1.25
4334 %half_ptr = OpTypePointer Private %half
4335 %half_ptr_var = OpVariable %half_ptr Private
4336 %void = OpTypeVoid
4337 %func = OpTypeFunction %void
4338 %main = OpFunction %void None %func
4339 %main_entry = OpLabel
4340 %_ = OpFConvert %half %float_1_25
4341 OpStore %half_ptr_var %_
4342 OpReturn
4343 OpFunctionEnd
4344 )";
4345
4346 CompileSuccessfully(spirv);
4347 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4348 EXPECT_THAT(
4349 getDiagnosticString(),
4350 HasSubstr("FPRoundingMode decoration can be applied only to the "
4351 "Object operand of an OpStore in the StorageBuffer, Uniform, "
4352 "PushConstant, Input, or Output Storage Classes."));
4353 }
4354
TEST_F(ValidateDecorations,FPRoundingModeMultipleOpStoreGood)4355 TEST_F(ValidateDecorations, FPRoundingModeMultipleOpStoreGood) {
4356 std::string spirv = R"(
4357 OpCapability Shader
4358 OpCapability Linkage
4359 OpCapability StorageBuffer16BitAccess
4360 OpExtension "SPV_KHR_storage_buffer_storage_class"
4361 OpExtension "SPV_KHR_variable_pointers"
4362 OpExtension "SPV_KHR_16bit_storage"
4363 OpMemoryModel Logical GLSL450
4364 OpEntryPoint GLCompute %main "main"
4365 OpDecorate %_ FPRoundingMode RTE
4366 %half = OpTypeFloat 16
4367 %float = OpTypeFloat 32
4368 %float_1_25 = OpConstant %float 1.25
4369 %half_ptr = OpTypePointer StorageBuffer %half
4370 %half_ptr_var_0 = OpVariable %half_ptr StorageBuffer
4371 %half_ptr_var_1 = OpVariable %half_ptr StorageBuffer
4372 %half_ptr_var_2 = OpVariable %half_ptr StorageBuffer
4373 %void = OpTypeVoid
4374 %func = OpTypeFunction %void
4375 %main = OpFunction %void None %func
4376 %main_entry = OpLabel
4377 %_ = OpFConvert %half %float_1_25
4378 OpStore %half_ptr_var_0 %_
4379 OpStore %half_ptr_var_1 %_
4380 OpStore %half_ptr_var_2 %_
4381 OpReturn
4382 OpFunctionEnd
4383 )";
4384
4385 CompileSuccessfully(spirv);
4386 EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4387 }
4388
TEST_F(ValidateDecorations,FPRoundingModeMultipleUsesBad)4389 TEST_F(ValidateDecorations, FPRoundingModeMultipleUsesBad) {
4390 std::string spirv = R"(
4391 OpCapability Shader
4392 OpCapability Linkage
4393 OpCapability StorageBuffer16BitAccess
4394 OpExtension "SPV_KHR_storage_buffer_storage_class"
4395 OpExtension "SPV_KHR_variable_pointers"
4396 OpExtension "SPV_KHR_16bit_storage"
4397 OpMemoryModel Logical GLSL450
4398 OpEntryPoint GLCompute %main "main"
4399 OpDecorate %_ FPRoundingMode RTE
4400 %half = OpTypeFloat 16
4401 %float = OpTypeFloat 32
4402 %float_1_25 = OpConstant %float 1.25
4403 %half_ptr = OpTypePointer StorageBuffer %half
4404 %half_ptr_var_0 = OpVariable %half_ptr StorageBuffer
4405 %half_ptr_var_1 = OpVariable %half_ptr StorageBuffer
4406 %void = OpTypeVoid
4407 %func = OpTypeFunction %void
4408 %main = OpFunction %void None %func
4409 %main_entry = OpLabel
4410 %_ = OpFConvert %half %float_1_25
4411 OpStore %half_ptr_var_0 %_
4412 %result = OpFAdd %half %_ %_
4413 OpStore %half_ptr_var_1 %_
4414 OpReturn
4415 OpFunctionEnd
4416 )";
4417
4418 CompileSuccessfully(spirv);
4419 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4420 EXPECT_THAT(getDiagnosticString(),
4421 HasSubstr("FPRoundingMode decoration can be applied only to the "
4422 "Object operand of an OpStore."));
4423 }
4424
TEST_F(ValidateDecorations,GroupDecorateTargetsDecorationGroup)4425 TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup) {
4426 std::string spirv = R"(
4427 OpCapability Shader
4428 OpCapability Linkage
4429 OpMemoryModel Logical GLSL450
4430 %1 = OpDecorationGroup
4431 OpGroupDecorate %1 %1
4432 )";
4433
4434 CompileSuccessfully(spirv);
4435 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4436 EXPECT_THAT(getDiagnosticString(),
4437 HasSubstr("OpGroupDecorate may not target OpDecorationGroup <id> "
4438 "'1[%1]'"));
4439 }
4440
TEST_F(ValidateDecorations,GroupDecorateTargetsDecorationGroup2)4441 TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup2) {
4442 std::string spirv = R"(
4443 OpCapability Shader
4444 OpCapability Linkage
4445 OpMemoryModel Logical GLSL450
4446 %1 = OpDecorationGroup
4447 OpGroupDecorate %1 %2 %1
4448 %2 = OpTypeVoid
4449 )";
4450
4451 CompileSuccessfully(spirv);
4452 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4453 EXPECT_THAT(getDiagnosticString(),
4454 HasSubstr("OpGroupDecorate may not target OpDecorationGroup <id> "
4455 "'1[%1]'"));
4456 }
4457
TEST_F(ValidateDecorations,RecurseThroughRuntimeArray)4458 TEST_F(ValidateDecorations, RecurseThroughRuntimeArray) {
4459 const std::string spirv = R"(
4460 OpCapability Shader
4461 OpCapability Linkage
4462 OpMemoryModel Logical GLSL450
4463 OpDecorate %outer Block
4464 OpMemberDecorate %inner 0 Offset 0
4465 OpMemberDecorate %inner 1 Offset 1
4466 OpDecorate %runtime ArrayStride 16
4467 OpMemberDecorate %outer 0 Offset 0
4468 %int = OpTypeInt 32 0
4469 %inner = OpTypeStruct %int %int
4470 %runtime = OpTypeRuntimeArray %inner
4471 %outer = OpTypeStruct %runtime
4472 %outer_ptr = OpTypePointer Uniform %outer
4473 %var = OpVariable %outer_ptr Uniform
4474 )";
4475
4476 CompileSuccessfully(spirv);
4477 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4478 EXPECT_THAT(
4479 getDiagnosticString(),
4480 HasSubstr("Structure id 2 decorated as Block for variable in Uniform "
4481 "storage class must follow standard uniform buffer layout "
4482 "rules: member 1 at offset 1 is not aligned to 4"));
4483 }
4484
TEST_F(ValidateDecorations,EmptyStructAtNonZeroOffsetGood)4485 TEST_F(ValidateDecorations, EmptyStructAtNonZeroOffsetGood) {
4486 const std::string spirv = R"(
4487 OpCapability Shader
4488 OpMemoryModel Logical GLSL450
4489 OpEntryPoint GLCompute %main "main"
4490 OpExecutionMode %main LocalSize 1 1 1
4491 OpDecorate %struct Block
4492 OpMemberDecorate %struct 0 Offset 0
4493 OpMemberDecorate %struct 1 Offset 16
4494 OpDecorate %var DescriptorSet 0
4495 OpDecorate %var Binding 0
4496 %void = OpTypeVoid
4497 %float = OpTypeFloat 32
4498 %empty = OpTypeStruct
4499 %struct = OpTypeStruct %float %empty
4500 %ptr_struct_ubo = OpTypePointer Uniform %struct
4501 %var = OpVariable %ptr_struct_ubo Uniform
4502 %voidfn = OpTypeFunction %void
4503 %main = OpFunction %void None %voidfn
4504 %entry = OpLabel
4505 OpReturn
4506 OpFunctionEnd
4507 )";
4508
4509 CompileSuccessfully(spirv);
4510 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4511 }
4512
4513 // Uniform decoration
4514
TEST_F(ValidateDecorations,UniformDecorationGood)4515 TEST_F(ValidateDecorations, UniformDecorationGood) {
4516 const std::string spirv = R"(
4517 OpCapability Shader
4518 OpMemoryModel Logical Simple
4519 OpEntryPoint GLCompute %main "main"
4520 OpExecutionMode %main LocalSize 1 1 1
4521 OpDecorate %int0 Uniform
4522 OpDecorate %var Uniform
4523 OpDecorate %val Uniform
4524 %void = OpTypeVoid
4525 %int = OpTypeInt 32 1
4526 %int0 = OpConstantNull %int
4527 %intptr = OpTypePointer Private %int
4528 %var = OpVariable %intptr Private
4529 %fn = OpTypeFunction %void
4530 %main = OpFunction %void None %fn
4531 %entry = OpLabel
4532 %val = OpLoad %int %var
4533 OpReturn
4534 OpFunctionEnd
4535 )";
4536
4537 CompileSuccessfully(spirv);
4538 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4539 EXPECT_THAT(getDiagnosticString(), Eq(""));
4540 }
4541
TEST_F(ValidateDecorations,UniformDecorationTargetsTypeBad)4542 TEST_F(ValidateDecorations, UniformDecorationTargetsTypeBad) {
4543 const std::string spirv = R"(
4544 OpCapability Shader
4545 OpMemoryModel Logical Simple
4546 OpEntryPoint GLCompute %main "main"
4547 OpExecutionMode %main LocalSize 1 1 1
4548 OpDecorate %fn Uniform
4549 %void = OpTypeVoid
4550 %fn = OpTypeFunction %void
4551 %main = OpFunction %void None %fn
4552 %entry = OpLabel
4553 OpReturn
4554 OpFunctionEnd
4555 )";
4556
4557 CompileSuccessfully(spirv);
4558 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4559 EXPECT_THAT(getDiagnosticString(),
4560 HasSubstr("Uniform decoration applied to a non-object"));
4561 EXPECT_THAT(getDiagnosticString(), HasSubstr("%2 = OpTypeFunction %void"));
4562 }
4563
TEST_F(ValidateDecorations,UniformDecorationTargetsVoidValueBad)4564 TEST_F(ValidateDecorations, UniformDecorationTargetsVoidValueBad) {
4565 const std::string spirv = R"(
4566 OpCapability Shader
4567 OpMemoryModel Logical Simple
4568 OpEntryPoint GLCompute %main "main"
4569 OpExecutionMode %main LocalSize 1 1 1
4570 OpName %call "call"
4571 OpName %myfunc "myfunc"
4572 OpDecorate %call Uniform
4573 %void = OpTypeVoid
4574 %fnty = OpTypeFunction %void
4575 %myfunc = OpFunction %void None %fnty
4576 %myfuncentry = OpLabel
4577 OpReturn
4578 OpFunctionEnd
4579 %main = OpFunction %void None %fnty
4580 %entry = OpLabel
4581 %call = OpFunctionCall %void %myfunc
4582 OpReturn
4583 OpFunctionEnd
4584 )";
4585
4586 CompileSuccessfully(spirv);
4587 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4588 EXPECT_THAT(getDiagnosticString(),
4589 HasSubstr("Uniform decoration applied to a value with void type\n"
4590 " %call = OpFunctionCall %void %myfunc"));
4591 }
4592
TEST_F(ValidateDecorations,MultipleOffsetDecorationsOnSameID)4593 TEST_F(ValidateDecorations, MultipleOffsetDecorationsOnSameID) {
4594 std::string spirv = R"(
4595 OpCapability Shader
4596 OpMemoryModel Logical GLSL450
4597 OpEntryPoint Fragment %1 "main"
4598 OpExecutionMode %1 OriginUpperLeft
4599
4600 OpMemberDecorate %struct 0 Offset 0
4601 OpMemberDecorate %struct 0 Offset 0
4602
4603 %void = OpTypeVoid
4604 %voidfn = OpTypeFunction %void
4605 %float = OpTypeFloat 32
4606 %struct = OpTypeStruct %float
4607
4608 %1 = OpFunction %void None %voidfn
4609 %label = OpLabel
4610 OpReturn
4611 OpFunctionEnd
4612 )";
4613
4614 CompileSuccessfully(spirv);
4615 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4616 EXPECT_THAT(getDiagnosticString(),
4617 HasSubstr("ID '2', member '0' decorated with Offset multiple "
4618 "times is not allowed."));
4619 }
4620
TEST_F(ValidateDecorations,MultipleArrayStrideDecorationsOnSameID)4621 TEST_F(ValidateDecorations, MultipleArrayStrideDecorationsOnSameID) {
4622 std::string spirv = R"(
4623 OpCapability Shader
4624 OpMemoryModel Logical GLSL450
4625 OpEntryPoint Fragment %1 "main"
4626 OpExecutionMode %1 OriginUpperLeft
4627
4628 OpDecorate %array ArrayStride 4
4629 OpDecorate %array ArrayStride 4
4630
4631 %void = OpTypeVoid
4632 %voidfn = OpTypeFunction %void
4633 %float = OpTypeFloat 32
4634 %uint = OpTypeInt 32 0
4635 %uint_4 = OpConstant %uint 4
4636 %array = OpTypeArray %float %uint_4
4637
4638 %1 = OpFunction %void None %voidfn
4639 %label = OpLabel
4640 OpReturn
4641 OpFunctionEnd
4642 )";
4643
4644 CompileSuccessfully(spirv);
4645 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4646 EXPECT_THAT(getDiagnosticString(),
4647 HasSubstr("ID '2' decorated with ArrayStride multiple "
4648 "times is not allowed."));
4649 }
4650
TEST_F(ValidateDecorations,MultipleMatrixStrideDecorationsOnSameID)4651 TEST_F(ValidateDecorations, MultipleMatrixStrideDecorationsOnSameID) {
4652 std::string spirv = R"(
4653 OpCapability Shader
4654 OpMemoryModel Logical GLSL450
4655 OpEntryPoint Fragment %1 "main"
4656 OpExecutionMode %1 OriginUpperLeft
4657
4658 OpMemberDecorate %struct 0 Offset 0
4659 OpMemberDecorate %struct 0 ColMajor
4660 OpMemberDecorate %struct 0 MatrixStride 16
4661 OpMemberDecorate %struct 0 MatrixStride 16
4662
4663 %void = OpTypeVoid
4664 %voidfn = OpTypeFunction %void
4665 %float = OpTypeFloat 32
4666 %fvec4 = OpTypeVector %float 4
4667 %fmat4 = OpTypeMatrix %fvec4 4
4668 %struct = OpTypeStruct %fmat4
4669
4670 %1 = OpFunction %void None %voidfn
4671 %label = OpLabel
4672 OpReturn
4673 OpFunctionEnd
4674 )";
4675
4676 CompileSuccessfully(spirv);
4677 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4678 EXPECT_THAT(getDiagnosticString(),
4679 HasSubstr("ID '2', member '0' decorated with MatrixStride "
4680 "multiple times is not allowed."));
4681 }
4682
TEST_F(ValidateDecorations,MultipleRowMajorDecorationsOnSameID)4683 TEST_F(ValidateDecorations, MultipleRowMajorDecorationsOnSameID) {
4684 std::string spirv = R"(
4685 OpCapability Shader
4686 OpMemoryModel Logical GLSL450
4687 OpEntryPoint Fragment %1 "main"
4688 OpExecutionMode %1 OriginUpperLeft
4689
4690 OpMemberDecorate %struct 0 Offset 0
4691 OpMemberDecorate %struct 0 MatrixStride 16
4692 OpMemberDecorate %struct 0 RowMajor
4693 OpMemberDecorate %struct 0 RowMajor
4694
4695 %void = OpTypeVoid
4696 %voidfn = OpTypeFunction %void
4697 %float = OpTypeFloat 32
4698 %fvec4 = OpTypeVector %float 4
4699 %fmat4 = OpTypeMatrix %fvec4 4
4700 %struct = OpTypeStruct %fmat4
4701
4702 %1 = OpFunction %void None %voidfn
4703 %label = OpLabel
4704 OpReturn
4705 OpFunctionEnd
4706 )";
4707
4708 CompileSuccessfully(spirv);
4709 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4710 EXPECT_THAT(getDiagnosticString(),
4711 HasSubstr("ID '2', member '0' decorated with RowMajor multiple "
4712 "times is not allowed."));
4713 }
4714
TEST_F(ValidateDecorations,MultipleColMajorDecorationsOnSameID)4715 TEST_F(ValidateDecorations, MultipleColMajorDecorationsOnSameID) {
4716 std::string spirv = R"(
4717 OpCapability Shader
4718 OpMemoryModel Logical GLSL450
4719 OpEntryPoint Fragment %1 "main"
4720 OpExecutionMode %1 OriginUpperLeft
4721
4722 OpMemberDecorate %struct 0 Offset 0
4723 OpMemberDecorate %struct 0 MatrixStride 16
4724 OpMemberDecorate %struct 0 ColMajor
4725 OpMemberDecorate %struct 0 ColMajor
4726
4727 %void = OpTypeVoid
4728 %voidfn = OpTypeFunction %void
4729 %float = OpTypeFloat 32
4730 %fvec4 = OpTypeVector %float 4
4731 %fmat4 = OpTypeMatrix %fvec4 4
4732 %struct = OpTypeStruct %fmat4
4733
4734 %1 = OpFunction %void None %voidfn
4735 %label = OpLabel
4736 OpReturn
4737 OpFunctionEnd
4738 )";
4739
4740 CompileSuccessfully(spirv);
4741 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4742 EXPECT_THAT(getDiagnosticString(),
4743 HasSubstr("ID '2', member '0' decorated with ColMajor multiple "
4744 "times is not allowed."));
4745 }
4746
TEST_F(ValidateDecorations,RowMajorAndColMajorDecorationsOnSameID)4747 TEST_F(ValidateDecorations, RowMajorAndColMajorDecorationsOnSameID) {
4748 std::string spirv = R"(
4749 OpCapability Shader
4750 OpMemoryModel Logical GLSL450
4751 OpEntryPoint Fragment %1 "main"
4752 OpExecutionMode %1 OriginUpperLeft
4753
4754 OpMemberDecorate %struct 0 Offset 0
4755 OpMemberDecorate %struct 0 MatrixStride 16
4756 OpMemberDecorate %struct 0 ColMajor
4757 OpMemberDecorate %struct 0 RowMajor
4758
4759 %void = OpTypeVoid
4760 %voidfn = OpTypeFunction %void
4761 %float = OpTypeFloat 32
4762 %fvec4 = OpTypeVector %float 4
4763 %fmat4 = OpTypeMatrix %fvec4 4
4764 %struct = OpTypeStruct %fmat4
4765
4766 %1 = OpFunction %void None %voidfn
4767 %label = OpLabel
4768 OpReturn
4769 OpFunctionEnd
4770 )";
4771
4772 CompileSuccessfully(spirv);
4773 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4774 EXPECT_THAT(getDiagnosticString(),
4775 HasSubstr("ID '2', member '0' decorated with both RowMajor and "
4776 "ColMajor is not allowed."));
4777 }
4778
TEST_F(ValidateDecorations,BlockAndBufferBlockDecorationsOnSameID)4779 TEST_F(ValidateDecorations, BlockAndBufferBlockDecorationsOnSameID) {
4780 std::string spirv = R"(
4781 OpCapability Shader
4782 OpMemoryModel Logical GLSL450
4783 OpEntryPoint Fragment %1 "main"
4784 OpExecutionMode %1 OriginUpperLeft
4785
4786 OpDecorate %struct Block
4787 OpDecorate %struct BufferBlock
4788 OpMemberDecorate %struct 0 Offset 0
4789 OpMemberDecorate %struct 0 MatrixStride 16
4790 OpMemberDecorate %struct 0 RowMajor
4791
4792 %void = OpTypeVoid
4793 %voidfn = OpTypeFunction %void
4794 %float = OpTypeFloat 32
4795 %fvec4 = OpTypeVector %float 4
4796 %fmat4 = OpTypeMatrix %fvec4 4
4797 %struct = OpTypeStruct %fmat4
4798
4799 %1 = OpFunction %void None %voidfn
4800 %label = OpLabel
4801 OpReturn
4802 OpFunctionEnd
4803 )";
4804
4805 CompileSuccessfully(spirv);
4806 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4807 EXPECT_THAT(
4808 getDiagnosticString(),
4809 HasSubstr(
4810 "ID '2' decorated with both BufferBlock and Block is not allowed."));
4811 }
4812
4813 } // namespace
4814 } // namespace val
4815 } // namespace spvtools
4816