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