1 // Copyright (c) 2022 The Khronos Group Inc.
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 // Tests instructions from SPV_EXT_mesh_shader
16 
17 #include <string>
18 
19 #include "gmock/gmock.h"
20 #include "test/val/val_fixtures.h"
21 
22 namespace spvtools {
23 namespace val {
24 namespace {
25 
26 using ::testing::HasSubstr;
27 using ::testing::Values;
28 
29 using ValidateMeshShading = spvtest::ValidateBase<bool>;
30 
TEST_F(ValidateMeshShading,EmitMeshTasksEXTNotLastInstructionUniversal)31 TEST_F(ValidateMeshShading, EmitMeshTasksEXTNotLastInstructionUniversal) {
32   const std::string body = R"(
33                OpCapability MeshShadingEXT
34                OpExtension "SPV_EXT_mesh_shader"
35                OpMemoryModel Logical GLSL450
36                OpEntryPoint TaskEXT %main "main" %p
37                OpExecutionModeId %main LocalSizeId %uint_1 %uint_1 %uint_1
38        %void = OpTypeVoid
39        %func = OpTypeFunction %void
40        %uint = OpTypeInt 32 0
41      %uint_1 = OpConstant %uint 1
42       %float = OpTypeFloat 32
43   %arr_float = OpTypeArray %float %uint_1
44     %Payload = OpTypeStruct %arr_float
45 %ptr_Payload = OpTypePointer TaskPayloadWorkgroupEXT %Payload
46           %p = OpVariable %ptr_Payload TaskPayloadWorkgroupEXT
47        %main = OpFunction %void None %func
48      %label1 = OpLabel
49                OpEmitMeshTasksEXT %uint_1 %uint_1 %uint_1 %p
50                OpBranch %label2
51      %label2 = OpLabel
52                OpReturn
53                OpFunctionEnd
54 )";
55 
56   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_4);
57   EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT,
58             ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
59   EXPECT_THAT(getDiagnosticString(),
60               HasSubstr("Branch must appear in a block"));
61 }
62 
TEST_F(ValidateMeshShading,EmitMeshTasksEXTNotLastInstructionVulkan)63 TEST_F(ValidateMeshShading, EmitMeshTasksEXTNotLastInstructionVulkan) {
64   const std::string body = R"(
65                OpCapability MeshShadingEXT
66                OpExtension "SPV_EXT_mesh_shader"
67                OpMemoryModel Logical GLSL450
68                OpEntryPoint TaskEXT %main "main" %p
69                OpExecutionModeId %main LocalSizeId %uint_1 %uint_1 %uint_1
70        %void = OpTypeVoid
71        %func = OpTypeFunction %void
72        %uint = OpTypeInt 32 0
73      %uint_1 = OpConstant %uint 1
74       %float = OpTypeFloat 32
75   %arr_float = OpTypeArray %float %uint_1
76     %Payload = OpTypeStruct %arr_float
77 %ptr_Payload = OpTypePointer TaskPayloadWorkgroupEXT %Payload
78           %p = OpVariable %ptr_Payload TaskPayloadWorkgroupEXT
79        %main = OpFunction %void None %func
80      %label1 = OpLabel
81                OpEmitMeshTasksEXT %uint_1 %uint_1 %uint_1 %p
82                OpReturn
83                OpFunctionEnd
84 )";
85 
86   CompileSuccessfully(body, SPV_ENV_VULKAN_1_2);
87   EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPV_ENV_VULKAN_1_2));
88   EXPECT_THAT(getDiagnosticString(),
89               HasSubstr("Return must appear in a block"));
90 }
91 
TEST_F(ValidateMeshShading,BasicTaskSuccess)92 TEST_F(ValidateMeshShading, BasicTaskSuccess) {
93   const std::string body = R"(
94                OpCapability MeshShadingEXT
95                OpExtension "SPV_EXT_mesh_shader"
96                OpMemoryModel Logical GLSL450
97                OpEntryPoint TaskEXT %main "main"
98        %void = OpTypeVoid
99        %func = OpTypeFunction %void
100        %main = OpFunction %void None %func
101       %label = OpLabel
102                OpReturn
103                OpFunctionEnd
104 )";
105 
106   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
107   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
108 }
109 
TEST_F(ValidateMeshShading,BasicMeshSuccess)110 TEST_F(ValidateMeshShading, BasicMeshSuccess) {
111   const std::string body = R"(
112                OpCapability MeshShadingEXT
113                OpExtension "SPV_EXT_mesh_shader"
114                OpMemoryModel Logical GLSL450
115                OpEntryPoint MeshEXT %main "main"
116                OpExecutionMode %main OutputVertices 1
117                OpExecutionMode %main OutputPrimitivesEXT 1
118                OpExecutionMode %main OutputTrianglesEXT
119        %void = OpTypeVoid
120        %func = OpTypeFunction %void
121        %main = OpFunction %void None %func
122       %label = OpLabel
123                OpReturn
124                OpFunctionEnd
125 )";
126 
127   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
128   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
129 }
130 
TEST_F(ValidateMeshShading,VulkanBasicMeshAndTaskSuccess)131 TEST_F(ValidateMeshShading, VulkanBasicMeshAndTaskSuccess) {
132   const std::string body = R"(
133                OpCapability MeshShadingEXT
134                OpExtension "SPV_EXT_mesh_shader"
135                OpExtension "SPV_NV_mesh_shader"
136                OpMemoryModel Logical GLSL450
137                OpEntryPoint MeshEXT %mainMesh "mainMesh"
138                OpEntryPoint TaskEXT %mainTask "mainTask"
139                OpExecutionMode %mainMesh OutputVertices 1
140                OpExecutionMode %mainMesh OutputPrimitivesEXT 1
141                OpExecutionMode %mainMesh OutputTrianglesEXT
142        %void = OpTypeVoid
143        %func = OpTypeFunction %void
144    %mainMesh = OpFunction %void None %func
145   %labelMesh = OpLabel
146                OpReturn
147                OpFunctionEnd
148    %mainTask = OpFunction %void None %func
149   %labelTask = OpLabel
150                OpReturn
151                OpFunctionEnd
152 )";
153 
154   CompileSuccessfully(body, SPV_ENV_VULKAN_1_2);
155   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
156 }
157 
TEST_F(ValidateMeshShading,VulkanBasicMeshAndTaskBad)158 TEST_F(ValidateMeshShading, VulkanBasicMeshAndTaskBad) {
159   const std::string body = R"(
160                OpCapability MeshShadingEXT
161                OpCapability MeshShadingNV
162                OpExtension "SPV_EXT_mesh_shader"
163                OpExtension "SPV_NV_mesh_shader"
164                OpMemoryModel Logical GLSL450
165                OpEntryPoint MeshEXT %mainMesh "mainMesh"
166                OpEntryPoint TaskNV %mainTask "mainTask"
167                OpExecutionMode %mainMesh OutputVertices 1
168                OpExecutionMode %mainMesh OutputPrimitivesEXT 1
169                OpExecutionMode %mainMesh OutputTrianglesEXT
170        %void = OpTypeVoid
171        %func = OpTypeFunction %void
172    %mainMesh = OpFunction %void None %func
173   %labelMesh = OpLabel
174                OpReturn
175                OpFunctionEnd
176    %mainTask = OpFunction %void None %func
177   %labelTask = OpLabel
178                OpReturn
179                OpFunctionEnd
180 )";
181 
182   CompileSuccessfully(body, SPV_ENV_VULKAN_1_2);
183   EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPV_ENV_VULKAN_1_2));
184   EXPECT_THAT(getDiagnosticString(),
185               AnyVUID("VUID-StandaloneSpirv-MeshEXT-07102"));
186   EXPECT_THAT(getDiagnosticString(),
187               HasSubstr("Module can't mix MeshEXT/TaskEXT with MeshNV/TaskNV "
188                         "Execution Model."));
189 }
190 
TEST_F(ValidateMeshShading,MeshMissingOutputVertices)191 TEST_F(ValidateMeshShading, MeshMissingOutputVertices) {
192   const std::string body = R"(
193                OpCapability MeshShadingEXT
194                OpExtension "SPV_EXT_mesh_shader"
195                OpMemoryModel Logical GLSL450
196                OpEntryPoint MeshEXT %main "main"
197                OpExecutionMode %main OutputPrimitivesEXT 1
198                OpExecutionMode %main OutputTrianglesEXT
199        %void = OpTypeVoid
200        %func = OpTypeFunction %void
201        %main = OpFunction %void None %func
202       %label = OpLabel
203                OpReturn
204                OpFunctionEnd
205 )";
206 
207   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
208   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
209             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
210   EXPECT_THAT(
211       getDiagnosticString(),
212       HasSubstr("MeshEXT execution model entry points must specify both "
213                 "OutputPrimitivesEXT and OutputVertices Execution Modes."));
214 }
215 
TEST_F(ValidateMeshShading,MeshMissingOutputPrimitivesEXT)216 TEST_F(ValidateMeshShading, MeshMissingOutputPrimitivesEXT) {
217   const std::string body = R"(
218                OpCapability MeshShadingEXT
219                OpExtension "SPV_EXT_mesh_shader"
220                OpMemoryModel Logical GLSL450
221                OpEntryPoint MeshEXT %main "main"
222                OpExecutionMode %main OutputVertices 1
223                OpExecutionMode %main OutputTrianglesEXT
224        %void = OpTypeVoid
225        %func = OpTypeFunction %void
226        %main = OpFunction %void None %func
227       %label = OpLabel
228                OpReturn
229                OpFunctionEnd
230 )";
231 
232   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
233   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
234             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
235   EXPECT_THAT(
236       getDiagnosticString(),
237       HasSubstr("MeshEXT execution model entry points must specify both "
238                 "OutputPrimitivesEXT and OutputVertices Execution Modes."));
239 }
240 
TEST_F(ValidateMeshShading,MeshMissingOutputType)241 TEST_F(ValidateMeshShading, MeshMissingOutputType) {
242   const std::string body = R"(
243                OpCapability MeshShadingEXT
244                OpExtension "SPV_EXT_mesh_shader"
245                OpMemoryModel Logical GLSL450
246                OpEntryPoint MeshEXT %main "main"
247                OpExecutionMode %main OutputVertices 1
248                OpExecutionMode %main OutputPrimitivesEXT 1
249        %void = OpTypeVoid
250        %func = OpTypeFunction %void
251        %main = OpFunction %void None %func
252       %label = OpLabel
253                OpReturn
254                OpFunctionEnd
255 )";
256 
257   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
258   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
259             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
260   EXPECT_THAT(getDiagnosticString(),
261               HasSubstr("MeshEXT execution model entry points must specify "
262                         "exactly one of OutputPoints, OutputLinesEXT, or "
263                         "OutputTrianglesEXT Execution Modes."));
264 }
265 
TEST_F(ValidateMeshShading,MeshMultipleOutputType)266 TEST_F(ValidateMeshShading, MeshMultipleOutputType) {
267   const std::string body = R"(
268                OpCapability MeshShadingEXT
269                OpExtension "SPV_EXT_mesh_shader"
270                OpMemoryModel Logical GLSL450
271                OpEntryPoint MeshEXT %main "main"
272                OpExecutionMode %main OutputVertices 1
273                OpExecutionMode %main OutputPrimitivesEXT 1
274                OpExecutionMode %main OutputLinesEXT
275                OpExecutionMode %main OutputTrianglesEXT
276        %void = OpTypeVoid
277        %func = OpTypeFunction %void
278        %main = OpFunction %void None %func
279       %label = OpLabel
280                OpReturn
281                OpFunctionEnd
282 )";
283 
284   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
285   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
286             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
287   EXPECT_THAT(getDiagnosticString(),
288               HasSubstr("MeshEXT execution model entry points must specify "
289                         "exactly one of OutputPoints, OutputLinesEXT, or "
290                         "OutputTrianglesEXT Execution Modes."));
291 }
292 
TEST_F(ValidateMeshShading,BadExecutionModelOutputLinesEXT)293 TEST_F(ValidateMeshShading, BadExecutionModelOutputLinesEXT) {
294   const std::string body = R"(
295                OpCapability MeshShadingEXT
296                OpExtension "SPV_EXT_mesh_shader"
297                OpMemoryModel Logical GLSL450
298                OpEntryPoint GLCompute %main "main"
299                OpExecutionMode %main OutputLinesEXT
300        %void = OpTypeVoid
301        %func = OpTypeFunction %void
302        %main = OpFunction %void None %func
303       %label = OpLabel
304                OpReturn
305                OpFunctionEnd
306 )";
307 
308   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
309   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
310             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
311   EXPECT_THAT(getDiagnosticString(),
312               HasSubstr("Execution mode can only be used with the MeshEXT or "
313                         "MeshNV execution model."));
314 }
315 
TEST_F(ValidateMeshShading,BadExecutionModelOutputTrianglesEXT)316 TEST_F(ValidateMeshShading, BadExecutionModelOutputTrianglesEXT) {
317   const std::string body = R"(
318                OpCapability MeshShadingEXT
319                OpExtension "SPV_EXT_mesh_shader"
320                OpMemoryModel Logical GLSL450
321                OpEntryPoint GLCompute %main "main"
322                OpExecutionMode %main OutputTrianglesEXT
323        %void = OpTypeVoid
324        %func = OpTypeFunction %void
325        %main = OpFunction %void None %func
326       %label = OpLabel
327                OpReturn
328                OpFunctionEnd
329 )";
330 
331   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
332   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
333             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
334   EXPECT_THAT(getDiagnosticString(),
335               HasSubstr("Execution mode can only be used with the MeshEXT or "
336                         "MeshNV execution model."));
337 }
338 
TEST_F(ValidateMeshShading,BadExecutionModelOutputPrimitivesEXT)339 TEST_F(ValidateMeshShading, BadExecutionModelOutputPrimitivesEXT) {
340   const std::string body = R"(
341                OpCapability MeshShadingEXT
342                OpExtension "SPV_EXT_mesh_shader"
343                OpMemoryModel Logical GLSL450
344                OpEntryPoint GLCompute %main "main"
345                OpExecutionMode %main OutputPrimitivesEXT 1
346        %void = OpTypeVoid
347        %func = OpTypeFunction %void
348        %main = OpFunction %void None %func
349       %label = OpLabel
350                OpReturn
351                OpFunctionEnd
352 )";
353 
354   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
355   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
356             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
357   EXPECT_THAT(getDiagnosticString(),
358               HasSubstr("Execution mode can only be used with the MeshEXT or "
359                         "MeshNV execution model."));
360 }
361 
TEST_F(ValidateMeshShading,OpEmitMeshTasksBadGroupCountSignedInt)362 TEST_F(ValidateMeshShading, OpEmitMeshTasksBadGroupCountSignedInt) {
363   const std::string body = R"(
364                OpCapability MeshShadingEXT
365                OpExtension "SPV_EXT_mesh_shader"
366                OpMemoryModel Logical GLSL450
367                OpEntryPoint TaskEXT %main "main"
368        %void = OpTypeVoid
369        %func = OpTypeFunction %void
370         %int = OpTypeInt 32 1
371        %uint = OpTypeInt 32 0
372       %int_1 = OpConstant %int 1
373      %uint_1 = OpConstant %uint 1
374        %main = OpFunction %void None %func
375        %label = OpLabel
376                OpEmitMeshTasksEXT %int_1 %uint_1 %uint_1
377                OpFunctionEnd
378 )";
379 
380   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
381   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
382             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
383   EXPECT_THAT(getDiagnosticString(),
384               HasSubstr("Group Count X must be a 32-bit unsigned int scalar"));
385 }
386 
TEST_F(ValidateMeshShading,OpEmitMeshTasksBadGroupCountVector)387 TEST_F(ValidateMeshShading, OpEmitMeshTasksBadGroupCountVector) {
388   const std::string body = R"(
389                OpCapability MeshShadingEXT
390                OpExtension "SPV_EXT_mesh_shader"
391                OpMemoryModel Logical GLSL450
392                OpEntryPoint TaskEXT %main "main"
393        %void = OpTypeVoid
394        %func = OpTypeFunction %void
395        %uint = OpTypeInt 32 0
396      %v2uint = OpTypeVector %uint 2
397 %_ptr_v2uint = OpTypePointer Function %v2uint
398      %uint_1 = OpConstant %uint 1
399   %composite = OpConstantComposite %v2uint %uint_1 %uint_1
400   %_ptr_uint = OpTypePointer Function %uint
401        %main = OpFunction %void None %func
402       %label = OpLabel
403           %x = OpVariable %_ptr_v2uint Function
404                OpStore %x %composite
405          %13 = OpAccessChain %_ptr_uint %x %uint_1
406          %14 = OpLoad %uint %13
407                OpEmitMeshTasksEXT %14 %composite %uint_1
408                OpFunctionEnd
409 )";
410 
411   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
412   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
413             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
414   EXPECT_THAT(getDiagnosticString(),
415               HasSubstr("Group Count Y must be a 32-bit unsigned int scalar"));
416 }
417 
TEST_F(ValidateMeshShading,OpEmitMeshTasksBadPayload)418 TEST_F(ValidateMeshShading, OpEmitMeshTasksBadPayload) {
419   const std::string body = R"(
420                OpCapability MeshShadingEXT
421                OpExtension "SPV_EXT_mesh_shader"
422                OpMemoryModel Logical GLSL450
423                OpEntryPoint TaskEXT %main "main" %payload
424        %void = OpTypeVoid
425        %func = OpTypeFunction %void
426        %uint = OpTypeInt 32 0
427        %task = OpTypeStruct %uint
428 %_ptr_Uniform = OpTypePointer Uniform %task
429     %payload = OpVariable %_ptr_Uniform Uniform
430      %uint_1 = OpConstant %uint 1
431        %main = OpFunction %void None %func
432       %label = OpLabel
433                OpEmitMeshTasksEXT %uint_1 %uint_1 %uint_1 %payload
434                OpFunctionEnd
435 )";
436 
437   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
438   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
439             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
440   EXPECT_THAT(getDiagnosticString(),
441               HasSubstr("Payload OpVariable must have a storage class of "
442                         "TaskPayloadWorkgroupEXT"));
443 }
444 
TEST_F(ValidateMeshShading,TaskPayloadWorkgroupBadExecutionModel)445 TEST_F(ValidateMeshShading, TaskPayloadWorkgroupBadExecutionModel) {
446   const std::string body = R"(
447                OpCapability MeshShadingEXT
448                OpExtension "SPV_EXT_mesh_shader"
449                OpMemoryModel Logical GLSL450
450                OpEntryPoint GLCompute %main "main" %payload
451        %void = OpTypeVoid
452        %func = OpTypeFunction %void
453        %uint = OpTypeInt 32 0
454 %_ptr_TaskPayloadWorkgroupEXT = OpTypePointer TaskPayloadWorkgroupEXT %uint
455     %payload = OpVariable %_ptr_TaskPayloadWorkgroupEXT TaskPayloadWorkgroupEXT
456        %main = OpFunction %void None %func
457       %label = OpLabel
458        %load = OpLoad %uint %payload
459                OpReturn
460                OpFunctionEnd
461 )";
462 
463   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
464   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
465   EXPECT_THAT(getDiagnosticString(),
466               HasSubstr("TaskPayloadWorkgroupEXT Storage Class is limited to "
467                         "TaskEXT and MeshKHR execution model"));
468 }
469 
TEST_F(ValidateMeshShading,OpSetMeshOutputsBadVertexCount)470 TEST_F(ValidateMeshShading, OpSetMeshOutputsBadVertexCount) {
471   const std::string body = R"(
472                OpCapability MeshShadingEXT
473                OpExtension "SPV_EXT_mesh_shader"
474                OpMemoryModel Logical GLSL450
475                OpEntryPoint MeshEXT %main "main"
476                OpExecutionMode %main OutputVertices 1
477                OpExecutionMode %main OutputPrimitivesNV 1
478                OpExecutionMode %main OutputTrianglesNV
479        %void = OpTypeVoid
480           %3 = OpTypeFunction %void
481         %int = OpTypeInt 32 1
482        %uint = OpTypeInt 32 0
483   %_ptr_int = OpTypePointer Function %int
484       %int_1 = OpConstant %int 1
485      %uint_1 = OpConstant %uint 1
486        %main = OpFunction %void None %3
487           %5 = OpLabel
488           %x = OpVariable %_ptr_int Function
489                OpStore %x %int_1
490        %load = OpLoad %int %x
491                OpSetMeshOutputsEXT %load %uint_1
492                OpReturn
493                OpFunctionEnd
494 )";
495 
496   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
497   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
498             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
499   EXPECT_THAT(getDiagnosticString(),
500               HasSubstr("Vertex Count must be a 32-bit unsigned int scalar"));
501 }
502 
TEST_F(ValidateMeshShading,OpSetMeshOutputsBadPrimitiveCount)503 TEST_F(ValidateMeshShading, OpSetMeshOutputsBadPrimitiveCount) {
504   const std::string body = R"(
505                OpCapability MeshShadingEXT
506                OpExtension "SPV_EXT_mesh_shader"
507                OpMemoryModel Logical GLSL450
508                OpEntryPoint MeshEXT %main "main"
509                OpExecutionMode %main OutputVertices 1
510                OpExecutionMode %main OutputPrimitivesNV 1
511                OpExecutionMode %main OutputTrianglesNV
512        %void = OpTypeVoid
513           %3 = OpTypeFunction %void
514         %int = OpTypeInt 32 1
515        %uint = OpTypeInt 32 0
516       %int_1 = OpConstant %int 1
517      %uint_1 = OpConstant %uint 1
518        %main = OpFunction %void None %3
519           %5 = OpLabel
520                OpSetMeshOutputsEXT %uint_1 %int_1
521                OpReturn
522                OpFunctionEnd
523 )";
524 
525   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
526   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
527             ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
528   EXPECT_THAT(
529       getDiagnosticString(),
530       HasSubstr("Primitive Count must be a 32-bit unsigned int scalar"));
531 }
532 
TEST_F(ValidateMeshShading,OpSetMeshOutputsBadExecutionModel)533 TEST_F(ValidateMeshShading, OpSetMeshOutputsBadExecutionModel) {
534   const std::string body = R"(
535                OpCapability MeshShadingEXT
536                OpExtension "SPV_EXT_mesh_shader"
537                OpMemoryModel Logical GLSL450
538                OpEntryPoint TaskEXT %main "main"
539        %void = OpTypeVoid
540           %3 = OpTypeFunction %void
541        %uint = OpTypeInt 32 0
542      %uint_1 = OpConstant %uint 1
543        %main = OpFunction %void None %3
544           %5 = OpLabel
545                OpSetMeshOutputsEXT %uint_1 %uint_1
546                OpReturn
547                OpFunctionEnd
548 )";
549 
550   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
551   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
552   EXPECT_THAT(
553       getDiagnosticString(),
554       HasSubstr("OpSetMeshOutputsEXT requires MeshEXT execution model"));
555 }
556 
TEST_F(ValidateMeshShading,OpSetMeshOutputsZeroSuccess)557 TEST_F(ValidateMeshShading, OpSetMeshOutputsZeroSuccess) {
558   const std::string body = R"(
559                OpCapability MeshShadingEXT
560                OpExtension "SPV_EXT_mesh_shader"
561                OpMemoryModel Logical GLSL450
562                OpEntryPoint MeshEXT %main "main"
563                OpExecutionMode %main OutputVertices 1
564                OpExecutionMode %main OutputPrimitivesNV 1
565                OpExecutionMode %main OutputTrianglesNV
566        %void = OpTypeVoid
567           %3 = OpTypeFunction %void
568        %uint = OpTypeInt 32 0
569      %uint_0 = OpConstant %uint 0
570        %main = OpFunction %void None %3
571           %5 = OpLabel
572                OpSetMeshOutputsEXT %uint_0 %uint_0
573                OpReturn
574                OpFunctionEnd
575 )";
576 
577   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
578   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
579 }
580 
TEST_F(ValidateMeshShading,OpEmitMeshTasksZeroSuccess)581 TEST_F(ValidateMeshShading, OpEmitMeshTasksZeroSuccess) {
582   const std::string body = R"(
583                OpCapability MeshShadingEXT
584                OpExtension "SPV_EXT_mesh_shader"
585                OpMemoryModel Logical GLSL450
586                OpEntryPoint TaskEXT %main "main"
587        %void = OpTypeVoid
588        %func = OpTypeFunction %void
589        %uint = OpTypeInt 32 0
590      %uint_0 = OpConstant %uint 1
591        %main = OpFunction %void None %func
592       %label = OpLabel
593                OpEmitMeshTasksEXT %uint_0 %uint_0 %uint_0
594                OpFunctionEnd
595 )";
596 
597   CompileSuccessfully(body, SPV_ENV_UNIVERSAL_1_5);
598   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
599 }
600 
601 }  // namespace
602 }  // namespace val
603 }  // namespace spvtools
604