• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 LunarG 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 #include <sstream>
16 #include <string>
17 
18 #include "gmock/gmock.h"
19 #include "test/unit_spirv.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::Not;
28 
29 using ValidatePrimitives = spvtest::ValidateBase<bool>;
30 
GenerateShaderCode(const std::string & body,const std::string & capabilities_and_extensions="OpCapability GeometryStreams",const std::string & execution_model="Geometry")31 std::string GenerateShaderCode(
32     const std::string& body,
33     const std::string& capabilities_and_extensions =
34         "OpCapability GeometryStreams",
35     const std::string& execution_model = "Geometry") {
36   std::ostringstream ss;
37   ss << capabilities_and_extensions << "\n";
38   ss << "OpMemoryModel Logical GLSL450\n";
39   ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
40   if (execution_model == "Geometry") {
41     ss << "OpExecutionMode %main InputPoints\n";
42     ss << "OpExecutionMode %main OutputPoints\n";
43   }
44 
45   ss << R"(
46 %void = OpTypeVoid
47 %func = OpTypeFunction %void
48 %f32 = OpTypeFloat 32
49 %u32 = OpTypeInt 32 0
50 %u32vec4 = OpTypeVector %u32 4
51 
52 %f32_0 = OpConstant %f32 0
53 %u32_0 = OpConstant %u32 0
54 %u32_1 = OpConstant %u32 1
55 %u32_2 = OpConstant %u32 2
56 %u32_3 = OpConstant %u32 3
57 %u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3
58 
59 %main = OpFunction %void None %func
60 %main_entry = OpLabel
61 )";
62 
63   ss << body;
64 
65   ss << R"(
66 OpReturn
67 OpFunctionEnd)";
68 
69   return ss.str();
70 }
71 
72 // Returns SPIR-V assembly fragment representing a function call,
73 // the end of the callee body, and the preamble and body of the called
74 // function with the given body, but missing the final return and
75 // function-end.  The result is of the form where it can be used in the
76 // |body| argument to GenerateShaderCode.
CallAndCallee(const std::string & body)77 std::string CallAndCallee(const std::string& body) {
78   std::ostringstream ss;
79   ss << R"(
80 %placeholder = OpFunctionCall %void %foo
81 OpReturn
82 OpFunctionEnd
83 
84 %foo = OpFunction %void None %func
85 %foo_entry = OpLabel
86 )";
87 
88   ss << body;
89 
90   return ss.str();
91 }
92 
93 // OpEmitVertex doesn't have any parameters, so other validation
94 // is handled by the binary parser, and generic dominance checks.
TEST_F(ValidatePrimitives,EmitVertexSuccess)95 TEST_F(ValidatePrimitives, EmitVertexSuccess) {
96   CompileSuccessfully(
97       GenerateShaderCode("OpEmitVertex", "OpCapability Geometry"));
98   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
99 }
100 
TEST_F(ValidatePrimitives,EmitVertexFailMissingCapability)101 TEST_F(ValidatePrimitives, EmitVertexFailMissingCapability) {
102   CompileSuccessfully(
103       GenerateShaderCode("OpEmitVertex", "OpCapability Shader", "Vertex"));
104   EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
105   EXPECT_THAT(
106       getDiagnosticString(),
107       HasSubstr(
108           "Opcode EmitVertex requires one of these capabilities: Geometry"));
109 }
110 
TEST_F(ValidatePrimitives,EmitVertexFailWrongExecutionMode)111 TEST_F(ValidatePrimitives, EmitVertexFailWrongExecutionMode) {
112   CompileSuccessfully(
113       GenerateShaderCode("OpEmitVertex", "OpCapability Geometry", "Vertex"));
114   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
115   EXPECT_THAT(
116       getDiagnosticString(),
117       HasSubstr("EmitVertex instructions require Geometry execution model"));
118 }
119 
TEST_F(ValidatePrimitives,EmitVertexFailWrongExecutionModeNestedFunction)120 TEST_F(ValidatePrimitives, EmitVertexFailWrongExecutionModeNestedFunction) {
121   CompileSuccessfully(GenerateShaderCode(CallAndCallee("OpEmitVertex"),
122                                          "OpCapability Geometry", "Vertex"));
123   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
124   EXPECT_THAT(
125       getDiagnosticString(),
126       HasSubstr("EmitVertex instructions require Geometry execution model"));
127 }
128 
129 // OpEndPrimitive doesn't have any parameters, so other validation
130 // is handled by the binary parser, and generic dominance checks.
TEST_F(ValidatePrimitives,EndPrimitiveSuccess)131 TEST_F(ValidatePrimitives, EndPrimitiveSuccess) {
132   CompileSuccessfully(
133       GenerateShaderCode("OpEndPrimitive", "OpCapability Geometry"));
134   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
135 }
136 
TEST_F(ValidatePrimitives,EndPrimitiveFailMissingCapability)137 TEST_F(ValidatePrimitives, EndPrimitiveFailMissingCapability) {
138   CompileSuccessfully(
139       GenerateShaderCode("OpEndPrimitive", "OpCapability Shader", "Vertex"));
140   EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
141   EXPECT_THAT(
142       getDiagnosticString(),
143       HasSubstr(
144           "Opcode EndPrimitive requires one of these capabilities: Geometry"));
145 }
146 
TEST_F(ValidatePrimitives,EndPrimitiveFailWrongExecutionMode)147 TEST_F(ValidatePrimitives, EndPrimitiveFailWrongExecutionMode) {
148   CompileSuccessfully(
149       GenerateShaderCode("OpEndPrimitive", "OpCapability Geometry", "Vertex"));
150   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
151   EXPECT_THAT(
152       getDiagnosticString(),
153       HasSubstr("EndPrimitive instructions require Geometry execution model"));
154 }
155 
TEST_F(ValidatePrimitives,EndPrimitiveFailWrongExecutionModeNestedFunction)156 TEST_F(ValidatePrimitives, EndPrimitiveFailWrongExecutionModeNestedFunction) {
157   CompileSuccessfully(GenerateShaderCode(CallAndCallee("OpEndPrimitive"),
158                                          "OpCapability Geometry", "Vertex"));
159   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
160   EXPECT_THAT(
161       getDiagnosticString(),
162       HasSubstr("EndPrimitive instructions require Geometry execution model"));
163 }
164 
TEST_F(ValidatePrimitives,EmitStreamVertexSuccess)165 TEST_F(ValidatePrimitives, EmitStreamVertexSuccess) {
166   const std::string body = R"(
167 OpEmitStreamVertex %u32_0
168 )";
169 
170   CompileSuccessfully(GenerateShaderCode(body));
171   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
172 }
173 
TEST_F(ValidatePrimitives,EmitStreamVertexFailMissingCapability)174 TEST_F(ValidatePrimitives, EmitStreamVertexFailMissingCapability) {
175   CompileSuccessfully(GenerateShaderCode("OpEmitStreamVertex %u32_0",
176                                          "OpCapability Shader", "Vertex"));
177   EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
178   EXPECT_THAT(getDiagnosticString(),
179               HasSubstr("Opcode EmitStreamVertex requires one of these "
180                         "capabilities: GeometryStreams"));
181 }
182 
TEST_F(ValidatePrimitives,EmitStreamVertexFailWrongExecutionMode)183 TEST_F(ValidatePrimitives, EmitStreamVertexFailWrongExecutionMode) {
184   CompileSuccessfully(GenerateShaderCode(
185       "OpEmitStreamVertex %u32_0", "OpCapability GeometryStreams", "Vertex"));
186   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
187   EXPECT_THAT(
188       getDiagnosticString(),
189       HasSubstr(
190           "EmitStreamVertex instructions require Geometry execution model"));
191 }
192 
TEST_F(ValidatePrimitives,EmitStreamVertexFailWrongExecutionModeNestedFunction)193 TEST_F(ValidatePrimitives,
194        EmitStreamVertexFailWrongExecutionModeNestedFunction) {
195   CompileSuccessfully(
196       GenerateShaderCode(CallAndCallee("OpEmitStreamVertex %u32_0"),
197                          "OpCapability GeometryStreams", "Vertex"));
198   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
199   EXPECT_THAT(
200       getDiagnosticString(),
201       HasSubstr(
202           "EmitStreamVertex instructions require Geometry execution model"));
203 }
204 
TEST_F(ValidatePrimitives,EmitStreamVertexNonInt)205 TEST_F(ValidatePrimitives, EmitStreamVertexNonInt) {
206   const std::string body = R"(
207 OpEmitStreamVertex %f32_0
208 )";
209 
210   CompileSuccessfully(GenerateShaderCode(body));
211   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
212   EXPECT_THAT(getDiagnosticString(),
213               HasSubstr("EmitStreamVertex: "
214                         "expected Stream to be int scalar"));
215 }
216 
TEST_F(ValidatePrimitives,EmitStreamVertexNonScalar)217 TEST_F(ValidatePrimitives, EmitStreamVertexNonScalar) {
218   const std::string body = R"(
219 OpEmitStreamVertex %u32vec4_0123
220 )";
221 
222   CompileSuccessfully(GenerateShaderCode(body));
223   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
224   EXPECT_THAT(getDiagnosticString(),
225               HasSubstr("EmitStreamVertex: "
226                         "expected Stream to be int scalar"));
227 }
228 
TEST_F(ValidatePrimitives,EmitStreamVertexNonConstant)229 TEST_F(ValidatePrimitives, EmitStreamVertexNonConstant) {
230   const std::string body = R"(
231 %val1 = OpIAdd %u32 %u32_0 %u32_1
232 OpEmitStreamVertex %val1
233 )";
234 
235   CompileSuccessfully(GenerateShaderCode(body));
236   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
237   EXPECT_THAT(getDiagnosticString(),
238               HasSubstr("EmitStreamVertex: "
239                         "expected Stream to be constant instruction"));
240 }
241 
TEST_F(ValidatePrimitives,EndStreamPrimitiveSuccess)242 TEST_F(ValidatePrimitives, EndStreamPrimitiveSuccess) {
243   const std::string body = R"(
244 OpEndStreamPrimitive %u32_0
245 )";
246 
247   CompileSuccessfully(GenerateShaderCode(body));
248   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
249 }
250 
TEST_F(ValidatePrimitives,EndStreamPrimitiveFailMissingCapability)251 TEST_F(ValidatePrimitives, EndStreamPrimitiveFailMissingCapability) {
252   CompileSuccessfully(GenerateShaderCode("OpEndStreamPrimitive %u32_0",
253                                          "OpCapability Shader", "Vertex"));
254   EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
255   EXPECT_THAT(getDiagnosticString(),
256               HasSubstr("Opcode EndStreamPrimitive requires one of these "
257                         "capabilities: GeometryStreams"));
258 }
259 
TEST_F(ValidatePrimitives,EndStreamPrimitiveFailWrongExecutionMode)260 TEST_F(ValidatePrimitives, EndStreamPrimitiveFailWrongExecutionMode) {
261   CompileSuccessfully(GenerateShaderCode(
262       "OpEndStreamPrimitive %u32_0", "OpCapability GeometryStreams", "Vertex"));
263   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
264   EXPECT_THAT(
265       getDiagnosticString(),
266       HasSubstr(
267           "EndStreamPrimitive instructions require Geometry execution model"));
268 }
269 
TEST_F(ValidatePrimitives,EndStreamPrimitiveFailWrongExecutionModeNestedFunction)270 TEST_F(ValidatePrimitives,
271        EndStreamPrimitiveFailWrongExecutionModeNestedFunction) {
272   CompileSuccessfully(
273       GenerateShaderCode(CallAndCallee("OpEndStreamPrimitive %u32_0"),
274                          "OpCapability GeometryStreams", "Vertex"));
275   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
276   EXPECT_THAT(
277       getDiagnosticString(),
278       HasSubstr(
279           "EndStreamPrimitive instructions require Geometry execution model"));
280 }
281 
TEST_F(ValidatePrimitives,EndStreamPrimitiveNonInt)282 TEST_F(ValidatePrimitives, EndStreamPrimitiveNonInt) {
283   const std::string body = R"(
284 OpEndStreamPrimitive %f32_0
285 )";
286 
287   CompileSuccessfully(GenerateShaderCode(body));
288   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
289   EXPECT_THAT(getDiagnosticString(),
290               HasSubstr("EndStreamPrimitive: "
291                         "expected Stream to be int scalar"));
292 }
293 
TEST_F(ValidatePrimitives,EndStreamPrimitiveNonScalar)294 TEST_F(ValidatePrimitives, EndStreamPrimitiveNonScalar) {
295   const std::string body = R"(
296 OpEndStreamPrimitive %u32vec4_0123
297 )";
298 
299   CompileSuccessfully(GenerateShaderCode(body));
300   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
301   EXPECT_THAT(getDiagnosticString(),
302               HasSubstr("EndStreamPrimitive: "
303                         "expected Stream to be int scalar"));
304 }
305 
TEST_F(ValidatePrimitives,EndStreamPrimitiveNonConstant)306 TEST_F(ValidatePrimitives, EndStreamPrimitiveNonConstant) {
307   const std::string body = R"(
308 %val1 = OpIAdd %u32 %u32_0 %u32_1
309 OpEndStreamPrimitive %val1
310 )";
311 
312   CompileSuccessfully(GenerateShaderCode(body));
313   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
314   EXPECT_THAT(getDiagnosticString(),
315               HasSubstr("EndStreamPrimitive: "
316                         "expected Stream to be constant instruction"));
317 }
318 
319 }  // namespace
320 }  // namespace val
321 }  // namespace spvtools
322