summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/tests/gl_tests/UniformBufferTest.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /gfx/angle/src/tests/gl_tests/UniformBufferTest.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'gfx/angle/src/tests/gl_tests/UniformBufferTest.cpp')
-rwxr-xr-xgfx/angle/src/tests/gl_tests/UniformBufferTest.cpp573
1 files changed, 573 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/gl_tests/UniformBufferTest.cpp b/gfx/angle/src/tests/gl_tests/UniformBufferTest.cpp
new file mode 100755
index 000000000..b3577bf30
--- /dev/null
+++ b/gfx/angle/src/tests/gl_tests/UniformBufferTest.cpp
@@ -0,0 +1,573 @@
+//
+// Copyright 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "test_utils/ANGLETest.h"
+#include "test_utils/gl_raii.h"
+
+using namespace angle;
+
+namespace
+{
+
+class UniformBufferTest : public ANGLETest
+{
+ protected:
+ UniformBufferTest()
+ {
+ setWindowWidth(128);
+ setWindowHeight(128);
+ setConfigRedBits(8);
+ setConfigGreenBits(8);
+ setConfigBlueBits(8);
+ setConfigAlphaBits(8);
+ }
+
+ void SetUp() override
+ {
+ ANGLETest::SetUp();
+
+ const std::string vertexShaderSource = SHADER_SOURCE
+ ( #version 300 es\n
+ in vec4 position;
+ void main()
+ {
+ gl_Position = position;
+ }
+ );
+ const std::string fragmentShaderSource = SHADER_SOURCE
+ ( #version 300 es\n
+ precision highp float;
+ uniform uni {
+ vec4 color;
+ };
+
+ out vec4 fragColor;
+
+ void main()
+ {
+ fragColor = color;
+ }
+ );
+
+ mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ ASSERT_NE(mProgram, 0u);
+
+ mUniformBufferIndex = glGetUniformBlockIndex(mProgram, "uni");
+ ASSERT_NE(mUniformBufferIndex, -1);
+
+ glGenBuffers(1, &mUniformBuffer);
+
+ ASSERT_GL_NO_ERROR();
+ }
+
+ void TearDown() override
+ {
+ glDeleteBuffers(1, &mUniformBuffer);
+ glDeleteProgram(mProgram);
+ ANGLETest::TearDown();
+ }
+
+ GLuint mProgram;
+ GLint mUniformBufferIndex;
+ GLuint mUniformBuffer;
+};
+
+// Basic UBO functionality.
+TEST_P(UniformBufferTest, Simple)
+{
+ glClear(GL_COLOR_BUFFER_BIT);
+ float floatData[4] = {0.5f, 0.75f, 0.25f, 1.0f};
+
+ glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4, floatData, GL_STATIC_DRAW);
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
+
+ glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
+ drawQuad(mProgram, "position", 0.5f);
+
+ ASSERT_GL_NO_ERROR();
+ EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
+}
+
+// Test that using a UBO with a non-zero offset and size actually works.
+// The first step of this test renders a color from a UBO with a zero offset.
+// The second step renders a color from a UBO with a non-zero offset.
+TEST_P(UniformBufferTest, UniformBufferRange)
+{
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ // Query the uniform buffer alignment requirement
+ GLint alignment;
+ glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
+
+ GLint64 maxUniformBlockSize;
+ glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
+ if (alignment >= maxUniformBlockSize)
+ {
+ // ANGLE doesn't implement UBO offsets for this platform.
+ // Ignore the test case.
+ return;
+ }
+
+ ASSERT_GL_NO_ERROR();
+
+ // Let's create a buffer which contains two vec4.
+ GLuint vec4Size = 4 * sizeof(float);
+ GLuint stride = 0;
+ do
+ {
+ stride += alignment;
+ }
+ while (stride < vec4Size);
+
+ std::vector<char> v(2 * stride);
+ float *first = reinterpret_cast<float*>(v.data());
+ float *second = reinterpret_cast<float*>(v.data() + stride);
+
+ first[0] = 10.f / 255.f;
+ first[1] = 20.f / 255.f;
+ first[2] = 30.f / 255.f;
+ first[3] = 40.f / 255.f;
+
+ second[0] = 110.f / 255.f;
+ second[1] = 120.f / 255.f;
+ second[2] = 130.f / 255.f;
+ second[3] = 140.f / 255.f;
+
+ glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
+ // We use on purpose a size which is not a multiple of the alignment.
+ glBufferData(GL_UNIFORM_BUFFER, stride + vec4Size, v.data(), GL_STATIC_DRAW);
+
+ glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
+
+ EXPECT_GL_NO_ERROR();
+
+ // Bind the first part of the uniform buffer and draw
+ // Use a size which is smaller than the alignment to check
+ // to check that this case is handle correctly in the conversion to 11.1.
+ glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, 0, vec4Size);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
+
+ // Bind the second part of the uniform buffer and draw
+ // Furthermore the D3D11.1 backend will internally round the vec4Size (16 bytes) to a stride (256 bytes)
+ // hence it will try to map the range [stride, 2 * stride] which is
+ // out-of-bound of the buffer bufferSize = stride + vec4Size < 2 * stride.
+ // Ensure that this behaviour works.
+ glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, stride, vec4Size);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_EQ(px, py, 110, 120, 130, 140);
+}
+
+// Test uniform block bindings.
+TEST_P(UniformBufferTest, UniformBufferBindings)
+{
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ ASSERT_GL_NO_ERROR();
+
+ // Let's create a buffer which contains one vec4.
+ GLuint vec4Size = 4 * sizeof(float);
+ std::vector<char> v(vec4Size);
+ float *first = reinterpret_cast<float*>(v.data());
+
+ first[0] = 10.f / 255.f;
+ first[1] = 20.f / 255.f;
+ first[2] = 30.f / 255.f;
+ first[3] = 40.f / 255.f;
+
+ glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
+ glBufferData(GL_UNIFORM_BUFFER, vec4Size, v.data(), GL_STATIC_DRAW);
+
+ EXPECT_GL_NO_ERROR();
+
+ // Try to bind the buffer to binding point 2
+ glUniformBlockBinding(mProgram, mUniformBufferIndex, 2);
+ glBindBufferBase(GL_UNIFORM_BUFFER, 2, mUniformBuffer);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
+
+ // Clear the framebuffer
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_EQ(px, py, 0, 0, 0, 0);
+
+ // Try to bind the buffer to another binding point
+ glUniformBlockBinding(mProgram, mUniformBufferIndex, 5);
+ glBindBufferBase(GL_UNIFORM_BUFFER, 5, mUniformBuffer);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
+}
+
+// Test that ANGLE handles used but unbound UBO.
+// 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)
+{
+ glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0);
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+}
+
+// Update a UBO many time and verify that ANGLE uses the latest version of the data.
+// https://code.google.com/p/angleproject/issues/detail?id=965
+TEST_P(UniformBufferTest, UniformBufferManyUpdates)
+{
+ // TODO(jmadill): Figure out why this fails on Intel OpenGL.
+ if (IsIntel() && IsOpenGL())
+ {
+ std::cout << "Test skipped on Intel OpenGL." << std::endl;
+ return;
+ }
+
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ ASSERT_GL_NO_ERROR();
+
+ float data[4];
+
+ glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(data), NULL, GL_DYNAMIC_DRAW);
+ glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
+
+ EXPECT_GL_NO_ERROR();
+
+ // Repeteadly update the data and draw
+ for (size_t i = 0; i < 10; ++i)
+ {
+ data[0] = (i + 10.f) / 255.f;
+ data[1] = (i + 20.f) / 255.f;
+ data[2] = (i + 30.f) / 255.f;
+ data[3] = (i + 40.f) / 255.f;
+
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(data), data);
+
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_EQ(px, py, i + 10, i + 20, i + 30, i + 40);
+ }
+}
+
+// Use a large number of buffer ranges (compared to the actual size of the UBO)
+TEST_P(UniformBufferTest, ManyUniformBufferRange)
+{
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ // Query the uniform buffer alignment requirement
+ GLint alignment;
+ glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
+
+ GLint64 maxUniformBlockSize;
+ glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
+ if (alignment >= maxUniformBlockSize)
+ {
+ // ANGLE doesn't implement UBO offsets for this platform.
+ // Ignore the test case.
+ return;
+ }
+
+ ASSERT_GL_NO_ERROR();
+
+ // Let's create a buffer which contains eight vec4.
+ GLuint vec4Size = 4 * sizeof(float);
+ GLuint stride = 0;
+ do
+ {
+ stride += alignment;
+ }
+ while (stride < vec4Size);
+
+ std::vector<char> v(8 * stride);
+
+ for (size_t i = 0; i < 8; ++i)
+ {
+ float *data = reinterpret_cast<float*>(v.data() + i * stride);
+
+ data[0] = (i + 10.f) / 255.f;
+ data[1] = (i + 20.f) / 255.f;
+ data[2] = (i + 30.f) / 255.f;
+ data[3] = (i + 40.f) / 255.f;
+ }
+
+ glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
+ glBufferData(GL_UNIFORM_BUFFER, v.size(), v.data(), GL_STATIC_DRAW);
+
+ glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
+
+ EXPECT_GL_NO_ERROR();
+
+ // Bind each possible offset
+ for (size_t i = 0; i < 8; ++i)
+ {
+ glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, stride);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
+ }
+
+ // Try to bind larger range
+ for (size_t i = 0; i < 7; ++i)
+ {
+ glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, 2 * stride);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
+ }
+
+ // Try to bind even larger range
+ for (size_t i = 0; i < 5; ++i)
+ {
+ glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, 4 * stride);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
+ }
+}
+
+// Tests that active uniforms have the right names.
+TEST_P(UniformBufferTest, ActiveUniformNames)
+{
+ const std::string &vertexShaderSource =
+ "#version 300 es\n"
+ "in vec2 position;\n"
+ "out vec2 v;\n"
+ "uniform blockName1 {\n"
+ " float f1;\n"
+ "} instanceName1;\n"
+ "uniform blockName2 {\n"
+ " float f2;\n"
+ "} instanceName2[1];\n"
+ "void main() {\n"
+ " v = vec2(instanceName1.f1, instanceName2[0].f2);\n"
+ " gl_Position = vec4(position, 0, 1);\n"
+ "}";
+
+ const std::string &fragmentShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "in vec2 v;\n"
+ "out vec4 color;\n"
+ "void main() {\n"
+ " color = vec4(v, 0, 1);\n"
+ "}";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ ASSERT_NE(0u, program);
+
+ GLint activeUniformBlocks;
+ glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &activeUniformBlocks);
+ ASSERT_EQ(2, activeUniformBlocks);
+
+ GLint maxLength;
+ GLsizei length;
+ glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxLength);
+ std::vector<GLchar> strBlockNameBuffer(maxLength + 1, 0);
+ glGetActiveUniformBlockName(program, 0, maxLength, &length, &strBlockNameBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ("blockName1", std::string(&strBlockNameBuffer[0]));
+
+ glGetActiveUniformBlockName(program, 1, maxLength, &length, &strBlockNameBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ("blockName2[0]", std::string(&strBlockNameBuffer[0]));
+
+ GLint activeUniforms;
+ glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniforms);
+
+ ASSERT_EQ(2, activeUniforms);
+
+ GLint size;
+ GLenum type;
+ glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
+ std::vector<GLchar> strUniformNameBuffer(maxLength + 1, 0);
+ glGetActiveUniform(program, 0, maxLength, &length, &size, &type, &strUniformNameBuffer[0]);
+
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(1, size);
+ EXPECT_GLENUM_EQ(GL_FLOAT, type);
+ EXPECT_EQ("blockName1.f1", std::string(&strUniformNameBuffer[0]));
+
+ glGetActiveUniform(program, 1, maxLength, &length, &size, &type, &strUniformNameBuffer[0]);
+
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(1, size);
+ EXPECT_GLENUM_EQ(GL_FLOAT, type);
+ EXPECT_EQ("blockName2.f2", std::string(&strUniformNameBuffer[0]));
+}
+
+// Tests active uniforms and blocks when the layout is std140, shared and packed.
+TEST_P(UniformBufferTest, ActiveUniformNumberAndName)
+{
+ // TODO(Jiajia): Figure out why this fails on Intel on Mac.
+ // This case can pass on Intel Mac-10.11/10.12. But it fails on Intel Mac-10.10.
+ if (IsIntel() && IsOSX())
+ {
+ std::cout << "Test skipped on Intel on Mac." << std::endl;
+ return;
+ }
+
+ // This case fails on all AMD platforms (Mac, Linux, Win).
+ // TODO(zmo): This actually passes on certain AMD cards, but we don't have
+ // a way to do device specific handling yet.
+ if (IsAMD())
+ {
+ std::cout << "Test skipped on AMD." << std::endl;
+ return;
+ }
+
+ const std::string &vertexShaderSource =
+ "#version 300 es\n"
+ "in vec2 position;\n"
+ "out float v;\n"
+ "struct S {\n"
+ " highp ivec3 a;\n"
+ " mediump ivec2 b[4];\n"
+ "};\n"
+ "layout(std140) uniform blockName0 {\n"
+ " S s0;\n"
+ " lowp vec2 v0;\n"
+ " S s1[2];\n"
+ " highp uint u0;\n"
+ "};\n"
+ "layout(std140) uniform blockName1 {\n"
+ " float f1;\n"
+ " bool b1;\n"
+ "} instanceName1;\n"
+ "layout(shared) uniform blockName2 {\n"
+ " float f2;\n"
+ "};\n"
+ "layout(packed) uniform blockName3 {\n"
+ " float f3;\n"
+ "};\n"
+ "void main() {\n"
+ " v = instanceName1.f1;\n"
+ " gl_Position = vec4(position, 0, 1);\n"
+ "}";
+
+ const std::string &fragmentShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "in float v;\n"
+ "out vec4 color;\n"
+ "void main() {\n"
+ " color = vec4(v, 0, 0, 1);\n"
+ "}";
+
+ ANGLE_GL_PROGRAM(program, vertexShaderSource, fragmentShaderSource);
+
+ // Note that the packed |blockName3| might (or might not) be optimized out.
+ GLint activeUniforms;
+ glGetProgramiv(program.get(), GL_ACTIVE_UNIFORMS, &activeUniforms);
+ EXPECT_GE(activeUniforms, 11);
+
+ GLint activeUniformBlocks;
+ glGetProgramiv(program.get(), GL_ACTIVE_UNIFORM_BLOCKS, &activeUniformBlocks);
+ EXPECT_GE(activeUniformBlocks, 3);
+
+ GLint maxLength, size;
+ GLenum type;
+ GLsizei length;
+ glGetProgramiv(program.get(), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
+ std::vector<GLchar> strBuffer(maxLength + 1, 0);
+
+ glGetActiveUniform(program.get(), 0, maxLength, &length, &size, &type, &strBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(1, size);
+ EXPECT_EQ("s0.a", std::string(&strBuffer[0]));
+
+ glGetActiveUniform(program.get(), 1, maxLength, &length, &size, &type, &strBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(4, size);
+ EXPECT_EQ("s0.b[0]", std::string(&strBuffer[0]));
+
+ glGetActiveUniform(program.get(), 2, maxLength, &length, &size, &type, &strBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(1, size);
+ EXPECT_EQ("v0", std::string(&strBuffer[0]));
+
+ glGetActiveUniform(program.get(), 3, maxLength, &length, &size, &type, &strBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(1, size);
+ EXPECT_EQ("s1[0].a", std::string(&strBuffer[0]));
+
+ glGetActiveUniform(program.get(), 4, maxLength, &length, &size, &type, &strBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(4, size);
+ EXPECT_EQ("s1[0].b[0]", std::string(&strBuffer[0]));
+
+ glGetActiveUniform(program.get(), 5, maxLength, &length, &size, &type, &strBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(1, size);
+ EXPECT_EQ("s1[1].a", std::string(&strBuffer[0]));
+
+ glGetActiveUniform(program.get(), 6, maxLength, &length, &size, &type, &strBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(4, size);
+ EXPECT_EQ("s1[1].b[0]", std::string(&strBuffer[0]));
+
+ glGetActiveUniform(program.get(), 7, maxLength, &length, &size, &type, &strBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(1, size);
+ EXPECT_EQ("u0", std::string(&strBuffer[0]));
+
+ glGetActiveUniform(program.get(), 8, maxLength, &length, &size, &type, &strBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(1, size);
+ EXPECT_EQ("blockName1.f1", std::string(&strBuffer[0]));
+
+ glGetActiveUniform(program.get(), 9, maxLength, &length, &size, &type, &strBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(1, size);
+ EXPECT_EQ("blockName1.b1", std::string(&strBuffer[0]));
+
+ glGetActiveUniform(program.get(), 10, maxLength, &length, &size, &type, &strBuffer[0]);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_EQ(1, size);
+ EXPECT_EQ("f2", std::string(&strBuffer[0]));
+}
+
+// Test that using a very large buffer to back a small uniform block works OK.
+TEST_P(UniformBufferTest, VeryLarge)
+{
+ glClear(GL_COLOR_BUFFER_BIT);
+ float floatData[4] = {0.5f, 0.75f, 0.25f, 1.0f};
+
+ GLsizei bigSize = 4096 * 64;
+ std::vector<GLubyte> zero(bigSize, 0);
+
+ glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
+ glBufferData(GL_UNIFORM_BUFFER, bigSize, zero.data(), GL_STATIC_DRAW);
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(float) * 4, floatData);
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
+
+ glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
+ drawQuad(mProgram, "position", 0.5f);
+
+ ASSERT_GL_NO_ERROR();
+ EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
+}
+
+// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
+ANGLE_INSTANTIATE_TEST(UniformBufferTest,
+ ES3_D3D11(),
+ ES3_D3D11_FL11_1(),
+ ES3_D3D11_FL11_1_REFERENCE(),
+ ES3_OPENGL(),
+ ES3_OPENGLES());
+
+} // namespace