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 #include "test_utils/ANGLETest.h"
8 
9 #include <array>
10 #include <cmath>
11 
12 using namespace angle;
13 
14 namespace
15 {
16 
17 class UniformTest : public ANGLETest
18 {
19   protected:
UniformTest()20     UniformTest() : mProgram(0), mUniformFLocation(-1), mUniformILocation(-1), mUniformBLocation(-1)
21     {
22         setWindowWidth(128);
23         setWindowHeight(128);
24         setConfigRedBits(8);
25         setConfigGreenBits(8);
26         setConfigBlueBits(8);
27         setConfigAlphaBits(8);
28     }
29 
SetUp()30     void SetUp() override
31     {
32         ANGLETest::SetUp();
33 
34         const std::string &vertexShader = "void main() { gl_Position = vec4(1); }";
35         const std::string &fragShader =
36             "precision mediump float;\n"
37             "uniform float uniF;\n"
38             "uniform int uniI;\n"
39             "uniform bool uniB;\n"
40             "uniform bool uniBArr[4];\n"
41             "void main() {\n"
42             "  gl_FragColor = vec4(uniF + float(uniI));\n"
43             "  gl_FragColor += vec4(uniB ? 1.0 : 0.0);\n"
44             "  gl_FragColor += vec4(uniBArr[0] ? 1.0 : 0.0);\n"
45             "}";
46 
47         mProgram = CompileProgram(vertexShader, fragShader);
48         ASSERT_NE(mProgram, 0u);
49 
50         mUniformFLocation = glGetUniformLocation(mProgram, "uniF");
51         ASSERT_NE(mUniformFLocation, -1);
52 
53         mUniformILocation = glGetUniformLocation(mProgram, "uniI");
54         ASSERT_NE(mUniformILocation, -1);
55 
56         mUniformBLocation = glGetUniformLocation(mProgram, "uniB");
57         ASSERT_NE(mUniformBLocation, -1);
58 
59         ASSERT_GL_NO_ERROR();
60     }
61 
TearDown()62     void TearDown() override
63     {
64         glDeleteProgram(mProgram);
65         ANGLETest::TearDown();
66     }
67 
68     GLuint mProgram;
69     GLint mUniformFLocation;
70     GLint mUniformILocation;
71     GLint mUniformBLocation;
72 };
73 
TEST_P(UniformTest,GetUniformNoCurrentProgram)74 TEST_P(UniformTest, GetUniformNoCurrentProgram)
75 {
76     glUseProgram(mProgram);
77     glUniform1f(mUniformFLocation, 1.0f);
78     glUniform1i(mUniformILocation, 1);
79     glUseProgram(0);
80 
81     GLfloat f;
82     glGetnUniformfvEXT(mProgram, mUniformFLocation, 4, &f);
83     ASSERT_GL_NO_ERROR();
84     EXPECT_EQ(1.0f, f);
85 
86     glGetUniformfv(mProgram, mUniformFLocation, &f);
87     ASSERT_GL_NO_ERROR();
88     EXPECT_EQ(1.0f, f);
89 
90     GLint i;
91     glGetnUniformivEXT(mProgram, mUniformILocation, 4, &i);
92     ASSERT_GL_NO_ERROR();
93     EXPECT_EQ(1, i);
94 
95     glGetUniformiv(mProgram, mUniformILocation, &i);
96     ASSERT_GL_NO_ERROR();
97     EXPECT_EQ(1, i);
98 }
99 
TEST_P(UniformTest,UniformArrayLocations)100 TEST_P(UniformTest, UniformArrayLocations)
101 {
102     // TODO(geofflang): Figure out why this is broken on Intel OpenGL
103     if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
104     {
105         std::cout << "Test skipped on Intel OpenGL." << std::endl;
106         return;
107     }
108 
109     const std::string vertexShader = SHADER_SOURCE
110     (
111         precision mediump float;
112         uniform float uPosition[4];
113         void main(void)
114         {
115             gl_Position = vec4(uPosition[0], uPosition[1], uPosition[2], uPosition[3]);
116         }
117     );
118 
119     const std::string fragShader = SHADER_SOURCE
120     (
121         precision mediump float;
122         uniform float uColor[4];
123         void main(void)
124         {
125             gl_FragColor = vec4(uColor[0], uColor[1], uColor[2], uColor[3]);
126         }
127     );
128 
129     GLuint program = CompileProgram(vertexShader, fragShader);
130     ASSERT_NE(program, 0u);
131 
132     // Array index zero should be equivalent to the un-indexed uniform
133     EXPECT_NE(-1, glGetUniformLocation(program, "uPosition"));
134     EXPECT_EQ(glGetUniformLocation(program, "uPosition"), glGetUniformLocation(program, "uPosition[0]"));
135 
136     EXPECT_NE(-1, glGetUniformLocation(program, "uColor"));
137     EXPECT_EQ(glGetUniformLocation(program, "uColor"), glGetUniformLocation(program, "uColor[0]"));
138 
139     // All array uniform locations should be unique
140     GLint positionLocations[4] =
141     {
142         glGetUniformLocation(program, "uPosition[0]"),
143         glGetUniformLocation(program, "uPosition[1]"),
144         glGetUniformLocation(program, "uPosition[2]"),
145         glGetUniformLocation(program, "uPosition[3]"),
146     };
147 
148     GLint colorLocations[4] =
149     {
150         glGetUniformLocation(program, "uColor[0]"),
151         glGetUniformLocation(program, "uColor[1]"),
152         glGetUniformLocation(program, "uColor[2]"),
153         glGetUniformLocation(program, "uColor[3]"),
154     };
155 
156     for (size_t i = 0; i < 4; i++)
157     {
158         EXPECT_NE(-1, positionLocations[i]);
159         EXPECT_NE(-1, colorLocations[i]);
160 
161         for (size_t j = i + 1; j < 4; j++)
162         {
163             EXPECT_NE(positionLocations[i], positionLocations[j]);
164             EXPECT_NE(colorLocations[i], colorLocations[j]);
165         }
166     }
167 
168     glDeleteProgram(program);
169 }
170 
171 // Test that float to integer GetUniform rounds values correctly.
TEST_P(UniformTest,FloatUniformStateQuery)172 TEST_P(UniformTest, FloatUniformStateQuery)
173 {
174     std::vector<double> inValues;
175     std::vector<GLfloat> expectedFValues;
176     std::vector<GLint> expectedIValues;
177 
178     double intMaxD = static_cast<double>(std::numeric_limits<GLint>::max());
179     double intMinD = static_cast<double>(std::numeric_limits<GLint>::min());
180 
181     // TODO(jmadill): Investigate rounding of .5
182     inValues.push_back(-1.0);
183     inValues.push_back(-0.6);
184     // inValues.push_back(-0.5); // undefined behaviour?
185     inValues.push_back(-0.4);
186     inValues.push_back(0.0);
187     inValues.push_back(0.4);
188     // inValues.push_back(0.5); // undefined behaviour?
189     inValues.push_back(0.6);
190     inValues.push_back(1.0);
191     inValues.push_back(999999.2);
192     inValues.push_back(intMaxD * 2.0);
193     inValues.push_back(intMaxD + 1.0);
194     inValues.push_back(intMinD * 2.0);
195     inValues.push_back(intMinD - 1.0);
196 
197     for (double value : inValues)
198     {
199         expectedFValues.push_back(static_cast<GLfloat>(value));
200 
201         double clampedValue = std::max(intMinD, std::min(intMaxD, value));
202         double rounded = round(clampedValue);
203         expectedIValues.push_back(static_cast<GLint>(rounded));
204     }
205 
206     glUseProgram(mProgram);
207     ASSERT_GL_NO_ERROR();
208 
209     for (size_t index = 0; index < inValues.size(); ++index)
210     {
211         GLfloat inValue       = static_cast<GLfloat>(inValues[index]);
212         GLfloat expectedValue = expectedFValues[index];
213 
214         glUniform1f(mUniformFLocation, inValue);
215         GLfloat testValue;
216         glGetUniformfv(mProgram, mUniformFLocation, &testValue);
217         ASSERT_GL_NO_ERROR();
218         EXPECT_EQ(expectedValue, testValue);
219     }
220 
221     for (size_t index = 0; index < inValues.size(); ++index)
222     {
223         GLfloat inValue     = static_cast<GLfloat>(inValues[index]);
224         GLint expectedValue = expectedIValues[index];
225 
226         glUniform1f(mUniformFLocation, inValue);
227         GLint testValue;
228         glGetUniformiv(mProgram, mUniformFLocation, &testValue);
229         ASSERT_GL_NO_ERROR();
230         EXPECT_EQ(expectedValue, testValue);
231     }
232 }
233 
234 // Test that integer to float GetUniform rounds values correctly.
TEST_P(UniformTest,IntUniformStateQuery)235 TEST_P(UniformTest, IntUniformStateQuery)
236 {
237     std::vector<GLint> inValues;
238     std::vector<GLint> expectedIValues;
239     std::vector<GLfloat> expectedFValues;
240 
241     GLint intMax = std::numeric_limits<GLint>::max();
242     GLint intMin = std::numeric_limits<GLint>::min();
243 
244     inValues.push_back(-1);
245     inValues.push_back(0);
246     inValues.push_back(1);
247     inValues.push_back(999999);
248     inValues.push_back(intMax);
249     inValues.push_back(intMax - 1);
250     inValues.push_back(intMin);
251     inValues.push_back(intMin + 1);
252 
253     for (GLint value : inValues)
254     {
255         expectedIValues.push_back(value);
256         expectedFValues.push_back(static_cast<GLfloat>(value));
257     }
258 
259     glUseProgram(mProgram);
260     ASSERT_GL_NO_ERROR();
261 
262     for (size_t index = 0; index < inValues.size(); ++index)
263     {
264         GLint inValue       = inValues[index];
265         GLint expectedValue = expectedIValues[index];
266 
267         glUniform1i(mUniformILocation, inValue);
268         GLint testValue;
269         glGetUniformiv(mProgram, mUniformILocation, &testValue);
270         ASSERT_GL_NO_ERROR();
271         EXPECT_EQ(expectedValue, testValue);
272     }
273 
274     for (size_t index = 0; index < inValues.size(); ++index)
275     {
276         GLint inValue         = inValues[index];
277         GLfloat expectedValue = expectedFValues[index];
278 
279         glUniform1i(mUniformILocation, inValue);
280         GLfloat testValue;
281         glGetUniformfv(mProgram, mUniformILocation, &testValue);
282         ASSERT_GL_NO_ERROR();
283         EXPECT_EQ(expectedValue, testValue);
284     }
285 }
286 
287 // Test that queries of boolean uniforms round correctly.
TEST_P(UniformTest,BooleanUniformStateQuery)288 TEST_P(UniformTest, BooleanUniformStateQuery)
289 {
290     glUseProgram(mProgram);
291     GLint intValue     = 0;
292     GLfloat floatValue = 0.0f;
293 
294     // Calling Uniform1i
295     glUniform1i(mUniformBLocation, GL_FALSE);
296 
297     glGetUniformiv(mProgram, mUniformBLocation, &intValue);
298     EXPECT_EQ(0, intValue);
299 
300     glGetUniformfv(mProgram, mUniformBLocation, &floatValue);
301     EXPECT_EQ(0.0f, floatValue);
302 
303     glUniform1i(mUniformBLocation, GL_TRUE);
304 
305     glGetUniformiv(mProgram, mUniformBLocation, &intValue);
306     EXPECT_EQ(1, intValue);
307 
308     glGetUniformfv(mProgram, mUniformBLocation, &floatValue);
309     EXPECT_EQ(1.0f, floatValue);
310 
311     // Calling Uniform1f
312     glUniform1f(mUniformBLocation, 0.0f);
313 
314     glGetUniformiv(mProgram, mUniformBLocation, &intValue);
315     EXPECT_EQ(0, intValue);
316 
317     glGetUniformfv(mProgram, mUniformBLocation, &floatValue);
318     EXPECT_EQ(0.0f, floatValue);
319 
320     glUniform1f(mUniformBLocation, 1.0f);
321 
322     glGetUniformiv(mProgram, mUniformBLocation, &intValue);
323     EXPECT_EQ(1, intValue);
324 
325     glGetUniformfv(mProgram, mUniformBLocation, &floatValue);
326     EXPECT_EQ(1.0f, floatValue);
327 
328     ASSERT_GL_NO_ERROR();
329 }
330 
331 // Test queries for arrays of boolean uniforms.
TEST_P(UniformTest,BooleanArrayUniformStateQuery)332 TEST_P(UniformTest, BooleanArrayUniformStateQuery)
333 {
334     glUseProgram(mProgram);
335     GLint boolValuesi[4]   = {0, 1, 0, 1};
336     GLfloat boolValuesf[4] = {0, 1, 0, 1};
337 
338     GLint locations[4] = {
339         glGetUniformLocation(mProgram, "uniBArr"),
340         glGetUniformLocation(mProgram, "uniBArr[1]"),
341         glGetUniformLocation(mProgram, "uniBArr[2]"),
342         glGetUniformLocation(mProgram, "uniBArr[3]"),
343     };
344 
345     // Calling Uniform1iv
346     glUniform1iv(locations[0], 4, boolValuesi);
347 
348     for (unsigned int idx = 0; idx < 4; ++idx)
349     {
350         int value = -1;
351         glGetUniformiv(mProgram, locations[idx], &value);
352         EXPECT_EQ(boolValuesi[idx], value);
353     }
354 
355     for (unsigned int idx = 0; idx < 4; ++idx)
356     {
357         float value = -1.0f;
358         glGetUniformfv(mProgram, locations[idx], &value);
359         EXPECT_EQ(boolValuesf[idx], value);
360     }
361 
362     // Calling Uniform1fv
363     glUniform1fv(locations[0], 4, boolValuesf);
364 
365     for (unsigned int idx = 0; idx < 4; ++idx)
366     {
367         int value = -1;
368         glGetUniformiv(mProgram, locations[idx], &value);
369         EXPECT_EQ(boolValuesi[idx], value);
370     }
371 
372     for (unsigned int idx = 0; idx < 4; ++idx)
373     {
374         float value = -1.0f;
375         glGetUniformfv(mProgram, locations[idx], &value);
376         EXPECT_EQ(boolValuesf[idx], value);
377     }
378 
379     ASSERT_GL_NO_ERROR();
380 }
381 
382 class UniformTestES3 : public ANGLETest
383 {
384   protected:
UniformTestES3()385     UniformTestES3() : mProgram(0) {}
386 
SetUp()387     void SetUp() override
388     {
389         ANGLETest::SetUp();
390     }
391 
TearDown()392     void TearDown() override
393     {
394         if (mProgram != 0)
395         {
396             glDeleteProgram(mProgram);
397             mProgram = 0;
398         }
399     }
400 
401     GLuint mProgram;
402 };
403 
404 // Test queries for transposed arrays of non-square matrix uniforms.
TEST_P(UniformTestES3,TranposedMatrixArrayUniformStateQuery)405 TEST_P(UniformTestES3, TranposedMatrixArrayUniformStateQuery)
406 {
407     const std::string &vertexShader =
408         "#version 300 es\n"
409         "void main() { gl_Position = vec4(1); }";
410     const std::string &fragShader =
411         "#version 300 es\n"
412         "precision mediump float;\n"
413         "uniform mat3x2 uniMat3x2[5];\n"
414         "out vec4 color;\n"
415         "void main() {\n"
416         "  color = vec4(uniMat3x2[0][0][0]);\n"
417         "}";
418 
419     mProgram = CompileProgram(vertexShader, fragShader);
420     ASSERT_NE(mProgram, 0u);
421 
422     glUseProgram(mProgram);
423 
424     std::vector<GLfloat> transposedValues;
425 
426     for (size_t arrayElement = 0; arrayElement < 5; ++arrayElement)
427     {
428         transposedValues.push_back(1.0f + arrayElement);
429         transposedValues.push_back(3.0f + arrayElement);
430         transposedValues.push_back(5.0f + arrayElement);
431         transposedValues.push_back(2.0f + arrayElement);
432         transposedValues.push_back(4.0f + arrayElement);
433         transposedValues.push_back(6.0f + arrayElement);
434     }
435 
436     // Setting as a clump
437     GLint baseLocation = glGetUniformLocation(mProgram, "uniMat3x2");
438     ASSERT_NE(-1, baseLocation);
439 
440     glUniformMatrix3x2fv(baseLocation, 5, GL_TRUE, &transposedValues[0]);
441 
442     for (size_t arrayElement = 0; arrayElement < 5; ++arrayElement)
443     {
444         std::stringstream nameStr;
445         nameStr << "uniMat3x2[" << arrayElement << "]";
446         std::string name = nameStr.str();
447         GLint location = glGetUniformLocation(mProgram, name.c_str());
448         ASSERT_NE(-1, location);
449 
450         std::vector<GLfloat> sequentialValues(6, 0);
451         glGetUniformfv(mProgram, location, &sequentialValues[0]);
452 
453         ASSERT_GL_NO_ERROR();
454 
455         for (size_t comp = 0; comp < 6; ++comp)
456         {
457             EXPECT_EQ(static_cast<GLfloat>(comp + 1 + arrayElement), sequentialValues[comp]);
458         }
459     }
460 }
461 
462 // Check that trying setting too many elements of an array doesn't overflow
TEST_P(UniformTestES3,OverflowArray)463 TEST_P(UniformTestES3, OverflowArray)
464 {
465     const std::string &vertexShader =
466         "#version 300 es\n"
467         "void main() { gl_Position = vec4(1); }";
468     const std::string &fragShader =
469         "#version 300 es\n"
470         "precision mediump float;\n"
471         "uniform float uniF[5];\n"
472         "uniform mat3x2 uniMat3x2[5];\n"
473         "out vec4 color;\n"
474         "void main() {\n"
475         "  color = vec4(uniMat3x2[0][0][0] + uniF[0]);\n"
476         "}";
477 
478     mProgram = CompileProgram(vertexShader, fragShader);
479     ASSERT_NE(mProgram, 0u);
480 
481     glUseProgram(mProgram);
482 
483     const size_t kOverflowSize = 10000;
484     std::vector<GLfloat> values(10000 * 6);
485 
486     // Setting as a clump
487     GLint floatLocation = glGetUniformLocation(mProgram, "uniF");
488     ASSERT_NE(-1, floatLocation);
489     GLint matLocation = glGetUniformLocation(mProgram, "uniMat3x2");
490     ASSERT_NE(-1, matLocation);
491 
492     // Set too many float uniforms
493     glUniform1fv(floatLocation, kOverflowSize, &values[0]);
494 
495     // Set too many matrix uniforms, transposed or not
496     glUniformMatrix3x2fv(matLocation, kOverflowSize, GL_FALSE, &values[0]);
497     glUniformMatrix3x2fv(matLocation, kOverflowSize, GL_TRUE, &values[0]);
498 
499     // Same checks but with offsets
500     GLint floatLocationOffset = glGetUniformLocation(mProgram, "uniF[3]");
501     ASSERT_NE(-1, floatLocationOffset);
502     GLint matLocationOffset = glGetUniformLocation(mProgram, "uniMat3x2[3]");
503     ASSERT_NE(-1, matLocationOffset);
504 
505     glUniform1fv(floatLocationOffset, kOverflowSize, &values[0]);
506     glUniformMatrix3x2fv(matLocationOffset, kOverflowSize, GL_FALSE, &values[0]);
507     glUniformMatrix3x2fv(matLocationOffset, kOverflowSize, GL_TRUE, &values[0]);
508 }
509 
510 // Check that sampler uniforms only show up one time in the list
TEST_P(UniformTest,SamplerUniformsAppearOnce)511 TEST_P(UniformTest, SamplerUniformsAppearOnce)
512 {
513     int maxVertexTextureImageUnits = 0;
514     glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextureImageUnits);
515 
516     if (maxVertexTextureImageUnits == 0)
517     {
518         std::cout << "Renderer doesn't support vertex texture fetch, skipping test" << std::endl;
519         return;
520     }
521 
522     const std::string &vertShader =
523         "attribute vec2 position;\n"
524         "uniform sampler2D tex2D;\n"
525         "varying vec4 color;\n"
526         "void main() {\n"
527         "  gl_Position = vec4(position, 0, 1);\n"
528         "  color = texture2D(tex2D, vec2(0));\n"
529         "}";
530 
531     const std::string &fragShader =
532         "precision mediump float;\n"
533         "varying vec4 color;\n"
534         "uniform sampler2D tex2D;\n"
535         "void main() {\n"
536         "  gl_FragColor = texture2D(tex2D, vec2(0)) + color;\n"
537         "}";
538 
539     GLuint program = CompileProgram(vertShader, fragShader);
540     ASSERT_NE(0u, program);
541 
542     GLint activeUniformsCount = 0;
543     glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniformsCount);
544     ASSERT_EQ(1, activeUniformsCount);
545 
546     GLint size       = 0;
547     GLenum type      = GL_NONE;
548     GLchar name[120] = {0};
549     glGetActiveUniform(program, 0, 100, nullptr, &size, &type, name);
550     EXPECT_EQ(1, size);
551     EXPECT_GLENUM_EQ(GL_SAMPLER_2D, type);
552     EXPECT_STREQ("tex2D", name);
553 
554     EXPECT_GL_NO_ERROR();
555 
556     glDeleteProgram(program);
557 }
558 
559 template <typename T, typename GetUniformV>
CheckOneElement(GetUniformV getUniformv,GLuint program,const std::string & name,int components,T canary)560 void CheckOneElement(GetUniformV getUniformv,
561                      GLuint program,
562                      const std::string &name,
563                      int components,
564                      T canary)
565 {
566     // The buffer getting the results has three chunks
567     //  - A chunk to see underflows
568     //  - A chunk that will hold the result
569     //  - A chunk to see overflows for when components = kChunkSize
570     static const size_t kChunkSize = 4;
571     std::array<T, 3 * kChunkSize> buffer;
572     buffer.fill(canary);
573 
574     GLint location = glGetUniformLocation(program, name.c_str());
575     ASSERT_NE(location, -1);
576 
577     getUniformv(program, location, &buffer[kChunkSize]);
578     for (size_t i = 0; i < kChunkSize; i++)
579     {
580         ASSERT_EQ(canary, buffer[i]);
581     }
582     for (size_t i = kChunkSize + components; i < buffer.size(); i++)
583     {
584         ASSERT_EQ(canary, buffer[i]);
585     }
586 }
587 
588 // Check that getting an element array doesn't return the whole array.
TEST_P(UniformTestES3,ReturnsOnlyOneArrayElement)589 TEST_P(UniformTestES3, ReturnsOnlyOneArrayElement)
590 {
591     static const size_t kArraySize = 4;
592     struct UniformArrayInfo
593     {
594         UniformArrayInfo(std::string type, std::string name, int components)
595             : type(type), name(name), components(components)
596         {
597         }
598         std::string type;
599         std::string name;
600         int components;
601     };
602 
603     // Check for various number of components and types
604     std::vector<UniformArrayInfo> uniformArrays;
605     uniformArrays.emplace_back("bool", "uBool", 1);
606     uniformArrays.emplace_back("vec2", "uFloat", 2);
607     uniformArrays.emplace_back("ivec3", "uInt", 3);
608     uniformArrays.emplace_back("uvec4", "uUint", 4);
609 
610     std::ostringstream uniformStream;
611     std::ostringstream additionStream;
612     for (const auto &array : uniformArrays)
613     {
614         uniformStream << "uniform " << array.type << " " << array.name << "["
615                       << ToString(kArraySize) << "];\n";
616 
617         // We need to make use of the uniforms or they get compiled out.
618         for (int i = 0; i < 4; i++)
619         {
620             if (array.components == 1)
621             {
622                 additionStream << " + float(" << array.name << "[" << i << "])";
623             }
624             else
625             {
626                 for (int component = 0; component < array.components; component++)
627                 {
628                     additionStream << " + float(" << array.name << "[" << i << "][" << component
629                                    << "])";
630                 }
631             }
632         }
633     }
634 
635     const std::string &vertexShader =
636         "#version 300 es\n" +
637         uniformStream.str() +
638         "void main()\n"
639         "{\n"
640         "    gl_Position = vec4(1.0" + additionStream.str() + ");\n"
641         "}";
642 
643     const std::string &fragmentShader =
644         "#version 300 es\n"
645         "precision mediump float;\n"
646         "out vec4 color;\n"
647         "void main ()\n"
648         "{\n"
649         "    color = vec4(1, 0, 0, 1);\n"
650         "}";
651 
652     mProgram = CompileProgram(vertexShader, fragmentShader);
653     ASSERT_NE(0u, mProgram);
654 
655     glUseProgram(mProgram);
656 
657     for (const auto &uniformArray : uniformArrays)
658     {
659         for (size_t index = 0; index < kArraySize; index++)
660         {
661             std::string strIndex = "[" + ToString(index) + "]";
662             // Check all the different glGetUniformv functions
663             CheckOneElement<float>(glGetUniformfv, mProgram, uniformArray.name + strIndex,
664                                    uniformArray.components, 42.4242f);
665             CheckOneElement<int>(glGetUniformiv, mProgram, uniformArray.name + strIndex,
666                                  uniformArray.components, 0x7BADBED5);
667             CheckOneElement<unsigned int>(glGetUniformuiv, mProgram, uniformArray.name + strIndex,
668                                           uniformArray.components, 0xDEADBEEF);
669         }
670     }
671 }
672 
673 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
674 ANGLE_INSTANTIATE_TEST(UniformTest,
675                        ES2_D3D9(),
676                        ES2_D3D11(),
677                        ES2_D3D11_FL9_3(),
678                        ES2_OPENGL(),
679                        ES2_OPENGLES());
680 ANGLE_INSTANTIATE_TEST(UniformTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
681 
682 } // namespace
683