1 // Copyright (c) 2022 The Khronos Group Inc.
2 // Copyright (c) 2022 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include <unordered_set>
17
18 #include "test/opt/pass_fixture.h"
19 #include "test/opt/pass_utils.h"
20
21 namespace spvtools {
22 namespace opt {
23 namespace {
24
25 using AnalyzeLiveInputTest = PassTest<::testing::Test>;
26
TEST_F(AnalyzeLiveInputTest,FragMultipleLocations)27 TEST_F(AnalyzeLiveInputTest, FragMultipleLocations) {
28 // Should report locations {2, 5}
29 //
30 // #version 450
31 //
32 // layout(location = 2) in Vertex
33 // {
34 // vec4 color0;
35 // vec4 color1;
36 // vec4 color2[3];
37 // } iVert;
38 //
39 // layout(location = 0) out vec4 oFragColor;
40 //
41 // void main()
42 // {
43 // oFragColor = iVert.color0 + iVert.color2[1];
44 // }
45 const std::string text = R"(
46 OpCapability Shader
47 %1 = OpExtInstImport "GLSL.std.450"
48 OpMemoryModel Logical GLSL450
49 OpEntryPoint Fragment %main "main" %oFragColor %iVert
50 OpExecutionMode %main OriginUpperLeft
51 OpSource GLSL 450
52 OpName %main "main"
53 OpName %oFragColor "oFragColor"
54 OpName %Vertex "Vertex"
55 OpMemberName %Vertex 0 "color0"
56 OpMemberName %Vertex 1 "color1"
57 OpMemberName %Vertex 2 "color2"
58 OpName %iVert "iVert"
59 OpDecorate %oFragColor Location 0
60 OpDecorate %Vertex Block
61 OpDecorate %iVert Location 2
62 %void = OpTypeVoid
63 %3 = OpTypeFunction %void
64 %float = OpTypeFloat 32
65 %v4float = OpTypeVector %float 4
66 %_ptr_Output_v4float = OpTypePointer Output %v4float
67 %oFragColor = OpVariable %_ptr_Output_v4float Output
68 %uint = OpTypeInt 32 0
69 %uint_3 = OpConstant %uint 3
70 %_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3
71 %Vertex = OpTypeStruct %v4float %v4float %_arr_v4float_uint_3
72 %_ptr_Input_Vertex = OpTypePointer Input %Vertex
73 %iVert = OpVariable %_ptr_Input_Vertex Input
74 %int = OpTypeInt 32 1
75 %int_0 = OpConstant %int 0
76 %_ptr_Input_v4float = OpTypePointer Input %v4float
77 %int_2 = OpConstant %int 2
78 %int_1 = OpConstant %int 1
79 %main = OpFunction %void None %3
80 %5 = OpLabel
81 %19 = OpAccessChain %_ptr_Input_v4float %iVert %int_0
82 %20 = OpLoad %v4float %19
83 %23 = OpAccessChain %_ptr_Input_v4float %iVert %int_2 %int_1
84 %24 = OpLoad %v4float %23
85 %25 = OpFAdd %v4float %20 %24
86 OpStore %oFragColor %25
87 OpReturn
88 OpFunctionEnd
89 )";
90
91 SetTargetEnv(SPV_ENV_VULKAN_1_3);
92 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
93
94 std::unordered_set<uint32_t> live_inputs;
95 std::unordered_set<uint32_t> live_builtins;
96 auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
97 text, true, &live_inputs, &live_builtins);
98
99 auto itr0 = live_inputs.find(0);
100 auto itr1 = live_inputs.find(1);
101 auto itr2 = live_inputs.find(2);
102 auto itr3 = live_inputs.find(3);
103 auto itr4 = live_inputs.find(4);
104 auto itr5 = live_inputs.find(5);
105 auto itr6 = live_inputs.find(6);
106
107 // Expect live_inputs == {2, 5}
108 EXPECT_TRUE(itr0 == live_inputs.end());
109 EXPECT_TRUE(itr1 == live_inputs.end());
110 EXPECT_TRUE(itr2 != live_inputs.end());
111 EXPECT_TRUE(itr3 == live_inputs.end());
112 EXPECT_TRUE(itr4 == live_inputs.end());
113 EXPECT_TRUE(itr5 != live_inputs.end());
114 EXPECT_TRUE(itr6 == live_inputs.end());
115 }
116
TEST_F(AnalyzeLiveInputTest,FragMatrix)117 TEST_F(AnalyzeLiveInputTest, FragMatrix) {
118 // Should report locations {2, 8, 9, 10, 11}
119 //
120 // #version 450
121 //
122 // uniform ui_name {
123 // int i;
124 // } ui_inst;
125 //
126 // layout(location = 2) in Vertex
127 // {
128 // vec4 color0;
129 // vec4 color1;
130 // mat4 color2;
131 // mat4 color3;
132 // mat4 color4;
133 // } iVert;
134 //
135 // // Output variable for the color
136 // layout(location = 0) out vec4 oFragColor;
137 //
138 // void main()
139 // {
140 // oFragColor = iVert.color0 + iVert.color3[ui_inst.i];
141 // }
142 const std::string text = R"(
143 OpCapability Shader
144 %1 = OpExtInstImport "GLSL.std.450"
145 OpMemoryModel Logical GLSL450
146 OpEntryPoint Fragment %main "main" %oFragColor %iVert %ui_inst
147 OpExecutionMode %main OriginUpperLeft
148 OpSource GLSL 450
149 OpName %main "main"
150 OpName %oFragColor "oFragColor"
151 OpName %Vertex "Vertex"
152 OpMemberName %Vertex 0 "color0"
153 OpMemberName %Vertex 1 "color1"
154 OpMemberName %Vertex 2 "color2"
155 OpMemberName %Vertex 3 "color3"
156 OpMemberName %Vertex 4 "color4"
157 OpName %iVert "iVert"
158 OpName %ui_name "ui_name"
159 OpMemberName %ui_name 0 "i"
160 OpName %ui_inst "ui_inst"
161 OpDecorate %oFragColor Location 0
162 OpDecorate %Vertex Block
163 OpDecorate %iVert Location 2
164 OpMemberDecorate %ui_name 0 Offset 0
165 OpDecorate %ui_name Block
166 OpDecorate %ui_inst DescriptorSet 0
167 OpDecorate %ui_inst Binding 0
168 %void = OpTypeVoid
169 %3 = OpTypeFunction %void
170 %float = OpTypeFloat 32
171 %v4float = OpTypeVector %float 4
172 %_ptr_Output_v4float = OpTypePointer Output %v4float
173 %oFragColor = OpVariable %_ptr_Output_v4float Output
174 %mat4v4float = OpTypeMatrix %v4float 4
175 %Vertex = OpTypeStruct %v4float %v4float %mat4v4float %mat4v4float %mat4v4float
176 %_ptr_Input_Vertex = OpTypePointer Input %Vertex
177 %iVert = OpVariable %_ptr_Input_Vertex Input
178 %int = OpTypeInt 32 1
179 %int_0 = OpConstant %int 0
180 %_ptr_Input_v4float = OpTypePointer Input %v4float
181 %int_3 = OpConstant %int 3
182 %ui_name = OpTypeStruct %int
183 %_ptr_Uniform_ui_name = OpTypePointer Uniform %ui_name
184 %ui_inst = OpVariable %_ptr_Uniform_ui_name Uniform
185 %_ptr_Uniform_int = OpTypePointer Uniform %int
186 %main = OpFunction %void None %3
187 %5 = OpLabel
188 %17 = OpAccessChain %_ptr_Input_v4float %iVert %int_0
189 %18 = OpLoad %v4float %17
190 %24 = OpAccessChain %_ptr_Uniform_int %ui_inst %int_0
191 %25 = OpLoad %int %24
192 %26 = OpAccessChain %_ptr_Input_v4float %iVert %int_3 %25
193 %27 = OpLoad %v4float %26
194 %28 = OpFAdd %v4float %18 %27
195 OpStore %oFragColor %28
196 OpReturn
197 OpFunctionEnd
198 )";
199
200 SetTargetEnv(SPV_ENV_VULKAN_1_3);
201 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
202
203 std::unordered_set<uint32_t> live_inputs;
204 std::unordered_set<uint32_t> live_builtins;
205 auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
206 text, true, &live_inputs, &live_builtins);
207
208 auto itr0 = live_inputs.find(0);
209 auto itr1 = live_inputs.find(1);
210 auto itr2 = live_inputs.find(2);
211 auto itr3 = live_inputs.find(3);
212 auto itr4 = live_inputs.find(4);
213 auto itr5 = live_inputs.find(5);
214 auto itr6 = live_inputs.find(6);
215 auto itr7 = live_inputs.find(7);
216 auto itr8 = live_inputs.find(8);
217 auto itr9 = live_inputs.find(9);
218 auto itr10 = live_inputs.find(10);
219 auto itr11 = live_inputs.find(11);
220 auto itr12 = live_inputs.find(12);
221 auto itr13 = live_inputs.find(13);
222 auto itr14 = live_inputs.find(14);
223 auto itr15 = live_inputs.find(15);
224
225 // Expect live_inputs == {2, 8, 9, 10, 11}
226 EXPECT_TRUE(itr0 == live_inputs.end());
227 EXPECT_TRUE(itr1 == live_inputs.end());
228 EXPECT_TRUE(itr2 != live_inputs.end());
229 EXPECT_TRUE(itr3 == live_inputs.end());
230 EXPECT_TRUE(itr4 == live_inputs.end());
231 EXPECT_TRUE(itr5 == live_inputs.end());
232 EXPECT_TRUE(itr6 == live_inputs.end());
233 EXPECT_TRUE(itr7 == live_inputs.end());
234 EXPECT_TRUE(itr8 != live_inputs.end());
235 EXPECT_TRUE(itr9 != live_inputs.end());
236 EXPECT_TRUE(itr10 != live_inputs.end());
237 EXPECT_TRUE(itr11 != live_inputs.end());
238 EXPECT_TRUE(itr12 == live_inputs.end());
239 EXPECT_TRUE(itr13 == live_inputs.end());
240 EXPECT_TRUE(itr14 == live_inputs.end());
241 EXPECT_TRUE(itr15 == live_inputs.end());
242 }
243
TEST_F(AnalyzeLiveInputTest,FragMemberLocs)244 TEST_F(AnalyzeLiveInputTest, FragMemberLocs) {
245 // Should report location {1}
246 //
247 // #version 450
248 //
249 // in Vertex
250 // {
251 // layout (location = 1) vec4 Cd;
252 // layout (location = 0) vec2 uv;
253 // } iVert;
254 //
255 // layout (location = 0) out vec4 fragColor;
256 //
257 // void main()
258 // {
259 // vec4 color = vec4(iVert.Cd);
260 // fragColor = color;
261 // }
262 const std::string text = R"(
263 OpCapability Shader
264 %1 = OpExtInstImport "GLSL.std.450"
265 OpMemoryModel Logical GLSL450
266 OpEntryPoint Fragment %main "main" %iVert %fragColor
267 OpExecutionMode %main OriginUpperLeft
268 OpSource GLSL 450
269 OpName %main "main"
270 OpName %color "color"
271 OpName %Vertex "Vertex"
272 OpMemberName %Vertex 0 "Cd"
273 OpMemberName %Vertex 1 "uv"
274 OpName %iVert "iVert"
275 OpName %fragColor "fragColor"
276 OpMemberDecorate %Vertex 0 Location 1
277 OpMemberDecorate %Vertex 1 Location 0
278 OpDecorate %Vertex Block
279 OpDecorate %fragColor Location 0
280 OpDecorate %_struct_27 Block
281 OpMemberDecorate %_struct_27 0 Location 1
282 %void = OpTypeVoid
283 %3 = OpTypeFunction %void
284 %float = OpTypeFloat 32
285 %v4float = OpTypeVector %float 4
286 %_ptr_Function_v4float = OpTypePointer Function %v4float
287 %v2float = OpTypeVector %float 2
288 %Vertex = OpTypeStruct %v4float %v2float
289 %_ptr_Input_Vertex = OpTypePointer Input %Vertex
290 %int = OpTypeInt 32 1
291 %int_0 = OpConstant %int 0
292 %_ptr_Input_v4float = OpTypePointer Input %v4float
293 %_ptr_Output_v4float = OpTypePointer Output %v4float
294 %fragColor = OpVariable %_ptr_Output_v4float Output
295 %_struct_27 = OpTypeStruct %v4float
296 %_ptr_Input__struct_27 = OpTypePointer Input %_struct_27
297 %iVert = OpVariable %_ptr_Input__struct_27 Input
298 %main = OpFunction %void None %3
299 %5 = OpLabel
300 %color = OpVariable %_ptr_Function_v4float Function
301 %17 = OpAccessChain %_ptr_Input_v4float %iVert %int_0
302 %18 = OpLoad %v4float %17
303 %19 = OpCompositeExtract %float %18 0
304 %20 = OpCompositeExtract %float %18 1
305 %21 = OpCompositeExtract %float %18 2
306 %22 = OpCompositeExtract %float %18 3
307 %23 = OpCompositeConstruct %v4float %19 %20 %21 %22
308 OpStore %color %23
309 %26 = OpLoad %v4float %color
310 OpStore %fragColor %26
311 OpReturn
312 OpFunctionEnd
313 )";
314
315 SetTargetEnv(SPV_ENV_VULKAN_1_3);
316 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
317
318 std::unordered_set<uint32_t> live_inputs;
319 std::unordered_set<uint32_t> live_builtins;
320 auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
321 text, true, &live_inputs, &live_builtins);
322
323 auto itr0 = live_inputs.find(0);
324 auto itr1 = live_inputs.find(1);
325
326 // Expect live_inputs == {2, 5}
327 EXPECT_TRUE(itr0 == live_inputs.end());
328 EXPECT_TRUE(itr1 != live_inputs.end());
329 }
330
TEST_F(AnalyzeLiveInputTest,ArrayedInput)331 TEST_F(AnalyzeLiveInputTest, ArrayedInput) {
332 // Tests handling of arrayed input seen in Tesc, Tese and Geom shaders.
333 //
334 // Should report location {1, 10}.
335 //
336 // #version 450
337 //
338 // layout (vertices = 4) out;
339 //
340 // layout (location = 1) in Vertex
341 // {
342 // vec4 p;
343 // vec3 n;
344 // vec4 f[100];
345 // } iVert[];
346 //
347 // layout (location = 0) out vec4 position[4];
348 //
349 // void main()
350 // {
351 // vec4 pos = iVert[gl_InvocationID].p *
352 // iVert[gl_InvocationID].f[7];
353 // position[gl_InvocationID] = pos;
354 // }
355 const std::string text = R"(
356 OpCapability Tessellation
357 %1 = OpExtInstImport "GLSL.std.450"
358 OpMemoryModel Logical GLSL450
359 OpEntryPoint TessellationControl %main "main" %iVert %gl_InvocationID %position
360 OpExecutionMode %main OutputVertices 4
361 OpSource GLSL 450
362 OpName %main "main"
363 OpName %Vertex "Vertex"
364 OpMemberName %Vertex 0 "p"
365 OpMemberName %Vertex 1 "n"
366 OpMemberName %Vertex 2 "f"
367 OpName %iVert "iVert"
368 OpName %gl_InvocationID "gl_InvocationID"
369 OpName %position "position"
370 OpDecorate %Vertex Block
371 OpDecorate %iVert Location 1
372 OpDecorate %gl_InvocationID BuiltIn InvocationId
373 OpDecorate %position Location 0
374 %void = OpTypeVoid
375 %3 = OpTypeFunction %void
376 %float = OpTypeFloat 32
377 %v4float = OpTypeVector %float 4
378 %v3float = OpTypeVector %float 3
379 %uint = OpTypeInt 32 0
380 %uint_100 = OpConstant %uint 100
381 %_arr_v4float_uint_100 = OpTypeArray %v4float %uint_100
382 %Vertex = OpTypeStruct %v4float %v3float %_arr_v4float_uint_100
383 %uint_32 = OpConstant %uint 32
384 %_arr_Vertex_uint_32 = OpTypeArray %Vertex %uint_32
385 %_ptr_Input__arr_Vertex_uint_32 = OpTypePointer Input %_arr_Vertex_uint_32
386 %iVert = OpVariable %_ptr_Input__arr_Vertex_uint_32 Input
387 %int = OpTypeInt 32 1
388 %_ptr_Input_int = OpTypePointer Input %int
389 %gl_InvocationID = OpVariable %_ptr_Input_int Input
390 %int_0 = OpConstant %int 0
391 %_ptr_Input_v4float = OpTypePointer Input %v4float
392 %int_2 = OpConstant %int 2
393 %int_7 = OpConstant %int 7
394 %uint_4 = OpConstant %uint 4
395 %_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4
396 %_ptr_Output__arr_v4float_uint_4 = OpTypePointer Output %_arr_v4float_uint_4
397 %position = OpVariable %_ptr_Output__arr_v4float_uint_4 Output
398 %_ptr_Output_v4float = OpTypePointer Output %v4float
399 %main = OpFunction %void None %3
400 %5 = OpLabel
401 %22 = OpLoad %int %gl_InvocationID
402 %25 = OpAccessChain %_ptr_Input_v4float %iVert %22 %int_0
403 %26 = OpLoad %v4float %25
404 %30 = OpAccessChain %_ptr_Input_v4float %iVert %22 %int_2 %int_7
405 %31 = OpLoad %v4float %30
406 %32 = OpFMul %v4float %26 %31
407 %40 = OpAccessChain %_ptr_Output_v4float %position %22
408 OpStore %40 %32
409 OpReturn
410 OpFunctionEnd
411 )";
412
413 SetTargetEnv(SPV_ENV_VULKAN_1_3);
414 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
415
416 std::unordered_set<uint32_t> live_inputs;
417 std::unordered_set<uint32_t> live_builtins;
418 auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
419 text, true, &live_inputs, &live_builtins);
420
421 auto itr0 = live_inputs.find(0);
422 auto itr1 = live_inputs.find(1);
423 auto itr2 = live_inputs.find(2);
424 auto itr3 = live_inputs.find(3);
425 auto itr4 = live_inputs.find(4);
426 auto itr5 = live_inputs.find(5);
427 auto itr6 = live_inputs.find(6);
428 auto itr7 = live_inputs.find(7);
429 auto itr8 = live_inputs.find(8);
430 auto itr9 = live_inputs.find(9);
431 auto itr10 = live_inputs.find(10);
432 auto itr11 = live_inputs.find(11);
433
434 // Expect live_inputs == {1, 10}
435 EXPECT_TRUE(itr0 == live_inputs.end());
436 EXPECT_TRUE(itr1 != live_inputs.end());
437 EXPECT_TRUE(itr2 == live_inputs.end());
438 EXPECT_TRUE(itr3 == live_inputs.end());
439 EXPECT_TRUE(itr4 == live_inputs.end());
440 EXPECT_TRUE(itr5 == live_inputs.end());
441 EXPECT_TRUE(itr6 == live_inputs.end());
442 EXPECT_TRUE(itr7 == live_inputs.end());
443 EXPECT_TRUE(itr8 == live_inputs.end());
444 EXPECT_TRUE(itr9 == live_inputs.end());
445 EXPECT_TRUE(itr10 != live_inputs.end());
446 EXPECT_TRUE(itr11 == live_inputs.end());
447 }
448
TEST_F(AnalyzeLiveInputTest,ArrayedInputMemberLocs)449 TEST_F(AnalyzeLiveInputTest, ArrayedInputMemberLocs) {
450 // Tests handling of member locs with arrayed input seen in Tesc, Tese
451 // and Geom shaders.
452 //
453 // Should report location {1, 12}.
454 //
455 // #version 450
456 //
457 // layout (vertices = 4) out;
458 //
459 // in Vertex
460 // {
461 // layout (location = 1) vec4 p;
462 // layout (location = 3) vec3 n;
463 // layout (location = 5) vec4 f[100];
464 // } iVert[];
465 //
466 // layout (location = 0) out vec4 position[4];
467 //
468 // void main()
469 // {
470 // vec4 pos = iVert[gl_InvocationID].p *
471 // iVert[gl_InvocationID].f[7];
472 // position[gl_InvocationID] = pos;
473 // }
474 const std::string text = R"(
475 OpCapability Tessellation
476 %1 = OpExtInstImport "GLSL.std.450"
477 OpMemoryModel Logical GLSL450
478 OpEntryPoint TessellationControl %main "main" %iVert %gl_InvocationID %position
479 OpExecutionMode %main OutputVertices 4
480 OpSource GLSL 450
481 OpName %main "main"
482 OpName %Vertex "Vertex"
483 OpMemberName %Vertex 0 "p"
484 OpMemberName %Vertex 1 "n"
485 OpMemberName %Vertex 2 "f"
486 OpName %iVert "iVert"
487 OpName %gl_InvocationID "gl_InvocationID"
488 OpName %position "position"
489 OpMemberDecorate %Vertex 0 Location 1
490 OpMemberDecorate %Vertex 1 Location 3
491 OpMemberDecorate %Vertex 2 Location 5
492 OpDecorate %Vertex Block
493 OpDecorate %gl_InvocationID BuiltIn InvocationId
494 OpDecorate %position Location 0
495 %void = OpTypeVoid
496 %3 = OpTypeFunction %void
497 %float = OpTypeFloat 32
498 %v4float = OpTypeVector %float 4
499 %v3float = OpTypeVector %float 3
500 %uint = OpTypeInt 32 0
501 %uint_100 = OpConstant %uint 100
502 %_arr_v4float_uint_100 = OpTypeArray %v4float %uint_100
503 %Vertex = OpTypeStruct %v4float %v3float %_arr_v4float_uint_100
504 %uint_32 = OpConstant %uint 32
505 %_arr_Vertex_uint_32 = OpTypeArray %Vertex %uint_32
506 %_ptr_Input__arr_Vertex_uint_32 = OpTypePointer Input %_arr_Vertex_uint_32
507 %iVert = OpVariable %_ptr_Input__arr_Vertex_uint_32 Input
508 %int = OpTypeInt 32 1
509 %_ptr_Input_int = OpTypePointer Input %int
510 %gl_InvocationID = OpVariable %_ptr_Input_int Input
511 %int_0 = OpConstant %int 0
512 %_ptr_Input_v4float = OpTypePointer Input %v4float
513 %int_2 = OpConstant %int 2
514 %int_7 = OpConstant %int 7
515 %uint_4 = OpConstant %uint 4
516 %_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4
517 %_ptr_Output__arr_v4float_uint_4 = OpTypePointer Output %_arr_v4float_uint_4
518 %position = OpVariable %_ptr_Output__arr_v4float_uint_4 Output
519 %_ptr_Output_v4float = OpTypePointer Output %v4float
520 %main = OpFunction %void None %3
521 %5 = OpLabel
522 %22 = OpLoad %int %gl_InvocationID
523 %25 = OpAccessChain %_ptr_Input_v4float %iVert %22 %int_0
524 %26 = OpLoad %v4float %25
525 %30 = OpAccessChain %_ptr_Input_v4float %iVert %22 %int_2 %int_7
526 %31 = OpLoad %v4float %30
527 %32 = OpFMul %v4float %26 %31
528 %40 = OpAccessChain %_ptr_Output_v4float %position %22
529 OpStore %40 %32
530 OpReturn
531 OpFunctionEnd
532 )";
533
534 SetTargetEnv(SPV_ENV_VULKAN_1_3);
535 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
536
537 std::unordered_set<uint32_t> live_inputs;
538 std::unordered_set<uint32_t> live_builtins;
539 auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
540 text, true, &live_inputs, &live_builtins);
541
542 auto itr0 = live_inputs.find(0);
543 auto itr1 = live_inputs.find(1);
544 auto itr2 = live_inputs.find(2);
545 auto itr3 = live_inputs.find(3);
546 auto itr4 = live_inputs.find(4);
547 auto itr5 = live_inputs.find(5);
548 auto itr6 = live_inputs.find(6);
549 auto itr7 = live_inputs.find(7);
550 auto itr8 = live_inputs.find(8);
551 auto itr9 = live_inputs.find(9);
552 auto itr10 = live_inputs.find(10);
553 auto itr11 = live_inputs.find(11);
554 auto itr12 = live_inputs.find(12);
555 auto itr13 = live_inputs.find(13);
556
557 // Expect live_inputs == {1, 12}
558 EXPECT_TRUE(itr0 == live_inputs.end());
559 EXPECT_TRUE(itr1 != live_inputs.end());
560 EXPECT_TRUE(itr2 == live_inputs.end());
561 EXPECT_TRUE(itr3 == live_inputs.end());
562 EXPECT_TRUE(itr4 == live_inputs.end());
563 EXPECT_TRUE(itr5 == live_inputs.end());
564 EXPECT_TRUE(itr6 == live_inputs.end());
565 EXPECT_TRUE(itr7 == live_inputs.end());
566 EXPECT_TRUE(itr8 == live_inputs.end());
567 EXPECT_TRUE(itr9 == live_inputs.end());
568 EXPECT_TRUE(itr10 == live_inputs.end());
569 EXPECT_TRUE(itr11 == live_inputs.end());
570 EXPECT_TRUE(itr12 != live_inputs.end());
571 EXPECT_TRUE(itr13 == live_inputs.end());
572 }
573
TEST_F(AnalyzeLiveInputTest,Builtins)574 TEST_F(AnalyzeLiveInputTest, Builtins) {
575 // Tests handling of builtin input seen in Tesc, Tese and Geom shaders.
576 //
577 // Should report builtin gl_PointSize only.
578 //
579 // #version 460
580 //
581 // layout(triangle_strip, max_vertices = 3) out;
582 // layout(triangles) in;
583 //
584 // void main()
585 // {
586 // for (int i = 0; i < 3; i++)
587 // {
588 // gl_Position = gl_in[i].gl_Position;
589 // gl_PointSize = gl_in[i].gl_PointSize;
590 //
591 // EmitVertex();
592 // }
593 //
594 // EndPrimitive();
595 // }
596 const std::string text = R"(
597 OpCapability Geometry
598 OpCapability GeometryPointSize
599 %1 = OpExtInstImport "GLSL.std.450"
600 OpMemoryModel Logical GLSL450
601 OpEntryPoint Geometry %main "main" %_ %gl_in
602 OpExecutionMode %main Triangles
603 OpExecutionMode %main Invocations 1
604 OpExecutionMode %main OutputTriangleStrip
605 OpExecutionMode %main OutputVertices 3
606 OpSource GLSL 460
607 OpName %main "main"
608 OpName %i "i"
609 OpName %gl_PerVertex "gl_PerVertex"
610 OpMemberName %gl_PerVertex 0 "gl_Position"
611 OpMemberName %gl_PerVertex 1 "gl_PointSize"
612 OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
613 OpMemberName %gl_PerVertex 3 "gl_CullDistance"
614 OpName %_ ""
615 OpName %gl_PerVertex_0 "gl_PerVertex"
616 OpMemberName %gl_PerVertex_0 0 "gl_Position"
617 OpMemberName %gl_PerVertex_0 1 "gl_PointSize"
618 OpMemberName %gl_PerVertex_0 2 "gl_ClipDistance"
619 OpMemberName %gl_PerVertex_0 3 "gl_CullDistance"
620 OpName %gl_in "gl_in"
621 OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
622 OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
623 OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
624 OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
625 OpDecorate %gl_PerVertex Block
626 OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
627 OpMemberDecorate %gl_PerVertex_0 1 BuiltIn PointSize
628 OpDecorate %gl_PerVertex_0 Block
629 %void = OpTypeVoid
630 %3 = OpTypeFunction %void
631 %int = OpTypeInt 32 1
632 %_ptr_Function_int = OpTypePointer Function %int
633 %int_0 = OpConstant %int 0
634 %int_3 = OpConstant %int 3
635 %bool = OpTypeBool
636 %float = OpTypeFloat 32
637 %v4float = OpTypeVector %float 4
638 %uint = OpTypeInt 32 0
639 %uint_1 = OpConstant %uint 1
640 %_arr_float_uint_1 = OpTypeArray %float %uint_1
641 %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
642 %_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
643 %_ = OpVariable %_ptr_Output_gl_PerVertex Output
644 %gl_PerVertex_0 = OpTypeStruct %v4float %float
645 %uint_3 = OpConstant %uint 3
646 %_arr_gl_PerVertex_0_uint_3 = OpTypeArray %gl_PerVertex_0 %uint_3
647 %_ptr_Input__arr_gl_PerVertex_0_uint_3 = OpTypePointer Input %_arr_gl_PerVertex_0_uint_3
648 %gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_0_uint_3 Input
649 %_ptr_Input_v4float = OpTypePointer Input %v4float
650 %_ptr_Output_v4float = OpTypePointer Output %v4float
651 %int_1 = OpConstant %int 1
652 %_ptr_Input_float = OpTypePointer Input %float
653 %_ptr_Output_float = OpTypePointer Output %float
654 %main = OpFunction %void None %3
655 %5 = OpLabel
656 %i = OpVariable %_ptr_Function_int Function
657 OpStore %i %int_0
658 OpBranch %10
659 %10 = OpLabel
660 OpLoopMerge %12 %13 None
661 OpBranch %14
662 %14 = OpLabel
663 %15 = OpLoad %int %i
664 %18 = OpSLessThan %bool %15 %int_3
665 OpBranchConditional %18 %11 %12
666 %11 = OpLabel
667 %32 = OpLoad %int %i
668 %34 = OpAccessChain %_ptr_Input_v4float %gl_in %32 %int_0
669 %35 = OpLoad %v4float %34
670 %37 = OpAccessChain %_ptr_Output_v4float %_ %int_0
671 OpStore %37 %35
672 %39 = OpLoad %int %i
673 %41 = OpAccessChain %_ptr_Input_float %gl_in %39 %int_1
674 %42 = OpLoad %float %41
675 %44 = OpAccessChain %_ptr_Output_float %_ %int_1
676 OpStore %44 %42
677 OpEmitVertex
678 OpBranch %13
679 %13 = OpLabel
680 %45 = OpLoad %int %i
681 %46 = OpIAdd %int %45 %int_1
682 OpStore %i %46
683 OpBranch %10
684 %12 = OpLabel
685 OpEndPrimitive
686 OpReturn
687 OpFunctionEnd
688 )";
689
690 SetTargetEnv(SPV_ENV_VULKAN_1_3);
691 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
692
693 std::unordered_set<uint32_t> live_inputs;
694 std::unordered_set<uint32_t> live_builtins;
695 auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
696 text, true, &live_inputs, &live_builtins);
697
698 auto itr0 = live_builtins.find((uint32_t)spv::BuiltIn::PointSize);
699 auto itr1 = live_builtins.find((uint32_t)spv::BuiltIn::ClipDistance);
700 auto itr2 = live_builtins.find((uint32_t)spv::BuiltIn::CullDistance);
701
702 // Expect live_builtins == { spv::BuiltIn::PointSize }
703 EXPECT_TRUE(itr0 != live_builtins.end());
704 EXPECT_TRUE(itr1 == live_builtins.end());
705 EXPECT_TRUE(itr2 == live_builtins.end());
706 }
707
TEST_F(AnalyzeLiveInputTest,ArrayedInputPatchLocs)708 TEST_F(AnalyzeLiveInputTest, ArrayedInputPatchLocs) {
709 // Tests handling of locs with arrayed input patch seen in Tese
710 //
711 // Should report location {3}.
712 //
713 // #version 450 core
714 //
715 // layout(triangles, ccw) in;
716 //
717 // layout(fractional_odd_spacing) in;
718 //
719 // layout(point_mode) in;
720 //
721 // layout(location=2) patch in float patchIn1[2];
722 //
723 // void main()
724 // {
725 // vec4 p = gl_in[1].gl_Position;
726 // gl_Position = p * patchIn1[1];
727 // }
728 const std::string text = R"(
729 OpCapability Tessellation
730 %1 = OpExtInstImport "GLSL.std.450"
731 OpMemoryModel Logical GLSL450
732 OpEntryPoint TessellationEvaluation %main "main" %gl_in %_ %patchIn1
733 OpExecutionMode %main Triangles
734 OpExecutionMode %main SpacingFractionalOdd
735 OpExecutionMode %main VertexOrderCcw
736 OpExecutionMode %main PointMode
737 OpSource GLSL 450
738 OpName %main "main"
739 OpName %p "p"
740 OpName %gl_PerVertex "gl_PerVertex"
741 OpMemberName %gl_PerVertex 0 "gl_Position"
742 OpName %gl_in "gl_in"
743 OpName %gl_PerVertex_0 "gl_PerVertex"
744 OpMemberName %gl_PerVertex_0 0 "gl_Position"
745 OpName %_ ""
746 OpName %patchIn1 "patchIn1"
747 OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
748 OpDecorate %gl_PerVertex Block
749 OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
750 OpDecorate %gl_PerVertex_0 Block
751 OpDecorate %patchIn1 Patch
752 OpDecorate %patchIn1 Location 2
753 %void = OpTypeVoid
754 %3 = OpTypeFunction %void
755 %float = OpTypeFloat 32
756 %v4float = OpTypeVector %float 4
757 %_ptr_Function_v4float = OpTypePointer Function %v4float
758 %uint = OpTypeInt 32 0
759 %uint_1 = OpConstant %uint 1
760 %_arr_float_uint_1 = OpTypeArray %float %uint_1
761 %gl_PerVertex = OpTypeStruct %v4float
762 %uint_32 = OpConstant %uint 32
763 %_arr_gl_PerVertex_uint_32 = OpTypeArray %gl_PerVertex %uint_32
764 %_ptr_Input__arr_gl_PerVertex_uint_32 = OpTypePointer Input %_arr_gl_PerVertex_uint_32
765 %gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_uint_32 Input
766 %int = OpTypeInt 32 1
767 %int_1 = OpConstant %int 1
768 %int_0 = OpConstant %int 0
769 %_ptr_Input_v4float = OpTypePointer Input %v4float
770 %gl_PerVertex_0 = OpTypeStruct %v4float
771 %_ptr_Output_gl_PerVertex_0 = OpTypePointer Output %gl_PerVertex_0
772 %_ = OpVariable %_ptr_Output_gl_PerVertex_0 Output
773 %uint_2 = OpConstant %uint 2
774 %_arr_float_uint_2 = OpTypeArray %float %uint_2
775 %_ptr_Input__arr_float_uint_2 = OpTypePointer Input %_arr_float_uint_2
776 %patchIn1 = OpVariable %_ptr_Input__arr_float_uint_2 Input
777 %_ptr_Input_float = OpTypePointer Input %float
778 %_ptr_Output_v4float = OpTypePointer Output %v4float
779 %main = OpFunction %void None %3
780 %5 = OpLabel
781 %p = OpVariable %_ptr_Function_v4float Function
782 %22 = OpAccessChain %_ptr_Input_v4float %gl_in %int_1 %int_0
783 %23 = OpLoad %v4float %22
784 OpStore %p %23
785 %27 = OpLoad %v4float %p
786 %33 = OpAccessChain %_ptr_Input_float %patchIn1 %int_1
787 %34 = OpLoad %float %33
788 %35 = OpVectorTimesScalar %v4float %27 %34
789 %37 = OpAccessChain %_ptr_Output_v4float %_ %int_0
790 OpStore %37 %35
791 OpReturn
792 OpFunctionEnd
793 )";
794
795 SetTargetEnv(SPV_ENV_VULKAN_1_3);
796 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
797
798 std::unordered_set<uint32_t> live_inputs;
799 std::unordered_set<uint32_t> live_builtins;
800 auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
801 text, true, &live_inputs, &live_builtins);
802
803 auto itr0 = live_inputs.find(0);
804 auto itr1 = live_inputs.find(1);
805 auto itr2 = live_inputs.find(2);
806 auto itr3 = live_inputs.find(3);
807
808 // Expect live_inputs == {3}
809 EXPECT_TRUE(itr0 == live_inputs.end());
810 EXPECT_TRUE(itr1 == live_inputs.end());
811 EXPECT_TRUE(itr2 == live_inputs.end());
812 EXPECT_TRUE(itr3 != live_inputs.end());
813 }
814
TEST_F(AnalyzeLiveInputTest,FragMultipleLocationsF16)815 TEST_F(AnalyzeLiveInputTest, FragMultipleLocationsF16) {
816 // Should report locations {2, 5}
817 //
818 // #version 450
819 //
820 // layout(location = 2) in Vertex
821 // {
822 // f16vec4 color0;
823 // f16vec4 color1;
824 // f16vec4 color2[3];
825 // } iVert;
826 //
827 // layout(location = 0) out f16vec4 oFragColor;
828 //
829 // void main()
830 // {
831 // oFragColor = iVert.color0 + iVert.color2[1];
832 // }
833 const std::string text = R"(
834 OpCapability Shader
835 OpCapability Float16
836 OpCapability StorageInputOutput16
837 %1 = OpExtInstImport "GLSL.std.450"
838 OpMemoryModel Logical GLSL450
839 OpEntryPoint Fragment %main "main" %oFragColor %iVert
840 OpExecutionMode %main OriginUpperLeft
841 OpSource GLSL 450
842 OpName %main "main"
843 OpName %oFragColor "oFragColor"
844 OpName %Vertex "Vertex"
845 OpMemberName %Vertex 0 "color0"
846 OpMemberName %Vertex 1 "color1"
847 OpMemberName %Vertex 2 "color2"
848 OpName %iVert "iVert"
849 OpDecorate %oFragColor Location 0
850 OpDecorate %Vertex Block
851 OpDecorate %iVert Location 2
852 %void = OpTypeVoid
853 %3 = OpTypeFunction %void
854 %half = OpTypeFloat 16
855 %v4half = OpTypeVector %half 4
856 %_ptr_Output_v4half = OpTypePointer Output %v4half
857 %oFragColor = OpVariable %_ptr_Output_v4half Output
858 %uint = OpTypeInt 32 0
859 %uint_3 = OpConstant %uint 3
860 %_arr_v4half_uint_3 = OpTypeArray %v4half %uint_3
861 %Vertex = OpTypeStruct %v4half %v4half %_arr_v4half_uint_3
862 %_ptr_Input_Vertex = OpTypePointer Input %Vertex
863 %iVert = OpVariable %_ptr_Input_Vertex Input
864 %int = OpTypeInt 32 1
865 %int_0 = OpConstant %int 0
866 %_ptr_Input_v4half = OpTypePointer Input %v4half
867 %int_2 = OpConstant %int 2
868 %int_1 = OpConstant %int 1
869 %main = OpFunction %void None %3
870 %5 = OpLabel
871 %19 = OpAccessChain %_ptr_Input_v4half %iVert %int_0
872 %20 = OpLoad %v4half %19
873 %23 = OpAccessChain %_ptr_Input_v4half %iVert %int_2 %int_1
874 %24 = OpLoad %v4half %23
875 %25 = OpFAdd %v4half %20 %24
876 OpStore %oFragColor %25
877 OpReturn
878 OpFunctionEnd
879 )";
880
881 SetTargetEnv(SPV_ENV_VULKAN_1_3);
882 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
883
884 std::unordered_set<uint32_t> live_inputs;
885 std::unordered_set<uint32_t> live_builtins;
886 auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
887 text, true, &live_inputs, &live_builtins);
888
889 auto itr0 = live_inputs.find(0);
890 auto itr1 = live_inputs.find(1);
891 auto itr2 = live_inputs.find(2);
892 auto itr3 = live_inputs.find(3);
893 auto itr4 = live_inputs.find(4);
894 auto itr5 = live_inputs.find(5);
895 auto itr6 = live_inputs.find(6);
896
897 // Expect live_inputs == {2, 5}
898 EXPECT_TRUE(itr0 == live_inputs.end());
899 EXPECT_TRUE(itr1 == live_inputs.end());
900 EXPECT_TRUE(itr2 != live_inputs.end());
901 EXPECT_TRUE(itr3 == live_inputs.end());
902 EXPECT_TRUE(itr4 == live_inputs.end());
903 EXPECT_TRUE(itr5 != live_inputs.end());
904 EXPECT_TRUE(itr6 == live_inputs.end());
905 }
906
907 } // namespace
908 } // namespace opt
909 } // namespace spvtools
910