• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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