• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2021 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 <vector>
16 
17 #include "gmock/gmock.h"
18 #include "source/opt/convert_to_sampled_image_pass.h"
19 #include "test/opt/pass_fixture.h"
20 #include "test/opt/pass_utils.h"
21 
22 namespace spvtools {
23 namespace opt {
24 namespace {
25 
26 using testing::Eq;
27 using VectorOfDescriptorSetAndBindingPairs =
28     std::vector<DescriptorSetAndBinding>;
29 
30 struct DescriptorSetAndBindingStringParsingTestCase {
31   const char* descriptor_set_binding_str;
32   bool expect_success;
33   VectorOfDescriptorSetAndBindingPairs expected_descriptor_set_binding_pairs;
34 };
35 
36 using DescriptorSetAndBindingStringParsingTest =
37     ::testing::TestWithParam<DescriptorSetAndBindingStringParsingTestCase>;
38 
TEST_P(DescriptorSetAndBindingStringParsingTest,TestCase)39 TEST_P(DescriptorSetAndBindingStringParsingTest, TestCase) {
40   const auto& tc = GetParam();
41   auto actual_descriptor_set_binding_pairs =
42       ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
43           tc.descriptor_set_binding_str);
44   if (tc.expect_success) {
45     EXPECT_NE(nullptr, actual_descriptor_set_binding_pairs);
46     if (actual_descriptor_set_binding_pairs) {
47       EXPECT_THAT(*actual_descriptor_set_binding_pairs,
48                   Eq(tc.expected_descriptor_set_binding_pairs));
49     }
50   } else {
51     EXPECT_EQ(nullptr, actual_descriptor_set_binding_pairs);
52   }
53 }
54 
55 INSTANTIATE_TEST_SUITE_P(
56     ValidString, DescriptorSetAndBindingStringParsingTest,
57     ::testing::ValuesIn(std::vector<
58                         DescriptorSetAndBindingStringParsingTestCase>{
59         // 0. empty vector
60         {"", true, VectorOfDescriptorSetAndBindingPairs({})},
61         // 1. one pair
62         {"100:1024", true,
63          VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{100,
64                                                                        1024}})},
65         // 2. two pairs
66         {"100:1024 200:2048", true,
67          VectorOfDescriptorSetAndBindingPairs(
68              {DescriptorSetAndBinding{100, 1024},
69               DescriptorSetAndBinding{200, 2048}})},
70         // 3. spaces between entries
71         {"100:1024 \n \r \t \v \f 200:2048", true,
72          VectorOfDescriptorSetAndBindingPairs(
73              {DescriptorSetAndBinding{100, 1024},
74               DescriptorSetAndBinding{200, 2048}})},
75         // 4. \t, \n, \r and spaces before spec id
76         {"   \n \r\t \t \v \f 100:1024", true,
77          VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{100,
78                                                                        1024}})},
79         // 5. \t, \n, \r and spaces after value string
80         {"100:1024   \n \r\t \t \v \f ", true,
81          VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{100,
82                                                                        1024}})},
83         // 6. maximum spec id
84         {"4294967295:0", true,
85          VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{
86              4294967295, 0}})},
87         // 7. minimum spec id
88         {"0:100", true,
89          VectorOfDescriptorSetAndBindingPairs({DescriptorSetAndBinding{0,
90                                                                        100}})},
91         // 8. multiple entries
92         {"101:1 102:2 103:3 104:4 200:201 9999:1000", true,
93          VectorOfDescriptorSetAndBindingPairs(
94              {DescriptorSetAndBinding{101, 1}, DescriptorSetAndBinding{102, 2},
95               DescriptorSetAndBinding{103, 3}, DescriptorSetAndBinding{104, 4},
96               DescriptorSetAndBinding{200, 201},
97               DescriptorSetAndBinding{9999, 1000}})},
98     }));
99 
100 INSTANTIATE_TEST_SUITE_P(
101     InvalidString, DescriptorSetAndBindingStringParsingTest,
102     ::testing::ValuesIn(
103         std::vector<DescriptorSetAndBindingStringParsingTestCase>{
104             // 0. missing default value
105             {"100:", false, VectorOfDescriptorSetAndBindingPairs{}},
106             // 1. descriptor set is not an integer
107             {"100.0:200", false, VectorOfDescriptorSetAndBindingPairs{}},
108             // 2. descriptor set is not a number
109             {"something_not_a_number:1", false,
110              VectorOfDescriptorSetAndBindingPairs{}},
111             // 3. only descriptor set number
112             {"100", false, VectorOfDescriptorSetAndBindingPairs{}},
113             // 4. empty descriptor set
114             {":3", false, VectorOfDescriptorSetAndBindingPairs{}},
115             // 5. only colon
116             {":", false, VectorOfDescriptorSetAndBindingPairs{}},
117             // 6. descriptor set overflow
118             {"4294967296:200", false, VectorOfDescriptorSetAndBindingPairs{}},
119             // 7. descriptor set less than 0
120             {"-1:200", false, VectorOfDescriptorSetAndBindingPairs{}},
121             // 8. nullptr
122             {nullptr, false, VectorOfDescriptorSetAndBindingPairs{}},
123             // 9. only a number is invalid
124             {"1234", false, VectorOfDescriptorSetAndBindingPairs{}},
125             // 10. invalid entry separator
126             {"12:34;23:14", false, VectorOfDescriptorSetAndBindingPairs{}},
127             // 11. invalid descriptor set and default value separator
128             {"12@34", false, VectorOfDescriptorSetAndBindingPairs{}},
129             // 12. spaces before colon
130             {"100   :1024", false, VectorOfDescriptorSetAndBindingPairs{}},
131             // 13. spaces after colon
132             {"100:   1024", false, VectorOfDescriptorSetAndBindingPairs{}},
133             // 14. descriptor set represented in hex float format is invalid
134             {"0x3p10:200", false, VectorOfDescriptorSetAndBindingPairs{}},
135         }));
136 
BuildShader(const char * shader_decorate_instructions,const char * shader_image_and_sampler_variables,const char * shader_body)137 std::string BuildShader(const char* shader_decorate_instructions,
138                         const char* shader_image_and_sampler_variables,
139                         const char* shader_body) {
140   // Base HLSL code:
141   //
142   // SamplerState sam : register(s2);
143   // Texture2D <float4> texture : register(t5);
144   //
145   // float4 main() : SV_TARGET {
146   //     return texture.SampleLevel(sam, float2(1, 2), 10, 2);
147   // }
148   std::stringstream ss;
149   ss << R"(
150                OpCapability Shader
151                OpMemoryModel Logical GLSL450
152                OpEntryPoint Fragment %main "main" %out_var_SV_TARGET
153                OpExecutionMode %main OriginUpperLeft
154                OpSource HLSL 600
155                OpName %type_sampler "type.sampler"
156                OpName %type_2d_image "type.2d.image"
157                OpName %out_var_SV_TARGET "out.var.SV_TARGET"
158                OpName %main "main"
159                OpName %type_sampled_image "type.sampled.image"
160                OpDecorate %out_var_SV_TARGET Location 0
161                )";
162   ss << shader_decorate_instructions;
163   ss << R"(
164       %float = OpTypeFloat 32
165     %float_1 = OpConstant %float 1
166     %float_2 = OpConstant %float 2
167     %v2float = OpTypeVector %float 2
168          %12 = OpConstantComposite %v2float %float_1 %float_2
169    %float_10 = OpConstant %float 10
170         %int = OpTypeInt 32 1
171       %int_2 = OpConstant %int 2
172       %v2int = OpTypeVector %int 2
173          %17 = OpConstantComposite %v2int %int_2 %int_2
174 %type_sampler = OpTypeSampler
175 %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
176 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
177 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
178     %v4float = OpTypeVector %float 4
179 %_ptr_Output_v4float = OpTypePointer Output %v4float
180        %void = OpTypeVoid
181          %23 = OpTypeFunction %void
182 %type_sampled_image = OpTypeSampledImage %type_2d_image
183                )";
184   ss << shader_image_and_sampler_variables;
185   ss << R"(
186 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
187        %main = OpFunction %void None %23
188          %24 = OpLabel
189   )";
190   ss << shader_body;
191   ss << R"(
192                OpReturn
193                OpFunctionEnd
194   )";
195   return ss.str();
196 }
197 
198 using ConvertToSampledImageTest = PassTest<::testing::Test>;
199 
TEST_F(ConvertToSampledImageTest,Texture2DAndSamplerToSampledImage)200 TEST_F(ConvertToSampledImageTest, Texture2DAndSamplerToSampledImage) {
201   const std::string shader = BuildShader(
202       R"(
203                OpDecorate %sam DescriptorSet 0
204                OpDecorate %sam Binding 5
205                OpDecorate %texture DescriptorSet 0
206                OpDecorate %texture Binding 5
207                )",
208       R"(
209             ; CHECK-NOT: OpVariable %_ptr_UniformConstant_type_2d_image
210 
211             ; CHECK: [[tex:%\w+]] = OpVariable %_ptr_UniformConstant_type_sampled_image UniformConstant
212         %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
213     %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
214                )",
215       R"(
216             ; CHECK: [[load:%\w+]] = OpLoad %type_sampled_image [[tex]]
217             ; CHECK: OpImageSampleExplicitLod %v4float [[load]]
218          %25 = OpLoad %type_2d_image %texture
219          %26 = OpLoad %type_sampler %sam
220          %27 = OpSampledImage %type_sampled_image %25 %26
221          %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17
222                OpStore %out_var_SV_TARGET %28
223                )");
224 
225   auto result = SinglePassRunAndMatch<ConvertToSampledImagePass>(
226       shader, /* do_validate = */ true,
227       VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 5}});
228 
229   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
230 }
231 
TEST_F(ConvertToSampledImageTest,Texture2DToSampledImage)232 TEST_F(ConvertToSampledImageTest, Texture2DToSampledImage) {
233   const std::string shader = BuildShader(
234       R"(
235                OpDecorate %sam DescriptorSet 0
236                OpDecorate %sam Binding 2
237                OpDecorate %texture DescriptorSet 0
238                OpDecorate %texture Binding 5
239                )",
240       R"(
241             ; CHECK: [[tex:%\w+]] = OpVariable %_ptr_UniformConstant_type_sampled_image UniformConstant
242         %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
243     %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
244                )",
245       R"(
246             ; CHECK: [[load:%\w+]] = OpLoad %type_sampled_image [[tex]]
247             ; CHECK: [[image_extraction:%\w+]] = OpImage %type_2d_image [[load]]
248             ; CHECK: OpSampledImage %type_sampled_image [[image_extraction]]
249          %25 = OpLoad %type_2d_image %texture
250          %26 = OpLoad %type_sampler %sam
251          %27 = OpSampledImage %type_sampled_image %25 %26
252          %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17
253                OpStore %out_var_SV_TARGET %28
254                )");
255 
256   auto result = SinglePassRunAndMatch<ConvertToSampledImagePass>(
257       shader, /* do_validate = */ true,
258       VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 5}});
259 
260   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
261 }
262 
TEST_F(ConvertToSampledImageTest,SamplerToSampledImage)263 TEST_F(ConvertToSampledImageTest, SamplerToSampledImage) {
264   const std::string shader = BuildShader(
265       R"(
266                OpDecorate %sam DescriptorSet 0
267                OpDecorate %sam Binding 2
268                OpDecorate %texture DescriptorSet 0
269                OpDecorate %texture Binding 5
270                )",
271       R"(
272         %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
273     %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
274                )",
275       R"(
276          %25 = OpLoad %type_2d_image %texture
277          %26 = OpLoad %type_sampler %sam
278          %27 = OpSampledImage %type_sampled_image %25 %26
279          %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17
280                OpStore %out_var_SV_TARGET %28
281                )");
282 
283   auto result = SinglePassRunToBinary<ConvertToSampledImagePass>(
284       shader, /* skip_nop = */ false,
285       VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 2}});
286 
287   EXPECT_EQ(std::get<1>(result), Pass::Status::Failure);
288 }
289 
TEST_F(ConvertToSampledImageTest,TwoImagesWithDuplicatedDescriptorSetBinding)290 TEST_F(ConvertToSampledImageTest, TwoImagesWithDuplicatedDescriptorSetBinding) {
291   const std::string shader = BuildShader(
292       R"(
293                OpDecorate %sam DescriptorSet 0
294                OpDecorate %sam Binding 2
295                OpDecorate %texture0 DescriptorSet 0
296                OpDecorate %texture0 Binding 5
297                OpDecorate %texture1 DescriptorSet 0
298                OpDecorate %texture1 Binding 5
299                )",
300       R"(
301         %sam = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
302    %texture0 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
303    %texture1 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
304                )",
305       R"(
306          %25 = OpLoad %type_2d_image %texture0
307          %26 = OpLoad %type_sampler %sam
308          %27 = OpSampledImage %type_sampled_image %25 %26
309          %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17
310                OpStore %out_var_SV_TARGET %28
311                )");
312 
313   auto result = SinglePassRunToBinary<ConvertToSampledImagePass>(
314       shader, /* skip_nop = */ false,
315       VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 5}});
316 
317   EXPECT_EQ(std::get<1>(result), Pass::Status::Failure);
318 }
319 
TEST_F(ConvertToSampledImageTest,TwoSamplersWithDuplicatedDescriptorSetBinding)320 TEST_F(ConvertToSampledImageTest,
321        TwoSamplersWithDuplicatedDescriptorSetBinding) {
322   const std::string shader = BuildShader(
323       R"(
324                OpDecorate %sam0 DescriptorSet 0
325                OpDecorate %sam0 Binding 2
326                OpDecorate %sam1 DescriptorSet 0
327                OpDecorate %sam1 Binding 2
328                OpDecorate %texture DescriptorSet 0
329                OpDecorate %texture Binding 5
330                )",
331       R"(
332        %sam0 = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
333        %sam1 = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
334     %texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
335                )",
336       R"(
337          %25 = OpLoad %type_2d_image %texture
338          %26 = OpLoad %type_sampler %sam0
339          %27 = OpSampledImage %type_sampled_image %25 %26
340          %28 = OpImageSampleExplicitLod %v4float %27 %12 Lod|ConstOffset %float_10 %17
341                OpStore %out_var_SV_TARGET %28
342                )");
343 
344   auto result = SinglePassRunToBinary<ConvertToSampledImagePass>(
345       shader, /* skip_nop = */ false,
346       VectorOfDescriptorSetAndBindingPairs{DescriptorSetAndBinding{0, 2}});
347 
348   EXPECT_EQ(std::get<1>(result), Pass::Status::Failure);
349 }
350 
351 }  // namespace
352 }  // namespace opt
353 }  // namespace spvtools
354