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