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 #include "test_utils/gl_raii.h"
9 
10 using namespace angle;
11 
12 namespace
13 {
14 
15 class UniformBufferTest : public ANGLETest
16 {
17   protected:
UniformBufferTest()18     UniformBufferTest()
19     {
20         setWindowWidth(128);
21         setWindowHeight(128);
22         setConfigRedBits(8);
23         setConfigGreenBits(8);
24         setConfigBlueBits(8);
25         setConfigAlphaBits(8);
26     }
27 
SetUp()28     void SetUp() override
29     {
30         ANGLETest::SetUp();
31 
32         const std::string vertexShaderSource = SHADER_SOURCE
33         (   #version 300 es\n
34             in vec4 position;
35             void main()
36             {
37                 gl_Position = position;
38             }
39         );
40         const std::string fragmentShaderSource = SHADER_SOURCE
41         (   #version 300 es\n
42             precision highp float;
43             uniform uni {
44                 vec4 color;
45             };
46 
47             out vec4 fragColor;
48 
49             void main()
50             {
51                 fragColor = color;
52             }
53         );
54 
55         mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
56         ASSERT_NE(mProgram, 0u);
57 
58         mUniformBufferIndex = glGetUniformBlockIndex(mProgram, "uni");
59         ASSERT_NE(mUniformBufferIndex, -1);
60 
61         glGenBuffers(1, &mUniformBuffer);
62 
63         ASSERT_GL_NO_ERROR();
64     }
65 
TearDown()66     void TearDown() override
67     {
68         glDeleteBuffers(1, &mUniformBuffer);
69         glDeleteProgram(mProgram);
70         ANGLETest::TearDown();
71     }
72 
73     GLuint mProgram;
74     GLint mUniformBufferIndex;
75     GLuint mUniformBuffer;
76 };
77 
78 // Basic UBO functionality.
TEST_P(UniformBufferTest,Simple)79 TEST_P(UniformBufferTest, Simple)
80 {
81     glClear(GL_COLOR_BUFFER_BIT);
82     float floatData[4] = {0.5f, 0.75f, 0.25f, 1.0f};
83 
84     glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
85     glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4, floatData, GL_STATIC_DRAW);
86 
87     glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
88 
89     glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
90     drawQuad(mProgram, "position", 0.5f);
91 
92     ASSERT_GL_NO_ERROR();
93     EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
94 }
95 
96 // Test that using a UBO with a non-zero offset and size actually works.
97 // The first step of this test renders a color from a UBO with a zero offset.
98 // The second step renders a color from a UBO with a non-zero offset.
TEST_P(UniformBufferTest,UniformBufferRange)99 TEST_P(UniformBufferTest, UniformBufferRange)
100 {
101     int px = getWindowWidth() / 2;
102     int py = getWindowHeight() / 2;
103 
104     // Query the uniform buffer alignment requirement
105     GLint alignment;
106     glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
107 
108     GLint64 maxUniformBlockSize;
109     glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
110     if (alignment >= maxUniformBlockSize)
111     {
112         // ANGLE doesn't implement UBO offsets for this platform.
113         // Ignore the test case.
114         return;
115     }
116 
117     ASSERT_GL_NO_ERROR();
118 
119     // Let's create a buffer which contains two vec4.
120     GLuint vec4Size = 4 * sizeof(float);
121     GLuint stride = 0;
122     do
123     {
124         stride += alignment;
125     }
126     while (stride < vec4Size);
127 
128     std::vector<char> v(2 * stride);
129     float *first = reinterpret_cast<float*>(v.data());
130     float *second = reinterpret_cast<float*>(v.data() + stride);
131 
132     first[0] = 10.f / 255.f;
133     first[1] = 20.f / 255.f;
134     first[2] = 30.f / 255.f;
135     first[3] = 40.f / 255.f;
136 
137     second[0] = 110.f / 255.f;
138     second[1] = 120.f / 255.f;
139     second[2] = 130.f / 255.f;
140     second[3] = 140.f / 255.f;
141 
142     glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
143     // We use on purpose a size which is not a multiple of the alignment.
144     glBufferData(GL_UNIFORM_BUFFER, stride + vec4Size, v.data(), GL_STATIC_DRAW);
145 
146     glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
147 
148     EXPECT_GL_NO_ERROR();
149 
150     // Bind the first part of the uniform buffer and draw
151     // Use a size which is smaller than the alignment to check
152     // to check that this case is handle correctly in the conversion to 11.1.
153     glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, 0, vec4Size);
154     drawQuad(mProgram, "position", 0.5f);
155     EXPECT_GL_NO_ERROR();
156     EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
157 
158     // Bind the second part of the uniform buffer and draw
159     // Furthermore the D3D11.1 backend will internally round the vec4Size (16 bytes) to a stride (256 bytes)
160     // hence it will try to map the range [stride, 2 * stride] which is
161     // out-of-bound of the buffer bufferSize = stride + vec4Size < 2 * stride.
162     // Ensure that this behaviour works.
163     glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, stride, vec4Size);
164     drawQuad(mProgram, "position", 0.5f);
165     EXPECT_GL_NO_ERROR();
166     EXPECT_PIXEL_EQ(px, py, 110, 120, 130, 140);
167 }
168 
169 // Test uniform block bindings.
TEST_P(UniformBufferTest,UniformBufferBindings)170 TEST_P(UniformBufferTest, UniformBufferBindings)
171 {
172     int px = getWindowWidth() / 2;
173     int py = getWindowHeight() / 2;
174 
175     ASSERT_GL_NO_ERROR();
176 
177     // Let's create a buffer which contains one vec4.
178     GLuint vec4Size = 4 * sizeof(float);
179     std::vector<char> v(vec4Size);
180     float *first = reinterpret_cast<float*>(v.data());
181 
182     first[0] = 10.f / 255.f;
183     first[1] = 20.f / 255.f;
184     first[2] = 30.f / 255.f;
185     first[3] = 40.f / 255.f;
186 
187     glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
188     glBufferData(GL_UNIFORM_BUFFER, vec4Size, v.data(), GL_STATIC_DRAW);
189 
190     EXPECT_GL_NO_ERROR();
191 
192     // Try to bind the buffer to binding point 2
193     glUniformBlockBinding(mProgram, mUniformBufferIndex, 2);
194     glBindBufferBase(GL_UNIFORM_BUFFER, 2, mUniformBuffer);
195     drawQuad(mProgram, "position", 0.5f);
196     EXPECT_GL_NO_ERROR();
197     EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
198 
199     // Clear the framebuffer
200     glClearColor(0.0, 0.0, 0.0, 0.0);
201     glClear(GL_COLOR_BUFFER_BIT);
202     EXPECT_PIXEL_EQ(px, py, 0, 0, 0, 0);
203 
204     // Try to bind the buffer to another binding point
205     glUniformBlockBinding(mProgram, mUniformBufferIndex, 5);
206     glBindBufferBase(GL_UNIFORM_BUFFER, 5, mUniformBuffer);
207     drawQuad(mProgram, "position", 0.5f);
208     EXPECT_GL_NO_ERROR();
209     EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
210 }
211 
212 // Test that ANGLE handles used but unbound UBO.
213 // TODO: A test case shouldn't depend on the error code of an undefined behaviour. Move this to unit tests of the validation layer.
TEST_P(UniformBufferTest,UnboundUniformBuffer)214 TEST_P(UniformBufferTest, UnboundUniformBuffer)
215 {
216     glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
217     glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0);
218     EXPECT_GL_NO_ERROR();
219 
220     drawQuad(mProgram, "position", 0.5f);
221     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
222 }
223 
224 // Update a UBO many time and verify that ANGLE uses the latest version of the data.
225 // https://code.google.com/p/angleproject/issues/detail?id=965
TEST_P(UniformBufferTest,UniformBufferManyUpdates)226 TEST_P(UniformBufferTest, UniformBufferManyUpdates)
227 {
228     // TODO(jmadill): Figure out why this fails on Intel OpenGL.
229     if (IsIntel() && IsOpenGL())
230     {
231         std::cout << "Test skipped on Intel OpenGL." << std::endl;
232         return;
233     }
234 
235     int px = getWindowWidth() / 2;
236     int py = getWindowHeight() / 2;
237 
238     ASSERT_GL_NO_ERROR();
239 
240     float data[4];
241 
242     glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
243     glBufferData(GL_UNIFORM_BUFFER, sizeof(data), NULL, GL_DYNAMIC_DRAW);
244     glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
245     glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
246 
247     EXPECT_GL_NO_ERROR();
248 
249     // Repeteadly update the data and draw
250     for (size_t i = 0; i < 10; ++i)
251     {
252         data[0] = (i + 10.f) / 255.f;
253         data[1] = (i + 20.f) / 255.f;
254         data[2] = (i + 30.f) / 255.f;
255         data[3] = (i + 40.f) / 255.f;
256 
257         glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(data), data);
258 
259         drawQuad(mProgram, "position", 0.5f);
260         EXPECT_GL_NO_ERROR();
261         EXPECT_PIXEL_EQ(px, py, i + 10, i + 20, i + 30, i + 40);
262     }
263 }
264 
265 // Use a large number of buffer ranges (compared to the actual size of the UBO)
TEST_P(UniformBufferTest,ManyUniformBufferRange)266 TEST_P(UniformBufferTest, ManyUniformBufferRange)
267 {
268     int px = getWindowWidth() / 2;
269     int py = getWindowHeight() / 2;
270 
271     // Query the uniform buffer alignment requirement
272     GLint alignment;
273     glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
274 
275     GLint64 maxUniformBlockSize;
276     glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
277     if (alignment >= maxUniformBlockSize)
278     {
279         // ANGLE doesn't implement UBO offsets for this platform.
280         // Ignore the test case.
281         return;
282     }
283 
284     ASSERT_GL_NO_ERROR();
285 
286     // Let's create a buffer which contains eight vec4.
287     GLuint vec4Size = 4 * sizeof(float);
288     GLuint stride = 0;
289     do
290     {
291         stride += alignment;
292     }
293     while (stride < vec4Size);
294 
295     std::vector<char> v(8 * stride);
296 
297     for (size_t i = 0; i < 8; ++i)
298     {
299         float *data = reinterpret_cast<float*>(v.data() + i * stride);
300 
301         data[0] = (i + 10.f) / 255.f;
302         data[1] = (i + 20.f) / 255.f;
303         data[2] = (i + 30.f) / 255.f;
304         data[3] = (i + 40.f) / 255.f;
305     }
306 
307     glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
308     glBufferData(GL_UNIFORM_BUFFER, v.size(), v.data(), GL_STATIC_DRAW);
309 
310     glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
311 
312     EXPECT_GL_NO_ERROR();
313 
314     // Bind each possible offset
315     for (size_t i = 0; i < 8; ++i)
316     {
317         glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, stride);
318         drawQuad(mProgram, "position", 0.5f);
319         EXPECT_GL_NO_ERROR();
320         EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
321     }
322 
323     // Try to bind larger range
324     for (size_t i = 0; i < 7; ++i)
325     {
326         glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, 2 * stride);
327         drawQuad(mProgram, "position", 0.5f);
328         EXPECT_GL_NO_ERROR();
329         EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
330     }
331 
332     // Try to bind even larger range
333     for (size_t i = 0; i < 5; ++i)
334     {
335         glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, 4 * stride);
336         drawQuad(mProgram, "position", 0.5f);
337         EXPECT_GL_NO_ERROR();
338         EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
339     }
340 }
341 
342 // Tests that active uniforms have the right names.
TEST_P(UniformBufferTest,ActiveUniformNames)343 TEST_P(UniformBufferTest, ActiveUniformNames)
344 {
345     const std::string &vertexShaderSource =
346         "#version 300 es\n"
347         "in vec2 position;\n"
348         "out vec2 v;\n"
349         "uniform blockName1 {\n"
350         "  float f1;\n"
351         "} instanceName1;\n"
352         "uniform blockName2 {\n"
353         "  float f2;\n"
354         "} instanceName2[1];\n"
355         "void main() {\n"
356         "  v = vec2(instanceName1.f1, instanceName2[0].f2);\n"
357         "  gl_Position = vec4(position, 0, 1);\n"
358         "}";
359 
360     const std::string &fragmentShaderSource =
361         "#version 300 es\n"
362         "precision highp float;\n"
363         "in vec2 v;\n"
364         "out vec4 color;\n"
365         "void main() {\n"
366         "  color = vec4(v, 0, 1);\n"
367         "}";
368 
369     GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
370     ASSERT_NE(0u, program);
371 
372     GLint activeUniformBlocks;
373     glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &activeUniformBlocks);
374     ASSERT_EQ(2, activeUniformBlocks);
375 
376     GLint maxLength;
377     GLsizei length;
378     glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxLength);
379     std::vector<GLchar> strBlockNameBuffer(maxLength + 1, 0);
380     glGetActiveUniformBlockName(program, 0, maxLength, &length, &strBlockNameBuffer[0]);
381     ASSERT_GL_NO_ERROR();
382     EXPECT_EQ("blockName1", std::string(&strBlockNameBuffer[0]));
383 
384     glGetActiveUniformBlockName(program, 1, maxLength, &length, &strBlockNameBuffer[0]);
385     ASSERT_GL_NO_ERROR();
386     EXPECT_EQ("blockName2[0]", std::string(&strBlockNameBuffer[0]));
387 
388     GLint activeUniforms;
389     glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniforms);
390 
391     ASSERT_EQ(2, activeUniforms);
392 
393     GLint size;
394     GLenum type;
395     glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
396     std::vector<GLchar> strUniformNameBuffer(maxLength + 1, 0);
397     glGetActiveUniform(program, 0, maxLength, &length, &size, &type, &strUniformNameBuffer[0]);
398 
399     ASSERT_GL_NO_ERROR();
400     EXPECT_EQ(1, size);
401     EXPECT_GLENUM_EQ(GL_FLOAT, type);
402     EXPECT_EQ("blockName1.f1", std::string(&strUniformNameBuffer[0]));
403 
404     glGetActiveUniform(program, 1, maxLength, &length, &size, &type, &strUniformNameBuffer[0]);
405 
406     ASSERT_GL_NO_ERROR();
407     EXPECT_EQ(1, size);
408     EXPECT_GLENUM_EQ(GL_FLOAT, type);
409     EXPECT_EQ("blockName2.f2", std::string(&strUniformNameBuffer[0]));
410 }
411 
412 // Tests active uniforms and blocks when the layout is std140, shared and packed.
TEST_P(UniformBufferTest,ActiveUniformNumberAndName)413 TEST_P(UniformBufferTest, ActiveUniformNumberAndName)
414 {
415     // TODO(Jiajia): Figure out why this fails on Intel on Mac.
416     // This case can pass on Intel Mac-10.11/10.12. But it fails on Intel Mac-10.10.
417     if (IsIntel() && IsOSX())
418     {
419         std::cout << "Test skipped on Intel on Mac." << std::endl;
420         return;
421     }
422 
423     // This case fails on all AMD platforms (Mac, Linux, Win).
424     // TODO(zmo): This actually passes on certain AMD cards, but we don't have
425     // a way to do device specific handling yet.
426     if (IsAMD())
427     {
428         std::cout << "Test skipped on AMD." << std::endl;
429         return;
430     }
431 
432     const std::string &vertexShaderSource =
433         "#version 300 es\n"
434         "in vec2 position;\n"
435         "out float v;\n"
436         "struct S {\n"
437         "  highp ivec3 a;\n"
438         "  mediump ivec2 b[4];\n"
439         "};\n"
440         "layout(std140) uniform blockName0 {\n"
441         "  S s0;\n"
442         "  lowp vec2 v0;\n"
443         "  S s1[2];\n"
444         "  highp uint u0;\n"
445         "};\n"
446         "layout(std140) uniform blockName1 {\n"
447         "  float f1;\n"
448         "  bool b1;\n"
449         "} instanceName1;\n"
450         "layout(shared) uniform blockName2 {\n"
451         "  float f2;\n"
452         "};\n"
453         "layout(packed) uniform blockName3 {\n"
454         "  float f3;\n"
455         "};\n"
456         "void main() {\n"
457         "  v = instanceName1.f1;\n"
458         "  gl_Position = vec4(position, 0, 1);\n"
459         "}";
460 
461     const std::string &fragmentShaderSource =
462         "#version 300 es\n"
463         "precision highp float;\n"
464         "in float v;\n"
465         "out vec4 color;\n"
466         "void main() {\n"
467         "  color = vec4(v, 0, 0, 1);\n"
468         "}";
469 
470     ANGLE_GL_PROGRAM(program, vertexShaderSource, fragmentShaderSource);
471 
472     // Note that the packed |blockName3| might (or might not) be optimized out.
473     GLint activeUniforms;
474     glGetProgramiv(program.get(), GL_ACTIVE_UNIFORMS, &activeUniforms);
475     EXPECT_GE(activeUniforms, 11);
476 
477     GLint activeUniformBlocks;
478     glGetProgramiv(program.get(), GL_ACTIVE_UNIFORM_BLOCKS, &activeUniformBlocks);
479     EXPECT_GE(activeUniformBlocks, 3);
480 
481     GLint maxLength, size;
482     GLenum type;
483     GLsizei length;
484     glGetProgramiv(program.get(), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
485     std::vector<GLchar> strBuffer(maxLength + 1, 0);
486 
487     glGetActiveUniform(program.get(), 0, maxLength, &length, &size, &type, &strBuffer[0]);
488     ASSERT_GL_NO_ERROR();
489     EXPECT_EQ(1, size);
490     EXPECT_EQ("s0.a", std::string(&strBuffer[0]));
491 
492     glGetActiveUniform(program.get(), 1, maxLength, &length, &size, &type, &strBuffer[0]);
493     ASSERT_GL_NO_ERROR();
494     EXPECT_EQ(4, size);
495     EXPECT_EQ("s0.b[0]", std::string(&strBuffer[0]));
496 
497     glGetActiveUniform(program.get(), 2, maxLength, &length, &size, &type, &strBuffer[0]);
498     ASSERT_GL_NO_ERROR();
499     EXPECT_EQ(1, size);
500     EXPECT_EQ("v0", std::string(&strBuffer[0]));
501 
502     glGetActiveUniform(program.get(), 3, maxLength, &length, &size, &type, &strBuffer[0]);
503     ASSERT_GL_NO_ERROR();
504     EXPECT_EQ(1, size);
505     EXPECT_EQ("s1[0].a", std::string(&strBuffer[0]));
506 
507     glGetActiveUniform(program.get(), 4, maxLength, &length, &size, &type, &strBuffer[0]);
508     ASSERT_GL_NO_ERROR();
509     EXPECT_EQ(4, size);
510     EXPECT_EQ("s1[0].b[0]", std::string(&strBuffer[0]));
511 
512     glGetActiveUniform(program.get(), 5, maxLength, &length, &size, &type, &strBuffer[0]);
513     ASSERT_GL_NO_ERROR();
514     EXPECT_EQ(1, size);
515     EXPECT_EQ("s1[1].a", std::string(&strBuffer[0]));
516 
517     glGetActiveUniform(program.get(), 6, maxLength, &length, &size, &type, &strBuffer[0]);
518     ASSERT_GL_NO_ERROR();
519     EXPECT_EQ(4, size);
520     EXPECT_EQ("s1[1].b[0]", std::string(&strBuffer[0]));
521 
522     glGetActiveUniform(program.get(), 7, maxLength, &length, &size, &type, &strBuffer[0]);
523     ASSERT_GL_NO_ERROR();
524     EXPECT_EQ(1, size);
525     EXPECT_EQ("u0", std::string(&strBuffer[0]));
526 
527     glGetActiveUniform(program.get(), 8, maxLength, &length, &size, &type, &strBuffer[0]);
528     ASSERT_GL_NO_ERROR();
529     EXPECT_EQ(1, size);
530     EXPECT_EQ("blockName1.f1", std::string(&strBuffer[0]));
531 
532     glGetActiveUniform(program.get(), 9, maxLength, &length, &size, &type, &strBuffer[0]);
533     ASSERT_GL_NO_ERROR();
534     EXPECT_EQ(1, size);
535     EXPECT_EQ("blockName1.b1", std::string(&strBuffer[0]));
536 
537     glGetActiveUniform(program.get(), 10, maxLength, &length, &size, &type, &strBuffer[0]);
538     ASSERT_GL_NO_ERROR();
539     EXPECT_EQ(1, size);
540     EXPECT_EQ("f2", std::string(&strBuffer[0]));
541 }
542 
543 // Test that using a very large buffer to back a small uniform block works OK.
TEST_P(UniformBufferTest,VeryLarge)544 TEST_P(UniformBufferTest, VeryLarge)
545 {
546     glClear(GL_COLOR_BUFFER_BIT);
547     float floatData[4] = {0.5f, 0.75f, 0.25f, 1.0f};
548 
549     GLsizei bigSize = 4096 * 64;
550     std::vector<GLubyte> zero(bigSize, 0);
551 
552     glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
553     glBufferData(GL_UNIFORM_BUFFER, bigSize, zero.data(), GL_STATIC_DRAW);
554     glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(float) * 4, floatData);
555 
556     glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
557 
558     glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
559     drawQuad(mProgram, "position", 0.5f);
560 
561     ASSERT_GL_NO_ERROR();
562     EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
563 }
564 
565 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
566 ANGLE_INSTANTIATE_TEST(UniformBufferTest,
567                        ES3_D3D11(),
568                        ES3_D3D11_FL11_1(),
569                        ES3_D3D11_FL11_1_REFERENCE(),
570                        ES3_OPENGL(),
571                        ES3_OPENGLES());
572 
573 } // namespace
574