• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2015-2016 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 // Assembler tests for instructions in the "Image Instructions" section of
16 // the SPIR-V spec.
17 
18 #include <string>
19 #include <vector>
20 
21 #include "gmock/gmock.h"
22 #include "test/test_fixture.h"
23 #include "test/unit_spirv.h"
24 
25 namespace spvtools {
26 namespace {
27 
28 using spvtest::MakeInstruction;
29 using spvtest::TextToBinaryTest;
30 using ::testing::Eq;
31 
32 // An example case for a mask value with operands.
33 struct ImageOperandsCase {
34   std::string image_operands;
35   // The expected mask, followed by its operands.
36   std::vector<uint32_t> expected_mask_and_operands;
37 };
38 
39 // Test all kinds of image operands.
40 
41 using ImageOperandsTest =
42     spvtest::TextToBinaryTestBase<::testing::TestWithParam<ImageOperandsCase>>;
43 
TEST_P(ImageOperandsTest,Sample)44 TEST_P(ImageOperandsTest, Sample) {
45   const std::string input =
46       "%2 = OpImageFetch %1 %3 %4" + GetParam().image_operands + "\n";
47   EXPECT_THAT(CompiledInstructions(input),
48               Eq(MakeInstruction(spv::Op::OpImageFetch, {1, 2, 3, 4},
49                                  GetParam().expected_mask_and_operands)));
50 }
51 
52 #define MASK(NAME) uint32_t(spv::ImageOperandsMask::NAME)
53 INSTANTIATE_TEST_SUITE_P(
54     TextToBinaryImageOperandsAny, ImageOperandsTest,
55     ::testing::ValuesIn(std::vector<ImageOperandsCase>{
56         // TODO(dneto): Rev32 adds many more values, and rearranges their
57         // values.
58         // Image operands are optional.
59         {"", {}},
60         // Test each kind, alone.
61         {" Bias %5", {MASK(Bias), 5}},
62         {" Lod %5", {MASK(Lod), 5}},
63         {" Grad %5 %6", {MASK(Grad), 5, 6}},
64         {" ConstOffset %5", {MASK(ConstOffset), 5}},
65         {" Offset %5", {MASK(Offset), 5}},
66         {" ConstOffsets %5", {MASK(ConstOffsets), 5}},
67         {" Sample %5", {MASK(Sample), 5}},
68         {" MinLod %5", {MASK(MinLod), 5}},
69     }));
70 #undef MASK
71 #define MASK(NAME) static_cast<uint32_t>(spv::ImageOperandsMask::NAME)
72 INSTANTIATE_TEST_SUITE_P(
73     TextToBinaryImageOperandsCombination, ImageOperandsTest,
74     ::testing::ValuesIn(std::vector<ImageOperandsCase>{
75         // TODO(dneto): Rev32 adds many more values, and rearranges their
76         // values.
77         // Test adjacent pairs, so we can easily debug the values when it fails.
78         {" Bias|Lod %5 %6", {MASK(Bias) | MASK(Lod), 5, 6}},
79         {" Lod|Grad %5 %6 %7", {MASK(Lod) | MASK(Grad), 5, 6, 7}},
80         {" Grad|ConstOffset %5 %6 %7",
81          {MASK(Grad) | MASK(ConstOffset), 5, 6, 7}},
82         {" ConstOffset|Offset %5 %6", {MASK(ConstOffset) | MASK(Offset), 5, 6}},
83         {" Offset|ConstOffsets %5 %6",
84          {MASK(Offset) | MASK(ConstOffsets), 5, 6}},
85         {" ConstOffsets|Sample %5 %6",
86          {MASK(ConstOffsets) | MASK(Sample), 5, 6}},
87         // Test all masks together.
88         {" Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample"
89          " %5 %6 %7 %8 %9 %10 %11 %12",
90          {MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) |
91               MASK(Offset) | MASK(ConstOffsets) | MASK(Sample),
92           5, 6, 7, 8, 9, 10, 11, 12}},
93         // The same, but with mask value names reversed.
94         {" Sample|ConstOffsets|Offset|ConstOffset|Grad|Lod|Bias"
95          " %5 %6 %7 %8 %9 %10 %11 %12",
96          {MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) |
97               MASK(Offset) | MASK(ConstOffsets) | MASK(Sample),
98           5, 6, 7, 8, 9, 10, 11, 12}}}));
99 #undef MASK
100 
TEST_F(ImageOperandsTest,WrongOperand)101 TEST_F(ImageOperandsTest, WrongOperand) {
102   EXPECT_THAT(CompileFailure("%r = OpImageFetch %t %i %c xxyyzz"),
103               Eq("Invalid image operand 'xxyyzz'."));
104 }
105 
106 // Test OpImage
107 
108 using OpImageTest = TextToBinaryTest;
109 
TEST_F(OpImageTest,Valid)110 TEST_F(OpImageTest, Valid) {
111   const std::string input = "%2 = OpImage %1 %3\n";
112   EXPECT_THAT(CompiledInstructions(input),
113               Eq(MakeInstruction(spv::Op::OpImage, {1, 2, 3})));
114 
115   // Test the disassembler.
116   EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input);
117 }
118 
TEST_F(OpImageTest,InvalidTypeOperand)119 TEST_F(OpImageTest, InvalidTypeOperand) {
120   EXPECT_THAT(CompileFailure("%2 = OpImage 42"),
121               Eq("Expected id to start with %."));
122 }
123 
TEST_F(OpImageTest,MissingSampledImageOperand)124 TEST_F(OpImageTest, MissingSampledImageOperand) {
125   EXPECT_THAT(CompileFailure("%2 = OpImage %1"),
126               Eq("Expected operand for OpImage instruction, but found the end "
127                  "of the stream."));
128 }
129 
TEST_F(OpImageTest,InvalidSampledImageOperand)130 TEST_F(OpImageTest, InvalidSampledImageOperand) {
131   EXPECT_THAT(CompileFailure("%2 = OpImage %1 1000"),
132               Eq("Expected id to start with %."));
133 }
134 
TEST_F(OpImageTest,TooManyOperands)135 TEST_F(OpImageTest, TooManyOperands) {
136   // We should improve this message, to say what instruction we're trying to
137   // parse.
138   EXPECT_THAT(CompileFailure("%2 = OpImage %1 %3 %4"),  // an Id
139               Eq("Expected '=', found end of stream."));
140 
141   EXPECT_THAT(CompileFailure("%2 = OpImage %1 %3 99"),  // a number
142               Eq("Expected <opcode> or <result-id> at the beginning of an "
143                  "instruction, found '99'."));
144   EXPECT_THAT(CompileFailure("%2 = OpImage %1 %3 \"abc\""),  // a string
145               Eq("Expected <opcode> or <result-id> at the beginning of an "
146                  "instruction, found '\"abc\"'."));
147 }
148 
149 // Test OpImageSparseRead
150 
151 using OpImageSparseReadTest = TextToBinaryTest;
152 
TEST_F(OpImageSparseReadTest,OnlyRequiredOperands)153 TEST_F(OpImageSparseReadTest, OnlyRequiredOperands) {
154   const std::string input = "%2 = OpImageSparseRead %1 %3 %4\n";
155   EXPECT_THAT(CompiledInstructions(input),
156               Eq(MakeInstruction(spv::Op::OpImageSparseRead, {1, 2, 3, 4})));
157   // Test the disassembler.
158   EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input);
159 }
160 
161 // Test all kinds of image operands on OpImageSparseRead
162 
163 using ImageSparseReadImageOperandsTest =
164     spvtest::TextToBinaryTestBase<::testing::TestWithParam<ImageOperandsCase>>;
165 
TEST_P(ImageSparseReadImageOperandsTest,Sample)166 TEST_P(ImageSparseReadImageOperandsTest, Sample) {
167   const std::string input =
168       "%2 = OpImageSparseRead %1 %3 %4" + GetParam().image_operands + "\n";
169   EXPECT_THAT(CompiledInstructions(input),
170               Eq(MakeInstruction(spv::Op::OpImageSparseRead, {1, 2, 3, 4},
171                                  GetParam().expected_mask_and_operands)));
172   // Test the disassembler.
173   EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input);
174 }
175 
176 #define MASK(NAME) uint32_t(spv::ImageOperandsMask::NAME)
177 INSTANTIATE_TEST_SUITE_P(ImageSparseReadImageOperandsAny,
178                          ImageSparseReadImageOperandsTest,
179                          ::testing::ValuesIn(std::vector<ImageOperandsCase>{
180                              // Image operands are optional.
181                              {"", {}},
182                              // Test each kind, alone.
183                              {" Bias %5", {MASK(Bias), 5}},
184                              {" Lod %5", {MASK(Lod), 5}},
185                              {" Grad %5 %6", {MASK(Grad), 5, 6}},
186                              {" ConstOffset %5", {MASK(ConstOffset), 5}},
187                              {" Offset %5", {MASK(Offset), 5}},
188                              {" ConstOffsets %5", {MASK(ConstOffsets), 5}},
189                              {" Sample %5", {MASK(Sample), 5}},
190                              {" MinLod %5", {MASK(MinLod), 5}},
191                          }));
192 #undef MASK
193 #define MASK(NAME) static_cast<uint32_t>(spv::ImageOperandsMask::NAME)
194 INSTANTIATE_TEST_SUITE_P(
195     ImageSparseReadImageOperandsCombination, ImageSparseReadImageOperandsTest,
196     ::testing::ValuesIn(std::vector<ImageOperandsCase>{
197         // values.
198         // Test adjacent pairs, so we can easily debug the values when it fails.
199         {" Bias|Lod %5 %6", {MASK(Bias) | MASK(Lod), 5, 6}},
200         {" Lod|Grad %5 %6 %7", {MASK(Lod) | MASK(Grad), 5, 6, 7}},
201         {" Grad|ConstOffset %5 %6 %7",
202          {MASK(Grad) | MASK(ConstOffset), 5, 6, 7}},
203         {" ConstOffset|Offset %5 %6", {MASK(ConstOffset) | MASK(Offset), 5, 6}},
204         {" Offset|ConstOffsets %5 %6",
205          {MASK(Offset) | MASK(ConstOffsets), 5, 6}},
206         {" ConstOffsets|Sample %5 %6",
207          {MASK(ConstOffsets) | MASK(Sample), 5, 6}},
208         // Test all masks together.
209         {" Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample"
210          " %5 %6 %7 %8 %9 %10 %11 %12",
211          {MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) |
212               MASK(Offset) | MASK(ConstOffsets) | MASK(Sample),
213           5, 6, 7, 8, 9, 10, 11, 12}},
214         // Don't try the masks reversed, since this is a round trip test,
215         // and the disassembler will sort them.
216     }));
217 #undef MASK
218 
TEST_F(OpImageSparseReadTest,InvalidTypeOperand)219 TEST_F(OpImageSparseReadTest, InvalidTypeOperand) {
220   EXPECT_THAT(CompileFailure("%2 = OpImageSparseRead 42"),
221               Eq("Expected id to start with %."));
222 }
223 
TEST_F(OpImageSparseReadTest,MissingImageOperand)224 TEST_F(OpImageSparseReadTest, MissingImageOperand) {
225   EXPECT_THAT(CompileFailure("%2 = OpImageSparseRead %1"),
226               Eq("Expected operand for OpImageSparseRead instruction, but "
227                  "found the end of the stream."));
228 }
229 
TEST_F(OpImageSparseReadTest,InvalidImageOperand)230 TEST_F(OpImageSparseReadTest, InvalidImageOperand) {
231   EXPECT_THAT(CompileFailure("%2 = OpImageSparseRead %1 1000"),
232               Eq("Expected id to start with %."));
233 }
234 
TEST_F(OpImageSparseReadTest,MissingCoordinateOperand)235 TEST_F(OpImageSparseReadTest, MissingCoordinateOperand) {
236   EXPECT_THAT(CompileFailure("%2 = OpImageSparseRead %1 %2"),
237               Eq("Expected operand for OpImageSparseRead instruction, but "
238                  "found the end of the stream."));
239 }
240 
TEST_F(OpImageSparseReadTest,InvalidCoordinateOperand)241 TEST_F(OpImageSparseReadTest, InvalidCoordinateOperand) {
242   EXPECT_THAT(CompileFailure("%2 = OpImageSparseRead %1 %2 1000"),
243               Eq("Expected id to start with %."));
244 }
245 
246 // TODO(dneto): OpSampledImage
247 // TODO(dneto): OpImageSampleImplicitLod
248 // TODO(dneto): OpImageSampleExplicitLod
249 // TODO(dneto): OpImageSampleDrefImplicitLod
250 // TODO(dneto): OpImageSampleDrefExplicitLod
251 // TODO(dneto): OpImageSampleProjImplicitLod
252 // TODO(dneto): OpImageSampleProjExplicitLod
253 // TODO(dneto): OpImageSampleProjDrefImplicitLod
254 // TODO(dneto): OpImageSampleProjDrefExplicitLod
255 // TODO(dneto): OpImageGather
256 // TODO(dneto): OpImageDrefGather
257 // TODO(dneto): OpImageRead
258 // TODO(dneto): OpImageWrite
259 // TODO(dneto): OpImageQueryFormat
260 // TODO(dneto): OpImageQueryOrder
261 // TODO(dneto): OpImageQuerySizeLod
262 // TODO(dneto): OpImageQuerySize
263 // TODO(dneto): OpImageQueryLod
264 // TODO(dneto): OpImageQueryLevels
265 // TODO(dneto): OpImageQuerySamples
266 // TODO(dneto): OpImageSparseSampleImplicitLod
267 // TODO(dneto): OpImageSparseSampleExplicitLod
268 // TODO(dneto): OpImageSparseSampleDrefImplicitLod
269 // TODO(dneto): OpImageSparseSampleDrefExplicitLod
270 // TODO(dneto): OpImageSparseSampleProjImplicitLod
271 // TODO(dneto): OpImageSparseSampleProjExplicitLod
272 // TODO(dneto): OpImageSparseSampleProjDrefImplicitLod
273 // TODO(dneto): OpImageSparseSampleProjDrefExplicitLod
274 // TODO(dneto): OpImageSparseFetch
275 // TODO(dneto): OpImageSparseDrefGather
276 // TODO(dneto): OpImageSparseTexelsResident
277 
278 }  // namespace
279 }  // namespace spvtools
280