• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 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 
7 // BindUniformLocationTest.cpp : Tests of the GL_CHROMIUM_bind_uniform_location extension.
8 
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11 
12 #include <cmath>
13 
14 using namespace angle;
15 
16 namespace
17 {
18 
19 class BindUniformLocationTest : public ANGLETest
20 {
21   protected:
BindUniformLocationTest()22     BindUniformLocationTest()
23     {
24         setWindowWidth(128);
25         setWindowHeight(128);
26         setConfigRedBits(8);
27         setConfigGreenBits(8);
28         setConfigBlueBits(8);
29         setConfigAlphaBits(8);
30     }
31 
testTearDown()32     void testTearDown() override
33     {
34         if (mProgram != 0)
35         {
36             glDeleteProgram(mProgram);
37         }
38     }
39 
40     GLuint mProgram = 0;
41 };
42 
43 // Test basic functionality of GL_CHROMIUM_bind_uniform_location
TEST_P(BindUniformLocationTest,Basic)44 TEST_P(BindUniformLocationTest, Basic)
45 {
46     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
47 
48     constexpr char kFS[] = R"(precision mediump float;
49 uniform vec4 u_colorC;
50 uniform vec4 u_colorB[2];
51 uniform vec4 u_colorA;
52 void main()
53 {
54     gl_FragColor = u_colorA + u_colorB[0] + u_colorB[1] + u_colorC;
55 })";
56 
57     GLint colorALocation = 3;
58     GLint colorBLocation = 10;
59     GLint colorCLocation = 5;
60 
61     mProgram = CompileProgram(essl1_shaders::vs::Simple(), kFS, [&](GLuint program) {
62         glBindUniformLocationCHROMIUM(program, colorALocation, "u_colorA");
63         glBindUniformLocationCHROMIUM(program, colorBLocation, "u_colorB[0]");
64         glBindUniformLocationCHROMIUM(program, colorCLocation, "u_colorC");
65     });
66     ASSERT_NE(0u, mProgram);
67 
68     glUseProgram(mProgram);
69 
70     static const float colorB[] = {
71         0.0f, 0.50f, 0.0f, 0.0f, 0.0f, 0.0f, 0.75f, 0.0f,
72     };
73 
74     glUniform4f(colorALocation, 0.25f, 0.0f, 0.0f, 0.0f);
75     glUniform4fv(colorBLocation, 2, colorB);
76     glUniform4f(colorCLocation, 0.0f, 0.0f, 0.0f, 1.0f);
77 
78     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
79 
80     EXPECT_GL_NO_ERROR();
81     EXPECT_PIXEL_NEAR(0, 0, 64, 128, 192, 255, 1.0);
82 }
83 
84 // Force a sampler location and make sure it samples the correct texture
TEST_P(BindUniformLocationTest,SamplerLocation)85 TEST_P(BindUniformLocationTest, SamplerLocation)
86 {
87     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
88 
89     constexpr char kFS[] = R"(precision mediump float;
90 uniform vec4 u_colorA;
91 uniform vec4 u_colorB[2];
92 uniform sampler2D u_sampler;
93 void main()
94 {
95     gl_FragColor = u_colorA + u_colorB[0] + u_colorB[1] + texture2D(u_sampler, vec2(0, 0));
96 })";
97 
98     GLint colorALocation  = 3;
99     GLint colorBLocation  = 10;
100     GLint samplerLocation = 1;
101 
102     mProgram = CompileProgram(essl1_shaders::vs::Simple(), kFS, [&](GLuint program) {
103         glBindUniformLocationCHROMIUM(program, colorALocation, "u_colorA");
104         glBindUniformLocationCHROMIUM(program, colorBLocation, "u_colorB[0]");
105         glBindUniformLocationCHROMIUM(program, samplerLocation, "u_sampler");
106     });
107     ASSERT_NE(0u, mProgram);
108 
109     glUseProgram(mProgram);
110 
111     static const float colorB[] = {
112         0.0f, 0.50f, 0.0f, 0.0f, 0.0f, 0.0f, 0.75f, 0.0f,
113     };
114 
115     glUniform4f(colorALocation, 0.25f, 0.0f, 0.0f, 0.0f);
116     glUniform4fv(colorBLocation, 2, colorB);
117 
118     // Point the texture at texture unit 2
119     glUniform1i(samplerLocation, 2);
120 
121     GLTexture texture;
122     glActiveTexture(GL_TEXTURE2);
123     glBindTexture(GL_TEXTURE_2D, texture);
124     constexpr GLubyte kTextureData[] = {32, 32, 32, 255};
125     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, kTextureData);
126 
127     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
128 
129     EXPECT_GL_NO_ERROR();
130     EXPECT_PIXEL_NEAR(0, 0, 96, 160, 224, 255, 1.0);
131 }
132 
133 // Test that conflicts are detected when two uniforms are bound to the same location
TEST_P(BindUniformLocationTest,ConflictsDetection)134 TEST_P(BindUniformLocationTest, ConflictsDetection)
135 {
136     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
137 
138     constexpr char kFS[] =
139         R"(precision mediump float;
140         uniform vec4 u_colorA;
141         uniform vec4 u_colorB;
142         void main()
143         {
144             gl_FragColor = u_colorA + u_colorB;
145         })";
146 
147     GLint colorALocation = 3;
148     GLint colorBLocation = 4;
149 
150     GLuint vs = CompileShader(GL_VERTEX_SHADER, essl1_shaders::vs::Simple());
151     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
152 
153     mProgram = glCreateProgram();
154     glAttachShader(mProgram, vs);
155     glDeleteShader(vs);
156     glAttachShader(mProgram, fs);
157     glDeleteShader(fs);
158 
159     glBindUniformLocationCHROMIUM(mProgram, colorALocation, "u_colorA");
160     // Bind u_colorB to location a, causing conflicts, link should fail.
161     glBindUniformLocationCHROMIUM(mProgram, colorALocation, "u_colorB");
162     glLinkProgram(mProgram);
163     GLint linked = 0;
164     glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
165     ASSERT_EQ(0, linked);
166 
167     // Bind u_colorB to location b, no conflicts, link should succeed.
168     glBindUniformLocationCHROMIUM(mProgram, colorBLocation, "u_colorB");
169     glLinkProgram(mProgram);
170     linked = 0;
171     glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
172     EXPECT_EQ(1, linked);
173 }
174 
175 // Test a use case of the chromium compositor
TEST_P(BindUniformLocationTest,Compositor)176 TEST_P(BindUniformLocationTest, Compositor)
177 {
178     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
179 
180     constexpr char kVS[] =
181         R"(attribute vec4 a_position;
182         attribute vec2 a_texCoord;
183         uniform mat4 matrix;
184         uniform vec2 color_a[4];
185         uniform vec4 color_b;
186         varying vec4 v_color;
187         void main()
188         {
189             v_color.xy = color_a[0] + color_a[1];
190             v_color.zw = color_a[2] + color_a[3];
191             v_color += color_b;
192             gl_Position = matrix * a_position;
193         })";
194 
195     constexpr char kFS[] =
196         R"(precision mediump float;
197         varying vec4 v_color;
198         uniform float alpha;
199         uniform vec4 multiplier;
200         uniform vec3 color_c[8];
201         void main()
202         {
203             vec4 color_c_sum = vec4(0.0);
204             color_c_sum.xyz += color_c[0];
205             color_c_sum.xyz += color_c[1];
206             color_c_sum.xyz += color_c[2];
207             color_c_sum.xyz += color_c[3];
208             color_c_sum.xyz += color_c[4];
209             color_c_sum.xyz += color_c[5];
210             color_c_sum.xyz += color_c[6];
211             color_c_sum.xyz += color_c[7];
212             color_c_sum.w = alpha;
213             color_c_sum *= multiplier;
214             gl_FragColor = v_color + color_c_sum;
215         })";
216 
217     int counter            = 6;
218     int matrixLocation     = counter++;
219     int colorALocation     = counter++;
220     int colorBLocation     = counter++;
221     int alphaLocation      = counter++;
222     int multiplierLocation = counter++;
223     int colorCLocation     = counter++;
224 
225     mProgram = CompileProgram(kVS, kFS, [&](GLuint program) {
226         glBindUniformLocationCHROMIUM(program, matrixLocation, "matrix");
227         glBindUniformLocationCHROMIUM(program, colorALocation, "color_a");
228         glBindUniformLocationCHROMIUM(program, colorBLocation, "color_b");
229         glBindUniformLocationCHROMIUM(program, alphaLocation, "alpha");
230         glBindUniformLocationCHROMIUM(program, multiplierLocation, "multiplier");
231         glBindUniformLocationCHROMIUM(program, colorCLocation, "color_c");
232     });
233     ASSERT_NE(0u, mProgram);
234 
235     glUseProgram(mProgram);
236 
237     static const float colorA[] = {
238         0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f,
239     };
240 
241     static const float colorC[] = {
242         0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f,
243         0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f,
244     };
245 
246     static const float identity[] = {
247         1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
248     };
249 
250     glUniformMatrix4fv(matrixLocation, 1, false, identity);
251     glUniform2fv(colorALocation, 4, colorA);
252     glUniform4f(colorBLocation, 0.2f, 0.2f, 0.2f, 0.2f);
253     glUniform1f(alphaLocation, 0.8f);
254     glUniform4f(multiplierLocation, 0.5f, 0.5f, 0.5f, 0.5f);
255     glUniform3fv(colorCLocation, 8, colorC);
256 
257     glDrawArrays(GL_TRIANGLES, 0, 6);
258 
259     drawQuad(mProgram, "a_position", 0.5f);
260 
261     EXPECT_PIXEL_EQ(0, 0, 204, 204, 204, 204);
262 }
263 
264 // Test that unused uniforms don't conflict when bound to the same location
TEST_P(BindUniformLocationTest,UnusedUniformUpdate)265 TEST_P(BindUniformLocationTest, UnusedUniformUpdate)
266 {
267     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
268 
269     ASSERT_NE(nullptr, glBindUniformLocationCHROMIUM);
270 
271     constexpr char kFS[] = R"(precision mediump float;
272 uniform vec4 u_colorA;
273 uniform float u_colorU;
274 uniform vec4 u_colorC;
275 void main()
276 {
277     gl_FragColor = u_colorA + u_colorC;
278 })";
279 
280     const GLint colorULocation      = 1;
281     const GLint nonexistingLocation = 5;
282     const GLint unboundLocation     = 6;
283 
284     mProgram = CompileProgram(essl1_shaders::vs::Simple(), kFS, [&](GLuint program) {
285         glBindUniformLocationCHROMIUM(program, colorULocation, "u_colorU");
286         // The non-existing uniform should behave like existing, but optimized away
287         // uniform.
288         glBindUniformLocationCHROMIUM(program, nonexistingLocation, "nonexisting");
289         // Let A and C be assigned automatic locations.
290     });
291     ASSERT_NE(0u, mProgram);
292 
293     glUseProgram(mProgram);
294 
295     // No errors on bound locations, since caller does not know
296     // if the driver optimizes them away or not.
297     glUniform1f(colorULocation, 0.25f);
298     EXPECT_GL_NO_ERROR();
299 
300     // No errors on bound locations of names that do not exist
301     // in the shader. Otherwise it would be inconsistent wrt the
302     // optimization case.
303     glUniform1f(nonexistingLocation, 0.25f);
304     EXPECT_GL_NO_ERROR();
305 
306     // The above are equal to updating -1.
307     glUniform1f(-1, 0.25f);
308     EXPECT_GL_NO_ERROR();
309 
310     // No errors when updating with other type either.
311     // The type can not be known with the non-existing case.
312     glUniform2f(colorULocation, 0.25f, 0.25f);
313     EXPECT_GL_NO_ERROR();
314     glUniform2f(nonexistingLocation, 0.25f, 0.25f);
315     EXPECT_GL_NO_ERROR();
316     glUniform2f(-1, 0.25f, 0.25f);
317     EXPECT_GL_NO_ERROR();
318 
319     // Ensure that driver or ANGLE has optimized the variable
320     // away and the test tests what it is supposed to.
321     EXPECT_EQ(-1, glGetUniformLocation(mProgram, "u_colorU"));
322 
323     // The bound location gets marked as used and the driver
324     // does not allocate other variables to that location.
325     EXPECT_NE(colorULocation, glGetUniformLocation(mProgram, "u_colorA"));
326     EXPECT_NE(colorULocation, glGetUniformLocation(mProgram, "u_colorC"));
327     EXPECT_NE(nonexistingLocation, glGetUniformLocation(mProgram, "u_colorA"));
328     EXPECT_NE(nonexistingLocation, glGetUniformLocation(mProgram, "u_colorC"));
329 
330     // Unintuitive: while specifying value works, getting the value does not.
331     GLfloat getResult = 0.0f;
332     glGetUniformfv(mProgram, colorULocation, &getResult);
333     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
334     glGetUniformfv(mProgram, nonexistingLocation, &getResult);
335     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
336     glGetUniformfv(mProgram, -1, &getResult);
337     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
338 
339     // Updating an unbound, non-existing location still causes
340     // an error.
341     glUniform1f(unboundLocation, 0.25f);
342     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
343 }
344 
345 // GL backend optimizes away a uniform in the vertex shader if it's only used to
346 // compute a varying that is never referenced in the fragment shader.
TEST_P(BindUniformLocationTest,UnusedUniformUpdateComplex)347 TEST_P(BindUniformLocationTest, UnusedUniformUpdateComplex)
348 {
349     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
350 
351     ASSERT_NE(nullptr, glBindUniformLocationCHROMIUM);
352 
353     constexpr char kVS[] = R"(precision highp float;
354 attribute vec4 a_position;
355 varying vec4 v_unused;
356 uniform vec4 u_unused;
357 void main()
358 {
359     gl_Position = a_position;
360     v_unused = u_unused;
361 }
362 )";
363 
364     constexpr char kFS[] = R"(precision mediump float;
365 varying vec4 v_unused;
366 void main()
367 {
368     gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
369 })";
370 
371     const GLint unusedLocation = 1;
372 
373     mProgram = CompileProgram(kVS, kFS, [&](GLuint program) {
374         glBindUniformLocationCHROMIUM(program, unusedLocation, "u_unused");
375     });
376     ASSERT_NE(0u, mProgram);
377 
378     glUseProgram(mProgram);
379 
380     // No errors on bound locations of names that do not exist
381     // in the shader. Otherwise it would be inconsistent wrt the
382     // optimization case.
383     glUniform4f(unusedLocation, 0.25f, 0.25f, 0.25f, 0.25f);
384     EXPECT_GL_NO_ERROR();
385 }
386 
387 // Test for a bug where using a sampler caused GL error if the mProgram had
388 // uniforms that were optimized away by the driver. This was only a problem with
389 // glBindUniformLocationCHROMIUM implementation. This could be reproed by
390 // binding the sampler to a location higher than the amount of active uniforms.
TEST_P(BindUniformLocationTest,UseSamplerWhenUnusedUniforms)391 TEST_P(BindUniformLocationTest, UseSamplerWhenUnusedUniforms)
392 {
393     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
394 
395     constexpr char kFS[] =
396         R"(uniform sampler2D tex;
397         void main()
398         {
399             gl_FragColor = texture2D(tex, vec2(1));
400         })";
401 
402     const GLuint texLocation = 54;
403 
404     mProgram = CompileProgram(essl1_shaders::vs::Simple(), kFS, [&](GLuint program) {
405         glBindUniformLocationCHROMIUM(program, texLocation, "tex");
406     });
407     ASSERT_NE(0u, mProgram);
408 
409     glUseProgram(mProgram);
410     glUniform1i(texLocation, 0);
411     EXPECT_GL_NO_ERROR();
412 }
413 
414 // Test for binding a statically used uniform to the same location as a non-statically used uniform.
415 // This is valid according to the extension spec.
TEST_P(BindUniformLocationTest,SameLocationForUsedAndUnusedUniform)416 TEST_P(BindUniformLocationTest, SameLocationForUsedAndUnusedUniform)
417 {
418     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
419 
420     constexpr char kFS[] =
421         R"(precision mediump float;
422         uniform vec4 a;
423         uniform vec4 b;
424         void main()
425         {
426             gl_FragColor = a;
427         })";
428 
429     const GLuint location = 54;
430 
431     mProgram = CompileProgram(essl1_shaders::vs::Zero(), kFS, [&](GLuint program) {
432         glBindUniformLocationCHROMIUM(program, location, "a");
433         glBindUniformLocationCHROMIUM(program, location, "b");
434     });
435     ASSERT_NE(0u, mProgram);
436 
437     glUseProgram(mProgram);
438     glUniform4f(location, 0.0, 1.0, 0.0, 1.0);
439     EXPECT_GL_NO_ERROR();
440 }
441 
442 class BindUniformLocationES31Test : public BindUniformLocationTest
443 {
444   protected:
BindUniformLocationES31Test()445     BindUniformLocationES31Test() : BindUniformLocationTest() {}
446 
linkProgramWithUniformLocation(const char * vs,const char * fs,const char * uniformName,GLint uniformLocation)447     void linkProgramWithUniformLocation(const char *vs,
448                                         const char *fs,
449                                         const char *uniformName,
450                                         GLint uniformLocation)
451     {
452         mProgram = CompileProgram(vs, fs, [&](GLuint program) {
453             glBindUniformLocationCHROMIUM(program, uniformLocation, uniformName);
454         });
455     }
456 };
457 
458 // Test for when the shader specifies an explicit uniform location with a layout qualifier and the
459 // bindUniformLocation API sets a consistent location.
TEST_P(BindUniformLocationES31Test,ConsistentWithLocationLayoutQualifier)460 TEST_P(BindUniformLocationES31Test, ConsistentWithLocationLayoutQualifier)
461 {
462     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
463 
464     constexpr char kFS[] =
465         "#version 310 es\n"
466         "uniform layout(location=2) highp sampler2D tex;\n"
467         "out highp vec4 my_FragColor;\n"
468         "void main()\n"
469         "{\n"
470         "    my_FragColor = texture(tex, vec2(1));\n"
471         "}\n";
472 
473     const GLuint texLocation = 2;
474 
475     linkProgramWithUniformLocation(essl31_shaders::vs::Zero(), kFS, "tex", texLocation);
476 
477     GLint linked = GL_FALSE;
478     glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
479     ASSERT_GL_TRUE(linked);
480 
481     EXPECT_EQ(static_cast<GLint>(texLocation), glGetUniformLocation(mProgram, "tex"));
482     glUseProgram(mProgram);
483     glUniform1i(texLocation, 0);
484     EXPECT_GL_NO_ERROR();
485 }
486 
487 // Test for when the shader specifies an explicit uniform location with a layout qualifier and the
488 // bindUniformLocation API sets a conflicting location for the same variable. The shader-set
489 // location should prevail.
TEST_P(BindUniformLocationES31Test,LocationLayoutQualifierOverridesAPIBinding)490 TEST_P(BindUniformLocationES31Test, LocationLayoutQualifierOverridesAPIBinding)
491 {
492     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
493 
494     constexpr char kFS[] =
495         "#version 310 es\n"
496         "uniform layout(location=2) highp sampler2D tex;\n"
497         "out highp vec4 my_FragColor;\n"
498         "void main()\n"
499         "{\n"
500         "    my_FragColor = texture(tex, vec2(1));\n"
501         "}\n";
502 
503     const GLuint shaderTexLocation = 2;
504     const GLuint texLocation       = 3;
505 
506     linkProgramWithUniformLocation(essl31_shaders::vs::Zero(), kFS, "tex", texLocation);
507 
508     GLint linked = GL_FALSE;
509     glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
510     ASSERT_GL_TRUE(linked);
511 
512     EXPECT_EQ(static_cast<GLint>(shaderTexLocation), glGetUniformLocation(mProgram, "tex"));
513     glUseProgram(mProgram);
514     glUniform1i(shaderTexLocation, 1);
515     EXPECT_GL_NO_ERROR();
516     glUniform1i(texLocation, 2);
517     EXPECT_GL_NO_ERROR();
518 }
519 
520 // Test for when the shader specifies an explicit uniform location with a layout qualifier and the
521 // bindUniformLocation API sets a conflicting location for a different variable. Linking should
522 // fail.
TEST_P(BindUniformLocationES31Test,LocationLayoutQualifierConflictsWithAPIBinding)523 TEST_P(BindUniformLocationES31Test, LocationLayoutQualifierConflictsWithAPIBinding)
524 {
525     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
526 
527     constexpr char kFS[] =
528         "#version 310 es\n"
529         "uniform layout(location=2) highp sampler2D tex;\n"
530         "uniform highp sampler2D tex2;\n"
531         "out highp vec4 my_FragColor;\n"
532         "void main()\n"
533         "{\n"
534         "    my_FragColor = texture(tex2, vec2(1));\n"
535         "}\n";
536 
537     const GLuint tex2Location = 2;
538 
539     linkProgramWithUniformLocation(essl31_shaders::vs::Zero(), kFS, "tex2", tex2Location);
540 
541     GLint linked = GL_FALSE;
542     glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
543     ASSERT_GL_FALSE(linked);
544 }
545 
546 // Test for binding a location for an array of arrays uniform.
TEST_P(BindUniformLocationES31Test,ArrayOfArrays)547 TEST_P(BindUniformLocationES31Test, ArrayOfArrays)
548 {
549     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
550 
551     constexpr char kFS[] =
552         R"(#version 310 es
553         precision highp float;
554         uniform vec4 sourceColor[2][1];
555         out highp vec4 my_FragColor;
556         void main()
557         {
558             my_FragColor = sourceColor[1][0];
559         })";
560 
561     const GLuint location = 8;
562 
563     linkProgramWithUniformLocation(essl31_shaders::vs::Simple(), kFS, "sourceColor[1]", location);
564 
565     GLint linked = GL_FALSE;
566     glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
567     ASSERT_GL_TRUE(linked);
568 
569     glUseProgram(mProgram);
570     glUniform4f(location, 0.0f, 1.0f, 0.0f, 1.0f);
571 
572     drawQuad(mProgram, essl31_shaders::PositionAttrib(), 0.5f);
573     EXPECT_GL_NO_ERROR();
574 
575     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
576 }
577 
578 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
579 // tests should be run against.
580 ANGLE_INSTANTIATE_TEST_ES2(BindUniformLocationTest);
581 
582 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BindUniformLocationES31Test);
583 ANGLE_INSTANTIATE_TEST_ES31(BindUniformLocationES31Test);
584 
585 }  // namespace
586