1 // Copyright (c) 2019 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 <string>
16
17 #include "test/opt/pass_fixture.h"
18 #include "test/opt/pass_utils.h"
19
20 namespace spvtools {
21 namespace opt {
22 namespace {
23
24 using DescriptorScalarReplacementTest = PassTest<::testing::Test>;
25
GetStructureArrayTestSpirv()26 std::string GetStructureArrayTestSpirv() {
27 // The SPIR-V for the following high-level shader:
28 // Flattening structures and arrays should result in the following binding
29 // numbers. Only the ones that are actually used in the shader should be in
30 // the final SPIR-V.
31 //
32 // globalS[0][0].t[0] 0 (used)
33 // globalS[0][0].t[1] 1
34 // globalS[0][0].s[0] 2 (used)
35 // globalS[0][0].s[1] 3
36 // globalS[0][1].t[0] 4
37 // globalS[0][1].t[1] 5
38 // globalS[0][1].s[0] 6
39 // globalS[0][1].s[1] 7
40 // globalS[1][0].t[0] 8
41 // globalS[1][0].t[1] 9
42 // globalS[1][0].s[0] 10
43 // globalS[1][0].s[1] 11
44 // globalS[1][1].t[0] 12
45 // globalS[1][1].t[1] 13 (used)
46 // globalS[1][1].s[0] 14
47 // globalS[1][1].s[1] 15 (used)
48
49 /*
50 struct S {
51 Texture2D t[2];
52 SamplerState s[2];
53 };
54
55 S globalS[2][2];
56
57 float4 main() : SV_Target {
58 return globalS[0][0].t[0].Sample(globalS[0][0].s[0], float2(0,0)) +
59 globalS[1][1].t[1].Sample(globalS[1][1].s[1], float2(0,0));
60 }
61 */
62
63 return R"(
64 OpCapability Shader
65 OpMemoryModel Logical GLSL450
66 OpEntryPoint Fragment %main "main" %out_var_SV_Target
67 OpExecutionMode %main OriginUpperLeft
68 OpName %S "S"
69 OpMemberName %S 0 "t"
70 OpMemberName %S 1 "s"
71 OpName %type_2d_image "type.2d.image"
72 OpName %type_sampler "type.sampler"
73 OpName %globalS "globalS"
74 OpName %out_var_SV_Target "out.var.SV_Target"
75 OpName %main "main"
76 OpName %src_main "src.main"
77 OpName %bb_entry "bb.entry"
78 OpName %type_sampled_image "type.sampled.image"
79 OpDecorate %out_var_SV_Target Location 0
80 OpDecorate %globalS DescriptorSet 0
81 OpDecorate %globalS Binding 0
82 %int = OpTypeInt 32 1
83 %int_0 = OpConstant %int 0
84 %int_1 = OpConstant %int 1
85 %float = OpTypeFloat 32
86 %float_0 = OpConstant %float 0
87 %v2float = OpTypeVector %float 2
88 %10 = OpConstantComposite %v2float %float_0 %float_0
89 %uint = OpTypeInt 32 0
90 %uint_2 = OpConstant %uint 2
91 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
92 %_arr_type_2d_image_uint_2 = OpTypeArray %type_2d_image %uint_2
93 %type_sampler = OpTypeSampler
94 %_arr_type_sampler_uint_2 = OpTypeArray %type_sampler %uint_2
95 %S = OpTypeStruct %_arr_type_2d_image_uint_2 %_arr_type_sampler_uint_2
96 %_arr_S_uint_2 = OpTypeArray %S %uint_2
97 %_arr__arr_S_uint_2_uint_2 = OpTypeArray %_arr_S_uint_2 %uint_2
98 %_ptr_UniformConstant__arr__arr_S_uint_2_uint_2 = OpTypePointer UniformConstant %_arr__arr_S_uint_2_uint_2
99 %v4float = OpTypeVector %float 4
100 %_ptr_Output_v4float = OpTypePointer Output %v4float
101 %void = OpTypeVoid
102 %24 = OpTypeFunction %void
103 %28 = OpTypeFunction %v4float
104 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
105 %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
106 %type_sampled_image = OpTypeSampledImage %type_2d_image
107 %globalS = OpVariable %_ptr_UniformConstant__arr__arr_S_uint_2_uint_2 UniformConstant
108 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
109 %main = OpFunction %void None %24
110 %25 = OpLabel
111 %26 = OpFunctionCall %v4float %src_main
112 OpStore %out_var_SV_Target %26
113 OpReturn
114 OpFunctionEnd
115 %src_main = OpFunction %v4float None %28
116 %bb_entry = OpLabel
117 %31 = OpAccessChain %_ptr_UniformConstant_type_2d_image %globalS %int_0 %int_0 %int_0 %int_0
118 %32 = OpLoad %type_2d_image %31
119 %34 = OpAccessChain %_ptr_UniformConstant_type_sampler %globalS %int_0 %int_0 %int_1 %int_0
120 %35 = OpLoad %type_sampler %34
121 %37 = OpSampledImage %type_sampled_image %32 %35
122 %38 = OpImageSampleImplicitLod %v4float %37 %10 None
123 %39 = OpAccessChain %_ptr_UniformConstant_type_2d_image %globalS %int_1 %int_1 %int_0 %int_1
124 %40 = OpLoad %type_2d_image %39
125 %41 = OpAccessChain %_ptr_UniformConstant_type_sampler %globalS %int_1 %int_1 %int_1 %int_1
126 %42 = OpLoad %type_sampler %41
127 %43 = OpSampledImage %type_sampled_image %40 %42
128 %44 = OpImageSampleImplicitLod %v4float %43 %10 None
129 %45 = OpFAdd %v4float %38 %44
130 OpReturnValue %45
131 OpFunctionEnd
132 )";
133 }
134
TEST_F(DescriptorScalarReplacementTest,ExpandArrayOfTextures)135 TEST_F(DescriptorScalarReplacementTest, ExpandArrayOfTextures) {
136 const std::string text = R"(
137 ; CHECK: OpDecorate [[var1:%\w+]] DescriptorSet 0
138 ; CHECK: OpDecorate [[var1]] Binding 0
139 ; CHECK: OpDecorate [[var2:%\w+]] DescriptorSet 0
140 ; CHECK: OpDecorate [[var2]] Binding 1
141 ; CHECK: OpDecorate [[var3:%\w+]] DescriptorSet 0
142 ; CHECK: OpDecorate [[var3]] Binding 2
143 ; CHECK: OpDecorate [[var4:%\w+]] DescriptorSet 0
144 ; CHECK: OpDecorate [[var4]] Binding 3
145 ; CHECK: OpDecorate [[var5:%\w+]] DescriptorSet 0
146 ; CHECK: OpDecorate [[var5]] Binding 4
147 ; CHECK: [[image_type:%\w+]] = OpTypeImage
148 ; CHECK: [[ptr_type:%\w+]] = OpTypePointer UniformConstant [[image_type]]
149 ; CHECK: [[var1]] = OpVariable [[ptr_type]] UniformConstant
150 ; CHECK: [[var2]] = OpVariable [[ptr_type]] UniformConstant
151 ; CHECK: [[var3]] = OpVariable [[ptr_type]] UniformConstant
152 ; CHECK: [[var4]] = OpVariable [[ptr_type]] UniformConstant
153 ; CHECK: [[var5]] = OpVariable [[ptr_type]] UniformConstant
154 ; CHECK: OpLoad [[image_type]] [[var1]]
155 ; CHECK: OpLoad [[image_type]] [[var2]]
156 ; CHECK: OpLoad [[image_type]] [[var3]]
157 ; CHECK: OpLoad [[image_type]] [[var4]]
158 ; CHECK: OpLoad [[image_type]] [[var5]]
159 OpCapability Shader
160 OpMemoryModel Logical GLSL450
161 OpEntryPoint Fragment %main "main"
162 OpExecutionMode %main OriginUpperLeft
163 OpSource HLSL 600
164 OpDecorate %MyTextures DescriptorSet 0
165 OpDecorate %MyTextures Binding 0
166 %int = OpTypeInt 32 1
167 %int_0 = OpConstant %int 0
168 %int_1 = OpConstant %int 1
169 %int_2 = OpConstant %int 2
170 %int_3 = OpConstant %int 3
171 %int_4 = OpConstant %int 4
172 %uint = OpTypeInt 32 0
173 %uint_5 = OpConstant %uint 5
174 %float = OpTypeFloat 32
175 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
176 %_arr_type_2d_image_uint_5 = OpTypeArray %type_2d_image %uint_5
177 %_ptr_UniformConstant__arr_type_2d_image_uint_5 = OpTypePointer UniformConstant %_arr_type_2d_image_uint_5
178 %v2float = OpTypeVector %float 2
179 %void = OpTypeVoid
180 %26 = OpTypeFunction %void
181 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
182 %MyTextures = OpVariable %_ptr_UniformConstant__arr_type_2d_image_uint_5 UniformConstant
183 %main = OpFunction %void None %26
184 %28 = OpLabel
185 %29 = OpUndef %v2float
186 %30 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_0
187 %31 = OpLoad %type_2d_image %30
188 %35 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_1
189 %36 = OpLoad %type_2d_image %35
190 %40 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_2
191 %41 = OpLoad %type_2d_image %40
192 %45 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_3
193 %46 = OpLoad %type_2d_image %45
194 %50 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_4
195 %51 = OpLoad %type_2d_image %50
196 OpReturn
197 OpFunctionEnd
198
199 )";
200
201 SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
202 }
203
TEST_F(DescriptorScalarReplacementTest,ExpandArrayOfSamplers)204 TEST_F(DescriptorScalarReplacementTest, ExpandArrayOfSamplers) {
205 const std::string text = R"(
206 ; CHECK: OpDecorate [[var1:%\w+]] DescriptorSet 0
207 ; CHECK: OpDecorate [[var1]] Binding 1
208 ; CHECK: OpDecorate [[var2:%\w+]] DescriptorSet 0
209 ; CHECK: OpDecorate [[var2]] Binding 2
210 ; CHECK: OpDecorate [[var3:%\w+]] DescriptorSet 0
211 ; CHECK: OpDecorate [[var3]] Binding 3
212 ; CHECK: [[sampler_type:%\w+]] = OpTypeSampler
213 ; CHECK: [[ptr_type:%\w+]] = OpTypePointer UniformConstant [[sampler_type]]
214 ; CHECK: [[var1]] = OpVariable [[ptr_type]] UniformConstant
215 ; CHECK: [[var2]] = OpVariable [[ptr_type]] UniformConstant
216 ; CHECK: [[var3]] = OpVariable [[ptr_type]] UniformConstant
217 ; CHECK: OpLoad [[sampler_type]] [[var1]]
218 ; CHECK: OpLoad [[sampler_type]] [[var2]]
219 ; CHECK: OpLoad [[sampler_type]] [[var3]]
220 OpCapability Shader
221 OpMemoryModel Logical GLSL450
222 OpEntryPoint Fragment %main "main"
223 OpExecutionMode %main OriginUpperLeft
224 OpSource HLSL 600
225 OpDecorate %MySampler DescriptorSet 0
226 OpDecorate %MySampler Binding 1
227 %int = OpTypeInt 32 1
228 %int_0 = OpConstant %int 0
229 %int_1 = OpConstant %int 1
230 %int_2 = OpConstant %int 2
231 %uint = OpTypeInt 32 0
232 %uint_3 = OpConstant %uint 3
233 %type_sampler = OpTypeSampler
234 %_arr_type_sampler_uint_3 = OpTypeArray %type_sampler %uint_3
235 %_ptr_UniformConstant__arr_type_sampler_uint_3 = OpTypePointer UniformConstant %_arr_type_sampler_uint_3
236 %void = OpTypeVoid
237 %26 = OpTypeFunction %void
238 %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
239 %MySampler = OpVariable %_ptr_UniformConstant__arr_type_sampler_uint_3 UniformConstant
240 %main = OpFunction %void None %26
241 %28 = OpLabel
242 %31 = OpAccessChain %_ptr_UniformConstant_type_sampler %MySampler %int_0
243 %32 = OpLoad %type_sampler %31
244 %35 = OpAccessChain %_ptr_UniformConstant_type_sampler %MySampler %int_1
245 %36 = OpLoad %type_sampler %35
246 %40 = OpAccessChain %_ptr_UniformConstant_type_sampler %MySampler %int_2
247 %41 = OpLoad %type_sampler %40
248 OpReturn
249 OpFunctionEnd
250 )";
251
252 SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
253 }
254
TEST_F(DescriptorScalarReplacementTest,ExpandArrayOfSSBOs)255 TEST_F(DescriptorScalarReplacementTest, ExpandArrayOfSSBOs) {
256 // Tests the expansion of an SSBO. Also check that an access chain with more
257 // than 1 index is correctly handled.
258 const std::string text = R"(
259 ; CHECK: OpDecorate [[var1:%\w+]] DescriptorSet 0
260 ; CHECK: OpDecorate [[var1]] Binding 0
261 ; CHECK: OpDecorate [[var2:%\w+]] DescriptorSet 0
262 ; CHECK: OpDecorate [[var2]] Binding 1
263 ; CHECK: OpTypeStruct
264 ; CHECK: [[struct_type:%\w+]] = OpTypeStruct
265 ; CHECK: [[ptr_type:%\w+]] = OpTypePointer Uniform [[struct_type]]
266 ; CHECK: [[var1]] = OpVariable [[ptr_type]] Uniform
267 ; CHECK: [[var2]] = OpVariable [[ptr_type]] Uniform
268 ; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var1]] %uint_0 %uint_0 %uint_0
269 ; CHECK: OpLoad %v4float [[ac1]]
270 ; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var2]] %uint_0 %uint_0 %uint_0
271 ; CHECK: OpLoad %v4float [[ac2]]
272 OpCapability Shader
273 OpMemoryModel Logical GLSL450
274 OpEntryPoint Fragment %main "main"
275 OpExecutionMode %main OriginUpperLeft
276 OpSource HLSL 600
277 OpDecorate %buffers DescriptorSet 0
278 OpDecorate %buffers Binding 0
279 OpMemberDecorate %S 0 Offset 0
280 OpDecorate %_runtimearr_S ArrayStride 16
281 OpMemberDecorate %type_StructuredBuffer_S 0 Offset 0
282 OpMemberDecorate %type_StructuredBuffer_S 0 NonWritable
283 OpDecorate %type_StructuredBuffer_S BufferBlock
284 %uint = OpTypeInt 32 0
285 %uint_0 = OpConstant %uint 0
286 %uint_1 = OpConstant %uint 1
287 %uint_2 = OpConstant %uint 2
288 %float = OpTypeFloat 32
289 %v4float = OpTypeVector %float 4
290 %S = OpTypeStruct %v4float
291 %_runtimearr_S = OpTypeRuntimeArray %S
292 %type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S
293 %_arr_type_StructuredBuffer_S_uint_2 = OpTypeArray %type_StructuredBuffer_S %uint_2
294 %_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 = OpTypePointer Uniform %_arr_type_StructuredBuffer_S_uint_2
295 %_ptr_Uniform_type_StructuredBuffer_S = OpTypePointer Uniform %type_StructuredBuffer_S
296 %void = OpTypeVoid
297 %19 = OpTypeFunction %void
298 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
299 %buffers = OpVariable %_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 Uniform
300 %main = OpFunction %void None %19
301 %21 = OpLabel
302 %22 = OpAccessChain %_ptr_Uniform_v4float %buffers %uint_0 %uint_0 %uint_0 %uint_0
303 %23 = OpLoad %v4float %22
304 %24 = OpAccessChain %_ptr_Uniform_type_StructuredBuffer_S %buffers %uint_1
305 %25 = OpAccessChain %_ptr_Uniform_v4float %24 %uint_0 %uint_0 %uint_0
306 %26 = OpLoad %v4float %25
307 OpReturn
308 OpFunctionEnd
309 )";
310
311 SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
312 }
313
TEST_F(DescriptorScalarReplacementTest,NameNewVariables)314 TEST_F(DescriptorScalarReplacementTest, NameNewVariables) {
315 // Checks that if the original variable has a name, then the new variables
316 // will have a name derived from that name.
317 const std::string text = R"(
318 ; CHECK: OpName [[var1:%\w+]] "SSBO[0]"
319 ; CHECK: OpName [[var2:%\w+]] "SSBO[1]"
320 ; CHECK: OpDecorate [[var1]] DescriptorSet 0
321 ; CHECK: OpDecorate [[var1]] Binding 0
322 ; CHECK: OpDecorate [[var2]] DescriptorSet 0
323 ; CHECK: OpDecorate [[var2]] Binding 1
324 ; CHECK: OpTypeStruct
325 ; CHECK: [[struct_type:%\w+]] = OpTypeStruct
326 ; CHECK: [[ptr_type:%\w+]] = OpTypePointer Uniform [[struct_type]]
327 ; CHECK: [[var1]] = OpVariable [[ptr_type]] Uniform
328 ; CHECK: [[var2]] = OpVariable [[ptr_type]] Uniform
329 ; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var1]] %uint_0 %uint_0 %uint_0
330 ; CHECK: OpLoad %v4float [[ac1]]
331 ; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var2]] %uint_0 %uint_0 %uint_0
332 ; CHECK: OpLoad %v4float [[ac2]]
333 OpCapability Shader
334 OpMemoryModel Logical GLSL450
335 OpEntryPoint Fragment %main "main"
336 OpExecutionMode %main OriginUpperLeft
337 OpSource HLSL 600
338 OpName %buffers "SSBO"
339 OpDecorate %buffers DescriptorSet 0
340 OpDecorate %buffers Binding 0
341 OpMemberDecorate %S 0 Offset 0
342 OpDecorate %_runtimearr_S ArrayStride 16
343 OpMemberDecorate %type_StructuredBuffer_S 0 Offset 0
344 OpMemberDecorate %type_StructuredBuffer_S 0 NonWritable
345 OpDecorate %type_StructuredBuffer_S BufferBlock
346 %uint = OpTypeInt 32 0
347 %uint_0 = OpConstant %uint 0
348 %uint_1 = OpConstant %uint 1
349 %uint_2 = OpConstant %uint 2
350 %float = OpTypeFloat 32
351 %v4float = OpTypeVector %float 4
352 %S = OpTypeStruct %v4float
353 %_runtimearr_S = OpTypeRuntimeArray %S
354 %type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S
355 %_arr_type_StructuredBuffer_S_uint_2 = OpTypeArray %type_StructuredBuffer_S %uint_2
356 %_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 = OpTypePointer Uniform %_arr_type_StructuredBuffer_S_uint_2
357 %_ptr_Uniform_type_StructuredBuffer_S = OpTypePointer Uniform %type_StructuredBuffer_S
358 %void = OpTypeVoid
359 %19 = OpTypeFunction %void
360 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
361 %buffers = OpVariable %_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 Uniform
362 %main = OpFunction %void None %19
363 %21 = OpLabel
364 %22 = OpAccessChain %_ptr_Uniform_v4float %buffers %uint_0 %uint_0 %uint_0 %uint_0
365 %23 = OpLoad %v4float %22
366 %24 = OpAccessChain %_ptr_Uniform_type_StructuredBuffer_S %buffers %uint_1
367 %25 = OpAccessChain %_ptr_Uniform_v4float %24 %uint_0 %uint_0 %uint_0
368 %26 = OpLoad %v4float %25
369 OpReturn
370 OpFunctionEnd
371 )";
372
373 SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
374 }
375
TEST_F(DescriptorScalarReplacementTest,DontExpandCBuffers)376 TEST_F(DescriptorScalarReplacementTest, DontExpandCBuffers) {
377 // Checks that constant buffers are not expanded.
378 // Constant buffers are represented as global structures, but they should not
379 // be replaced with new variables for their elements.
380 /*
381 cbuffer MyCbuffer : register(b1) {
382 float2 a;
383 float2 b;
384 };
385 float main() : A {
386 return a.x + b.y;
387 }
388 */
389 const std::string text = R"(
390 ; CHECK: OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_0 %int_0
391 ; CHECK: OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_1 %int_1
392 OpCapability Shader
393 OpMemoryModel Logical GLSL450
394 OpEntryPoint Vertex %main "main" %out_var_A
395 OpSource HLSL 600
396 OpName %type_MyCbuffer "type.MyCbuffer"
397 OpMemberName %type_MyCbuffer 0 "a"
398 OpMemberName %type_MyCbuffer 1 "b"
399 OpName %MyCbuffer "MyCbuffer"
400 OpName %out_var_A "out.var.A"
401 OpName %main "main"
402 OpDecorate %out_var_A Location 0
403 OpDecorate %MyCbuffer DescriptorSet 0
404 OpDecorate %MyCbuffer Binding 1
405 OpMemberDecorate %type_MyCbuffer 0 Offset 0
406 OpMemberDecorate %type_MyCbuffer 1 Offset 8
407 OpDecorate %type_MyCbuffer Block
408 %int = OpTypeInt 32 1
409 %int_0 = OpConstant %int 0
410 %int_1 = OpConstant %int 1
411 %float = OpTypeFloat 32
412 %v2float = OpTypeVector %float 2
413 %type_MyCbuffer = OpTypeStruct %v2float %v2float
414 %_ptr_Uniform_type_MyCbuffer = OpTypePointer Uniform %type_MyCbuffer
415 %_ptr_Output_float = OpTypePointer Output %float
416 %void = OpTypeVoid
417 %13 = OpTypeFunction %void
418 %_ptr_Uniform_float = OpTypePointer Uniform %float
419 %MyCbuffer = OpVariable %_ptr_Uniform_type_MyCbuffer Uniform
420 %out_var_A = OpVariable %_ptr_Output_float Output
421 %main = OpFunction %void None %13
422 %15 = OpLabel
423 %16 = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_0 %int_0
424 %17 = OpLoad %float %16
425 %18 = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_1 %int_1
426 %19 = OpLoad %float %18
427 %20 = OpFAdd %float %17 %19
428 OpStore %out_var_A %20
429 OpReturn
430 OpFunctionEnd
431 )";
432
433 SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
434 }
435
TEST_F(DescriptorScalarReplacementTest,DontExpandStructuredBuffers)436 TEST_F(DescriptorScalarReplacementTest, DontExpandStructuredBuffers) {
437 // Checks that structured buffers are not expanded.
438 // Structured buffers are represented as global structures, that have one
439 // member which is a runtime array.
440 /*
441 struct S {
442 float2 a;
443 float2 b;
444 };
445 RWStructuredBuffer<S> sb;
446 float main() : A {
447 return sb[0].a.x + sb[0].b.x;
448 }
449 */
450 const std::string text = R"(
451 ; CHECK: OpAccessChain %_ptr_Uniform_float %sb %int_0 %uint_0 %int_0 %int_0
452 ; CHECK: OpAccessChain %_ptr_Uniform_float %sb %int_0 %uint_0 %int_1 %int_0
453 OpCapability Shader
454 OpMemoryModel Logical GLSL450
455 OpEntryPoint Vertex %main "main" %out_var_A
456 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
457 OpName %S "S"
458 OpMemberName %S 0 "a"
459 OpMemberName %S 1 "b"
460 OpName %sb "sb"
461 OpName %out_var_A "out.var.A"
462 OpName %main "main"
463 OpDecorate %out_var_A Location 0
464 OpDecorate %sb DescriptorSet 0
465 OpDecorate %sb Binding 0
466 OpMemberDecorate %S 0 Offset 0
467 OpMemberDecorate %S 1 Offset 8
468 OpDecorate %_runtimearr_S ArrayStride 16
469 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
470 OpDecorate %type_RWStructuredBuffer_S BufferBlock
471 %int = OpTypeInt 32 1
472 %int_0 = OpConstant %int 0
473 %uint = OpTypeInt 32 0
474 %uint_0 = OpConstant %uint 0
475 %int_1 = OpConstant %int 1
476 %float = OpTypeFloat 32
477 %v2float = OpTypeVector %float 2
478 %S = OpTypeStruct %v2float %v2float
479 %_runtimearr_S = OpTypeRuntimeArray %S
480 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
481 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
482 %_ptr_Output_float = OpTypePointer Output %float
483 %void = OpTypeVoid
484 %17 = OpTypeFunction %void
485 %_ptr_Uniform_float = OpTypePointer Uniform %float
486 %sb = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
487 %out_var_A = OpVariable %_ptr_Output_float Output
488 %main = OpFunction %void None %17
489 %19 = OpLabel
490 %20 = OpAccessChain %_ptr_Uniform_float %sb %int_0 %uint_0 %int_0 %int_0
491 %21 = OpLoad %float %20
492 %22 = OpAccessChain %_ptr_Uniform_float %sb %int_0 %uint_0 %int_1 %int_0
493 %23 = OpLoad %float %22
494 %24 = OpFAdd %float %21 %23
495 OpStore %out_var_A %24
496 OpReturn
497 OpFunctionEnd
498 )";
499
500 SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
501 }
502
TEST_F(DescriptorScalarReplacementTest,StructureArrayNames)503 TEST_F(DescriptorScalarReplacementTest, StructureArrayNames) {
504 // Checks that names are properly generated for multi-dimension arrays and
505 // structure members.
506 const std::string checks = R"(
507 ; CHECK: OpName %globalS_0__0__t_0_ "globalS[0][0].t[0]"
508 ; CHECK: OpName %globalS_0__0__s_0_ "globalS[0][0].s[0]"
509 ; CHECK: OpName %globalS_1__1__t_1_ "globalS[1][1].t[1]"
510 ; CHECK: OpName %globalS_1__1__s_1_ "globalS[1][1].s[1]"
511 )";
512
513 const std::string text = checks + GetStructureArrayTestSpirv();
514 SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
515 }
516
TEST_F(DescriptorScalarReplacementTest,StructureArrayBindings)517 TEST_F(DescriptorScalarReplacementTest, StructureArrayBindings) {
518 // Checks that flattening structures and arrays results in correct binding
519 // numbers.
520 const std::string checks = R"(
521 ; CHECK: OpDecorate %globalS_0__0__t_0_ Binding 0
522 ; CHECK: OpDecorate %globalS_0__0__s_0_ Binding 2
523 ; CHECK: OpDecorate %globalS_1__1__t_1_ Binding 13
524 ; CHECK: OpDecorate %globalS_1__1__s_1_ Binding 15
525 )";
526
527 const std::string text = checks + GetStructureArrayTestSpirv();
528 SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
529 }
530
TEST_F(DescriptorScalarReplacementTest,StructureArrayReplacements)531 TEST_F(DescriptorScalarReplacementTest, StructureArrayReplacements) {
532 // Checks that all access chains indexing into structures and/or arrays are
533 // replaced with direct access to replacement variables.
534 const std::string checks = R"(
535 ; CHECK-NOT: OpAccessChain
536 ; CHECK: OpLoad %type_2d_image %globalS_0__0__t_0_
537 ; CHECK: OpLoad %type_sampler %globalS_0__0__s_0_
538 ; CHECK: OpLoad %type_2d_image %globalS_1__1__t_1_
539 ; CHECK: OpLoad %type_sampler %globalS_1__1__s_1_
540 )";
541
542 const std::string text = checks + GetStructureArrayTestSpirv();
543 SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
544 }
545
TEST_F(DescriptorScalarReplacementTest,ResourceStructAsFunctionParam)546 TEST_F(DescriptorScalarReplacementTest, ResourceStructAsFunctionParam) {
547 // Checks that a mix of OpAccessChain, OpLoad, and OpCompositeExtract patterns
548 // can be properly replaced with replacement variables.
549 // This pattern can be seen when a global structure of resources is passed to
550 // a function.
551
552 /* High-level source:
553 // globalS[0].t[0] binding: 0 (used)
554 // globalS[0].t[1] binding: 1 (used)
555 // globalS[0].tt[0].s[0] binding: 2
556 // globalS[0].tt[0].s[1] binding: 3 (used)
557 // globalS[0].tt[0].s[2] binding: 4
558 // globalS[0].tt[1].s[0] binding: 5
559 // globalS[0].tt[1].s[1] binding: 6
560 // globalS[0].tt[1].s[2] binding: 7 (used)
561 // globalS[1].t[0] binding: 8 (used)
562 // globalS[1].t[1] binding: 9 (used)
563 // globalS[1].tt[0].s[0] binding: 10
564 // globalS[1].tt[0].s[1] binding: 11 (used)
565 // globalS[1].tt[0].s[2] binding: 12
566 // globalS[1].tt[1].s[0] binding: 13
567 // globalS[1].tt[1].s[1] binding: 14
568 // globalS[1].tt[1].s[2] binding: 15 (used)
569
570 struct T {
571 SamplerState s[3];
572 };
573
574 struct S {
575 Texture2D t[2];
576 T tt[2];
577 };
578
579 float4 tex2D(S x, float2 v) {
580 return x.t[0].Sample(x.tt[0].s[1], v) + x.t[1].Sample(x.tt[1].s[2], v);
581 }
582
583 S globalS[2];
584
585 float4 main() : SV_Target {
586 return tex2D(globalS[0], float2(0,0)) + tex2D(globalS[1], float2(0,0)) ;
587 }
588 */
589 const std::string shader = R"(
590 OpCapability Shader
591 OpMemoryModel Logical GLSL450
592 OpEntryPoint Fragment %main "main" %out_var_SV_Target
593 OpExecutionMode %main OriginUpperLeft
594 OpName %S "S"
595 OpMemberName %S 0 "t"
596 OpMemberName %S 1 "tt"
597 OpName %type_2d_image "type.2d.image"
598 OpName %T "T"
599 OpMemberName %T 0 "s"
600 OpName %type_sampler "type.sampler"
601 OpName %globalS "globalS"
602 OpName %out_var_SV_Target "out.var.SV_Target"
603 OpName %main "main"
604 OpName %type_sampled_image "type.sampled.image"
605 OpDecorate %out_var_SV_Target Location 0
606 OpDecorate %globalS DescriptorSet 0
607 OpDecorate %globalS Binding 0
608 %int = OpTypeInt 32 1
609 %int_0 = OpConstant %int 0
610 %float = OpTypeFloat 32
611 %float_0 = OpConstant %float 0
612 %v2float = OpTypeVector %float 2
613 %14 = OpConstantComposite %v2float %float_0 %float_0
614 %int_1 = OpConstant %int 1
615 %uint = OpTypeInt 32 0
616 %uint_2 = OpConstant %uint 2
617 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
618 %_arr_type_2d_image_uint_2 = OpTypeArray %type_2d_image %uint_2
619 %uint_3 = OpConstant %uint 3
620 %type_sampler = OpTypeSampler
621 %_arr_type_sampler_uint_3 = OpTypeArray %type_sampler %uint_3
622 %T = OpTypeStruct %_arr_type_sampler_uint_3
623 %_arr_T_uint_2 = OpTypeArray %T %uint_2
624 %S = OpTypeStruct %_arr_type_2d_image_uint_2 %_arr_T_uint_2
625 %_arr_S_uint_2 = OpTypeArray %S %uint_2
626 %_ptr_UniformConstant__arr_S_uint_2 = OpTypePointer UniformConstant %_arr_S_uint_2
627 %v4float = OpTypeVector %float 4
628 %_ptr_Output_v4float = OpTypePointer Output %v4float
629 %void = OpTypeVoid
630 %27 = OpTypeFunction %void
631 %_ptr_UniformConstant_S = OpTypePointer UniformConstant %S
632 %type_sampled_image = OpTypeSampledImage %type_2d_image
633 %globalS = OpVariable %_ptr_UniformConstant__arr_S_uint_2 UniformConstant
634 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
635 %main = OpFunction %void None %27
636 %29 = OpLabel
637 %30 = OpAccessChain %_ptr_UniformConstant_S %globalS %int_0
638 %31 = OpLoad %S %30
639 %32 = OpCompositeExtract %_arr_type_2d_image_uint_2 %31 0
640 %33 = OpCompositeExtract %type_2d_image %32 0
641 %34 = OpCompositeExtract %type_2d_image %32 1
642 %35 = OpCompositeExtract %_arr_T_uint_2 %31 1
643 %36 = OpCompositeExtract %T %35 0
644 %37 = OpCompositeExtract %_arr_type_sampler_uint_3 %36 0
645 %38 = OpCompositeExtract %type_sampler %37 1
646 %39 = OpCompositeExtract %T %35 1
647 %40 = OpCompositeExtract %_arr_type_sampler_uint_3 %39 0
648 %41 = OpCompositeExtract %type_sampler %40 2
649 %42 = OpSampledImage %type_sampled_image %33 %38
650 %43 = OpImageSampleImplicitLod %v4float %42 %14 None
651 %44 = OpSampledImage %type_sampled_image %34 %41
652 %45 = OpImageSampleImplicitLod %v4float %44 %14 None
653 %46 = OpFAdd %v4float %43 %45
654 %47 = OpAccessChain %_ptr_UniformConstant_S %globalS %int_1
655 %48 = OpLoad %S %47
656 %49 = OpCompositeExtract %_arr_type_2d_image_uint_2 %48 0
657 %50 = OpCompositeExtract %type_2d_image %49 0
658 %51 = OpCompositeExtract %type_2d_image %49 1
659 %52 = OpCompositeExtract %_arr_T_uint_2 %48 1
660 %53 = OpCompositeExtract %T %52 0
661 %54 = OpCompositeExtract %_arr_type_sampler_uint_3 %53 0
662 %55 = OpCompositeExtract %type_sampler %54 1
663 %56 = OpCompositeExtract %T %52 1
664 %57 = OpCompositeExtract %_arr_type_sampler_uint_3 %56 0
665 %58 = OpCompositeExtract %type_sampler %57 2
666 %59 = OpSampledImage %type_sampled_image %50 %55
667 %60 = OpImageSampleImplicitLod %v4float %59 %14 None
668 %61 = OpSampledImage %type_sampled_image %51 %58
669 %62 = OpImageSampleImplicitLod %v4float %61 %14 None
670 %63 = OpFAdd %v4float %60 %62
671 %64 = OpFAdd %v4float %46 %63
672 OpStore %out_var_SV_Target %64
673 OpReturn
674 OpFunctionEnd
675 )";
676
677 const std::string checks = R"(
678 ; CHECK: OpName %globalS_0__t_0_ "globalS[0].t[0]"
679 ; CHECK: OpName %globalS_0__t_1_ "globalS[0].t[1]"
680 ; CHECK: OpName %globalS_1__t_0_ "globalS[1].t[0]"
681 ; CHECK: OpName %globalS_1__t_1_ "globalS[1].t[1]"
682 ; CHECK: OpName %globalS_0__tt_0__s_1_ "globalS[0].tt[0].s[1]"
683 ; CHECK: OpName %globalS_0__tt_1__s_2_ "globalS[0].tt[1].s[2]"
684 ; CHECK: OpName %globalS_1__tt_0__s_1_ "globalS[1].tt[0].s[1]"
685 ; CHECK: OpName %globalS_1__tt_1__s_2_ "globalS[1].tt[1].s[2]"
686 ; CHECK: OpDecorate %globalS_0__t_0_ Binding 0
687 ; CHECK: OpDecorate %globalS_0__t_1_ Binding 1
688 ; CHECK: OpDecorate %globalS_1__t_0_ Binding 8
689 ; CHECK: OpDecorate %globalS_1__t_1_ Binding 9
690 ; CHECK: OpDecorate %globalS_0__tt_0__s_1_ Binding 3
691 ; CHECK: OpDecorate %globalS_0__tt_1__s_2_ Binding 7
692 ; CHECK: OpDecorate %globalS_1__tt_0__s_1_ Binding 11
693 ; CHECK: OpDecorate %globalS_1__tt_1__s_2_ Binding 15
694
695 ; CHECK: %globalS_0__t_0_ = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
696 ; CHECK: %globalS_0__t_1_ = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
697 ; CHECK: %globalS_1__t_0_ = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
698 ; CHECK: %globalS_1__t_1_ = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
699 ; CHECK: %globalS_0__tt_0__s_1_ = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
700 ; CHECK: %globalS_0__tt_1__s_2_ = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
701 ; CHECK: %globalS_1__tt_0__s_1_ = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
702 ; CHECK: %globalS_1__tt_1__s_2_ = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
703
704 ; CHECK: [[img_1:%\w+]] = OpLoad %type_2d_image %globalS_0__t_0_
705 ; CHECK: [[img_2:%\w+]] = OpLoad %type_2d_image %globalS_0__t_1_
706 ; CHECK: [[sampler_1:%\w+]] = OpLoad %type_sampler %globalS_0__tt_0__s_1_
707 ; CHECK: [[sampler_2:%\w+]] = OpLoad %type_sampler %globalS_0__tt_1__s_2_
708
709 ; CHECK: [[sampled_img_1:%\w+]] = OpSampledImage %type_sampled_image [[img_1]] [[sampler_1]]
710 ; CHECK: [[sample_1:%\w+]] = OpImageSampleImplicitLod %v4float [[sampled_img_1]]
711 ; CHECK: [[sampled_img_2:%\w+]] = OpSampledImage %type_sampled_image [[img_2]] [[sampler_2]]
712 ; CHECK: [[sample_2:%\w+]] = OpImageSampleImplicitLod %v4float [[sampled_img_2]]
713 ; CHECK: OpFAdd %v4float [[sample_1]] [[sample_2]]
714
715 ; CHECK: [[img_3:%\w+]] = OpLoad %type_2d_image %globalS_1__t_0_
716 ; CHECK: [[img_4:%\w+]] = OpLoad %type_2d_image %globalS_1__t_1_
717 ; CHECK: [[sampler_3:%\w+]] = OpLoad %type_sampler %globalS_1__tt_0__s_1_
718 ; CHECK: [[sampler_4:%\w+]] = OpLoad %type_sampler %globalS_1__tt_1__s_2_
719
720 ; CHECK: [[sampled_img_3:%\w+]] = OpSampledImage %type_sampled_image [[img_3]] [[sampler_3]]
721 ; CHECK: [[sample_3:%\w+]] = OpImageSampleImplicitLod %v4float [[sampled_img_3]]
722 ; CHECK: [[sampled_img_4:%\w+]] = OpSampledImage %type_sampled_image [[img_4]] [[sampler_4]]
723 ; CHECK: [[sample_4:%\w+]] = OpImageSampleImplicitLod %v4float [[sampled_img_4]]
724 ; CHECK: OpFAdd %v4float [[sample_3]] [[sample_4]]
725 )";
726
727 SinglePassRunAndMatch<DescriptorScalarReplacement>(checks + shader, true);
728 }
729
TEST_F(DescriptorScalarReplacementTest,BindingForResourceArrayOfStructs)730 TEST_F(DescriptorScalarReplacementTest, BindingForResourceArrayOfStructs) {
731 // Check that correct binding numbers are given to an array of descriptors
732 // to structs.
733
734 const std::string shader = R"(
735 ; CHECK: OpDecorate {{%\w+}} Binding 0
736 ; CHECK: OpDecorate {{%\w+}} Binding 1
737 OpCapability Shader
738 %1 = OpExtInstImport "GLSL.std.450"
739 OpMemoryModel Logical GLSL450
740 OpEntryPoint Fragment %2 "psmain"
741 OpExecutionMode %2 OriginUpperLeft
742 OpDecorate %5 DescriptorSet 0
743 OpDecorate %5 Binding 0
744 OpMemberDecorate %_struct_4 0 Offset 0
745 OpMemberDecorate %_struct_4 1 Offset 4
746 OpDecorate %_struct_4 Block
747 %float = OpTypeFloat 32
748 %int = OpTypeInt 32 1
749 %int_0 = OpConstant %int 0
750 %int_1 = OpConstant %int 1
751 %uint = OpTypeInt 32 0
752 %uint_2 = OpConstant %uint 2
753 %_struct_4 = OpTypeStruct %float %int
754 %_arr__struct_4_uint_2 = OpTypeArray %_struct_4 %uint_2
755 %_ptr_Uniform__arr__struct_4_uint_2 = OpTypePointer Uniform %_arr__struct_4_uint_2
756 %void = OpTypeVoid
757 %25 = OpTypeFunction %void
758 %_ptr_Uniform_int = OpTypePointer Uniform %int
759 %5 = OpVariable %_ptr_Uniform__arr__struct_4_uint_2 Uniform
760 %2 = OpFunction %void None %25
761 %29 = OpLabel
762 %40 = OpAccessChain %_ptr_Uniform_int %5 %int_0 %int_1
763 %41 = OpAccessChain %_ptr_Uniform_int %5 %int_1 %int_1
764 OpReturn
765 OpFunctionEnd
766 )";
767
768 SinglePassRunAndMatch<DescriptorScalarReplacement>(shader, true);
769 }
770
TEST_F(DescriptorScalarReplacementTest,MemberDecorationForResourceStruct)771 TEST_F(DescriptorScalarReplacementTest, MemberDecorationForResourceStruct) {
772 // Check that an OpMemberDecorate instruction is correctly converted to a
773 // OpDecorate instruction.
774
775 const std::string shader = R"(
776 ; CHECK: OpDecorate [[t:%\w+]] DescriptorSet 0
777 ; CHECK: OpDecorate [[t]] Binding 0
778 ; CHECK: OpDecorate [[t]] RelaxedPrecision
779 ; CHECK: OpDecorate [[s:%\w+]] DescriptorSet 0
780 ; CHECK: OpDecorate [[s]] Binding 1
781 OpCapability Shader
782 OpMemoryModel Logical GLSL450
783 OpEntryPoint Fragment %PSMain "PSMain" %in_var_TEXCOORD %out_var_SV_Target
784 OpExecutionMode %PSMain OriginUpperLeft
785 OpSource HLSL 600
786 OpName %sampler2D_h "sampler2D_h"
787 OpMemberName %sampler2D_h 0 "t"
788 OpMemberName %sampler2D_h 1 "s"
789 OpName %type_2d_image "type.2d.image"
790 OpName %type_sampler "type.sampler"
791 OpName %_MainTex "_MainTex"
792 OpName %in_var_TEXCOORD "in.var.TEXCOORD"
793 OpName %out_var_SV_Target "out.var.SV_Target"
794 OpName %PSMain "PSMain"
795 OpName %type_sampled_image "type.sampled.image"
796 OpDecorate %in_var_TEXCOORD Location 0
797 OpDecorate %out_var_SV_Target Location 0
798 OpDecorate %_MainTex DescriptorSet 0
799 OpDecorate %_MainTex Binding 0
800 OpMemberDecorate %sampler2D_h 0 RelaxedPrecision
801 OpDecorate %out_var_SV_Target RelaxedPrecision
802 OpDecorate %69 RelaxedPrecision
803 %float = OpTypeFloat 32
804 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
805 %type_sampler = OpTypeSampler
806 %sampler2D_h = OpTypeStruct %type_2d_image %type_sampler
807 %_ptr_UniformConstant_sampler2D_h = OpTypePointer UniformConstant %sampler2D_h
808 %v2float = OpTypeVector %float 2
809 %_ptr_Input_v2float = OpTypePointer Input %v2float
810 %v4float = OpTypeVector %float 4
811 %_ptr_Output_v4float = OpTypePointer Output %v4float
812 %void = OpTypeVoid
813 %35 = OpTypeFunction %void
814 %type_sampled_image = OpTypeSampledImage %type_2d_image
815 %_MainTex = OpVariable %_ptr_UniformConstant_sampler2D_h UniformConstant
816 %in_var_TEXCOORD = OpVariable %_ptr_Input_v2float Input
817 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
818 %PSMain = OpFunction %void None %35
819 %43 = OpLabel
820 %44 = OpLoad %v2float %in_var_TEXCOORD
821 %57 = OpLoad %sampler2D_h %_MainTex
822 %72 = OpCompositeExtract %type_2d_image %57 0
823 %73 = OpCompositeExtract %type_sampler %57 1
824 %68 = OpSampledImage %type_sampled_image %72 %73
825 %69 = OpImageSampleImplicitLod %v4float %68 %44 None
826 OpStore %out_var_SV_Target %69
827 OpReturn
828 OpFunctionEnd
829 )";
830
831 SinglePassRunAndMatch<DescriptorScalarReplacement>(shader, true);
832 }
833
TEST_F(DescriptorScalarReplacementTest,DecorateStringForReflect)834 TEST_F(DescriptorScalarReplacementTest, DecorateStringForReflect) {
835 // Check that an OpDecorateString instruction is correctly cloned to new
836 // variable.
837
838 const std::string shader = R"(
839 ; CHECK: OpName %g_testTextures_0_ "g_testTextures[0]"
840 ; CHECK: OpDecorate %g_testTextures_0_ DescriptorSet 0
841 ; CHECK: OpDecorate %g_testTextures_0_ Binding 0
842 ; CHECK: OpDecorateString %g_testTextures_0_ UserTypeGOOGLE "texture2d"
843 OpCapability Shader
844 OpExtension "SPV_GOOGLE_hlsl_functionality1"
845 OpExtension "SPV_GOOGLE_user_type"
846 OpMemoryModel Logical GLSL450
847 OpEntryPoint Fragment %main "main" %gl_FragCoord %out_var_SV_Target
848 OpExecutionMode %main OriginUpperLeft
849 OpSource HLSL 600
850 OpName %type_2d_image "type.2d.image"
851 OpName %g_testTextures "g_testTextures"
852 OpName %out_var_SV_Target "out.var.SV_Target"
853 OpName %main "main"
854 OpName %param_var_vPixelPos "param.var.vPixelPos"
855 OpName %src_main "src.main"
856 OpName %vPixelPos "vPixelPos"
857 OpName %bb_entry "bb.entry"
858 OpDecorate %gl_FragCoord BuiltIn FragCoord
859 OpDecorateString %gl_FragCoord UserSemantic "SV_Position"
860 OpDecorateString %out_var_SV_Target UserSemantic "SV_Target"
861 OpDecorate %out_var_SV_Target Location 0
862 OpDecorate %g_testTextures DescriptorSet 0
863 OpDecorate %g_testTextures Binding 0
864 OpDecorateString %g_testTextures UserTypeGOOGLE "texture2d"
865 %uint = OpTypeInt 32 0
866 %uint_0 = OpConstant %uint 0
867 %int = OpTypeInt 32 1
868 %int_0 = OpConstant %int 0
869 %uint_2 = OpConstant %uint 2
870 %float = OpTypeFloat 32
871 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
872 %_arr_type_2d_image_uint_2 = OpTypeArray %type_2d_image %uint_2
873 %_ptr_UniformConstant__arr_type_2d_image_uint_2 = OpTypePointer UniformConstant %_arr_type_2d_image_uint_2
874 %v4float = OpTypeVector %float 4
875 %_ptr_Input_v4float = OpTypePointer Input %v4float
876 %_ptr_Output_v4float = OpTypePointer Output %v4float
877 %void = OpTypeVoid
878 %18 = OpTypeFunction %void
879 %_ptr_Function_v4float = OpTypePointer Function %v4float
880 %25 = OpTypeFunction %v4float %_ptr_Function_v4float
881 %v2float = OpTypeVector %float 2
882 %v3uint = OpTypeVector %uint 3
883 %v3int = OpTypeVector %int 3
884 %v2int = OpTypeVector %int 2
885 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
886 %g_testTextures = OpVariable %_ptr_UniformConstant__arr_type_2d_image_uint_2 UniformConstant
887 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
888 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
889 %main = OpFunction %void None %18
890 %19 = OpLabel
891 %param_var_vPixelPos = OpVariable %_ptr_Function_v4float Function
892 %22 = OpLoad %v4float %gl_FragCoord
893 OpStore %param_var_vPixelPos %22
894 %23 = OpFunctionCall %v4float %src_main %param_var_vPixelPos
895 OpStore %out_var_SV_Target %23
896 OpReturn
897 OpFunctionEnd
898 %src_main = OpFunction %v4float None %25
899 %vPixelPos = OpFunctionParameter %_ptr_Function_v4float
900 %bb_entry = OpLabel
901 %28 = OpLoad %v4float %vPixelPos
902 %30 = OpVectorShuffle %v2float %28 %28 0 1
903 %31 = OpCompositeExtract %float %30 0
904 %32 = OpCompositeExtract %float %30 1
905 %33 = OpConvertFToU %uint %31
906 %34 = OpConvertFToU %uint %32
907 %36 = OpCompositeConstruct %v3uint %33 %34 %uint_0
908 %38 = OpBitcast %v3int %36
909 %40 = OpVectorShuffle %v2int %38 %38 0 1
910 %41 = OpCompositeExtract %int %38 2
911 %43 = OpAccessChain %_ptr_UniformConstant_type_2d_image %g_testTextures %int_0
912 %44 = OpLoad %type_2d_image %43
913 %45 = OpImageFetch %v4float %44 %40 Lod %41
914 OpReturnValue %45
915 OpFunctionEnd
916 )";
917
918 SinglePassRunAndMatch<DescriptorScalarReplacement>(shader, true);
919 }
920
TEST_F(DescriptorScalarReplacementTest,ExpandArrayInOpEntryPoint)921 TEST_F(DescriptorScalarReplacementTest, ExpandArrayInOpEntryPoint) {
922 const std::string text = R"(; SPIR-V
923 ; Version: 1.6
924 ; Bound: 31
925 ; Schema: 0
926 OpCapability Shader
927 OpMemoryModel Logical GLSL450
928
929 ; CHECK: OpEntryPoint GLCompute %main "main" %output_0_ %output_1_
930
931 OpEntryPoint GLCompute %main "main" %output
932 OpExecutionMode %main LocalSize 1 1 1
933 OpSource HLSL 670
934 OpName %type_RWByteAddressBuffer "type.RWByteAddressBuffer"
935 OpName %output "output"
936 OpName %main "main"
937 OpName %src_main "src.main"
938 OpName %bb_entry "bb.entry"
939
940 ; CHECK: OpDecorate %output_1_ DescriptorSet 0
941 ; CHECK: OpDecorate %output_1_ Binding 1
942 ; CHECK: OpDecorate %output_0_ DescriptorSet 0
943 ; CHECK: OpDecorate %output_0_ Binding 0
944
945 OpDecorate %output DescriptorSet 0
946 OpDecorate %output Binding 0
947
948 OpDecorate %_runtimearr_uint ArrayStride 4
949 OpMemberDecorate %type_RWByteAddressBuffer 0 Offset 0
950 OpDecorate %type_RWByteAddressBuffer Block
951 %int = OpTypeInt 32 1
952 %int_1 = OpConstant %int 1
953 %uint = OpTypeInt 32 0
954 %uint_0 = OpConstant %uint 0
955 %uint_2 = OpConstant %uint 2
956 %uint_32 = OpConstant %uint 32
957 %_runtimearr_uint = OpTypeRuntimeArray %uint
958 %type_RWByteAddressBuffer = OpTypeStruct %_runtimearr_uint
959 %_arr_type_RWByteAddressBuffer_uint_2 = OpTypeArray %type_RWByteAddressBuffer %uint_2
960 %_ptr_StorageBuffer__arr_type_RWByteAddressBuffer_uint_2 = OpTypePointer StorageBuffer %_arr_type_RWByteAddressBuffer_uint_2
961 %void = OpTypeVoid
962 %23 = OpTypeFunction %void
963 %_ptr_StorageBuffer_type_RWByteAddressBuffer = OpTypePointer StorageBuffer %type_RWByteAddressBuffer
964 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
965
966 ; CHECK: %output_1_ = OpVariable %_ptr_StorageBuffer_type_RWByteAddressBuffer StorageBuffer
967 ; CHECK: %output_0_ = OpVariable %_ptr_StorageBuffer_type_RWByteAddressBuffer StorageBuffer
968
969 %output = OpVariable %_ptr_StorageBuffer__arr_type_RWByteAddressBuffer_uint_2 StorageBuffer
970
971 %main = OpFunction %void None %23
972 %26 = OpLabel
973 %27 = OpFunctionCall %void %src_main
974 OpReturn
975 OpFunctionEnd
976 %src_main = OpFunction %void None %23
977 %bb_entry = OpLabel
978 %28 = OpAccessChain %_ptr_StorageBuffer_type_RWByteAddressBuffer %output %int_1
979 %29 = OpShiftRightLogical %uint %uint_0 %uint_2
980 %30 = OpAccessChain %_ptr_StorageBuffer_uint %28 %uint_0 %29
981 OpStore %30 %uint_32
982 OpReturn
983 OpFunctionEnd
984 )";
985
986 SinglePassRunAndMatch<DescriptorScalarReplacement>(text, false);
987 }
988
989 } // namespace
990 } // namespace opt
991 } // namespace spvtools
992