1 // Copyright (c) 2024 Epic Games, 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 #include <string>
16
17 #include "gmock/gmock.h"
18 #include "source/opt/struct_packing_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 StructPackingTest = PassTest<::testing::Test>;
27
TEST_F(StructPackingTest,PackSimpleStructStd140)28 TEST_F(StructPackingTest, PackSimpleStructStd140) {
29 // #version 420
30 //
31 // layout(std140, binding = 0) uniform Globals {
32 // layout(offset = 16) vec3 a_xyz;
33 // float a_w;
34 // layout(offset = 128) vec3 b_xyz;
35 // int b_w;
36 // };
37 //
38 // void main() {}
39 const std::string spirv = R"(
40 OpCapability Shader
41 %1 = OpExtInstImport "GLSL.std.450"
42 OpMemoryModel Logical GLSL450
43 OpEntryPoint Fragment %main "main"
44 OpExecutionMode %main OriginLowerLeft
45 OpSource GLSL 420
46 OpName %main "main"
47 OpName %Globals "Globals"
48 OpMemberName %Globals 0 "a_xyz"
49 OpMemberName %Globals 1 "a_w"
50 OpMemberName %Globals 2 "b_xyz"
51 OpMemberName %Globals 3 "b_w"
52 OpName %_ ""
53 ; CHECK: OpMemberDecorate %Globals 0 Offset 0
54 OpMemberDecorate %Globals 0 Offset 16
55 ; CHECK: OpMemberDecorate %Globals 1 Offset 12
56 OpMemberDecorate %Globals 1 Offset 28
57 ; CHECK: OpMemberDecorate %Globals 2 Offset 16
58 OpMemberDecorate %Globals 2 Offset 128
59 ; CHECK: OpMemberDecorate %Globals 3 Offset 28
60 OpMemberDecorate %Globals 3 Offset 140
61 OpDecorate %Globals Block
62 OpDecorate %_ DescriptorSet 0
63 OpDecorate %_ Binding 0
64 %void = OpTypeVoid
65 %3 = OpTypeFunction %void
66 %float = OpTypeFloat 32
67 %v3float = OpTypeVector %float 3
68 %int = OpTypeInt 32 1
69 %Globals = OpTypeStruct %v3float %float %v3float %int
70 %_ptr_Uniform_Globals = OpTypePointer Uniform %Globals
71 %_ = OpVariable %_ptr_Uniform_Globals Uniform
72 %main = OpFunction %void None %3
73 %5 = OpLabel
74 OpReturn
75 OpFunctionEnd
76 )";
77
78 SinglePassRunAndMatch<StructPackingPass>(
79 spirv, true, "Globals", StructPackingPass::PackingRules::Std140);
80 }
81
TEST_F(StructPackingTest,PackSimpleStructWithPaddingStd140)82 TEST_F(StructPackingTest, PackSimpleStructWithPaddingStd140) {
83 // #version 420
84 //
85 // layout(std140, binding = 0) uniform Globals {
86 // layout(offset = 16) vec3 a_xyz;
87 // float a_w;
88 // float b_x_padding_yzw;
89 // layout(offset = 128) vec3 c_xyz;
90 // int c_w;
91 // };
92 //
93 // void main() {}
94 const std::string spirv = R"(
95 OpCapability Shader
96 %1 = OpExtInstImport "GLSL.std.450"
97 OpMemoryModel Logical GLSL450
98 OpEntryPoint Fragment %main "main"
99 OpExecutionMode %main OriginLowerLeft
100 OpSource GLSL 420
101 OpName %main "main"
102 OpName %Globals "Globals"
103 OpMemberName %Globals 0 "a_xyz"
104 OpMemberName %Globals 1 "a_w"
105 OpMemberName %Globals 2 "b_x_padding_yzw"
106 OpMemberName %Globals 3 "c_xyz"
107 OpMemberName %Globals 4 "c_w"
108 OpName %_ ""
109 ; CHECK: OpMemberDecorate %Globals 0 Offset 0
110 OpMemberDecorate %Globals 0 Offset 16
111 ; CHECK: OpMemberDecorate %Globals 1 Offset 12
112 OpMemberDecorate %Globals 1 Offset 28
113 ; CHECK: OpMemberDecorate %Globals 2 Offset 16
114 OpMemberDecorate %Globals 2 Offset 32
115 ; CHECK: OpMemberDecorate %Globals 3 Offset 32
116 OpMemberDecorate %Globals 3 Offset 128
117 ; CHECK: OpMemberDecorate %Globals 4 Offset 44
118 OpMemberDecorate %Globals 4 Offset 140
119 OpDecorate %Globals Block
120 OpDecorate %_ DescriptorSet 0
121 OpDecorate %_ Binding 0
122 %void = OpTypeVoid
123 %3 = OpTypeFunction %void
124 %float = OpTypeFloat 32
125 %v3float = OpTypeVector %float 3
126 %int = OpTypeInt 32 1
127 %Globals = OpTypeStruct %v3float %float %float %v3float %int
128 %_ptr_Uniform_Globals = OpTypePointer Uniform %Globals
129 %_ = OpVariable %_ptr_Uniform_Globals Uniform
130 %main = OpFunction %void None %3
131 %5 = OpLabel
132 OpReturn
133 OpFunctionEnd
134 )";
135
136 SinglePassRunAndMatch<StructPackingPass>(
137 spirv, true, "Globals", StructPackingPass::PackingRules::Std140);
138 }
139
TEST_F(StructPackingTest,PackSimpleScalarArrayStd140)140 TEST_F(StructPackingTest, PackSimpleScalarArrayStd140) {
141 // #version 420
142 //
143 // layout(std140, binding = 0) uniform Globals {
144 // layout(offset = 16) float a[2];
145 // layout(offset = 128) float b[2]; // Must become offset 32 with std140
146 // };
147 //
148 // void main() {}
149 const std::string spirv = R"(
150 OpCapability Shader
151 %1 = OpExtInstImport "GLSL.std.450"
152 OpMemoryModel Logical GLSL450
153 OpEntryPoint Fragment %main "main"
154 OpExecutionMode %main OriginLowerLeft
155 OpSource GLSL 420
156 OpName %main "main"
157 OpName %Globals "Globals"
158 OpMemberName %Globals 0 "a"
159 OpMemberName %Globals 1 "b"
160 OpName %_ ""
161 OpDecorate %_arr_float_uint_2 ArrayStride 16
162 OpDecorate %_arr_float_uint_2_0 ArrayStride 16
163 ; CHECK: OpMemberDecorate %Globals 0 Offset 0
164 OpMemberDecorate %Globals 0 Offset 16
165 ; CHECK: OpMemberDecorate %Globals 1 Offset 32
166 OpMemberDecorate %Globals 1 Offset 128
167 OpDecorate %Globals Block
168 OpDecorate %_ DescriptorSet 0
169 OpDecorate %_ Binding 0
170 %void = OpTypeVoid
171 %3 = OpTypeFunction %void
172 %float = OpTypeFloat 32
173 %uint = OpTypeInt 32 0
174 %uint_2 = OpConstant %uint 2
175 %_arr_float_uint_2 = OpTypeArray %float %uint_2
176 %_arr_float_uint_2_0 = OpTypeArray %float %uint_2
177 %Globals = OpTypeStruct %_arr_float_uint_2 %_arr_float_uint_2_0
178 %_ptr_Uniform_Globals = OpTypePointer Uniform %Globals
179 %_ = OpVariable %_ptr_Uniform_Globals Uniform
180 %main = OpFunction %void None %3
181 %5 = OpLabel
182 OpReturn
183 OpFunctionEnd
184 )";
185
186 SinglePassRunAndMatch<StructPackingPass>(
187 spirv, true, "Globals", StructPackingPass::PackingRules::Std140);
188 }
189
TEST_F(StructPackingTest,PackSimpleScalarArrayStd430)190 TEST_F(StructPackingTest, PackSimpleScalarArrayStd430) {
191 // #version 430
192 //
193 // layout(std430, binding = 0) buffer Globals {
194 // layout(offset = 16) float a[2];
195 // layout(offset = 128) float b[2]; // Must become offset 8 with std430
196 // };
197 //
198 // void main() {}
199 const std::string spirv = R"(
200 OpCapability Shader
201 %1 = OpExtInstImport "GLSL.std.450"
202 OpMemoryModel Logical GLSL450
203 OpEntryPoint Fragment %main "main"
204 OpExecutionMode %main OriginLowerLeft
205 OpSource GLSL 430
206 OpName %main "main"
207 OpName %Globals "Globals"
208 OpMemberName %Globals 0 "a"
209 OpMemberName %Globals 1 "b"
210 OpName %_ ""
211 OpDecorate %_arr_float_uint_2 ArrayStride 4
212 OpDecorate %_arr_float_uint_2_0 ArrayStride 4
213 ; CHECK: OpMemberDecorate %Globals 0 Offset 0
214 OpMemberDecorate %Globals 0 Offset 16
215 ; CHECK: OpMemberDecorate %Globals 1 Offset 8
216 OpMemberDecorate %Globals 1 Offset 128
217 OpDecorate %Globals BufferBlock
218 OpDecorate %_ DescriptorSet 0
219 OpDecorate %_ Binding 0
220 %void = OpTypeVoid
221 %3 = OpTypeFunction %void
222 %float = OpTypeFloat 32
223 %uint = OpTypeInt 32 0
224 %uint_2 = OpConstant %uint 2
225 %_arr_float_uint_2 = OpTypeArray %float %uint_2
226 %_arr_float_uint_2_0 = OpTypeArray %float %uint_2
227 %Globals = OpTypeStruct %_arr_float_uint_2 %_arr_float_uint_2_0
228 %_ptr_Uniform_Globals = OpTypePointer Uniform %Globals
229 %_ = OpVariable %_ptr_Uniform_Globals Uniform
230 %main = OpFunction %void None %3
231 %5 = OpLabel
232 OpReturn
233 OpFunctionEnd
234 )";
235
236 SinglePassRunAndMatch<StructPackingPass>(
237 spirv, true, "Globals", StructPackingPass::PackingRules::Std430);
238 }
239
240 } // namespace
241 } // namespace opt
242 } // namespace spvtools
243