1 //
2 // Copyright 2024 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // SeparateDeclarations.cpp:
7 // Tests that compound declarations are rewritten to type declarations and variable declarations.
8 //
9
10 #include "GLSLANG/ShaderLang.h"
11 #include "angle_gl.h"
12 #include "gtest/gtest.h"
13 #include "tests/test_utils/compiler_test.h"
14
15 using namespace sh;
16
17 namespace
18 {
19
20 class SeparateDeclarations : public MatchOutputCodeTest
21 {
22 public:
SeparateDeclarations()23 SeparateDeclarations() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_ESSL_OUTPUT)
24 {
25 ShCompileOptions defaultCompileOptions = {};
26 defaultCompileOptions.validateAST = true;
27 setDefaultCompileOptions(defaultCompileOptions);
28 }
29 };
30
31 class SeparateCompoundStructDeclarations : public MatchOutputCodeTest
32 {
33 public:
SeparateCompoundStructDeclarations()34 SeparateCompoundStructDeclarations() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_ESSL_OUTPUT)
35 {
36 ShCompileOptions defaultCompileOptions = {};
37 defaultCompileOptions.validateAST = true;
38 defaultCompileOptions.separateCompoundStructDeclarations = true;
39 setDefaultCompileOptions(defaultCompileOptions);
40 }
41 };
42
43 class SeparateStructFunctionDeclarations : public MatchOutputCodeTest
44 {
45 public:
SeparateStructFunctionDeclarations()46 SeparateStructFunctionDeclarations() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_ESSL_OUTPUT)
47 {
48 ShCompileOptions defaultCompileOptions = {};
49 defaultCompileOptions.validateAST = true;
50 setDefaultCompileOptions(defaultCompileOptions);
51 }
52 };
53
TEST_F(SeparateDeclarations,Arrays)54 TEST_F(SeparateDeclarations, Arrays)
55 {
56 const char kShader[] = R"(#version 300 es
57 precision highp float;
58 int a[1] = int[1](1), b[1] = int[1](2);
59 out vec4 o;
60 void main() {
61 if (a[0] == b[0])
62 o = vec4(1);
63 })";
64 const char kExpected[] = R"(#version 300 es
65 const mediump int sbbd = 1;
66 mediump int _ua[1] = int[1](sbbd);
67 const mediump int sbbe = 2;
68 mediump int _ub[1] = int[1](sbbe);
69 out highp vec4 _uo;
70 void main(){
71 if ((_ua[0] == _ub[0]))
72 {
73 (_uo = vec4(1.0, 1.0, 1.0, 1.0));
74 }
75 }
76 )";
77 compile(kShader);
78 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
79 }
80
TEST_F(SeparateDeclarations,StructNoChange)81 TEST_F(SeparateDeclarations, StructNoChange)
82 {
83 const char kShader[] = R"(#version 300 es
84 precision highp float;
85 struct S { vec3 d; } a;
86 out vec4 o;
87 void main() {
88 if (a.d == vec3(2))
89 o = vec4(1);
90 })";
91 const char kExpected[] = R"(#version 300 es
92 struct _uS {
93 highp vec3 _ud;
94 } _ua;
95 out highp vec4 _uo;
96 void main(){
97 if ((_ua._ud == vec3(2.0, 2.0, 2.0)))
98 {
99 (_uo = vec4(1.0, 1.0, 1.0, 1.0));
100 }
101 }
102 )";
103 compile(kShader);
104 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
105 }
106
TEST_F(SeparateDeclarations,Structs)107 TEST_F(SeparateDeclarations, Structs)
108 {
109 const char kShader[] = R"(#version 300 es
110 precision highp float;
111 struct S { vec3 d; } a, b;
112 out vec4 o;
113 void main() {
114 if (a.d == b.d)
115 o = vec4(1);
116 })";
117 const char kExpected[] = R"(#version 300 es
118 struct _uS {
119 highp vec3 _ud;
120 } _ua;
121 _uS _ub;
122 out highp vec4 _uo;
123 void main(){
124 if ((_ua._ud == _ub._ud))
125 {
126 (_uo = vec4(1.0, 1.0, 1.0, 1.0));
127 }
128 }
129 )";
130 compile(kShader);
131 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
132 }
133
TEST_F(SeparateDeclarations,AnonymousStructNoChange)134 TEST_F(SeparateDeclarations, AnonymousStructNoChange)
135 {
136 const char kShader[] = R"(#version 300 es
137 precision highp float;
138 struct { vec3 d; } a;
139 out vec4 o;
140 void main() {
141 if (any(lessThan(a.d, vec3(2))))
142 o = vec4(1);
143 })";
144 const char kExpected[] = R"(#version 300 es
145 struct {
146 highp vec3 _ud;
147 } _ua;
148 out highp vec4 _uo;
149 void main(){
150 if (any(lessThan(_ua._ud, vec3(2.0, 2.0, 2.0))))
151 {
152 (_uo = vec4(1.0, 1.0, 1.0, 1.0));
153 }
154 }
155 )";
156 compile(kShader);
157 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
158 }
159
TEST_F(SeparateDeclarations,AnonymousStructs)160 TEST_F(SeparateDeclarations, AnonymousStructs)
161 {
162 const char kShader[] = R"(#version 300 es
163 precision highp float;
164 struct { vec3 d; } a, b;
165 out vec4 o;
166 void main() {
167 if (any(lessThan(a.d, b.d)))
168 o = vec4(1);
169 })";
170 const char kExpected[] = R"(#version 300 es
171 struct sbbe {
172 highp vec3 _ud;
173 } _ua;
174 sbbe _ub;
175 out highp vec4 _uo;
176 void main(){
177 if (any(lessThan(_ua._ud, _ub._ud)))
178 {
179 (_uo = vec4(1.0, 1.0, 1.0, 1.0));
180 }
181 }
182 )";
183 compile(kShader);
184 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
185 }
186
TEST_F(SeparateCompoundStructDeclarations,AnonymousStruct)187 TEST_F(SeparateCompoundStructDeclarations, AnonymousStruct)
188 {
189 const char kShader[] = R"(#version 300 es
190 precision highp float;
191 struct { vec3 d; } a;
192 out vec4 o;
193 void main() {
194 if (any(lessThan(a.d, vec3(2))))
195 o = vec4(1);
196 })";
197 const char kExpected[] = R"(#version 300 es
198 struct sbbd {
199 highp vec3 _ud;
200 };
201 sbbd _ua;
202 out highp vec4 _uo;
203 void main(){
204 if (any(lessThan(_ua._ud, vec3(2.0, 2.0, 2.0))))
205 {
206 (_uo = vec4(1.0, 1.0, 1.0, 1.0));
207 }
208 }
209 )";
210 compile(kShader);
211 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
212 }
213
TEST_F(SeparateCompoundStructDeclarations,AnonymousStructs)214 TEST_F(SeparateCompoundStructDeclarations, AnonymousStructs)
215 {
216 const char kShader[] = R"(#version 300 es
217 precision highp float;
218 struct { vec3 d; } a, b;
219 out vec4 o;
220 void main() {
221 if (any(lessThan(a.d, b.d)))
222 o = vec4(1);
223 })";
224 const char kExpected[] = R"(#version 300 es
225 struct sbbe {
226 highp vec3 _ud;
227 };
228 sbbe _ua;
229 sbbe _ub;
230 out highp vec4 _uo;
231 void main(){
232 if (any(lessThan(_ua._ud, _ub._ud)))
233 {
234 (_uo = vec4(1.0, 1.0, 1.0, 1.0));
235 }
236 }
237 )";
238 compile(kShader);
239 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
240 }
241
TEST_F(SeparateCompoundStructDeclarations,Struct)242 TEST_F(SeparateCompoundStructDeclarations, Struct)
243 {
244 const char kShader[] = R"(#version 300 es
245 precision highp float;
246 struct S { vec3 d; } a, b;
247 out vec4 o;
248 void main() {
249 if (a.d == b.d)
250 o = vec4(1);
251 })";
252 const char kExpected[] = R"(#version 300 es
253 struct _uS {
254 highp vec3 _ud;
255 };
256 _uS _ua;
257 _uS _ub;
258 out highp vec4 _uo;
259 void main(){
260 if ((_ua._ud == _ub._ud))
261 {
262 (_uo = vec4(1.0, 1.0, 1.0, 1.0));
263 }
264 }
265 )";
266 compile(kShader);
267 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
268 }
269
TEST_F(SeparateCompoundStructDeclarations,ConstStruct)270 TEST_F(SeparateCompoundStructDeclarations, ConstStruct)
271 {
272 const char kShader[] = R"(#version 300 es
273 precision highp float;
274 out vec4 o;
275 void main()
276 {
277 const struct s2 {
278 int i;
279 } s22 = s2(8);
280 const struct s1 {
281 s2 ss;
282 mat4 m;
283 } s11 = s1(s22, mat4(5));
284 if (s11.ss.i > int(o.x))
285 o = vec4(1);
286 })";
287 const char kExpected[] = R"(#version 300 es
288 out highp vec4 _uo;
289 void main(){
290 const mediump int sbc3 = 8;
291 if ((sbc3 > int(_uo.x)))
292 {
293 (_uo = vec4(1.0, 1.0, 1.0, 1.0));
294 }
295 }
296 )";
297 compile(kShader);
298 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
299 }
300
301 // Example of what the const struct does before evaluating constants.
TEST_F(SeparateCompoundStructDeclarations,ConstStructsCrossRef)302 TEST_F(SeparateCompoundStructDeclarations, ConstStructsCrossRef)
303 {
304 const char kShader[] = R"(#version 300 es
305 precision highp float;
306 out vec4 o;
307 void main()
308 {
309 struct s2 {
310 int i;
311 } s22 = s2(8);
312 struct s1 {
313 s2 ss;
314 mat4 m;
315 } s11 = s1(s22, mat4(5));
316 if (s11.ss.i > int(o.x))
317 o = vec4(1);
318 })";
319 const char kExpected[] = R"(#version 300 es
320 out highp vec4 _uo;
321 void main(){
322 struct _us2 {
323 mediump int _ui;
324 };
325 _us2 _us22 = _us2(8);
326 struct _us1 {
327 _us2 _uss;
328 highp mat4 _um;
329 };
330 _us1 _us11 = _us1(_us22, mat4(5.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 5.0));
331 if ((_us11._uss._ui > int(_uo.x)))
332 {
333 (_uo = vec4(1.0, 1.0, 1.0, 1.0));
334 }
335 }
336 )";
337 compile(kShader);
338 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
339 }
340
341 // Test that struct name validation takes into account that intenal symbol namespace
342 // is different to user namespace. The test should be kept in sync so that struct sbbf is the same
343 // textual symbol as what the anonymous struct gets.
TEST_F(SeparateCompoundStructDeclarations,InternalSymbolNoCrash)344 TEST_F(SeparateCompoundStructDeclarations, InternalSymbolNoCrash)
345 {
346 const char kShader[] = R"(
347 precision highp float;
348 struct { vec4 e; } g;
349 struct sbbf { vec4 f; };
350 void main(){
351 sbbf s;
352 gl_FragColor = g.e + s.f;
353 })";
354 compile(kShader);
355 const char kExpected[] = R"(struct sbbf {
356 highp vec4 _ue;
357 };
358 sbbf _ug;
359 struct _usbbf {
360 highp vec4 _uf;
361 };
362 void main(){
363 _usbbf _us;
364 (gl_FragColor = (_ug._ue + _us._uf));
365 }
366 )";
367 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
368 }
369
TEST_F(SeparateStructFunctionDeclarations,StructInStruct)370 TEST_F(SeparateStructFunctionDeclarations, StructInStruct)
371 {
372 const char kShader[] = R"(#version 300 es
373 struct S {
374 int f;
375 };
376 struct S2 { S h; } o()
377 {
378 return S2(S(1));
379 }
380 void main() {
381 S2 s2 = o();
382 })";
383 const char kExpected[] = R"(#version 300 es
384 struct _uS {
385 mediump int _uf;
386 };
387 struct _uS2 {
388 _uS _uh;
389 };
390 _uS2 _uo(){
391 return _uS2(_uS(1));
392 }
393 void main(){
394 _uS2 _us2 = _uo();
395 }
396 )";
397 compile(kShader);
398 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
399 }
400
TEST_F(SeparateStructFunctionDeclarations,StructInAnonymousStruct)401 TEST_F(SeparateStructFunctionDeclarations, StructInAnonymousStruct)
402 {
403 const char kShader[] = R"(#version 300 es
404 struct S {
405 int f;
406 };
407 struct { S h; } o();
408 void main() {
409 })";
410 const char kExpected[] = R"(#version 300 es
411 void main(){
412 }
413 )";
414 compile(kShader);
415 EXPECT_EQ(kExpected, outputCode(SH_ESSL_OUTPUT));
416 }
417
418 } // namespace
419