• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Tint Authors.
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 "src/reader/spirv/enum_converter.h"
16 
17 #include <string>
18 
19 #include "gmock/gmock.h"
20 
21 namespace tint {
22 namespace reader {
23 namespace spirv {
24 namespace {
25 
26 // Pipeline stage
27 
28 struct PipelineStageCase {
29   SpvExecutionModel model;
30   bool expect_success;
31   ast::PipelineStage expected;
32 };
operator <<(std::ostream & out,PipelineStageCase psc)33 inline std::ostream& operator<<(std::ostream& out, PipelineStageCase psc) {
34   out << "PipelineStageCase{ SpvExecutionModel:" << int(psc.model)
35       << " expect_success?:" << int(psc.expect_success)
36       << " expected:" << int(psc.expected) << "}";
37   return out;
38 }
39 
40 class SpvPipelineStageTest : public testing::TestWithParam<PipelineStageCase> {
41  public:
SpvPipelineStageTest()42   SpvPipelineStageTest()
43       : success_(true),
44         fail_stream_(&success_, &errors_),
45         converter_(fail_stream_) {}
46 
error() const47   std::string error() const { return errors_.str(); }
48 
49  protected:
50   bool success_ = true;
51   std::stringstream errors_;
52   FailStream fail_stream_;
53   EnumConverter converter_;
54 };
55 
TEST_P(SpvPipelineStageTest,Samples)56 TEST_P(SpvPipelineStageTest, Samples) {
57   const auto params = GetParam();
58 
59   const auto result = converter_.ToPipelineStage(params.model);
60   EXPECT_EQ(success_, params.expect_success);
61   if (params.expect_success) {
62     EXPECT_EQ(result, params.expected);
63     EXPECT_TRUE(error().empty());
64   } else {
65     EXPECT_EQ(result, params.expected);
66     EXPECT_THAT(error(),
67                 ::testing::StartsWith("unknown SPIR-V execution model:"));
68   }
69 }
70 
71 INSTANTIATE_TEST_SUITE_P(
72     EnumConverterGood,
73     SpvPipelineStageTest,
74     testing::Values(PipelineStageCase{SpvExecutionModelVertex, true,
75                                       ast::PipelineStage::kVertex},
76                     PipelineStageCase{SpvExecutionModelFragment, true,
77                                       ast::PipelineStage::kFragment},
78                     PipelineStageCase{SpvExecutionModelGLCompute, true,
79                                       ast::PipelineStage::kCompute}));
80 
81 INSTANTIATE_TEST_SUITE_P(
82     EnumConverterBad,
83     SpvPipelineStageTest,
84     testing::Values(PipelineStageCase{static_cast<SpvExecutionModel>(9999),
85                                       false, ast::PipelineStage::kNone},
86                     PipelineStageCase{SpvExecutionModelTessellationControl,
87                                       false, ast::PipelineStage::kNone}));
88 
89 // Storage class
90 
91 struct StorageClassCase {
92   SpvStorageClass sc;
93   bool expect_success;
94   ast::StorageClass expected;
95 };
operator <<(std::ostream & out,StorageClassCase scc)96 inline std::ostream& operator<<(std::ostream& out, StorageClassCase scc) {
97   out << "StorageClassCase{ SpvStorageClass:" << int(scc.sc)
98       << " expect_success?:" << int(scc.expect_success)
99       << " expected:" << int(scc.expected) << "}";
100   return out;
101 }
102 
103 class SpvStorageClassTest : public testing::TestWithParam<StorageClassCase> {
104  public:
SpvStorageClassTest()105   SpvStorageClassTest()
106       : success_(true),
107         fail_stream_(&success_, &errors_),
108         converter_(fail_stream_) {}
109 
error() const110   std::string error() const { return errors_.str(); }
111 
112  protected:
113   bool success_ = true;
114   std::stringstream errors_;
115   FailStream fail_stream_;
116   EnumConverter converter_;
117 };
118 
TEST_P(SpvStorageClassTest,Samples)119 TEST_P(SpvStorageClassTest, Samples) {
120   const auto params = GetParam();
121 
122   const auto result = converter_.ToStorageClass(params.sc);
123   EXPECT_EQ(success_, params.expect_success);
124   if (params.expect_success) {
125     EXPECT_EQ(result, params.expected);
126     EXPECT_TRUE(error().empty());
127   } else {
128     EXPECT_EQ(result, params.expected);
129     EXPECT_THAT(error(),
130                 ::testing::StartsWith("unknown SPIR-V storage class: "));
131   }
132 }
133 
134 INSTANTIATE_TEST_SUITE_P(
135     EnumConverterGood,
136     SpvStorageClassTest,
137     testing::Values(
138         StorageClassCase{SpvStorageClassInput, true, ast::StorageClass::kInput},
139         StorageClassCase{SpvStorageClassOutput, true,
140                          ast::StorageClass::kOutput},
141         StorageClassCase{SpvStorageClassUniform, true,
142                          ast::StorageClass::kUniform},
143         StorageClassCase{SpvStorageClassWorkgroup, true,
144                          ast::StorageClass::kWorkgroup},
145         StorageClassCase{SpvStorageClassUniformConstant, true,
146                          ast::StorageClass::kNone},
147         StorageClassCase{SpvStorageClassStorageBuffer, true,
148                          ast::StorageClass::kStorage},
149         StorageClassCase{SpvStorageClassImage, true, ast::StorageClass::kImage},
150         StorageClassCase{SpvStorageClassPrivate, true,
151                          ast::StorageClass::kPrivate},
152         StorageClassCase{SpvStorageClassFunction, true,
153                          ast::StorageClass::kFunction}));
154 
155 INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
156                          SpvStorageClassTest,
157                          testing::Values(StorageClassCase{
158                              static_cast<SpvStorageClass>(9999), false,
159                              ast::StorageClass::kInvalid}));
160 
161 // Builtin
162 
163 struct BuiltinCase {
164   SpvBuiltIn builtin;
165   bool expect_success;
166   ast::Builtin expected;
167 };
operator <<(std::ostream & out,BuiltinCase bc)168 inline std::ostream& operator<<(std::ostream& out, BuiltinCase bc) {
169   out << "BuiltinCase{ SpvBuiltIn:" << int(bc.builtin)
170       << " expect_success?:" << int(bc.expect_success)
171       << " expected:" << int(bc.expected) << "}";
172   return out;
173 }
174 
175 class SpvBuiltinTest : public testing::TestWithParam<BuiltinCase> {
176  public:
SpvBuiltinTest()177   SpvBuiltinTest()
178       : success_(true),
179         fail_stream_(&success_, &errors_),
180         converter_(fail_stream_) {}
181 
error() const182   std::string error() const { return errors_.str(); }
183 
184  protected:
185   bool success_ = true;
186   std::stringstream errors_;
187   FailStream fail_stream_;
188   EnumConverter converter_;
189 };
190 
TEST_P(SpvBuiltinTest,Samples)191 TEST_P(SpvBuiltinTest, Samples) {
192   const auto params = GetParam();
193 
194   const auto result = converter_.ToBuiltin(params.builtin);
195   EXPECT_EQ(success_, params.expect_success);
196   if (params.expect_success) {
197     EXPECT_EQ(result, params.expected);
198     EXPECT_TRUE(error().empty());
199   } else {
200     EXPECT_EQ(result, params.expected);
201     EXPECT_THAT(error(), ::testing::StartsWith("unknown SPIR-V builtin: "));
202   }
203 }
204 
205 INSTANTIATE_TEST_SUITE_P(
206     EnumConverterGood_Input,
207     SpvBuiltinTest,
208     testing::Values(
209         BuiltinCase{SpvBuiltInPosition, true, ast::Builtin::kPosition},
210         BuiltinCase{SpvBuiltInInstanceIndex, true,
211                     ast::Builtin::kInstanceIndex},
212         BuiltinCase{SpvBuiltInFrontFacing, true, ast::Builtin::kFrontFacing},
213         BuiltinCase{SpvBuiltInFragCoord, true, ast::Builtin::kPosition},
214         BuiltinCase{SpvBuiltInLocalInvocationId, true,
215                     ast::Builtin::kLocalInvocationId},
216         BuiltinCase{SpvBuiltInLocalInvocationIndex, true,
217                     ast::Builtin::kLocalInvocationIndex},
218         BuiltinCase{SpvBuiltInGlobalInvocationId, true,
219                     ast::Builtin::kGlobalInvocationId},
220         BuiltinCase{SpvBuiltInWorkgroupId, true, ast::Builtin::kWorkgroupId},
221         BuiltinCase{SpvBuiltInSampleId, true, ast::Builtin::kSampleIndex},
222         BuiltinCase{SpvBuiltInSampleMask, true, ast::Builtin::kSampleMask}));
223 
224 INSTANTIATE_TEST_SUITE_P(
225     EnumConverterGood_Output,
226     SpvBuiltinTest,
227     testing::Values(
228         BuiltinCase{SpvBuiltInPosition, true, ast::Builtin::kPosition},
229         BuiltinCase{SpvBuiltInFragDepth, true, ast::Builtin::kFragDepth},
230         BuiltinCase{SpvBuiltInSampleMask, true, ast::Builtin::kSampleMask}));
231 
232 INSTANTIATE_TEST_SUITE_P(
233     EnumConverterBad,
234     SpvBuiltinTest,
235     testing::Values(
236         BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::Builtin::kNone},
237         BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::Builtin::kNone},
238         BuiltinCase{SpvBuiltInNumWorkgroups, false, ast::Builtin::kNone}));
239 
240 // Dim
241 
242 struct DimCase {
243   SpvDim dim;
244   bool arrayed;
245   bool expect_success;
246   ast::TextureDimension expected;
247 };
operator <<(std::ostream & out,DimCase dc)248 inline std::ostream& operator<<(std::ostream& out, DimCase dc) {
249   out << "DimCase{ SpvDim:" << int(dc.dim) << " arrayed?:" << int(dc.arrayed)
250       << " expect_success?:" << int(dc.expect_success)
251       << " expected:" << int(dc.expected) << "}";
252   return out;
253 }
254 
255 class SpvDimTest : public testing::TestWithParam<DimCase> {
256  public:
SpvDimTest()257   SpvDimTest()
258       : success_(true),
259         fail_stream_(&success_, &errors_),
260         converter_(fail_stream_) {}
261 
error() const262   std::string error() const { return errors_.str(); }
263 
264  protected:
265   bool success_ = true;
266   std::stringstream errors_;
267   FailStream fail_stream_;
268   EnumConverter converter_;
269 };
270 
TEST_P(SpvDimTest,Samples)271 TEST_P(SpvDimTest, Samples) {
272   const auto params = GetParam();
273 
274   const auto result = converter_.ToDim(params.dim, params.arrayed);
275   EXPECT_EQ(success_, params.expect_success);
276   if (params.expect_success) {
277     EXPECT_EQ(result, params.expected);
278     EXPECT_TRUE(error().empty());
279   } else {
280     EXPECT_EQ(result, params.expected);
281     EXPECT_THAT(error(), ::testing::HasSubstr("dimension"));
282   }
283 }
284 
285 INSTANTIATE_TEST_SUITE_P(
286     EnumConverterGood,
287     SpvDimTest,
288     testing::Values(
289         // Non-arrayed
290         DimCase{SpvDim1D, false, true, ast::TextureDimension::k1d},
291         DimCase{SpvDim2D, false, true, ast::TextureDimension::k2d},
292         DimCase{SpvDim3D, false, true, ast::TextureDimension::k3d},
293         DimCase{SpvDimCube, false, true, ast::TextureDimension::kCube},
294         // Arrayed
295         DimCase{SpvDim2D, true, true, ast::TextureDimension::k2dArray},
296         DimCase{SpvDimCube, true, true, ast::TextureDimension::kCubeArray}));
297 
298 INSTANTIATE_TEST_SUITE_P(
299     EnumConverterBad,
300     SpvDimTest,
301     testing::Values(
302         // Invalid SPIR-V dimensionality.
303         DimCase{SpvDimMax, false, false, ast::TextureDimension::kNone},
304         DimCase{SpvDimMax, true, false, ast::TextureDimension::kNone},
305         // Vulkan non-arrayed dimensionalities not supported by WGSL.
306         DimCase{SpvDimRect, false, false, ast::TextureDimension::kNone},
307         DimCase{SpvDimBuffer, false, false, ast::TextureDimension::kNone},
308         DimCase{SpvDimSubpassData, false, false, ast::TextureDimension::kNone},
309         // Arrayed dimensionalities not supported by WGSL
310         DimCase{SpvDim3D, true, false, ast::TextureDimension::kNone},
311         DimCase{SpvDimRect, true, false, ast::TextureDimension::kNone},
312         DimCase{SpvDimBuffer, true, false, ast::TextureDimension::kNone},
313         DimCase{SpvDimSubpassData, true, false, ast::TextureDimension::kNone}));
314 
315 // ImageFormat
316 
317 struct ImageFormatCase {
318   SpvImageFormat format;
319   bool expect_success;
320   ast::ImageFormat expected;
321 };
operator <<(std::ostream & out,ImageFormatCase ifc)322 inline std::ostream& operator<<(std::ostream& out, ImageFormatCase ifc) {
323   out << "ImageFormatCase{ SpvImageFormat:" << int(ifc.format)
324       << " expect_success?:" << int(ifc.expect_success)
325       << " expected:" << int(ifc.expected) << "}";
326   return out;
327 }
328 
329 class SpvImageFormatTest : public testing::TestWithParam<ImageFormatCase> {
330  public:
SpvImageFormatTest()331   SpvImageFormatTest()
332       : success_(true),
333         fail_stream_(&success_, &errors_),
334         converter_(fail_stream_) {}
335 
error() const336   std::string error() const { return errors_.str(); }
337 
338  protected:
339   bool success_ = true;
340   std::stringstream errors_;
341   FailStream fail_stream_;
342   EnumConverter converter_;
343 };
344 
TEST_P(SpvImageFormatTest,Samples)345 TEST_P(SpvImageFormatTest, Samples) {
346   const auto params = GetParam();
347 
348   const auto result = converter_.ToImageFormat(params.format);
349   EXPECT_EQ(success_, params.expect_success) << params;
350   if (params.expect_success) {
351     EXPECT_EQ(result, params.expected);
352     EXPECT_TRUE(error().empty());
353   } else {
354     EXPECT_EQ(result, params.expected);
355     EXPECT_THAT(error(), ::testing::StartsWith("invalid image format: "));
356   }
357 }
358 
359 INSTANTIATE_TEST_SUITE_P(
360     EnumConverterGood,
361     SpvImageFormatTest,
362     testing::Values(
363         // Unknown.  This is used for sampled images.
364         ImageFormatCase{SpvImageFormatUnknown, true, ast::ImageFormat::kNone},
365         // 8 bit channels
366         ImageFormatCase{SpvImageFormatRgba8, true,
367                         ast::ImageFormat::kRgba8Unorm},
368         ImageFormatCase{SpvImageFormatRgba8Snorm, true,
369                         ast::ImageFormat::kRgba8Snorm},
370         ImageFormatCase{SpvImageFormatRgba8ui, true,
371                         ast::ImageFormat::kRgba8Uint},
372         ImageFormatCase{SpvImageFormatRgba8i, true,
373                         ast::ImageFormat::kRgba8Sint},
374         // 16 bit channels
375         ImageFormatCase{SpvImageFormatRgba16ui, true,
376                         ast::ImageFormat::kRgba16Uint},
377         ImageFormatCase{SpvImageFormatRgba16i, true,
378                         ast::ImageFormat::kRgba16Sint},
379         ImageFormatCase{SpvImageFormatRgba16f, true,
380                         ast::ImageFormat::kRgba16Float},
381         // 32 bit channels
382         // ... 1 channel
383         ImageFormatCase{SpvImageFormatR32ui, true, ast::ImageFormat::kR32Uint},
384         ImageFormatCase{SpvImageFormatR32i, true, ast::ImageFormat::kR32Sint},
385         ImageFormatCase{SpvImageFormatR32f, true, ast::ImageFormat::kR32Float},
386         // ... 2 channels
387         ImageFormatCase{SpvImageFormatRg32ui, true,
388                         ast::ImageFormat::kRg32Uint},
389         ImageFormatCase{SpvImageFormatRg32i, true, ast::ImageFormat::kRg32Sint},
390         ImageFormatCase{SpvImageFormatRg32f, true,
391                         ast::ImageFormat::kRg32Float},
392         // ... 4 channels
393         ImageFormatCase{SpvImageFormatRgba32ui, true,
394                         ast::ImageFormat::kRgba32Uint},
395         ImageFormatCase{SpvImageFormatRgba32i, true,
396                         ast::ImageFormat::kRgba32Sint},
397         ImageFormatCase{SpvImageFormatRgba32f, true,
398                         ast::ImageFormat::kRgba32Float}));
399 
400 INSTANTIATE_TEST_SUITE_P(
401     EnumConverterBad,
402     SpvImageFormatTest,
403     testing::Values(
404         // Scanning in order from the SPIR-V spec.
405         ImageFormatCase{SpvImageFormatRg16f, false, ast::ImageFormat::kNone},
406         ImageFormatCase{SpvImageFormatR11fG11fB10f, false,
407                         ast::ImageFormat::kNone},
408         ImageFormatCase{SpvImageFormatR16f, false, ast::ImageFormat::kNone},
409         ImageFormatCase{SpvImageFormatRgb10A2, false, ast::ImageFormat::kNone},
410         ImageFormatCase{SpvImageFormatRg16, false, ast::ImageFormat::kNone},
411         ImageFormatCase{SpvImageFormatRg8, false, ast::ImageFormat::kNone},
412         ImageFormatCase{SpvImageFormatR16, false, ast::ImageFormat::kNone},
413         ImageFormatCase{SpvImageFormatR8, false, ast::ImageFormat::kNone},
414         ImageFormatCase{SpvImageFormatRgba16Snorm, false,
415                         ast::ImageFormat::kNone},
416         ImageFormatCase{SpvImageFormatRg16Snorm, false,
417                         ast::ImageFormat::kNone},
418         ImageFormatCase{SpvImageFormatRg8Snorm, false, ast::ImageFormat::kNone},
419         ImageFormatCase{SpvImageFormatRg16i, false, ast::ImageFormat::kNone},
420         ImageFormatCase{SpvImageFormatRg8i, false, ast::ImageFormat::kNone},
421         ImageFormatCase{SpvImageFormatR8i, false, ast::ImageFormat::kNone},
422         ImageFormatCase{SpvImageFormatRgb10a2ui, false,
423                         ast::ImageFormat::kNone},
424         ImageFormatCase{SpvImageFormatRg16ui, false, ast::ImageFormat::kNone},
425         ImageFormatCase{SpvImageFormatRg8ui, false, ast::ImageFormat::kNone}));
426 
427 }  // namespace
428 }  // namespace spirv
429 }  // namespace reader
430 }  // namespace tint
431