xref: /aosp_15_r20/external/angle/src/tests/compiler_tests/ShaderVariable_test.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2014 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 // CollectVariables_test.cpp:
7 //   Some tests for shader inspection
8 //
9 
10 #include "GLSLANG/ShaderLang.h"
11 #include "angle_gl.h"
12 #include "compiler/translator/Compiler.h"
13 #include "gtest/gtest.h"
14 
15 namespace sh
16 {
17 
18 class ShaderVariableTest : public testing::Test
19 {
20   public:
ShaderVariableTest()21     ShaderVariableTest() : mVariablesCompileOptions{}, mObjectCodeCompileOptions{}
22     {
23         mObjectCodeCompileOptions.objectCode = true;
24     }
25 
26   protected:
27     ShCompileOptions mVariablesCompileOptions;
28     ShCompileOptions mObjectCodeCompileOptions;
29 };
30 
TEST_F(ShaderVariableTest,FindInfoByMappedName)31 TEST_F(ShaderVariableTest, FindInfoByMappedName)
32 {
33     // struct A {
34     //   float x[2];
35     //   vec3 y;
36     // };
37     // struct B {
38     //   A a[3];
39     // };
40     // B uni[2];
41     ShaderVariable uni(0, 2);
42     uni.name              = "uni";
43     uni.mappedName        = "m_uni";
44     uni.structOrBlockName = "B";
45     {
46         ShaderVariable a(0, 3);
47         a.name              = "a";
48         a.mappedName        = "m_a";
49         a.structOrBlockName = "A";
50         {
51             ShaderVariable x(GL_FLOAT, 2);
52             x.name       = "x";
53             x.mappedName = "m_x";
54             a.fields.push_back(x);
55 
56             ShaderVariable y(GL_FLOAT_VEC3);
57             y.name       = "y";
58             y.mappedName = "m_y";
59             a.fields.push_back(y);
60         }
61         uni.fields.push_back(a);
62     }
63 
64     const ShaderVariable *leafVar = nullptr;
65     std::string originalFullName;
66 
67     std::string mappedFullName = "wrongName";
68     EXPECT_FALSE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
69 
70     mappedFullName = "m_uni";
71     EXPECT_TRUE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
72     EXPECT_EQ(&uni, leafVar);
73     EXPECT_STREQ("uni", originalFullName.c_str());
74 
75     mappedFullName = "m_uni[0].m_a[1].wrongName";
76     EXPECT_FALSE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
77 
78     mappedFullName = "m_uni[0].m_a[1].m_x";
79     EXPECT_TRUE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
80     EXPECT_EQ(&(uni.fields[0].fields[0]), leafVar);
81     EXPECT_STREQ("uni[0].a[1].x", originalFullName.c_str());
82 
83     mappedFullName = "m_uni[0].m_a[1].m_x[0]";
84     EXPECT_TRUE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
85     EXPECT_EQ(&(uni.fields[0].fields[0]), leafVar);
86     EXPECT_STREQ("uni[0].a[1].x[0]", originalFullName.c_str());
87 
88     mappedFullName = "m_uni[0].m_a[1].m_y";
89     EXPECT_TRUE(uni.findInfoByMappedName(mappedFullName, &leafVar, &originalFullName));
90     EXPECT_EQ(&(uni.fields[0].fields[1]), leafVar);
91     EXPECT_STREQ("uni[0].a[1].y", originalFullName.c_str());
92 }
93 
TEST_F(ShaderVariableTest,IsSameUniformWithDifferentFieldOrder)94 TEST_F(ShaderVariableTest, IsSameUniformWithDifferentFieldOrder)
95 {
96     // struct A {
97     //   float x;
98     //   float y;
99     // };
100     // uniform A uni;
101     ShaderVariable vx_a;
102     vx_a.name              = "uni";
103     vx_a.mappedName        = "m_uni";
104     vx_a.structOrBlockName = "A";
105     {
106         ShaderVariable x(GL_FLOAT);
107         x.name       = "x";
108         x.mappedName = "m_x";
109         vx_a.fields.push_back(x);
110 
111         ShaderVariable y(GL_FLOAT);
112         y.name       = "y";
113         y.mappedName = "m_y";
114         vx_a.fields.push_back(y);
115     }
116 
117     // struct A {
118     //   float y;
119     //   float x;
120     // };
121     // uniform A uni;
122     ShaderVariable fx_a;
123     fx_a.name              = "uni";
124     fx_a.mappedName        = "m_uni";
125     fx_a.structOrBlockName = "A";
126     {
127         ShaderVariable y(GL_FLOAT);
128         y.name       = "y";
129         y.mappedName = "m_y";
130         fx_a.fields.push_back(y);
131 
132         ShaderVariable x(GL_FLOAT);
133         x.name       = "x";
134         x.mappedName = "m_x";
135         fx_a.fields.push_back(x);
136     }
137 
138     EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
139 }
140 
TEST_F(ShaderVariableTest,IsSameUniformWithDifferentStructNames)141 TEST_F(ShaderVariableTest, IsSameUniformWithDifferentStructNames)
142 {
143     // struct A {
144     //   float x;
145     //   float y;
146     // };
147     // uniform A uni;
148     ShaderVariable vx_a;
149     vx_a.name              = "uni";
150     vx_a.mappedName        = "m_uni";
151     vx_a.structOrBlockName = "A";
152     {
153         ShaderVariable x(GL_FLOAT);
154         x.name       = "x";
155         x.mappedName = "m_x";
156         vx_a.fields.push_back(x);
157 
158         ShaderVariable y(GL_FLOAT);
159         y.name       = "y";
160         y.mappedName = "m_y";
161         vx_a.fields.push_back(y);
162     }
163 
164     // struct B {
165     //   float x;
166     //   float y;
167     // };
168     // uniform B uni;
169     ShaderVariable fx_a;
170     fx_a.name       = "uni";
171     fx_a.mappedName = "m_uni";
172     {
173         ShaderVariable x(GL_FLOAT);
174         x.name       = "x";
175         x.mappedName = "m_x";
176         fx_a.fields.push_back(x);
177 
178         ShaderVariable y(GL_FLOAT);
179         y.name       = "y";
180         y.mappedName = "m_y";
181         fx_a.fields.push_back(y);
182     }
183 
184     fx_a.structOrBlockName = "B";
185     EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
186 
187     fx_a.structOrBlockName = "A";
188     EXPECT_TRUE(vx_a.isSameUniformAtLinkTime(fx_a));
189 
190     fx_a.structOrBlockName = "";
191     EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
192 }
193 
TEST_F(ShaderVariableTest,IsSameVaryingWithDifferentInvariance)194 TEST_F(ShaderVariableTest, IsSameVaryingWithDifferentInvariance)
195 {
196     // invariant varying float vary;
197     ShaderVariable vx;
198     vx.type        = GL_FLOAT;
199     vx.precision   = GL_MEDIUM_FLOAT;
200     vx.name        = "vary";
201     vx.mappedName  = "m_vary";
202     vx.staticUse   = true;
203     vx.isInvariant = true;
204 
205     // varying float vary;
206     ShaderVariable fx;
207     fx.type        = GL_FLOAT;
208     fx.precision   = GL_MEDIUM_FLOAT;
209     fx.name        = "vary";
210     fx.mappedName  = "m_vary";
211     fx.staticUse   = true;
212     fx.isInvariant = false;
213 
214     // Default to ESSL1 behavior: invariance must match
215     EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx));
216     EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 100));
217     // ESSL3 behavior: invariance doesn't need to match
218     EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 300));
219 
220     // invariant varying float vary;
221     fx.isInvariant = true;
222     EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx));
223     EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 100));
224     EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 300));
225 }
226 
227 // Test that using invariant varyings doesn't trigger a double delete.
TEST_F(ShaderVariableTest,InvariantDoubleDeleteBug)228 TEST_F(ShaderVariableTest, InvariantDoubleDeleteBug)
229 {
230     ShBuiltInResources resources;
231     sh::InitBuiltInResources(&resources);
232 
233     ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
234                                               SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
235     EXPECT_NE(static_cast<ShHandle>(0), compiler);
236 
237     const char *program[] = {
238         "attribute vec4 position;\n"
239         "varying float v;\n"
240         "invariant v;\n"
241         "void main() {\n"
242         "  v = 1.0;\n"
243         "  gl_Position = position;\n"
244         "}"};
245 
246     EXPECT_TRUE(sh::Compile(compiler, program, 1, mObjectCodeCompileOptions));
247     EXPECT_TRUE(sh::Compile(compiler, program, 1, mObjectCodeCompileOptions));
248     sh::Destruct(compiler);
249 }
250 
TEST_F(ShaderVariableTest,IllegalInvariantVarying)251 TEST_F(ShaderVariableTest, IllegalInvariantVarying)
252 {
253     ShBuiltInResources resources;
254     sh::InitBuiltInResources(&resources);
255 
256     ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
257                                               SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
258     EXPECT_NE(static_cast<ShHandle>(0), compiler);
259 
260     const char *program1[] = {
261         R"(void foo()
262         {
263         }
264         varying vec4 v_varying;
265         invariant v_varying;
266         void main()
267         {
268            foo();
269            gl_Position = v_varying;
270         })"};
271     const char *program2[] = {
272         "varying vec4 v_varying;\n"
273         "void foo() {\n"
274         "  invariant v_varying;\n"
275         "}\n"
276         "void main() {\n"
277         "  foo();\n"
278         "  gl_Position = v_varying;\n"
279         "}"};
280 
281     EXPECT_TRUE(sh::Compile(compiler, program1, 1, mVariablesCompileOptions));
282     EXPECT_FALSE(sh::Compile(compiler, program2, 1, mVariablesCompileOptions));
283     sh::Destruct(compiler);
284 }
285 
TEST_F(ShaderVariableTest,InvariantLeakAcrossShaders)286 TEST_F(ShaderVariableTest, InvariantLeakAcrossShaders)
287 {
288     ShBuiltInResources resources;
289     sh::InitBuiltInResources(&resources);
290 
291     ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
292                                               SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
293     EXPECT_NE(static_cast<ShHandle>(0), compiler);
294 
295     const char *program1[] = {
296         "varying vec4 v_varying;\n"
297         "invariant v_varying;\n"
298         "void main() {\n"
299         "  gl_Position = v_varying;\n"
300         "}"};
301     const char *program2[] = {
302         "varying vec4 v_varying;\n"
303         "void main() {\n"
304         "  gl_Position = v_varying;\n"
305         "}"};
306 
307     EXPECT_TRUE(sh::Compile(compiler, program1, 1, mVariablesCompileOptions));
308     const std::vector<sh::ShaderVariable> *varyings = sh::GetOutputVaryings(compiler);
309     for (const sh::ShaderVariable &varying : *varyings)
310     {
311         if (varying.name == "v_varying")
312         {
313             EXPECT_TRUE(varying.isInvariant);
314         }
315     }
316     EXPECT_TRUE(sh::Compile(compiler, program2, 1, mVariablesCompileOptions));
317     varyings = sh::GetOutputVaryings(compiler);
318     for (const sh::ShaderVariable &varying : *varyings)
319     {
320         if (varying.name == "v_varying")
321         {
322             EXPECT_FALSE(varying.isInvariant);
323         }
324     }
325     sh::Destruct(compiler);
326 }
327 
TEST_F(ShaderVariableTest,GlobalInvariantLeakAcrossShaders)328 TEST_F(ShaderVariableTest, GlobalInvariantLeakAcrossShaders)
329 {
330     ShBuiltInResources resources;
331     sh::InitBuiltInResources(&resources);
332 
333     ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
334                                               SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
335     EXPECT_NE(static_cast<ShHandle>(0), compiler);
336 
337     const char *program1[] = {
338         "#pragma STDGL invariant(all)\n"
339         "varying vec4 v_varying;\n"
340         "void main() {\n"
341         "  gl_Position = v_varying;\n"
342         "}"};
343     const char *program2[] = {
344         "varying vec4 v_varying;\n"
345         "void main() {\n"
346         "  gl_Position = v_varying;\n"
347         "}"};
348 
349     EXPECT_TRUE(sh::Compile(compiler, program1, 1, mVariablesCompileOptions));
350     const std::vector<sh::ShaderVariable> *varyings = sh::GetOutputVaryings(compiler);
351     for (const sh::ShaderVariable &varying : *varyings)
352     {
353         if (varying.name == "v_varying")
354         {
355             EXPECT_TRUE(varying.isInvariant);
356         }
357     }
358     EXPECT_TRUE(sh::Compile(compiler, program2, 1, mVariablesCompileOptions));
359     varyings = sh::GetOutputVaryings(compiler);
360     for (const sh::ShaderVariable &varying : *varyings)
361     {
362         if (varying.name == "v_varying")
363         {
364             EXPECT_FALSE(varying.isInvariant);
365         }
366     }
367     sh::Destruct(compiler);
368 }
369 
TEST_F(ShaderVariableTest,BuiltinInvariantVarying)370 TEST_F(ShaderVariableTest, BuiltinInvariantVarying)
371 {
372     ShBuiltInResources resources;
373     sh::InitBuiltInResources(&resources);
374 
375     ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
376                                               SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
377     EXPECT_NE(static_cast<ShHandle>(0), compiler);
378 
379     const char *program1[] = {
380         "invariant gl_Position;\n"
381         "void main() {\n"
382         "  gl_Position = vec4(0, 0, 0, 0);\n"
383         "}"};
384     const char *program2[] = {
385         "void main() {\n"
386         "  gl_Position = vec4(0, 0, 0, 0);\n"
387         "}"};
388     const char *program3[] = {
389         "void main() {\n"
390         "  invariant gl_Position;\n"
391         "  gl_Position = vec4(0, 0, 0, 0);\n"
392         "}"};
393 
394     EXPECT_TRUE(sh::Compile(compiler, program1, 1, mVariablesCompileOptions));
395     const std::vector<sh::ShaderVariable> *varyings = sh::GetOutputVaryings(compiler);
396     for (const sh::ShaderVariable &varying : *varyings)
397     {
398         if (varying.name == "gl_Position")
399         {
400             EXPECT_TRUE(varying.isInvariant);
401         }
402     }
403     EXPECT_TRUE(sh::Compile(compiler, program2, 1, mVariablesCompileOptions));
404     varyings = sh::GetOutputVaryings(compiler);
405     for (const sh::ShaderVariable &varying : *varyings)
406     {
407         if (varying.name == "gl_Position")
408         {
409             EXPECT_FALSE(varying.isInvariant);
410         }
411     }
412     EXPECT_FALSE(sh::Compile(compiler, program3, 1, mVariablesCompileOptions));
413     sh::Destruct(compiler);
414 }
415 
416 // Verify in ES3.1 two varyings with either same name or same declared location can match.
TEST_F(ShaderVariableTest,IsSameVaryingWithDifferentName)417 TEST_F(ShaderVariableTest, IsSameVaryingWithDifferentName)
418 {
419     // Varying float vary1;
420     ShaderVariable vx;
421     vx.type        = GL_FLOAT;
422     vx.precision   = GL_MEDIUM_FLOAT;
423     vx.name        = "vary1";
424     vx.mappedName  = "m_vary1";
425     vx.staticUse   = true;
426     vx.isInvariant = false;
427 
428     // Varying float vary2;
429     ShaderVariable fx;
430     fx.type        = GL_FLOAT;
431     fx.precision   = GL_MEDIUM_FLOAT;
432     fx.name        = "vary2";
433     fx.mappedName  = "m_vary2";
434     fx.staticUse   = true;
435     fx.isInvariant = false;
436 
437     // ESSL3 behavior: name must match
438     EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 300));
439 
440     // ESSL3.1 behavior:
441     // [OpenGL ES 3.1 SPEC Chapter 7.4.1]
442     // An output variable is considered to match an input variable in the subsequent shader if:
443     // - the two variables match in name, type, and qualification; or
444     // - the two variables are declared with the same location qualifier and match in type and
445     //   qualification.
446     vx.location = 0;
447     fx.location = 0;
448     EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 310));
449 
450     fx.name       = vx.name;
451     fx.mappedName = vx.mappedName;
452 
453     fx.location = -1;
454     EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 310));
455 
456     fx.location = 1;
457     EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 310));
458 
459     fx.location = 0;
460     EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 310));
461 }
462 
463 // Test that using two consecutive underscores (__) can be used for declaring an identifier
TEST_F(ShaderVariableTest,DoubleUnderscoresForIdentifier)464 TEST_F(ShaderVariableTest, DoubleUnderscoresForIdentifier)
465 {
466     ShBuiltInResources resources;
467     sh::InitBuiltInResources(&resources);
468 
469     ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES3_SPEC,
470                                               SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
471     EXPECT_NE(static_cast<ShHandle>(0), compiler);
472 
473     const char *front_underscores[] = {
474         "#version 300 es\n"
475         "in vec4 __position;\n"
476         "out float v;\n"
477         "void main() {\n"
478         "  v = 1.0;\n"
479         "  gl_Position = __position;\n"
480         "}"};
481     EXPECT_TRUE(sh::Compile(compiler, front_underscores, 1, mObjectCodeCompileOptions));
482 
483     const char *middle_underscores[] = {
484         "#version 300 es\n"
485         "in vec4 position__in;\n"
486         "out float v;\n"
487         "void main() {\n"
488         "  v = 1.0;\n"
489         "  gl_Position = position__in;\n"
490         "}"};
491     EXPECT_TRUE(sh::Compile(compiler, middle_underscores, 1, mObjectCodeCompileOptions));
492 
493     const char *end_underscores[] = {
494         "#version 300 es\n"
495         "in vec4 position__;\n"
496         "out float v;\n"
497         "void main() {\n"
498         "  v = 1.0;\n"
499         "  gl_Position = position__;\n"
500         "}"};
501     EXPECT_TRUE(sh::Compile(compiler, end_underscores, 1, mObjectCodeCompileOptions));
502 
503     sh::Destruct(compiler);
504 }
505 
506 }  // namespace sh
507