• 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(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