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