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(
66 getDiagnosticString(),
67 HasSubstr("In the Vulkan environment, GLCompute execution model entry "
68 "points require either the LocalSize execution mode or an "
69 "object decorated with WorkgroupSize must be specified."));
70 }
71
TEST_F(ValidateMode,GLComputeNoModeVulkanWorkgroupSize)72 TEST_F(ValidateMode, GLComputeNoModeVulkanWorkgroupSize) {
73 const std::string spirv = R"(
74 OpCapability Shader
75 OpMemoryModel Logical GLSL450
76 OpEntryPoint GLCompute %main "main"
77 OpDecorate %int3_1 BuiltIn WorkgroupSize
78 %int = OpTypeInt 32 0
79 %int3 = OpTypeVector %int 3
80 %int_1 = OpConstant %int 1
81 %int3_1 = OpConstantComposite %int3 %int_1 %int_1 %int_1
82 )" + kVoidFunction;
83
84 spv_target_env env = SPV_ENV_VULKAN_1_0;
85 CompileSuccessfully(spirv, env);
86 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
87 }
88
TEST_F(ValidateMode,GLComputeVulkanLocalSize)89 TEST_F(ValidateMode, GLComputeVulkanLocalSize) {
90 const std::string spirv = R"(
91 OpCapability Shader
92 OpMemoryModel Logical GLSL450
93 OpEntryPoint GLCompute %main "main"
94 OpExecutionMode %main LocalSize 1 1 1
95 )" + kVoidFunction;
96
97 spv_target_env env = SPV_ENV_VULKAN_1_0;
98 CompileSuccessfully(spirv, env);
99 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
100 }
101
TEST_F(ValidateMode,FragmentOriginLowerLeftVulkan)102 TEST_F(ValidateMode, FragmentOriginLowerLeftVulkan) {
103 const std::string spirv = R"(
104 OpCapability Shader
105 OpMemoryModel Logical GLSL450
106 OpEntryPoint Fragment %main "main"
107 OpExecutionMode %main OriginLowerLeft
108 )" + kVoidFunction;
109
110 spv_target_env env = SPV_ENV_VULKAN_1_0;
111 CompileSuccessfully(spirv, env);
112 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
113 EXPECT_THAT(getDiagnosticString(),
114 HasSubstr("In the Vulkan environment, the OriginLowerLeft "
115 "execution mode must not be used."));
116 }
117
TEST_F(ValidateMode,FragmentPixelCenterIntegerVulkan)118 TEST_F(ValidateMode, FragmentPixelCenterIntegerVulkan) {
119 const std::string spirv = R"(
120 OpCapability Shader
121 OpMemoryModel Logical GLSL450
122 OpEntryPoint Fragment %main "main"
123 OpExecutionMode %main OriginUpperLeft
124 OpExecutionMode %main PixelCenterInteger
125 )" + kVoidFunction;
126
127 spv_target_env env = SPV_ENV_VULKAN_1_0;
128 CompileSuccessfully(spirv, env);
129 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
130 EXPECT_THAT(getDiagnosticString(),
131 HasSubstr("In the Vulkan environment, the PixelCenterInteger "
132 "execution mode must not be used."));
133 }
134
TEST_F(ValidateMode,GeometryNoOutputMode)135 TEST_F(ValidateMode, GeometryNoOutputMode) {
136 const std::string spirv = R"(
137 OpCapability Geometry
138 OpMemoryModel Logical GLSL450
139 OpEntryPoint Geometry %main "main"
140 OpExecutionMode %main InputPoints
141 )" + kVoidFunction;
142
143 CompileSuccessfully(spirv);
144 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
145 EXPECT_THAT(getDiagnosticString(),
146 HasSubstr("Geometry execution model entry points must specify "
147 "exactly one of OutputPoints, OutputLineStrip or "
148 "OutputTriangleStrip execution modes."));
149 }
150
TEST_F(ValidateMode,GeometryNoInputMode)151 TEST_F(ValidateMode, GeometryNoInputMode) {
152 const std::string spirv = R"(
153 OpCapability Geometry
154 OpMemoryModel Logical GLSL450
155 OpEntryPoint Geometry %main "main"
156 OpExecutionMode %main OutputPoints
157 )" + kVoidFunction;
158
159 CompileSuccessfully(spirv);
160 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
161 EXPECT_THAT(
162 getDiagnosticString(),
163 HasSubstr("Geometry execution model entry points must specify exactly "
164 "one of InputPoints, InputLines, InputLinesAdjacency, "
165 "Triangles or InputTrianglesAdjacency execution modes."));
166 }
167
TEST_F(ValidateMode,FragmentNoOrigin)168 TEST_F(ValidateMode, FragmentNoOrigin) {
169 const std::string spirv = R"(
170 OpCapability Shader
171 OpMemoryModel Logical GLSL450
172 OpEntryPoint Fragment %main "main"
173 )" + kVoidFunction;
174
175 CompileSuccessfully(spirv);
176 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
177 EXPECT_THAT(
178 getDiagnosticString(),
179 HasSubstr("Fragment execution model entry points require either an "
180 "OriginUpperLeft or OriginLowerLeft execution mode."));
181 }
182
TEST_F(ValidateMode,FragmentBothOrigins)183 TEST_F(ValidateMode, FragmentBothOrigins) {
184 const std::string spirv = R"(
185 OpCapability Shader
186 OpMemoryModel Logical GLSL450
187 OpEntryPoint Fragment %main "main"
188 OpExecutionMode %main OriginUpperLeft
189 OpExecutionMode %main OriginLowerLeft
190 )" + kVoidFunction;
191
192 CompileSuccessfully(spirv);
193 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
194 EXPECT_THAT(
195 getDiagnosticString(),
196 HasSubstr("Fragment execution model entry points can only specify one of "
197 "OriginUpperLeft or OriginLowerLeft execution modes."));
198 }
199
TEST_F(ValidateMode,FragmentDepthGreaterAndLess)200 TEST_F(ValidateMode, FragmentDepthGreaterAndLess) {
201 const std::string spirv = R"(
202 OpCapability Shader
203 OpMemoryModel Logical GLSL450
204 OpEntryPoint Fragment %main "main"
205 OpExecutionMode %main OriginUpperLeft
206 OpExecutionMode %main DepthGreater
207 OpExecutionMode %main DepthLess
208 )" + kVoidFunction;
209
210 CompileSuccessfully(spirv);
211 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
212 EXPECT_THAT(getDiagnosticString(),
213 HasSubstr("Fragment execution model entry points can specify at "
214 "most one of DepthGreater, DepthLess or DepthUnchanged "
215 "execution modes."));
216 }
217
TEST_F(ValidateMode,FragmentDepthGreaterAndUnchanged)218 TEST_F(ValidateMode, FragmentDepthGreaterAndUnchanged) {
219 const std::string spirv = R"(
220 OpCapability Shader
221 OpMemoryModel Logical GLSL450
222 OpEntryPoint Fragment %main "main"
223 OpExecutionMode %main OriginUpperLeft
224 OpExecutionMode %main DepthGreater
225 OpExecutionMode %main DepthUnchanged
226 )" + kVoidFunction;
227
228 CompileSuccessfully(spirv);
229 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
230 EXPECT_THAT(getDiagnosticString(),
231 HasSubstr("Fragment execution model entry points can specify at "
232 "most one of DepthGreater, DepthLess or DepthUnchanged "
233 "execution modes."));
234 }
235
TEST_F(ValidateMode,FragmentDepthLessAndUnchanged)236 TEST_F(ValidateMode, FragmentDepthLessAndUnchanged) {
237 const std::string spirv = R"(
238 OpCapability Shader
239 OpMemoryModel Logical GLSL450
240 OpEntryPoint Fragment %main "main"
241 OpExecutionMode %main OriginUpperLeft
242 OpExecutionMode %main DepthLess
243 OpExecutionMode %main DepthUnchanged
244 )" + kVoidFunction;
245
246 CompileSuccessfully(spirv);
247 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
248 EXPECT_THAT(getDiagnosticString(),
249 HasSubstr("Fragment execution model entry points can specify at "
250 "most one of DepthGreater, DepthLess or DepthUnchanged "
251 "execution modes."));
252 }
253
TEST_F(ValidateMode,FragmentAllDepths)254 TEST_F(ValidateMode, FragmentAllDepths) {
255 const std::string spirv = R"(
256 OpCapability Shader
257 OpMemoryModel Logical GLSL450
258 OpEntryPoint Fragment %main "main"
259 OpExecutionMode %main OriginUpperLeft
260 OpExecutionMode %main DepthGreater
261 OpExecutionMode %main DepthLess
262 OpExecutionMode %main DepthUnchanged
263 )" + kVoidFunction;
264
265 CompileSuccessfully(spirv);
266 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
267 EXPECT_THAT(getDiagnosticString(),
268 HasSubstr("Fragment execution model entry points can specify at "
269 "most one of DepthGreater, DepthLess or DepthUnchanged "
270 "execution modes."));
271 }
272
TEST_F(ValidateMode,TessellationControlSpacingEqualAndFractionalOdd)273 TEST_F(ValidateMode, TessellationControlSpacingEqualAndFractionalOdd) {
274 const std::string spirv = R"(
275 OpCapability Tessellation
276 OpMemoryModel Logical GLSL450
277 OpEntryPoint TessellationControl %main "main"
278 OpExecutionMode %main SpacingEqual
279 OpExecutionMode %main SpacingFractionalOdd
280 )" + kVoidFunction;
281
282 CompileSuccessfully(spirv);
283 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
284 EXPECT_THAT(getDiagnosticString(),
285 HasSubstr("Tessellation execution model entry points can specify "
286 "at most one of SpacingEqual, SpacingFractionalOdd or "
287 "SpacingFractionalEven execution modes."));
288 }
289
TEST_F(ValidateMode,TessellationControlSpacingEqualAndSpacingFractionalEven)290 TEST_F(ValidateMode, TessellationControlSpacingEqualAndSpacingFractionalEven) {
291 const std::string spirv = R"(
292 OpCapability Tessellation
293 OpMemoryModel Logical GLSL450
294 OpEntryPoint TessellationControl %main "main"
295 OpExecutionMode %main SpacingEqual
296 OpExecutionMode %main SpacingFractionalEven
297 )" + kVoidFunction;
298
299 CompileSuccessfully(spirv);
300 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
301 EXPECT_THAT(getDiagnosticString(),
302 HasSubstr("Tessellation execution model entry points can specify "
303 "at most one of SpacingEqual, SpacingFractionalOdd or "
304 "SpacingFractionalEven execution modes."));
305 }
306
TEST_F(ValidateMode,TessellationControlSpacingFractionalOddAndSpacingFractionalEven)307 TEST_F(ValidateMode,
308 TessellationControlSpacingFractionalOddAndSpacingFractionalEven) {
309 const std::string spirv = R"(
310 OpCapability Tessellation
311 OpMemoryModel Logical GLSL450
312 OpEntryPoint TessellationControl %main "main"
313 OpExecutionMode %main SpacingFractionalOdd
314 OpExecutionMode %main SpacingFractionalEven
315 )" + kVoidFunction;
316
317 CompileSuccessfully(spirv);
318 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
319 EXPECT_THAT(getDiagnosticString(),
320 HasSubstr("Tessellation execution model entry points can specify "
321 "at most one of SpacingEqual, SpacingFractionalOdd or "
322 "SpacingFractionalEven execution modes."));
323 }
324
TEST_F(ValidateMode,TessellationControlAllSpacing)325 TEST_F(ValidateMode, TessellationControlAllSpacing) {
326 const std::string spirv = R"(
327 OpCapability Tessellation
328 OpMemoryModel Logical GLSL450
329 OpEntryPoint TessellationControl %main "main"
330 OpExecutionMode %main SpacingEqual
331 OpExecutionMode %main SpacingFractionalOdd
332 OpExecutionMode %main SpacingFractionalEven
333 )" + kVoidFunction;
334
335 CompileSuccessfully(spirv);
336 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
337 EXPECT_THAT(getDiagnosticString(),
338 HasSubstr("Tessellation execution model entry points can specify "
339 "at most one of SpacingEqual, SpacingFractionalOdd or "
340 "SpacingFractionalEven execution modes."));
341 }
342
TEST_F(ValidateMode,TessellationEvaluationSpacingEqualAndSpacingFractionalOdd)343 TEST_F(ValidateMode,
344 TessellationEvaluationSpacingEqualAndSpacingFractionalOdd) {
345 const std::string spirv = R"(
346 OpCapability Tessellation
347 OpMemoryModel Logical GLSL450
348 OpEntryPoint TessellationEvaluation %main "main"
349 OpExecutionMode %main SpacingEqual
350 OpExecutionMode %main SpacingFractionalOdd
351 )" + kVoidFunction;
352
353 CompileSuccessfully(spirv);
354 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
355 EXPECT_THAT(getDiagnosticString(),
356 HasSubstr("Tessellation execution model entry points can specify "
357 "at most one of SpacingEqual, SpacingFractionalOdd or "
358 "SpacingFractionalEven execution modes."));
359 }
360
TEST_F(ValidateMode,TessellationEvaluationSpacingEqualAndSpacingFractionalEven)361 TEST_F(ValidateMode,
362 TessellationEvaluationSpacingEqualAndSpacingFractionalEven) {
363 const std::string spirv = R"(
364 OpCapability Tessellation
365 OpMemoryModel Logical GLSL450
366 OpEntryPoint TessellationEvaluation %main "main"
367 OpExecutionMode %main SpacingEqual
368 OpExecutionMode %main SpacingFractionalEven
369 )" + kVoidFunction;
370
371 CompileSuccessfully(spirv);
372 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
373 EXPECT_THAT(getDiagnosticString(),
374 HasSubstr("Tessellation execution model entry points can specify "
375 "at most one of SpacingEqual, SpacingFractionalOdd or "
376 "SpacingFractionalEven execution modes."));
377 }
378
TEST_F(ValidateMode,TessellationEvaluationSpacingFractionalOddAndSpacingFractionalEven)379 TEST_F(ValidateMode,
380 TessellationEvaluationSpacingFractionalOddAndSpacingFractionalEven) {
381 const std::string spirv = R"(
382 OpCapability Tessellation
383 OpMemoryModel Logical GLSL450
384 OpEntryPoint TessellationEvaluation %main "main"
385 OpExecutionMode %main SpacingFractionalOdd
386 OpExecutionMode %main SpacingFractionalEven
387 )" + kVoidFunction;
388
389 CompileSuccessfully(spirv);
390 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
391 EXPECT_THAT(getDiagnosticString(),
392 HasSubstr("Tessellation execution model entry points can specify "
393 "at most one of SpacingEqual, SpacingFractionalOdd or "
394 "SpacingFractionalEven execution modes."));
395 }
396
TEST_F(ValidateMode,TessellationEvaluationAllSpacing)397 TEST_F(ValidateMode, TessellationEvaluationAllSpacing) {
398 const std::string spirv = R"(
399 OpCapability Tessellation
400 OpMemoryModel Logical GLSL450
401 OpEntryPoint TessellationEvaluation %main "main"
402 OpExecutionMode %main SpacingEqual
403 OpExecutionMode %main SpacingFractionalOdd
404 OpExecutionMode %main SpacingFractionalEven
405 )" + kVoidFunction;
406
407 CompileSuccessfully(spirv);
408 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
409 EXPECT_THAT(getDiagnosticString(),
410 HasSubstr("Tessellation execution model entry points can specify "
411 "at most one of SpacingEqual, SpacingFractionalOdd or "
412 "SpacingFractionalEven execution modes."));
413 }
414
TEST_F(ValidateMode,TessellationControlBothVertex)415 TEST_F(ValidateMode, TessellationControlBothVertex) {
416 const std::string spirv = R"(
417 OpCapability Tessellation
418 OpMemoryModel Logical GLSL450
419 OpEntryPoint TessellationControl %main "main"
420 OpExecutionMode %main VertexOrderCw
421 OpExecutionMode %main VertexOrderCcw
422 )" + kVoidFunction;
423
424 CompileSuccessfully(spirv);
425 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
426 EXPECT_THAT(
427 getDiagnosticString(),
428 HasSubstr("Tessellation execution model entry points can specify at most "
429 "one of VertexOrderCw or VertexOrderCcw execution modes."));
430 }
431
TEST_F(ValidateMode,TessellationEvaluationBothVertex)432 TEST_F(ValidateMode, TessellationEvaluationBothVertex) {
433 const std::string spirv = R"(
434 OpCapability Tessellation
435 OpMemoryModel Logical GLSL450
436 OpEntryPoint TessellationEvaluation %main "main"
437 OpExecutionMode %main VertexOrderCw
438 OpExecutionMode %main VertexOrderCcw
439 )" + kVoidFunction;
440
441 CompileSuccessfully(spirv);
442 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
443 EXPECT_THAT(
444 getDiagnosticString(),
445 HasSubstr("Tessellation execution model entry points can specify at most "
446 "one of VertexOrderCw or VertexOrderCcw execution modes."));
447 }
448
449 using ValidateModeGeometry = spvtest::ValidateBase<std::tuple<
450 std::tuple<std::string, std::string, std::string, std::string, std::string>,
451 std::tuple<std::string, std::string, std::string>>>;
452
TEST_P(ValidateModeGeometry,ExecutionMode)453 TEST_P(ValidateModeGeometry, ExecutionMode) {
454 std::vector<std::string> input_modes;
455 std::vector<std::string> output_modes;
456 input_modes.push_back(std::get<0>(std::get<0>(GetParam())));
457 input_modes.push_back(std::get<1>(std::get<0>(GetParam())));
458 input_modes.push_back(std::get<2>(std::get<0>(GetParam())));
459 input_modes.push_back(std::get<3>(std::get<0>(GetParam())));
460 input_modes.push_back(std::get<4>(std::get<0>(GetParam())));
461 output_modes.push_back(std::get<0>(std::get<1>(GetParam())));
462 output_modes.push_back(std::get<1>(std::get<1>(GetParam())));
463 output_modes.push_back(std::get<2>(std::get<1>(GetParam())));
464
465 std::ostringstream sstr;
466 sstr << "OpCapability Geometry\n";
467 sstr << "OpMemoryModel Logical GLSL450\n";
468 sstr << "OpEntryPoint Geometry %main \"main\"\n";
469 size_t num_input_modes = 0;
470 for (auto input : input_modes) {
471 if (!input.empty()) {
472 num_input_modes++;
473 sstr << "OpExecutionMode %main " << input << "\n";
474 }
475 }
476 size_t num_output_modes = 0;
477 for (auto output : output_modes) {
478 if (!output.empty()) {
479 num_output_modes++;
480 sstr << "OpExecutionMode %main " << output << "\n";
481 }
482 }
483 sstr << "%void = OpTypeVoid\n";
484 sstr << "%void_fn = OpTypeFunction %void\n";
485 sstr << "%int = OpTypeInt 32 0\n";
486 sstr << "%int1 = OpConstant %int 1\n";
487 sstr << "%main = OpFunction %void None %void_fn\n";
488 sstr << "%entry = OpLabel\n";
489 sstr << "OpReturn\n";
490 sstr << "OpFunctionEnd\n";
491
492 CompileSuccessfully(sstr.str());
493 if (num_input_modes == 1 && num_output_modes == 1) {
494 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
495 } else {
496 EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
497 if (num_input_modes != 1) {
498 EXPECT_THAT(getDiagnosticString(),
499 HasSubstr("Geometry execution model entry points must "
500 "specify exactly one of InputPoints, InputLines, "
501 "InputLinesAdjacency, Triangles or "
502 "InputTrianglesAdjacency execution modes."));
503 } else {
504 EXPECT_THAT(
505 getDiagnosticString(),
506 HasSubstr("Geometry execution model entry points must specify "
507 "exactly one of OutputPoints, OutputLineStrip or "
508 "OutputTriangleStrip execution modes."));
509 }
510 }
511 }
512
513 INSTANTIATE_TEST_CASE_P(
514 GeometryRequiredModes, ValidateModeGeometry,
515 Combine(Combine(Values("InputPoints", ""), Values("InputLines", ""),
516 Values("InputLinesAdjacency", ""), Values("Triangles", ""),
517 Values("InputTrianglesAdjacency", "")),
518 Combine(Values("OutputPoints", ""), Values("OutputLineStrip", ""),
519 Values("OutputTriangleStrip", ""))));
520
521 using ValidateModeExecution =
522 spvtest::ValidateBase<std::tuple<spv_result_t, std::string, std::string,
523 std::string, spv_target_env>>;
524
TEST_P(ValidateModeExecution,ExecutionMode)525 TEST_P(ValidateModeExecution, ExecutionMode) {
526 const spv_result_t expectation = std::get<0>(GetParam());
527 const std::string error = std::get<1>(GetParam());
528 const std::string model = std::get<2>(GetParam());
529 const std::string mode = std::get<3>(GetParam());
530 const spv_target_env env = std::get<4>(GetParam());
531
532 std::ostringstream sstr;
533 sstr << "OpCapability Shader\n";
534 sstr << "OpCapability Geometry\n";
535 sstr << "OpCapability Tessellation\n";
536 sstr << "OpCapability TransformFeedback\n";
537 if (!spvIsVulkanEnv(env)) {
538 sstr << "OpCapability Kernel\n";
539 if (env == SPV_ENV_UNIVERSAL_1_3) {
540 sstr << "OpCapability SubgroupDispatch\n";
541 }
542 }
543 sstr << "OpMemoryModel Logical GLSL450\n";
544 sstr << "OpEntryPoint " << model << " %main \"main\"\n";
545 if (mode.find("LocalSizeId") == 0 || mode.find("LocalSizeHintId") == 0 ||
546 mode.find("SubgroupsPerWorkgroupId") == 0) {
547 sstr << "OpExecutionModeId %main " << mode << "\n";
548 } else {
549 sstr << "OpExecutionMode %main " << mode << "\n";
550 }
551 if (model == "Geometry") {
552 if (!(mode.find("InputPoints") == 0 || mode.find("InputLines") == 0 ||
553 mode.find("InputLinesAdjacency") == 0 ||
554 mode.find("Triangles") == 0 ||
555 mode.find("InputTrianglesAdjacency") == 0)) {
556 // Exactly one of the above modes is required for Geometry shaders.
557 sstr << "OpExecutionMode %main InputPoints\n";
558 }
559 if (!(mode.find("OutputPoints") == 0 || mode.find("OutputLineStrip") == 0 ||
560 mode.find("OutputTriangleStrip") == 0)) {
561 // Exactly one of the above modes is required for Geometry shaders.
562 sstr << "OpExecutionMode %main OutputPoints\n";
563 }
564 } else if (model == "Fragment") {
565 if (!(mode.find("OriginUpperLeft") == 0 ||
566 mode.find("OriginLowerLeft") == 0)) {
567 // Exactly one of the above modes is required for Fragment shaders.
568 sstr << "OpExecutionMode %main OriginUpperLeft\n";
569 }
570 }
571 sstr << "%void = OpTypeVoid\n";
572 sstr << "%void_fn = OpTypeFunction %void\n";
573 sstr << "%int = OpTypeInt 32 0\n";
574 sstr << "%int1 = OpConstant %int 1\n";
575 sstr << "%main = OpFunction %void None %void_fn\n";
576 sstr << "%entry = OpLabel\n";
577 sstr << "OpReturn\n";
578 sstr << "OpFunctionEnd\n";
579
580 CompileSuccessfully(sstr.str(), env);
581 EXPECT_THAT(expectation, ValidateInstructions(env));
582 if (expectation != SPV_SUCCESS) {
583 EXPECT_THAT(getDiagnosticString(), HasSubstr(error));
584 }
585 }
586
587 INSTANTIATE_TEST_CASE_P(
588 ValidateModeGeometryOnlyGoodSpv10, ValidateModeExecution,
589 Combine(Values(SPV_SUCCESS), Values(""), Values("Geometry"),
590 Values("Invocations 3", "InputPoints", "InputLines",
591 "InputLinesAdjacency", "InputTrianglesAdjacency",
592 "OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
593 Values(SPV_ENV_UNIVERSAL_1_0)));
594
595 INSTANTIATE_TEST_CASE_P(
596 ValidateModeGeometryOnlyBadSpv10, ValidateModeExecution,
597 Combine(Values(SPV_ERROR_INVALID_DATA),
598 Values("Execution mode can only be used with the Geometry "
599 "execution model."),
600 Values("Fragment", "TessellationEvaluation", "TessellationControl",
601 "GLCompute", "Vertex", "Kernel"),
602 Values("Invocations 3", "InputPoints", "InputLines",
603 "InputLinesAdjacency", "InputTrianglesAdjacency",
604 "OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
605 Values(SPV_ENV_UNIVERSAL_1_0)));
606
607 INSTANTIATE_TEST_CASE_P(
608 ValidateModeTessellationOnlyGoodSpv10, ValidateModeExecution,
609 Combine(Values(SPV_SUCCESS), Values(""),
610 Values("TessellationControl", "TessellationEvaluation"),
611 Values("SpacingEqual", "SpacingFractionalEven",
612 "SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
613 "PointMode", "Quads", "Isolines"),
614 Values(SPV_ENV_UNIVERSAL_1_0)));
615
616 INSTANTIATE_TEST_CASE_P(
617 ValidateModeTessellationOnlyBadSpv10, ValidateModeExecution,
618 Combine(Values(SPV_ERROR_INVALID_DATA),
619 Values("Execution mode can only be used with a tessellation "
620 "execution model."),
621 Values("Fragment", "Geometry", "GLCompute", "Vertex", "Kernel"),
622 Values("SpacingEqual", "SpacingFractionalEven",
623 "SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
624 "PointMode", "Quads", "Isolines"),
625 Values(SPV_ENV_UNIVERSAL_1_0)));
626
627 INSTANTIATE_TEST_CASE_P(ValidateModeGeometryAndTessellationGoodSpv10,
628 ValidateModeExecution,
629 Combine(Values(SPV_SUCCESS), Values(""),
630 Values("TessellationControl",
631 "TessellationEvaluation", "Geometry"),
632 Values("Triangles", "OutputVertices 3"),
633 Values(SPV_ENV_UNIVERSAL_1_0)));
634
635 INSTANTIATE_TEST_CASE_P(
636 ValidateModeGeometryAndTessellationBadSpv10, ValidateModeExecution,
637 Combine(Values(SPV_ERROR_INVALID_DATA),
638 Values("Execution mode can only be used with a Geometry or "
639 "tessellation execution model."),
640 Values("Fragment", "GLCompute", "Vertex", "Kernel"),
641 Values("Triangles", "OutputVertices 3"),
642 Values(SPV_ENV_UNIVERSAL_1_0)));
643
644 INSTANTIATE_TEST_CASE_P(
645 ValidateModeFragmentOnlyGoodSpv10, ValidateModeExecution,
646 Combine(Values(SPV_SUCCESS), Values(""), Values("Fragment"),
647 Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
648 "EarlyFragmentTests", "DepthReplacing", "DepthLess",
649 "DepthUnchanged"),
650 Values(SPV_ENV_UNIVERSAL_1_0)));
651
652 INSTANTIATE_TEST_CASE_P(
653 ValidateModeFragmentOnlyBadSpv10, ValidateModeExecution,
654 Combine(Values(SPV_ERROR_INVALID_DATA),
655 Values("Execution mode can only be used with the Fragment "
656 "execution model."),
657 Values("Geometry", "TessellationControl", "TessellationEvaluation",
658 "GLCompute", "Vertex", "Kernel"),
659 Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
660 "EarlyFragmentTests", "DepthReplacing", "DepthLess",
661 "DepthUnchanged"),
662 Values(SPV_ENV_UNIVERSAL_1_0)));
663
664 INSTANTIATE_TEST_CASE_P(ValidateModeKernelOnlyGoodSpv13, ValidateModeExecution,
665 Combine(Values(SPV_SUCCESS), Values(""),
666 Values("Kernel"),
667 Values("LocalSizeHint 1 1 1", "VecTypeHint 4",
668 "ContractionOff",
669 "LocalSizeHintId %int1"),
670 Values(SPV_ENV_UNIVERSAL_1_3)));
671
672 INSTANTIATE_TEST_CASE_P(
673 ValidateModeKernelOnlyBadSpv13, ValidateModeExecution,
674 Combine(
675 Values(SPV_ERROR_INVALID_DATA),
676 Values(
677 "Execution mode can only be used with the Kernel execution model."),
678 Values("Geometry", "TessellationControl", "TessellationEvaluation",
679 "GLCompute", "Vertex", "Fragment"),
680 Values("LocalSizeHint 1 1 1", "VecTypeHint 4", "ContractionOff",
681 "LocalSizeHintId %int1"),
682 Values(SPV_ENV_UNIVERSAL_1_3)));
683
684 INSTANTIATE_TEST_CASE_P(
685 ValidateModeGLComputeAndKernelGoodSpv13, ValidateModeExecution,
686 Combine(Values(SPV_SUCCESS), Values(""), Values("Kernel", "GLCompute"),
687 Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
688 Values(SPV_ENV_UNIVERSAL_1_3)));
689
690 INSTANTIATE_TEST_CASE_P(
691 ValidateModeGLComputeAndKernelBadSpv13, ValidateModeExecution,
692 Combine(Values(SPV_ERROR_INVALID_DATA),
693 Values("Execution mode can only be used with a Kernel or GLCompute "
694 "execution model."),
695 Values("Geometry", "TessellationControl", "TessellationEvaluation",
696 "Fragment", "Vertex"),
697 Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
698 Values(SPV_ENV_UNIVERSAL_1_3)));
699
700 INSTANTIATE_TEST_CASE_P(
701 ValidateModeAllGoodSpv13, ValidateModeExecution,
702 Combine(Values(SPV_SUCCESS), Values(""),
703 Values("Kernel", "GLCompute", "Geometry", "TessellationControl",
704 "TessellationEvaluation", "Fragment", "Vertex"),
705 Values("Xfb", "Initializer", "Finalizer", "SubgroupSize 1",
706 "SubgroupsPerWorkgroup 1", "SubgroupsPerWorkgroupId %int1"),
707 Values(SPV_ENV_UNIVERSAL_1_3)));
708
TEST_F(ValidateModeExecution,MeshNVLocalSize)709 TEST_F(ValidateModeExecution, MeshNVLocalSize) {
710 const std::string spirv = R"(
711 OpCapability Shader
712 OpCapability MeshShadingNV
713 OpExtension "SPV_NV_mesh_shader"
714 OpMemoryModel Logical GLSL450
715 OpEntryPoint MeshNV %main "main"
716 OpExecutionMode %main LocalSize 1 1 1
717 )" + kVoidFunction;
718
719 CompileSuccessfully(spirv);
720 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
721 }
722
TEST_F(ValidateModeExecution,TaskNVLocalSize)723 TEST_F(ValidateModeExecution, TaskNVLocalSize) {
724 const std::string spirv = R"(
725 OpCapability Shader
726 OpCapability MeshShadingNV
727 OpExtension "SPV_NV_mesh_shader"
728 OpMemoryModel Logical GLSL450
729 OpEntryPoint TaskNV %main "main"
730 OpExecutionMode %main LocalSize 1 1 1
731 )" + kVoidFunction;
732
733 CompileSuccessfully(spirv);
734 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
735 }
736
TEST_F(ValidateModeExecution,MeshNVOutputPoints)737 TEST_F(ValidateModeExecution, MeshNVOutputPoints) {
738 const std::string spirv = R"(
739 OpCapability Shader
740 OpCapability MeshShadingNV
741 OpExtension "SPV_NV_mesh_shader"
742 OpMemoryModel Logical GLSL450
743 OpEntryPoint MeshNV %main "main"
744 OpExecutionMode %main OutputPoints
745 )" + kVoidFunction;
746
747 CompileSuccessfully(spirv);
748 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
749 }
750
TEST_F(ValidateModeExecution,MeshNVOutputVertices)751 TEST_F(ValidateModeExecution, MeshNVOutputVertices) {
752 const std::string spirv = R"(
753 OpCapability Shader
754 OpCapability MeshShadingNV
755 OpExtension "SPV_NV_mesh_shader"
756 OpMemoryModel Logical GLSL450
757 OpEntryPoint MeshNV %main "main"
758 OpExecutionMode %main OutputVertices 42
759 )" + kVoidFunction;
760
761 CompileSuccessfully(spirv);
762 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
763 }
764
TEST_F(ValidateModeExecution,MeshNVLocalSizeId)765 TEST_F(ValidateModeExecution, MeshNVLocalSizeId) {
766 const std::string spirv = R"(
767 OpCapability Shader
768 OpCapability MeshShadingNV
769 OpExtension "SPV_NV_mesh_shader"
770 OpMemoryModel Logical GLSL450
771 OpEntryPoint MeshNV %main "main"
772 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
773 %int = OpTypeInt 32 0
774 %int_1 = OpConstant %int 1
775 )" + kVoidFunction;
776
777 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
778 CompileSuccessfully(spirv, env);
779 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
780 }
781
TEST_F(ValidateModeExecution,TaskNVLocalSizeId)782 TEST_F(ValidateModeExecution, TaskNVLocalSizeId) {
783 const std::string spirv = R"(
784 OpCapability Shader
785 OpCapability MeshShadingNV
786 OpExtension "SPV_NV_mesh_shader"
787 OpMemoryModel Logical GLSL450
788 OpEntryPoint TaskNV %main "main"
789 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
790 %int = OpTypeInt 32 0
791 %int_1 = OpConstant %int 1
792 )" + kVoidFunction;
793
794 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
795 CompileSuccessfully(spirv, env);
796 EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
797 }
798
799 } // namespace
800 } // namespace val
801 } // namespace spvtools
802