1 // Copyright (c) 2018 Google LLC.
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 #include <sstream>
16 #include <string>
17 #include <vector>
18
19 #include "gmock/gmock.h"
20 #include "source/spirv_target_env.h"
21 #include "test/test_fixture.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::Combine;
30 using ::testing::HasSubstr;
31 using ::testing::Values;
32 using ::testing::ValuesIn;
33
34 using ValidateMode = spvtest::ValidateBase<bool>;
35
36 const std::string kVoidFunction = R"(%void = OpTypeVoid
37 %void_fn = OpTypeFunction %void
38 %main = OpFunction %void None %void_fn
39 %entry = OpLabel
40 OpReturn
41 OpFunctionEnd
42 )";
43
TEST_F(ValidateMode,GLComputeNoMode)44 TEST_F(ValidateMode, GLComputeNoMode) {
45 const std::string spirv = R"(
46 OpCapability Shader
47 OpMemoryModel Logical GLSL450
48 OpEntryPoint GLCompute %main "main"
49 )" + kVoidFunction;
50
51 CompileSuccessfully(spirv);
52 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
53 }
54
TEST_F(ValidateMode,GLComputeNoModeVulkan)55 TEST_F(ValidateMode, GLComputeNoModeVulkan) {
56 const std::string spirv = R"(
57 OpCapability Shader
58 OpMemoryModel Logical GLSL450
59 OpEntryPoint GLCompute %main "main"
60 )" + kVoidFunction;
61
62 spv_target_env env = SPV_ENV_VULKAN_1_0;
63 CompileSuccessfully(spirv, env);
64 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
65 EXPECT_THAT(getDiagnosticString(),
66 AnyVUID("VUID-StandaloneSpirv-LocalSize-06426"));
67 EXPECT_THAT(
68 getDiagnosticString(),
69 HasSubstr(
70 "In the Vulkan environment, GLCompute execution model entry "
71 "points require either the LocalSize or LocalSizeId execution mode "
72 "or an object decorated with WorkgroupSize must be specified."));
73 }
74
TEST_F(ValidateMode,GLComputeNoModeVulkanWorkgroupSize)75 TEST_F(ValidateMode, GLComputeNoModeVulkanWorkgroupSize) {
76 const std::string spirv = R"(
77 OpCapability Shader
78 OpMemoryModel Logical GLSL450
79 OpEntryPoint GLCompute %main "main"
80 OpDecorate %int3_1 BuiltIn WorkgroupSize
81 %int = OpTypeInt 32 0
82 %int3 = OpTypeVector %int 3
83 %int_1 = OpConstant %int 1
84 %int3_1 = OpConstantComposite %int3 %int_1 %int_1 %int_1
85 )" + kVoidFunction;
86
87 spv_target_env env = SPV_ENV_VULKAN_1_0;
88 CompileSuccessfully(spirv, env);
89 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
90 }
91
TEST_F(ValidateMode,GLComputeVulkanLocalSize)92 TEST_F(ValidateMode, GLComputeVulkanLocalSize) {
93 const std::string spirv = R"(
94 OpCapability Shader
95 OpMemoryModel Logical GLSL450
96 OpEntryPoint GLCompute %main "main"
97 OpExecutionMode %main LocalSize 1 1 1
98 )" + kVoidFunction;
99
100 spv_target_env env = SPV_ENV_VULKAN_1_0;
101 CompileSuccessfully(spirv, env);
102 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
103 }
104
TEST_F(ValidateMode,GLComputeVulkanLocalSizeIdBad)105 TEST_F(ValidateMode, GLComputeVulkanLocalSizeIdBad) {
106 const std::string spirv = R"(
107 OpCapability Shader
108 OpMemoryModel Logical GLSL450
109 OpEntryPoint GLCompute %main "main"
110 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
111 %int = OpTypeInt 32 0
112 %int_1 = OpConstant %int 1
113 )" + kVoidFunction;
114
115 spv_target_env env = SPV_ENV_VULKAN_1_1; // need SPIR-V 1.2
116 CompileSuccessfully(spirv, env);
117 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
118 EXPECT_THAT(
119 getDiagnosticString(),
120 HasSubstr("LocalSizeId mode is not allowed by the current environment."));
121 }
122
TEST_F(ValidateMode,GLComputeVulkanLocalSizeIdGood)123 TEST_F(ValidateMode, GLComputeVulkanLocalSizeIdGood) {
124 const std::string spirv = R"(
125 OpCapability Shader
126 OpMemoryModel Logical GLSL450
127 OpEntryPoint GLCompute %main "main"
128 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
129 %int = OpTypeInt 32 0
130 %int_1 = OpConstant %int 1
131 )" + kVoidFunction;
132
133 spv_target_env env = SPV_ENV_VULKAN_1_1; // need SPIR-V 1.2
134 CompileSuccessfully(spirv, env);
135 spvValidatorOptionsSetAllowLocalSizeId(getValidatorOptions(), true);
136 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
137 }
138
TEST_F(ValidateMode,FragmentOriginLowerLeftVulkan)139 TEST_F(ValidateMode, FragmentOriginLowerLeftVulkan) {
140 const std::string spirv = R"(
141 OpCapability Shader
142 OpMemoryModel Logical GLSL450
143 OpEntryPoint Fragment %main "main"
144 OpExecutionMode %main OriginLowerLeft
145 )" + kVoidFunction;
146
147 spv_target_env env = SPV_ENV_VULKAN_1_0;
148 CompileSuccessfully(spirv, env);
149 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
150 EXPECT_THAT(getDiagnosticString(),
151 AnyVUID("VUID-StandaloneSpirv-OriginLowerLeft-04653"));
152 EXPECT_THAT(getDiagnosticString(),
153 HasSubstr("In the Vulkan environment, the OriginLowerLeft "
154 "execution mode must not be used."));
155 }
156
TEST_F(ValidateMode,FragmentPixelCenterIntegerVulkan)157 TEST_F(ValidateMode, FragmentPixelCenterIntegerVulkan) {
158 const std::string spirv = R"(
159 OpCapability Shader
160 OpMemoryModel Logical GLSL450
161 OpEntryPoint Fragment %main "main"
162 OpExecutionMode %main OriginUpperLeft
163 OpExecutionMode %main PixelCenterInteger
164 )" + kVoidFunction;
165
166 spv_target_env env = SPV_ENV_VULKAN_1_0;
167 CompileSuccessfully(spirv, env);
168 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
169 EXPECT_THAT(getDiagnosticString(),
170 AnyVUID("VUID-StandaloneSpirv-PixelCenterInteger-04654"));
171 EXPECT_THAT(getDiagnosticString(),
172 HasSubstr("In the Vulkan environment, the PixelCenterInteger "
173 "execution mode must not be used."));
174 }
175
TEST_F(ValidateMode,GeometryNoOutputMode)176 TEST_F(ValidateMode, GeometryNoOutputMode) {
177 const std::string spirv = R"(
178 OpCapability Geometry
179 OpMemoryModel Logical GLSL450
180 OpEntryPoint Geometry %main "main"
181 OpExecutionMode %main InputPoints
182 )" + kVoidFunction;
183
184 CompileSuccessfully(spirv);
185 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
186 EXPECT_THAT(getDiagnosticString(),
187 HasSubstr("Geometry execution model entry points must specify "
188 "exactly one of OutputPoints, OutputLineStrip or "
189 "OutputTriangleStrip execution modes."));
190 }
191
TEST_F(ValidateMode,GeometryNoInputMode)192 TEST_F(ValidateMode, GeometryNoInputMode) {
193 const std::string spirv = R"(
194 OpCapability Geometry
195 OpMemoryModel Logical GLSL450
196 OpEntryPoint Geometry %main "main"
197 OpExecutionMode %main OutputPoints
198 )" + kVoidFunction;
199
200 CompileSuccessfully(spirv);
201 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
202 EXPECT_THAT(
203 getDiagnosticString(),
204 HasSubstr("Geometry execution model entry points must specify exactly "
205 "one of InputPoints, InputLines, InputLinesAdjacency, "
206 "Triangles or InputTrianglesAdjacency execution modes."));
207 }
208
TEST_F(ValidateMode,FragmentNoOrigin)209 TEST_F(ValidateMode, FragmentNoOrigin) {
210 const std::string spirv = R"(
211 OpCapability Shader
212 OpMemoryModel Logical GLSL450
213 OpEntryPoint Fragment %main "main"
214 )" + kVoidFunction;
215
216 CompileSuccessfully(spirv);
217 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
218 EXPECT_THAT(
219 getDiagnosticString(),
220 HasSubstr("Fragment execution model entry points require either an "
221 "OriginUpperLeft or OriginLowerLeft execution mode."));
222 }
223
TEST_F(ValidateMode,FragmentBothOrigins)224 TEST_F(ValidateMode, FragmentBothOrigins) {
225 const std::string spirv = R"(
226 OpCapability Shader
227 OpMemoryModel Logical GLSL450
228 OpEntryPoint Fragment %main "main"
229 OpExecutionMode %main OriginUpperLeft
230 OpExecutionMode %main OriginLowerLeft
231 )" + kVoidFunction;
232
233 CompileSuccessfully(spirv);
234 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
235 EXPECT_THAT(
236 getDiagnosticString(),
237 HasSubstr("Fragment execution model entry points can only specify one of "
238 "OriginUpperLeft or OriginLowerLeft execution modes."));
239 }
240
TEST_F(ValidateMode,FragmentDepthGreaterAndLess)241 TEST_F(ValidateMode, FragmentDepthGreaterAndLess) {
242 const std::string spirv = R"(
243 OpCapability Shader
244 OpMemoryModel Logical GLSL450
245 OpEntryPoint Fragment %main "main"
246 OpExecutionMode %main OriginUpperLeft
247 OpExecutionMode %main DepthGreater
248 OpExecutionMode %main DepthLess
249 )" + kVoidFunction;
250
251 CompileSuccessfully(spirv);
252 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
253 EXPECT_THAT(getDiagnosticString(),
254 HasSubstr("Fragment execution model entry points can specify at "
255 "most one of DepthGreater, DepthLess or DepthUnchanged "
256 "execution modes."));
257 }
258
TEST_F(ValidateMode,FragmentDepthGreaterAndUnchanged)259 TEST_F(ValidateMode, FragmentDepthGreaterAndUnchanged) {
260 const std::string spirv = R"(
261 OpCapability Shader
262 OpMemoryModel Logical GLSL450
263 OpEntryPoint Fragment %main "main"
264 OpExecutionMode %main OriginUpperLeft
265 OpExecutionMode %main DepthGreater
266 OpExecutionMode %main DepthUnchanged
267 )" + kVoidFunction;
268
269 CompileSuccessfully(spirv);
270 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
271 EXPECT_THAT(getDiagnosticString(),
272 HasSubstr("Fragment execution model entry points can specify at "
273 "most one of DepthGreater, DepthLess or DepthUnchanged "
274 "execution modes."));
275 }
276
TEST_F(ValidateMode,FragmentDepthLessAndUnchanged)277 TEST_F(ValidateMode, FragmentDepthLessAndUnchanged) {
278 const std::string spirv = R"(
279 OpCapability Shader
280 OpMemoryModel Logical GLSL450
281 OpEntryPoint Fragment %main "main"
282 OpExecutionMode %main OriginUpperLeft
283 OpExecutionMode %main DepthLess
284 OpExecutionMode %main DepthUnchanged
285 )" + kVoidFunction;
286
287 CompileSuccessfully(spirv);
288 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
289 EXPECT_THAT(getDiagnosticString(),
290 HasSubstr("Fragment execution model entry points can specify at "
291 "most one of DepthGreater, DepthLess or DepthUnchanged "
292 "execution modes."));
293 }
294
TEST_F(ValidateMode,FragmentAllDepths)295 TEST_F(ValidateMode, FragmentAllDepths) {
296 const std::string spirv = R"(
297 OpCapability Shader
298 OpMemoryModel Logical GLSL450
299 OpEntryPoint Fragment %main "main"
300 OpExecutionMode %main OriginUpperLeft
301 OpExecutionMode %main DepthGreater
302 OpExecutionMode %main DepthLess
303 OpExecutionMode %main DepthUnchanged
304 )" + kVoidFunction;
305
306 CompileSuccessfully(spirv);
307 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
308 EXPECT_THAT(getDiagnosticString(),
309 HasSubstr("Fragment execution model entry points can specify at "
310 "most one of DepthGreater, DepthLess or DepthUnchanged "
311 "execution modes."));
312 }
313
TEST_F(ValidateMode,TessellationControlSpacingEqualAndFractionalOdd)314 TEST_F(ValidateMode, TessellationControlSpacingEqualAndFractionalOdd) {
315 const std::string spirv = R"(
316 OpCapability Tessellation
317 OpMemoryModel Logical GLSL450
318 OpEntryPoint TessellationControl %main "main"
319 OpExecutionMode %main SpacingEqual
320 OpExecutionMode %main SpacingFractionalOdd
321 )" + kVoidFunction;
322
323 CompileSuccessfully(spirv);
324 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
325 EXPECT_THAT(getDiagnosticString(),
326 HasSubstr("Tessellation execution model entry points can specify "
327 "at most one of SpacingEqual, SpacingFractionalOdd or "
328 "SpacingFractionalEven execution modes."));
329 }
330
TEST_F(ValidateMode,TessellationControlSpacingEqualAndSpacingFractionalEven)331 TEST_F(ValidateMode, TessellationControlSpacingEqualAndSpacingFractionalEven) {
332 const std::string spirv = R"(
333 OpCapability Tessellation
334 OpMemoryModel Logical GLSL450
335 OpEntryPoint TessellationControl %main "main"
336 OpExecutionMode %main SpacingEqual
337 OpExecutionMode %main SpacingFractionalEven
338 )" + kVoidFunction;
339
340 CompileSuccessfully(spirv);
341 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
342 EXPECT_THAT(getDiagnosticString(),
343 HasSubstr("Tessellation execution model entry points can specify "
344 "at most one of SpacingEqual, SpacingFractionalOdd or "
345 "SpacingFractionalEven execution modes."));
346 }
347
TEST_F(ValidateMode,TessellationControlSpacingFractionalOddAndSpacingFractionalEven)348 TEST_F(ValidateMode,
349 TessellationControlSpacingFractionalOddAndSpacingFractionalEven) {
350 const std::string spirv = R"(
351 OpCapability Tessellation
352 OpMemoryModel Logical GLSL450
353 OpEntryPoint TessellationControl %main "main"
354 OpExecutionMode %main SpacingFractionalOdd
355 OpExecutionMode %main SpacingFractionalEven
356 )" + kVoidFunction;
357
358 CompileSuccessfully(spirv);
359 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
360 EXPECT_THAT(getDiagnosticString(),
361 HasSubstr("Tessellation execution model entry points can specify "
362 "at most one of SpacingEqual, SpacingFractionalOdd or "
363 "SpacingFractionalEven execution modes."));
364 }
365
TEST_F(ValidateMode,TessellationControlAllSpacing)366 TEST_F(ValidateMode, TessellationControlAllSpacing) {
367 const std::string spirv = R"(
368 OpCapability Tessellation
369 OpMemoryModel Logical GLSL450
370 OpEntryPoint TessellationControl %main "main"
371 OpExecutionMode %main SpacingEqual
372 OpExecutionMode %main SpacingFractionalOdd
373 OpExecutionMode %main SpacingFractionalEven
374 )" + kVoidFunction;
375
376 CompileSuccessfully(spirv);
377 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
378 EXPECT_THAT(getDiagnosticString(),
379 HasSubstr("Tessellation execution model entry points can specify "
380 "at most one of SpacingEqual, SpacingFractionalOdd or "
381 "SpacingFractionalEven execution modes."));
382 }
383
TEST_F(ValidateMode,TessellationEvaluationSpacingEqualAndSpacingFractionalOdd)384 TEST_F(ValidateMode,
385 TessellationEvaluationSpacingEqualAndSpacingFractionalOdd) {
386 const std::string spirv = R"(
387 OpCapability Tessellation
388 OpMemoryModel Logical GLSL450
389 OpEntryPoint TessellationEvaluation %main "main"
390 OpExecutionMode %main SpacingEqual
391 OpExecutionMode %main SpacingFractionalOdd
392 )" + kVoidFunction;
393
394 CompileSuccessfully(spirv);
395 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
396 EXPECT_THAT(getDiagnosticString(),
397 HasSubstr("Tessellation execution model entry points can specify "
398 "at most one of SpacingEqual, SpacingFractionalOdd or "
399 "SpacingFractionalEven execution modes."));
400 }
401
TEST_F(ValidateMode,TessellationEvaluationSpacingEqualAndSpacingFractionalEven)402 TEST_F(ValidateMode,
403 TessellationEvaluationSpacingEqualAndSpacingFractionalEven) {
404 const std::string spirv = R"(
405 OpCapability Tessellation
406 OpMemoryModel Logical GLSL450
407 OpEntryPoint TessellationEvaluation %main "main"
408 OpExecutionMode %main SpacingEqual
409 OpExecutionMode %main SpacingFractionalEven
410 )" + kVoidFunction;
411
412 CompileSuccessfully(spirv);
413 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
414 EXPECT_THAT(getDiagnosticString(),
415 HasSubstr("Tessellation execution model entry points can specify "
416 "at most one of SpacingEqual, SpacingFractionalOdd or "
417 "SpacingFractionalEven execution modes."));
418 }
419
TEST_F(ValidateMode,TessellationEvaluationSpacingFractionalOddAndSpacingFractionalEven)420 TEST_F(ValidateMode,
421 TessellationEvaluationSpacingFractionalOddAndSpacingFractionalEven) {
422 const std::string spirv = R"(
423 OpCapability Tessellation
424 OpMemoryModel Logical GLSL450
425 OpEntryPoint TessellationEvaluation %main "main"
426 OpExecutionMode %main SpacingFractionalOdd
427 OpExecutionMode %main SpacingFractionalEven
428 )" + kVoidFunction;
429
430 CompileSuccessfully(spirv);
431 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
432 EXPECT_THAT(getDiagnosticString(),
433 HasSubstr("Tessellation execution model entry points can specify "
434 "at most one of SpacingEqual, SpacingFractionalOdd or "
435 "SpacingFractionalEven execution modes."));
436 }
437
TEST_F(ValidateMode,TessellationEvaluationAllSpacing)438 TEST_F(ValidateMode, TessellationEvaluationAllSpacing) {
439 const std::string spirv = R"(
440 OpCapability Tessellation
441 OpMemoryModel Logical GLSL450
442 OpEntryPoint TessellationEvaluation %main "main"
443 OpExecutionMode %main SpacingEqual
444 OpExecutionMode %main SpacingFractionalOdd
445 OpExecutionMode %main SpacingFractionalEven
446 )" + kVoidFunction;
447
448 CompileSuccessfully(spirv);
449 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
450 EXPECT_THAT(getDiagnosticString(),
451 HasSubstr("Tessellation execution model entry points can specify "
452 "at most one of SpacingEqual, SpacingFractionalOdd or "
453 "SpacingFractionalEven execution modes."));
454 }
455
TEST_F(ValidateMode,TessellationControlBothVertex)456 TEST_F(ValidateMode, TessellationControlBothVertex) {
457 const std::string spirv = R"(
458 OpCapability Tessellation
459 OpMemoryModel Logical GLSL450
460 OpEntryPoint TessellationControl %main "main"
461 OpExecutionMode %main VertexOrderCw
462 OpExecutionMode %main VertexOrderCcw
463 )" + kVoidFunction;
464
465 CompileSuccessfully(spirv);
466 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
467 EXPECT_THAT(
468 getDiagnosticString(),
469 HasSubstr("Tessellation execution model entry points can specify at most "
470 "one of VertexOrderCw or VertexOrderCcw execution modes."));
471 }
472
TEST_F(ValidateMode,TessellationEvaluationBothVertex)473 TEST_F(ValidateMode, TessellationEvaluationBothVertex) {
474 const std::string spirv = R"(
475 OpCapability Tessellation
476 OpMemoryModel Logical GLSL450
477 OpEntryPoint TessellationEvaluation %main "main"
478 OpExecutionMode %main VertexOrderCw
479 OpExecutionMode %main VertexOrderCcw
480 )" + kVoidFunction;
481
482 CompileSuccessfully(spirv);
483 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
484 EXPECT_THAT(
485 getDiagnosticString(),
486 HasSubstr("Tessellation execution model entry points can specify at most "
487 "one of VertexOrderCw or VertexOrderCcw execution modes."));
488 }
489
490 using ValidateModeGeometry = spvtest::ValidateBase<std::tuple<
491 std::tuple<std::string, std::string, std::string, std::string, std::string>,
492 std::tuple<std::string, std::string, std::string>>>;
493
TEST_P(ValidateModeGeometry,ExecutionMode)494 TEST_P(ValidateModeGeometry, ExecutionMode) {
495 std::vector<std::string> input_modes;
496 std::vector<std::string> output_modes;
497 input_modes.push_back(std::get<0>(std::get<0>(GetParam())));
498 input_modes.push_back(std::get<1>(std::get<0>(GetParam())));
499 input_modes.push_back(std::get<2>(std::get<0>(GetParam())));
500 input_modes.push_back(std::get<3>(std::get<0>(GetParam())));
501 input_modes.push_back(std::get<4>(std::get<0>(GetParam())));
502 output_modes.push_back(std::get<0>(std::get<1>(GetParam())));
503 output_modes.push_back(std::get<1>(std::get<1>(GetParam())));
504 output_modes.push_back(std::get<2>(std::get<1>(GetParam())));
505
506 std::ostringstream sstr;
507 sstr << "OpCapability Geometry\n";
508 sstr << "OpMemoryModel Logical GLSL450\n";
509 sstr << "OpEntryPoint Geometry %main \"main\"\n";
510 size_t num_input_modes = 0;
511 for (auto input : input_modes) {
512 if (!input.empty()) {
513 num_input_modes++;
514 sstr << "OpExecutionMode %main " << input << "\n";
515 }
516 }
517 size_t num_output_modes = 0;
518 for (auto output : output_modes) {
519 if (!output.empty()) {
520 num_output_modes++;
521 sstr << "OpExecutionMode %main " << output << "\n";
522 }
523 }
524 sstr << "%void = OpTypeVoid\n";
525 sstr << "%void_fn = OpTypeFunction %void\n";
526 sstr << "%int = OpTypeInt 32 0\n";
527 sstr << "%int1 = OpConstant %int 1\n";
528 sstr << "%main = OpFunction %void None %void_fn\n";
529 sstr << "%entry = OpLabel\n";
530 sstr << "OpReturn\n";
531 sstr << "OpFunctionEnd\n";
532
533 CompileSuccessfully(sstr.str());
534 if (num_input_modes == 1 && num_output_modes == 1) {
535 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
536 } else {
537 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
538 if (num_input_modes != 1) {
539 EXPECT_THAT(getDiagnosticString(),
540 HasSubstr("Geometry execution model entry points must "
541 "specify exactly one of InputPoints, InputLines, "
542 "InputLinesAdjacency, Triangles or "
543 "InputTrianglesAdjacency execution modes."));
544 } else {
545 EXPECT_THAT(
546 getDiagnosticString(),
547 HasSubstr("Geometry execution model entry points must specify "
548 "exactly one of OutputPoints, OutputLineStrip or "
549 "OutputTriangleStrip execution modes."));
550 }
551 }
552 }
553
554 INSTANTIATE_TEST_SUITE_P(
555 GeometryRequiredModes, ValidateModeGeometry,
556 Combine(Combine(Values("InputPoints", ""), Values("InputLines", ""),
557 Values("InputLinesAdjacency", ""), Values("Triangles", ""),
558 Values("InputTrianglesAdjacency", "")),
559 Combine(Values("OutputPoints", ""), Values("OutputLineStrip", ""),
560 Values("OutputTriangleStrip", ""))));
561
562 using ValidateModeExecution =
563 spvtest::ValidateBase<std::tuple<spv_result_t, std::string, std::string,
564 std::string, spv_target_env>>;
565
TEST_P(ValidateModeExecution,ExecutionMode)566 TEST_P(ValidateModeExecution, ExecutionMode) {
567 const spv_result_t expectation = std::get<0>(GetParam());
568 const std::string error = std::get<1>(GetParam());
569 const std::string model = std::get<2>(GetParam());
570 const std::string mode = std::get<3>(GetParam());
571 const spv_target_env env = std::get<4>(GetParam());
572
573 std::ostringstream sstr;
574 sstr << "OpCapability Shader\n";
575 sstr << "OpCapability Geometry\n";
576 sstr << "OpCapability Tessellation\n";
577 sstr << "OpCapability TransformFeedback\n";
578 if (!spvIsVulkanEnv(env)) {
579 sstr << "OpCapability Kernel\n";
580 if (env == SPV_ENV_UNIVERSAL_1_3) {
581 sstr << "OpCapability SubgroupDispatch\n";
582 }
583 }
584 sstr << "OpMemoryModel Logical GLSL450\n";
585 sstr << "OpEntryPoint " << model << " %main \"main\"\n";
586 if (mode.find("LocalSizeId") == 0 || mode.find("LocalSizeHintId") == 0 ||
587 mode.find("SubgroupsPerWorkgroupId") == 0) {
588 sstr << "OpExecutionModeId %main " << mode << "\n";
589 } else {
590 sstr << "OpExecutionMode %main " << mode << "\n";
591 }
592 if (model == "Geometry") {
593 if (!(mode.find("InputPoints") == 0 || mode.find("InputLines") == 0 ||
594 mode.find("InputLinesAdjacency") == 0 ||
595 mode.find("Triangles") == 0 ||
596 mode.find("InputTrianglesAdjacency") == 0)) {
597 // Exactly one of the above modes is required for Geometry shaders.
598 sstr << "OpExecutionMode %main InputPoints\n";
599 }
600 if (!(mode.find("OutputPoints") == 0 || mode.find("OutputLineStrip") == 0 ||
601 mode.find("OutputTriangleStrip") == 0)) {
602 // Exactly one of the above modes is required for Geometry shaders.
603 sstr << "OpExecutionMode %main OutputPoints\n";
604 }
605 } else if (model == "Fragment") {
606 if (!(mode.find("OriginUpperLeft") == 0 ||
607 mode.find("OriginLowerLeft") == 0)) {
608 // Exactly one of the above modes is required for Fragment shaders.
609 sstr << "OpExecutionMode %main OriginUpperLeft\n";
610 }
611 }
612 sstr << "%void = OpTypeVoid\n";
613 sstr << "%void_fn = OpTypeFunction %void\n";
614 sstr << "%int = OpTypeInt 32 0\n";
615 sstr << "%int1 = OpConstant %int 1\n";
616 sstr << "%main = OpFunction %void None %void_fn\n";
617 sstr << "%entry = OpLabel\n";
618 sstr << "OpReturn\n";
619 sstr << "OpFunctionEnd\n";
620
621 CompileSuccessfully(sstr.str(), env);
622 EXPECT_THAT(expectation, ValidateInstructions(env));
623 if (expectation != SPV_SUCCESS) {
624 EXPECT_THAT(getDiagnosticString(), HasSubstr(error));
625 }
626 }
627
628 INSTANTIATE_TEST_SUITE_P(
629 ValidateModeGeometryOnlyGoodSpv10, ValidateModeExecution,
630 Combine(Values(SPV_SUCCESS), Values(""), Values("Geometry"),
631 Values("Invocations 3", "InputPoints", "InputLines",
632 "InputLinesAdjacency", "InputTrianglesAdjacency",
633 "OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
634 Values(SPV_ENV_UNIVERSAL_1_0)));
635
636 INSTANTIATE_TEST_SUITE_P(
637 ValidateModeGeometryOnlyBadSpv10, ValidateModeExecution,
638 Combine(Values(SPV_ERROR_INVALID_DATA),
639 Values("Execution mode can only be used with the Geometry "
640 "execution model."),
641 Values("Fragment", "TessellationEvaluation", "TessellationControl",
642 "GLCompute", "Vertex", "Kernel"),
643 Values("Invocations 3", "InputPoints", "InputLines",
644 "InputLinesAdjacency", "InputTrianglesAdjacency",
645 "OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
646 Values(SPV_ENV_UNIVERSAL_1_0)));
647
648 INSTANTIATE_TEST_SUITE_P(
649 ValidateModeTessellationOnlyGoodSpv10, ValidateModeExecution,
650 Combine(Values(SPV_SUCCESS), Values(""),
651 Values("TessellationControl", "TessellationEvaluation"),
652 Values("SpacingEqual", "SpacingFractionalEven",
653 "SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
654 "PointMode", "Quads", "Isolines"),
655 Values(SPV_ENV_UNIVERSAL_1_0)));
656
657 INSTANTIATE_TEST_SUITE_P(
658 ValidateModeTessellationOnlyBadSpv10, ValidateModeExecution,
659 Combine(Values(SPV_ERROR_INVALID_DATA),
660 Values("Execution mode can only be used with a tessellation "
661 "execution model."),
662 Values("Fragment", "Geometry", "GLCompute", "Vertex", "Kernel"),
663 Values("SpacingEqual", "SpacingFractionalEven",
664 "SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
665 "PointMode", "Quads", "Isolines"),
666 Values(SPV_ENV_UNIVERSAL_1_0)));
667
668 INSTANTIATE_TEST_SUITE_P(ValidateModeGeometryAndTessellationGoodSpv10,
669 ValidateModeExecution,
670 Combine(Values(SPV_SUCCESS), Values(""),
671 Values("TessellationControl",
672 "TessellationEvaluation", "Geometry"),
673 Values("Triangles", "OutputVertices 3"),
674 Values(SPV_ENV_UNIVERSAL_1_0)));
675
676 INSTANTIATE_TEST_SUITE_P(
677 ValidateModeGeometryAndTessellationBadSpv10, ValidateModeExecution,
678 Combine(Values(SPV_ERROR_INVALID_DATA),
679 Values("Execution mode can only be used with a Geometry or "
680 "tessellation execution model."),
681 Values("Fragment", "GLCompute", "Vertex", "Kernel"),
682 Values("Triangles", "OutputVertices 3"),
683 Values(SPV_ENV_UNIVERSAL_1_0)));
684
685 INSTANTIATE_TEST_SUITE_P(
686 ValidateModeFragmentOnlyGoodSpv10, ValidateModeExecution,
687 Combine(Values(SPV_SUCCESS), Values(""), Values("Fragment"),
688 Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
689 "EarlyFragmentTests", "DepthReplacing", "DepthLess",
690 "DepthUnchanged"),
691 Values(SPV_ENV_UNIVERSAL_1_0)));
692
693 INSTANTIATE_TEST_SUITE_P(
694 ValidateModeFragmentOnlyBadSpv10, ValidateModeExecution,
695 Combine(Values(SPV_ERROR_INVALID_DATA),
696 Values("Execution mode can only be used with the Fragment "
697 "execution model."),
698 Values("Geometry", "TessellationControl", "TessellationEvaluation",
699 "GLCompute", "Vertex", "Kernel"),
700 Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
701 "EarlyFragmentTests", "DepthReplacing", "DepthGreater",
702 "DepthLess", "DepthUnchanged"),
703 Values(SPV_ENV_UNIVERSAL_1_0)));
704
705 INSTANTIATE_TEST_SUITE_P(ValidateModeKernelOnlyGoodSpv13, ValidateModeExecution,
706 Combine(Values(SPV_SUCCESS), Values(""),
707 Values("Kernel"),
708 Values("LocalSizeHint 1 1 1", "VecTypeHint 4",
709 "ContractionOff",
710 "LocalSizeHintId %int1 %int1 %int1"),
711 Values(SPV_ENV_UNIVERSAL_1_3)));
712
713 INSTANTIATE_TEST_SUITE_P(
714 ValidateModeKernelOnlyBadSpv13, ValidateModeExecution,
715 Combine(
716 Values(SPV_ERROR_INVALID_DATA),
717 Values(
718 "Execution mode can only be used with the Kernel execution model."),
719 Values("Geometry", "TessellationControl", "TessellationEvaluation",
720 "GLCompute", "Vertex", "Fragment"),
721 Values("LocalSizeHint 1 1 1", "VecTypeHint 4", "ContractionOff",
722 "LocalSizeHintId %int1 %int1 %int1"),
723 Values(SPV_ENV_UNIVERSAL_1_3)));
724
725 INSTANTIATE_TEST_SUITE_P(
726 ValidateModeGLComputeAndKernelGoodSpv13, ValidateModeExecution,
727 Combine(Values(SPV_SUCCESS), Values(""), Values("Kernel", "GLCompute"),
728 Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
729 Values(SPV_ENV_UNIVERSAL_1_3)));
730
731 INSTANTIATE_TEST_SUITE_P(
732 ValidateModeGLComputeAndKernelBadSpv13, ValidateModeExecution,
733 Combine(Values(SPV_ERROR_INVALID_DATA),
734 Values("Execution mode can only be used with a Kernel or GLCompute "
735 "execution model."),
736 Values("Geometry", "TessellationControl", "TessellationEvaluation",
737 "Fragment", "Vertex"),
738 Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
739 Values(SPV_ENV_UNIVERSAL_1_3)));
740
741 INSTANTIATE_TEST_SUITE_P(
742 ValidateModeAllGoodSpv13, ValidateModeExecution,
743 Combine(Values(SPV_SUCCESS), Values(""),
744 Values("Kernel", "GLCompute", "Geometry", "TessellationControl",
745 "TessellationEvaluation", "Fragment", "Vertex"),
746 Values("Xfb", "Initializer", "Finalizer", "SubgroupSize 1",
747 "SubgroupsPerWorkgroup 1", "SubgroupsPerWorkgroupId %int1"),
748 Values(SPV_ENV_UNIVERSAL_1_3)));
749
TEST_F(ValidateModeExecution,MeshNVLocalSize)750 TEST_F(ValidateModeExecution, MeshNVLocalSize) {
751 const std::string spirv = R"(
752 OpCapability Shader
753 OpCapability MeshShadingNV
754 OpExtension "SPV_NV_mesh_shader"
755 OpMemoryModel Logical GLSL450
756 OpEntryPoint MeshNV %main "main"
757 OpExecutionMode %main LocalSize 1 1 1
758 )" + kVoidFunction;
759
760 CompileSuccessfully(spirv);
761 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
762 }
763
TEST_F(ValidateModeExecution,TaskNVLocalSize)764 TEST_F(ValidateModeExecution, TaskNVLocalSize) {
765 const std::string spirv = R"(
766 OpCapability Shader
767 OpCapability MeshShadingNV
768 OpExtension "SPV_NV_mesh_shader"
769 OpMemoryModel Logical GLSL450
770 OpEntryPoint TaskNV %main "main"
771 OpExecutionMode %main LocalSize 1 1 1
772 )" + kVoidFunction;
773
774 CompileSuccessfully(spirv);
775 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
776 }
777
TEST_F(ValidateModeExecution,MeshNVOutputPoints)778 TEST_F(ValidateModeExecution, MeshNVOutputPoints) {
779 const std::string spirv = R"(
780 OpCapability Shader
781 OpCapability MeshShadingNV
782 OpExtension "SPV_NV_mesh_shader"
783 OpMemoryModel Logical GLSL450
784 OpEntryPoint MeshNV %main "main"
785 OpExecutionMode %main OutputPoints
786 )" + kVoidFunction;
787
788 CompileSuccessfully(spirv);
789 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
790 }
791
TEST_F(ValidateModeExecution,MeshNVOutputVertices)792 TEST_F(ValidateModeExecution, MeshNVOutputVertices) {
793 const std::string spirv = R"(
794 OpCapability Shader
795 OpCapability MeshShadingNV
796 OpExtension "SPV_NV_mesh_shader"
797 OpMemoryModel Logical GLSL450
798 OpEntryPoint MeshNV %main "main"
799 OpExecutionMode %main OutputVertices 42
800 )" + kVoidFunction;
801
802 CompileSuccessfully(spirv);
803 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
804 }
805
TEST_F(ValidateModeExecution,MeshNVLocalSizeId)806 TEST_F(ValidateModeExecution, MeshNVLocalSizeId) {
807 const std::string spirv = R"(
808 OpCapability Shader
809 OpCapability MeshShadingNV
810 OpExtension "SPV_NV_mesh_shader"
811 OpMemoryModel Logical GLSL450
812 OpEntryPoint MeshNV %main "main"
813 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
814 %int = OpTypeInt 32 0
815 %int_1 = OpConstant %int 1
816 )" + kVoidFunction;
817
818 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
819 CompileSuccessfully(spirv, env);
820 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
821 }
822
TEST_F(ValidateModeExecution,TaskNVLocalSizeId)823 TEST_F(ValidateModeExecution, TaskNVLocalSizeId) {
824 const std::string spirv = R"(
825 OpCapability Shader
826 OpCapability MeshShadingNV
827 OpExtension "SPV_NV_mesh_shader"
828 OpMemoryModel Logical GLSL450
829 OpEntryPoint TaskNV %main "main"
830 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
831 %int = OpTypeInt 32 0
832 %int_1 = OpConstant %int 1
833 )" + kVoidFunction;
834
835 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
836 CompileSuccessfully(spirv, env);
837 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
838 }
839
TEST_F(ValidateModeExecution,ExecModeSubgroupsPerWorkgroupIdBad)840 TEST_F(ValidateModeExecution, ExecModeSubgroupsPerWorkgroupIdBad) {
841 const std::string spirv = R"(
842 OpCapability Shader
843 OpCapability SubgroupDispatch
844 OpMemoryModel Logical GLSL450
845 OpEntryPoint Vertex %main "main"
846 OpExecutionMode %main SubgroupsPerWorkgroupId %int_1
847 %int = OpTypeInt 32 0
848 %int_1 = OpConstant %int 1
849 )" + kVoidFunction;
850
851 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
852 CompileSuccessfully(spirv, env);
853 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
854 EXPECT_THAT(getDiagnosticString(),
855 HasSubstr("OpExecutionMode is only valid when the Mode operand "
856 "is an execution mode that takes no Extra Operands"));
857 }
858
TEST_F(ValidateModeExecution,ExecModeIdSubgroupsPerWorkgroupIdGood)859 TEST_F(ValidateModeExecution, ExecModeIdSubgroupsPerWorkgroupIdGood) {
860 const std::string spirv = R"(
861 OpCapability Shader
862 OpCapability SubgroupDispatch
863 OpMemoryModel Logical GLSL450
864 OpEntryPoint Vertex %main "main"
865 OpExecutionModeId %main SubgroupsPerWorkgroupId %int_1
866 %int = OpTypeInt 32 0
867 %int_1 = OpConstant %int 1
868 )" + kVoidFunction;
869
870 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
871 CompileSuccessfully(spirv, env);
872 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
873 }
874
TEST_F(ValidateModeExecution,ExecModeIdSubgroupsPerWorkgroupIdNonConstantBad)875 TEST_F(ValidateModeExecution, ExecModeIdSubgroupsPerWorkgroupIdNonConstantBad) {
876 const std::string spirv = R"(
877 OpCapability Shader
878 OpCapability SubgroupDispatch
879 OpMemoryModel Logical GLSL450
880 OpEntryPoint Vertex %main "main"
881 OpExecutionModeId %main SubgroupsPerWorkgroupId %int_1
882 %int = OpTypeInt 32 0
883 %int_ptr = OpTypePointer Private %int
884 %int_1 = OpVariable %int_ptr Private
885 )" + kVoidFunction;
886
887 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
888 CompileSuccessfully(spirv, env);
889 EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
890 EXPECT_THAT(getDiagnosticString(),
891 HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
892 "constant instructions."));
893 }
894
TEST_F(ValidateModeExecution,ExecModeLocalSizeHintIdBad)895 TEST_F(ValidateModeExecution, ExecModeLocalSizeHintIdBad) {
896 const std::string spirv = R"(
897 OpCapability Kernel
898 OpCapability Shader
899 OpMemoryModel Logical GLSL450
900 OpEntryPoint Kernel %main "main"
901 OpExecutionMode %main LocalSizeHintId %int_1 %int_1 %int_1
902 %int = OpTypeInt 32 0
903 %int_1 = OpConstant %int 1
904 )" + kVoidFunction;
905
906 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
907 CompileSuccessfully(spirv, env);
908 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
909 EXPECT_THAT(getDiagnosticString(),
910 HasSubstr("OpExecutionMode is only valid when the Mode operand "
911 "is an execution mode that takes no Extra Operands"));
912 }
913
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeHintIdGood)914 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeHintIdGood) {
915 const std::string spirv = R"(
916 OpCapability Kernel
917 OpCapability Shader
918 OpMemoryModel Logical GLSL450
919 OpEntryPoint Kernel %main "main"
920 OpExecutionModeId %main LocalSizeHintId %int_1 %int_1 %int_1
921 %int = OpTypeInt 32 0
922 %int_1 = OpConstant %int 1
923 )" + kVoidFunction;
924
925 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
926 CompileSuccessfully(spirv, env);
927 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
928 }
929
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeHintIdNonConstantBad)930 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeHintIdNonConstantBad) {
931 const std::string spirv = R"(
932 OpCapability Kernel
933 OpCapability Shader
934 OpMemoryModel Logical GLSL450
935 OpEntryPoint Vertex %main "main"
936 OpExecutionModeId %main LocalSizeHintId %int_1 %int_1 %int_1
937 %int = OpTypeInt 32 0
938 %int_ptr = OpTypePointer Private %int
939 %int_1 = OpVariable %int_ptr Private
940 )" + kVoidFunction;
941
942 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
943 CompileSuccessfully(spirv, env);
944 EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
945 EXPECT_THAT(getDiagnosticString(),
946 HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
947 "constant instructions."));
948 }
949
TEST_F(ValidateModeExecution,ExecModeLocalSizeIdBad)950 TEST_F(ValidateModeExecution, ExecModeLocalSizeIdBad) {
951 const std::string spirv = R"(
952 OpCapability Kernel
953 OpCapability Shader
954 OpMemoryModel Logical GLSL450
955 OpEntryPoint Kernel %main "main"
956 OpExecutionMode %main LocalSizeId %int_1 %int_1 %int_1
957 %int = OpTypeInt 32 0
958 %int_1 = OpConstant %int 1
959 )" + kVoidFunction;
960
961 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
962 CompileSuccessfully(spirv, env);
963 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
964 EXPECT_THAT(getDiagnosticString(),
965 HasSubstr("OpExecutionMode is only valid when the Mode operand "
966 "is an execution mode that takes no Extra Operands"));
967 }
968
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeIdGood)969 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeIdGood) {
970 const std::string spirv = R"(
971 OpCapability Kernel
972 OpCapability Shader
973 OpMemoryModel Logical GLSL450
974 OpEntryPoint Kernel %main "main"
975 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
976 %int = OpTypeInt 32 0
977 %int_1 = OpConstant %int 1
978 )" + kVoidFunction;
979
980 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
981 CompileSuccessfully(spirv, env);
982 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
983 }
984
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeIdNonConstantBad)985 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeIdNonConstantBad) {
986 const std::string spirv = R"(
987 OpCapability Kernel
988 OpCapability Shader
989 OpMemoryModel Logical GLSL450
990 OpEntryPoint Vertex %main "main"
991 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
992 %int = OpTypeInt 32 0
993 %int_ptr = OpTypePointer Private %int
994 %int_1 = OpVariable %int_ptr Private
995 )" + kVoidFunction;
996
997 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
998 CompileSuccessfully(spirv, env);
999 EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
1000 EXPECT_THAT(getDiagnosticString(),
1001 HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
1002 "constant instructions."));
1003 }
1004
TEST_F(ValidateMode,FragmentShaderInterlockVertexBad)1005 TEST_F(ValidateMode, FragmentShaderInterlockVertexBad) {
1006 const std::string spirv = R"(
1007 OpCapability Shader
1008 OpCapability FragmentShaderPixelInterlockEXT
1009 OpExtension "SPV_EXT_fragment_shader_interlock"
1010 OpMemoryModel Logical GLSL450
1011 OpEntryPoint Vertex %main "main"
1012 OpExecutionMode %main PixelInterlockOrderedEXT
1013 )" + kVoidFunction;
1014
1015 CompileSuccessfully(spirv);
1016 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1017 EXPECT_THAT(
1018 getDiagnosticString(),
1019 HasSubstr(
1020 "Execution mode can only be used with the Fragment execution model"));
1021 }
1022
TEST_F(ValidateMode,FragmentShaderInterlockTooManyModesBad)1023 TEST_F(ValidateMode, FragmentShaderInterlockTooManyModesBad) {
1024 const std::string spirv = R"(
1025 OpCapability Shader
1026 OpCapability FragmentShaderPixelInterlockEXT
1027 OpCapability FragmentShaderSampleInterlockEXT
1028 OpExtension "SPV_EXT_fragment_shader_interlock"
1029 OpMemoryModel Logical GLSL450
1030 OpEntryPoint Fragment %main "main"
1031 OpExecutionMode %main OriginUpperLeft
1032 OpExecutionMode %main PixelInterlockOrderedEXT
1033 OpExecutionMode %main SampleInterlockOrderedEXT
1034 )" + kVoidFunction;
1035
1036 CompileSuccessfully(spirv);
1037 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1038 EXPECT_THAT(
1039 getDiagnosticString(),
1040 HasSubstr("Fragment execution model entry points can specify at most "
1041 "one fragment shader interlock execution mode"));
1042 }
1043
TEST_F(ValidateMode,FragmentShaderInterlockNoModeBad)1044 TEST_F(ValidateMode, FragmentShaderInterlockNoModeBad) {
1045 const std::string spirv = R"(
1046 OpCapability Shader
1047 OpCapability FragmentShaderPixelInterlockEXT
1048 OpExtension "SPV_EXT_fragment_shader_interlock"
1049 OpMemoryModel Logical GLSL450
1050 OpEntryPoint Fragment %main "main"
1051 OpExecutionMode %main OriginUpperLeft
1052 %void = OpTypeVoid
1053 %void_fn = OpTypeFunction %void
1054 %func = OpFunction %void None %void_fn
1055 %entryf = OpLabel
1056 OpBeginInvocationInterlockEXT
1057 OpEndInvocationInterlockEXT
1058 OpReturn
1059 OpFunctionEnd
1060 %main = OpFunction %void None %void_fn
1061 %entry = OpLabel
1062 %1 = OpFunctionCall %void %func
1063 OpReturn
1064 OpFunctionEnd
1065 )";
1066
1067 CompileSuccessfully(spirv);
1068 EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions());
1069 EXPECT_THAT(
1070 getDiagnosticString(),
1071 HasSubstr(
1072 "OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT require a "
1073 "fragment shader interlock execution mode"));
1074 }
1075
TEST_F(ValidateMode,FragmentShaderInterlockGood)1076 TEST_F(ValidateMode, FragmentShaderInterlockGood) {
1077 const std::string spirv = R"(
1078 OpCapability Shader
1079 OpCapability FragmentShaderPixelInterlockEXT
1080 OpExtension "SPV_EXT_fragment_shader_interlock"
1081 OpMemoryModel Logical GLSL450
1082 OpEntryPoint Fragment %main "main"
1083 OpExecutionMode %main OriginUpperLeft
1084 OpExecutionMode %main PixelInterlockOrderedEXT
1085 %void = OpTypeVoid
1086 %void_fn = OpTypeFunction %void
1087 %func = OpFunction %void None %void_fn
1088 %entryf = OpLabel
1089 OpBeginInvocationInterlockEXT
1090 OpEndInvocationInterlockEXT
1091 OpReturn
1092 OpFunctionEnd
1093 %main = OpFunction %void None %void_fn
1094 %entry = OpLabel
1095 %1 = OpFunctionCall %void %func
1096 OpReturn
1097 OpFunctionEnd
1098 )";
1099
1100 CompileSuccessfully(spirv);
1101 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
1102 }
1103
TEST_F(ValidateMode,FragmentShaderDemoteVertexBad)1104 TEST_F(ValidateMode, FragmentShaderDemoteVertexBad) {
1105 const std::string spirv = R"(
1106 OpCapability Shader
1107 OpCapability DemoteToHelperInvocationEXT
1108 OpExtension "SPV_EXT_demote_to_helper_invocation"
1109 OpMemoryModel Logical GLSL450
1110 OpEntryPoint Vertex %main "main"
1111 %bool = OpTypeBool
1112 %void = OpTypeVoid
1113 %void_fn = OpTypeFunction %void
1114 %main = OpFunction %void None %void_fn
1115 %entry = OpLabel
1116 OpDemoteToHelperInvocationEXT
1117 %1 = OpIsHelperInvocationEXT %bool
1118 OpReturn
1119 OpFunctionEnd
1120 )";
1121
1122 CompileSuccessfully(spirv);
1123 EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions());
1124 EXPECT_THAT(
1125 getDiagnosticString(),
1126 HasSubstr(
1127 "OpDemoteToHelperInvocationEXT requires Fragment execution model"));
1128 EXPECT_THAT(
1129 getDiagnosticString(),
1130 HasSubstr("OpIsHelperInvocationEXT requires Fragment execution model"));
1131 }
1132
TEST_F(ValidateMode,FragmentShaderDemoteGood)1133 TEST_F(ValidateMode, FragmentShaderDemoteGood) {
1134 const std::string spirv = R"(
1135 OpCapability Shader
1136 OpCapability DemoteToHelperInvocationEXT
1137 OpExtension "SPV_EXT_demote_to_helper_invocation"
1138 OpMemoryModel Logical GLSL450
1139 OpEntryPoint Fragment %main "main"
1140 OpExecutionMode %main OriginUpperLeft
1141 %bool = OpTypeBool
1142 %void = OpTypeVoid
1143 %void_fn = OpTypeFunction %void
1144 %main = OpFunction %void None %void_fn
1145 %entry = OpLabel
1146 OpDemoteToHelperInvocationEXT
1147 %1 = OpIsHelperInvocationEXT %bool
1148 OpReturn
1149 OpFunctionEnd
1150 )";
1151
1152 CompileSuccessfully(spirv);
1153 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
1154 }
1155
TEST_F(ValidateMode,FragmentShaderDemoteBadType)1156 TEST_F(ValidateMode, FragmentShaderDemoteBadType) {
1157 const std::string spirv = R"(
1158 OpCapability Shader
1159 OpCapability DemoteToHelperInvocationEXT
1160 OpExtension "SPV_EXT_demote_to_helper_invocation"
1161 OpMemoryModel Logical GLSL450
1162 OpEntryPoint Fragment %main "main"
1163 OpExecutionMode %main OriginUpperLeft
1164 %u32 = OpTypeInt 32 0
1165 %void = OpTypeVoid
1166 %void_fn = OpTypeFunction %void
1167 %main = OpFunction %void None %void_fn
1168 %entry = OpLabel
1169 OpDemoteToHelperInvocationEXT
1170 %1 = OpIsHelperInvocationEXT %u32
1171 OpReturn
1172 OpFunctionEnd
1173 )";
1174
1175 CompileSuccessfully(spirv);
1176 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1177 EXPECT_THAT(getDiagnosticString(),
1178 HasSubstr("Expected bool scalar type as Result Type"));
1179 }
1180
TEST_F(ValidateMode,LocalSizeIdVulkan1p3DoesNotRequireOption)1181 TEST_F(ValidateMode, LocalSizeIdVulkan1p3DoesNotRequireOption) {
1182 const std::string spirv = R"(
1183 OpCapability Shader
1184 OpMemoryModel Logical GLSL450
1185 OpEntryPoint GLCompute %main "main"
1186 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
1187 %void = OpTypeVoid
1188 %int = OpTypeInt 32 0
1189 %int_1 = OpConstant %int 1
1190 %void_fn = OpTypeFunction %void
1191 %main = OpFunction %void None %void_fn
1192 %entry = OpLabel
1193 OpReturn
1194 OpFunctionEnd
1195 )";
1196
1197 CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3);
1198 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
1199 }
1200
1201 } // namespace
1202 } // namespace val
1203 } // namespace spvtools
1204