xref: /aosp_15_r20/external/angle/src/tests/compiler_tests/WGSLOutput_test.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 // WGSLOutput_test.cpp:
7 //   Tests for corect WGSL translations.
8 //
9 
10 #include <regex>
11 
12 #include "GLSLANG/ShaderLang.h"
13 #include "angle_gl.h"
14 #include "gtest/gtest.h"
15 #include "tests/test_utils/compiler_test.h"
16 
17 using namespace sh;
18 
19 class WGSLVertexOutputTest : public MatchOutputCodeTest
20 {
21   public:
WGSLVertexOutputTest()22     WGSLVertexOutputTest() : MatchOutputCodeTest(GL_VERTEX_SHADER, SH_WGSL_OUTPUT)
23     {
24         ShCompileOptions defaultCompileOptions = {};
25         defaultCompileOptions.validateAST      = true;
26         setDefaultCompileOptions(defaultCompileOptions);
27     }
28 };
29 
30 class WGSLOutputTest : public MatchOutputCodeTest
31 {
32   public:
WGSLOutputTest()33     WGSLOutputTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_WGSL_OUTPUT)
34     {
35         ShCompileOptions defaultCompileOptions = {};
36         defaultCompileOptions.validateAST      = true;
37         setDefaultCompileOptions(defaultCompileOptions);
38     }
39 };
40 
TEST_F(WGSLOutputTest,BasicTranslation)41 TEST_F(WGSLOutputTest, BasicTranslation)
42 {
43     const std::string &shaderString =
44         R"(#version 310 es
45         precision highp float;
46 
47         out vec4 outColor;
48 
49         struct Foo {
50             float x;
51             float y;
52             vec3 multiArray[2][3];
53             mat3 aMatrix;
54         };
55 
56         vec4 doFoo(Foo foo, float zw);
57 
58         vec4 doFoo(Foo foo, float zw)
59         {
60             // foo.x = foo.y;
61             return vec4(foo.x, foo.y, zw, zw);
62         }
63 
64         Foo returnFoo(Foo foo) {
65           return foo;
66         }
67 
68         float returnFloat(float x) {
69           return x;
70         }
71 
72         float takeArgs(vec2 x, float y) {
73           return y;
74         }
75 
76         void main()
77         {
78             Foo foo;
79             // Struct field accesses.
80             foo.x = 2.0;
81             foo.y = 2.0;
82             // Complicated constUnion should be emitted correctly.
83             foo.multiArray = vec3[][](
84               vec3[](
85                 vec3(1.0, 2.0, 3.0),
86                 vec3(1.0, 2.0, 3.0),
87                 vec3(1.0, 2.0, 3.0)),
88               vec3[](
89                 vec3(4.0, 5.0, 6.0),
90                 vec3(4.0, 5.0, 6.0),
91                 vec3(4.0, 5.0, 6.0)
92               )
93             );
94             int arrIndex = 1;
95             // Access an array index with a constant index.
96             float f = foo.multiArray[0][1].x;
97             // Access an array index with a non-const index, should clamp by default.
98             float f2 = foo.multiArray[0][arrIndex].x;
99             gl_FragDepth = f + f2;
100             doFoo(returnFoo(foo), returnFloat(3.0));
101             takeArgs(vec2(1.0, 2.0), foo.x);
102             returnFloat(doFoo(foo, 7.0 + 9.0).x);
103             outColor = vec4(0.0, 0.0, 0.0, 0.0);
104         })";
105     const std::string &outputString =
106         R"(struct ANGLE_Output_Global {
107   outColor : vec4<f32>,
108   gl_FragDepth_ : f32,
109 };
110 
111 var<private> ANGLE_output_global : ANGLE_Output_Global;
112 
113 struct ANGLE_Output_Annotated {
114   @location(@@@@@@) outColor : vec4<f32>,
115   @builtin(frag_depth) gl_FragDepth_ : f32,
116 };
117 
118 ;
119 
120 struct _uFoo
121 {
122   _ux : f32,
123   _uy : f32,
124   _umultiArray : array<array<vec3<f32>, 3>, 2>,
125   _uaMatrix : mat3x3<f32>,
126 };
127 
128 fn _udoFoo(_ufoo : _uFoo, _uzw : f32) -> vec4<f32>;
129 
130 fn _udoFoo(_ufoo : _uFoo, _uzw : f32) -> vec4<f32>
131 {
132   return vec4<f32>((_ufoo)._ux, (_ufoo)._uy, _uzw, _uzw);
133 }
134 
135 fn _ureturnFoo(_ufoo : _uFoo) -> _uFoo
136 {
137   return _ufoo;
138 }
139 
140 fn _ureturnFloat(_ux : f32) -> f32
141 {
142   return _ux;
143 }
144 
145 fn _utakeArgs(_ux : vec2<f32>, _uy : f32) -> f32
146 {
147   return _uy;
148 }
149 
150 fn _umain()
151 {
152   var _ufoo : _uFoo;
153   ((_ufoo)._ux) = (2.0f);
154   ((_ufoo)._uy) = (2.0f);
155   ((_ufoo)._umultiArray) = (array<array<vec3<f32>, 3>, 2>(array<vec3<f32>, 3>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(1.0f, 2.0f, 3.0f)), array<vec3<f32>, 3>(vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(4.0f, 5.0f, 6.0f))));
156   var _uarrIndex : i32 = (1i);
157   var _uf : f32 = (((((_ufoo)._umultiArray)[0i])[1i]).x);
158   var _uf2 : f32 = (((((_ufoo)._umultiArray)[0i])[clamp((_uarrIndex), 0, 2)]).x);
159   (ANGLE_output_global.gl_FragDepth_) = ((_uf) + (_uf2));
160   _udoFoo(_ureturnFoo(_ufoo), _ureturnFloat(3.0f));
161   _utakeArgs(vec2<f32>(1.0f, 2.0f), (_ufoo)._ux);
162   _ureturnFloat((_udoFoo(_ufoo, 16.0f)).x);
163   (ANGLE_output_global.outColor) = (vec4<f32>(0.0f, 0.0f, 0.0f, 0.0f));
164 }
165 @fragment
166 fn wgslMain() -> ANGLE_Output_Annotated
167 {
168   _umain();
169   var ANGLE_output_annotated : ANGLE_Output_Annotated;
170   ANGLE_output_annotated.outColor = ANGLE_output_global.outColor;
171   ANGLE_output_annotated.gl_FragDepth_ = ANGLE_output_global.gl_FragDepth_;
172   return ANGLE_output_annotated;
173 }
174 )";
175     compile(shaderString);
176     EXPECT_TRUE(foundInCode(outputString.c_str()));
177 }
178 
TEST_F(WGSLOutputTest,ControlFlow)179 TEST_F(WGSLOutputTest, ControlFlow)
180 {
181     const std::string &shaderString =
182         R"(#version 300 es
183         precision highp float;
184 
185         int ifElseDemo() {
186           int x = 5;
187           if (x == 5) {
188             return 6;
189           } else if (x == 6) {
190             return 7;
191           } else {
192             return 8;
193           }
194         }
195 
196         void switchDemo() {
197           int x = 5;
198           switch (x) {
199           case 5:
200           case 6:
201             discard;
202           case 7: {
203             return;
204           }
205           case 8:
206           case 9:
207             {
208               x = 7;
209             }
210             return;
211           default:
212             return;
213           }
214         }
215 
216         void forLoopDemo() {
217           for (int i = 0; i < 5; i++) {
218             if (i == 4) {
219               break;
220             } else if (i == 5) {
221               continue;
222             }
223           }
224         }
225 
226         void whileLoopDemo() {
227           int i = 0;
228           while (i < 5) {
229             i++;
230           }
231 
232           do {
233             i++;
234           } while (i < 5);
235         }
236 
237         void main()
238         {
239           ifElseDemo();
240           switchDemo();
241           forLoopDemo();
242           whileLoopDemo();
243         })";
244     const std::string &outputString =
245         R"(fn _uifElseDemo() -> i32
246 {
247   var _ux : i32 = (5i);
248   if ((_ux) == (5i))
249   {
250     return 6i;
251   }
252   else
253   {
254     if ((_ux) == (6i))
255     {
256       return 7i;
257     }
258     else
259     {
260       return 8i;
261     }
262   }
263 }
264 
265 fn _uswitchDemo()
266 {
267   var _ux : i32 = (5i);
268   switch _ux
269   {
270     case 5i, 6i:
271     {
272       discard;
273     }
274     case 7i:
275     {
276       {
277         return;
278       }
279     }
280     case 8i, 9i:
281     {
282       {
283         (_ux) = (7i);
284       }
285       return;
286     }
287     case default:
288     {
289       return;
290     }
291   }
292 }
293 
294 fn _uforLoopDemo()
295 {
296   for (var _ui : i32 = (0i); (_ui) < (5i); (_ui)++)
297   {
298     if ((_ui) == (4i))
299     {
300       break;
301     }
302     else
303     {
304       if ((_ui) == (5i))
305       {
306         continue;
307       }
308     }
309   }
310 }
311 
312 fn _uwhileLoopDemo()
313 {
314   var _ui : i32 = (0i);
315   while ((_ui) < (5i))
316   {
317     (_ui)++;
318   }
319   loop {
320     {
321       (_ui)++;
322     }
323     if (!((_ui) < (5i)) { break; }
324   }
325 }
326 
327 fn _umain()
328 {
329   _uifElseDemo();
330   _uswitchDemo();
331   _uforLoopDemo();
332   _uwhileLoopDemo();
333 }
334 @fragment
335 fn wgslMain()
336 {
337   _umain();
338 }
339 )";
340     compile(shaderString);
341     EXPECT_TRUE(foundInCode(outputString.c_str()));
342 }
343 
TEST_F(WGSLOutputTest,GLFragColorWithUniform)344 TEST_F(WGSLOutputTest, GLFragColorWithUniform)
345 {
346     const std::string &shaderString =
347         R"(
348 uniform mediump vec4 u_color;
349 void main(void)
350 {
351     gl_FragColor = u_color;
352 })";
353     const std::string &outputString =
354         R"(struct ANGLE_Output_Global {
355   gl_FragColor_ : vec4<f32>,
356 };
357 
358 var<private> ANGLE_output_global : ANGLE_Output_Global;
359 
360 struct ANGLE_Output_Annotated {
361   @location(0) gl_FragColor_ : vec4<f32>,
362 };
363 
364 struct ANGLE_DefaultUniformBlock {
365   u_color : vec4<f32>,
366 };
367 
368 @group(0) @binding(1) var<uniform> ANGLE_defaultUniformBlock : ANGLE_DefaultUniformBlock;
369 ;
370 
371 fn _umain()
372 {
373   (ANGLE_output_global.gl_FragColor_) = (ANGLE_defaultUniformBlock.u_color);
374 }
375 @fragment
376 fn wgslMain() -> ANGLE_Output_Annotated
377 {
378   _umain();
379   var ANGLE_output_annotated : ANGLE_Output_Annotated;
380   ANGLE_output_annotated.gl_FragColor_ = ANGLE_output_global.gl_FragColor_;
381   return ANGLE_output_annotated;
382 }
383 )";
384     compile(shaderString);
385     EXPECT_TRUE(foundInCode(outputString.c_str()));
386 }
387 
TEST_F(WGSLOutputTest,UniformsWithNestedStructs)388 TEST_F(WGSLOutputTest, UniformsWithNestedStructs)
389 {
390     const std::string &shaderString =
391         R"(precision mediump float;
392 struct NestedUniforms {
393     float x;
394 };
395 struct Uniforms {
396     NestedUniforms a;
397     float b;
398     float c;
399     float[5] d;
400     float e;
401 };
402 uniform Uniforms unis;
403 void main() {
404     gl_FragColor = vec4(unis.a.x, unis.b, unis.c, 1.0);
405 })";
406     const std::string &outputString =
407         R"(Output_Global {
408   gl_FragColor_ : vec4<f32>,
409 };
410 
411 var<private> ANGLE_output_global : ANGLE_Output_Global;
412 
413 struct ANGLE_Output_Annotated {
414   @location(0) gl_FragColor_ : vec4<f32>,
415 };
416 
417 struct ANGLE_DefaultUniformBlock {
418   unis : _uUniforms,
419 };
420 
421 @group(0) @binding(1) var<uniform> ANGLE_defaultUniformBlock : ANGLE_DefaultUniformBlock;
422 struct _uNestedUniforms
423 {
424   @align(16) _ux : f32,
425 };
426 
427 struct _uUniforms
428 {
429   @align(16) _ua : _uNestedUniforms,
430   @align(16) _ub : f32,
431   _uc : f32,
432   @align(16) _ud : array<f32, 5>,
433   _ue : f32,
434 };
435 
436 ;
437 
438 fn _umain()
439 {
440   (ANGLE_output_global.gl_FragColor_) = (vec4<f32>(((ANGLE_defaultUniformBlock.unis)._ua)._ux, (ANGLE_defaultUniformBlock.unis)._ub, (ANGLE_defaultUniformBlock.unis)._uc, 1.0f));
441 }
442 @fragment
443 fn wgslMain() -> ANGLE_Output_Annotated
444 {
445   _umain();
446   var ANGLE_output_annotated : ANGLE_Output_Annotated;
447   ANGLE_output_annotated.gl_FragColor_ = ANGLE_output_global.gl_FragColor_;
448   return ANGLE_output_annotated;
449 })";
450     compile(shaderString);
451     EXPECT_TRUE(foundInCode(outputString.c_str()));
452 }
453