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