| // |
| // 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/angle_test_configs.h" |
| #include "test_utils/angle_test_instantiate.h" |
| #include "test_utils/gl_raii.h" |
| #include "util/gles_loader_autogen.h" |
| #include "util/shader_utils.h" |
| |
| #include <array> |
| #include <cmath> |
| #include <sstream> |
| |
| using namespace angle; |
| |
| namespace |
| { |
| |
| class SimpleUniformTest : public ANGLETest<> |
| { |
| protected: |
| SimpleUniformTest() |
| { |
| setWindowWidth(128); |
| setWindowHeight(128); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| } |
| }; |
| |
| // Test that we can get and set a float uniform successfully. |
| TEST_P(SimpleUniformTest, FloatUniformStateQuery) |
| { |
| constexpr char kFragShader[] = R"(precision mediump float; |
| uniform float uniF; |
| void main() { |
| gl_FragColor = vec4(uniF, 0.0, 0.0, 0.0); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Zero(), kFragShader); |
| glUseProgram(program); |
| GLint uniformLocation = glGetUniformLocation(program, "uniF"); |
| ASSERT_NE(uniformLocation, -1); |
| |
| GLfloat expected = 1.02f; |
| glUniform1f(uniformLocation, expected); |
| |
| GLfloat f = 0.0f; |
| glGetUniformfv(program, uniformLocation, &f); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(f, expected); |
| } |
| |
| // Test that we can get and set an int uniform successfully. |
| TEST_P(SimpleUniformTest, IntUniformStateQuery) |
| { |
| constexpr char kFragShader[] = R"(uniform int uniI; |
| void main() { |
| gl_FragColor = vec4(uniI, 0.0, 0.0, 0.0); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Zero(), kFragShader); |
| glUseProgram(program); |
| |
| GLint uniformLocation = glGetUniformLocation(program, "uniI"); |
| ASSERT_NE(uniformLocation, -1); |
| |
| GLint expected = 4; |
| glUniform1i(uniformLocation, expected); |
| |
| GLint i = 0; |
| glGetUniformiv(program, uniformLocation, &i); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(i, expected); |
| } |
| |
| // Test that we can get and set a vec2 uniform successfully. |
| TEST_P(SimpleUniformTest, FloatVec2UniformStateQuery) |
| { |
| constexpr char kFragShader[] = R"(precision mediump float; |
| uniform vec2 uniVec2; |
| void main() { |
| gl_FragColor = vec4(uniVec2, 0.0, 0.0); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Zero(), kFragShader); |
| glUseProgram(program); |
| |
| GLint uniformLocation = glGetUniformLocation(program, "uniVec2"); |
| ASSERT_NE(uniformLocation, -1); |
| |
| std::vector<GLfloat> expected = {{1.0f, 0.5f}}; |
| glUniform2fv(uniformLocation, 1, expected.data()); |
| |
| std::vector<GLfloat> floats(2, 0); |
| glGetUniformfv(program, uniformLocation, floats.data()); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(floats, expected); |
| } |
| |
| // Test that we can get and set a vec3 uniform successfully. |
| TEST_P(SimpleUniformTest, FloatVec3UniformStateQuery) |
| { |
| constexpr char kFragShader[] = R"(precision mediump float; |
| uniform vec3 uniVec3; |
| void main() { |
| gl_FragColor = vec4(uniVec3, 0.0); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Zero(), kFragShader); |
| glUseProgram(program); |
| |
| GLint uniformLocation = glGetUniformLocation(program, "uniVec3"); |
| ASSERT_NE(uniformLocation, -1); |
| |
| std::vector<GLfloat> expected = {{1.0f, 0.5f, 0.2f}}; |
| glUniform3fv(uniformLocation, 1, expected.data()); |
| |
| std::vector<GLfloat> floats(3, 0); |
| glGetUniformfv(program, uniformLocation, floats.data()); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(floats, expected); |
| } |
| |
| // Test that we can get and set a vec4 uniform successfully. |
| TEST_P(SimpleUniformTest, FloatVec4UniformStateQuery) |
| { |
| constexpr char kFragShader[] = R"(precision mediump float; |
| uniform vec4 uniVec4; |
| void main() { |
| gl_FragColor = uniVec4; |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Zero(), kFragShader); |
| glUseProgram(program); |
| |
| GLint uniformLocation = glGetUniformLocation(program, "uniVec4"); |
| ASSERT_NE(uniformLocation, -1); |
| |
| std::vector<GLfloat> expected = {{1.0f, 0.5f, 0.2f, -0.8f}}; |
| glUniform4fv(uniformLocation, 1, expected.data()); |
| |
| std::vector<GLfloat> floats(4, 0); |
| glGetUniformfv(program, uniformLocation, floats.data()); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(floats, expected); |
| } |
| |
| // Test that we can get and set a 2x2 float Matrix uniform successfully. |
| TEST_P(SimpleUniformTest, FloatMatrix2UniformStateQuery) |
| { |
| constexpr char kFragShader[] = R"(precision mediump float; |
| uniform mat2 umat2; |
| void main() { |
| gl_FragColor = vec4(umat2); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Zero(), kFragShader); |
| glUseProgram(program); |
| |
| GLint uniformLocation = glGetUniformLocation(program, "umat2"); |
| ASSERT_NE(uniformLocation, -1); |
| |
| std::vector<GLfloat> expected = {{1.0f, 0.5f, 0.2f, -0.8f}}; |
| glUniformMatrix2fv(uniformLocation, 1, false, expected.data()); |
| |
| std::vector<GLfloat> floats(4, 0); |
| glGetUniformfv(program, uniformLocation, floats.data()); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(floats, expected); |
| } |
| |
| // Test that we can get and set a 3x3 float Matrix uniform successfully. |
| TEST_P(SimpleUniformTest, FloatMatrix3UniformStateQuery) |
| { |
| constexpr char kFragShader[] = R"(precision mediump float; |
| uniform mat3 umat3; |
| void main() { |
| gl_FragColor = vec4(umat3); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Zero(), kFragShader); |
| glUseProgram(program); |
| |
| GLint uniformLocation = glGetUniformLocation(program, "umat3"); |
| ASSERT_NE(uniformLocation, -1); |
| |
| std::vector<GLfloat> expected = {{1.0f, 0.5f, 0.2f, -0.8f, -0.2f, 0.1f, 0.1f, 0.2f, 0.7f}}; |
| glUniformMatrix3fv(uniformLocation, 1, false, expected.data()); |
| |
| std::vector<GLfloat> floats(9, 0); |
| glGetUniformfv(program, uniformLocation, floats.data()); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(floats, expected); |
| } |
| |
| // Test that we can get and set a 4x4 float Matrix uniform successfully. |
| TEST_P(SimpleUniformTest, FloatMatrix4UniformStateQuery) |
| { |
| constexpr char kFragShader[] = R"(precision mediump float; |
| uniform mat4 umat4; |
| void main() { |
| gl_FragColor = umat4 * vec4(1.0, 1.0, 1.0, 1.0); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Zero(), kFragShader); |
| glUseProgram(program); |
| |
| GLint uniformLocation = glGetUniformLocation(program, "umat4"); |
| ASSERT_NE(uniformLocation, -1); |
| |
| std::vector<GLfloat> expected = {{1.0f, 0.5f, 0.2f, -0.8f, -0.2f, 0.1f, 0.1f, 0.2f, 0.7f, 0.1f, |
| 0.7f, 0.1f, 0.7f, 0.1f, 0.7f, 0.1f}}; |
| glUniformMatrix4fv(uniformLocation, 1, false, expected.data()); |
| |
| std::vector<GLfloat> floats(16, 0); |
| glGetUniformfv(program, uniformLocation, floats.data()); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(floats, expected); |
| } |
| |
| // Test that we can get and set a float array of uniforms. |
| TEST_P(SimpleUniformTest, FloatArrayUniformStateQuery) |
| { |
| |
| constexpr char kFragShader[] = R"( |
| precision mediump float; |
| uniform float ufloats[4]; |
| void main() { |
| gl_FragColor = vec4(ufloats[0], ufloats[1], ufloats[2], ufloats[3]); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Zero(), kFragShader); |
| glUseProgram(program); |
| std::vector<GLfloat> expected = {{0.1f, 0.2f, 0.3f, 0.4f}}; |
| |
| for (size_t i = 0; i < expected.size(); i++) |
| { |
| std::string locationName = "ufloats[" + std::to_string(i) + "]"; |
| GLint uniformLocation = glGetUniformLocation(program, locationName.c_str()); |
| glUniform1f(uniformLocation, expected[i]); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_NE(uniformLocation, -1); |
| |
| GLfloat result = 0; |
| glGetUniformfv(program, uniformLocation, &result); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(result, expected[i]); |
| } |
| } |
| |
| // Test that we can get and set an array of matrices uniform. |
| TEST_P(SimpleUniformTest, ArrayOfMat3UniformStateQuery) |
| { |
| constexpr char kFragShader[] = R"( |
| precision mediump float; |
| uniform mat3 umatarray[2]; |
| void main() { |
| gl_FragColor = vec4(umatarray[1]); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Zero(), kFragShader); |
| glUseProgram(program); |
| std::vector<std::vector<GLfloat>> expected = { |
| {1.0f, 0.5f, 0.2f, -0.8f, -0.2f, 0.1f, 0.1f, 0.2f, 0.7f}, |
| {0.9f, 0.4f, 0.1f, -0.9f, -0.3f, 0.0f, 0.0f, 0.1f, 0.6f}}; |
| |
| for (size_t i = 0; i < expected.size(); i++) |
| { |
| std::string locationName = "umatarray[" + std::to_string(i) + "]"; |
| GLint uniformLocation = glGetUniformLocation(program, locationName.c_str()); |
| glUniformMatrix3fv(uniformLocation, 1, false, expected[i].data()); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_NE(uniformLocation, -1); |
| |
| std::vector<GLfloat> results(9, 0); |
| glGetUniformfv(program, uniformLocation, results.data()); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(results, expected[i]); |
| } |
| } |
| |
| // Test that we can get and set an int array of uniforms. |
| TEST_P(SimpleUniformTest, FloatIntUniformStateQuery) |
| { |
| |
| constexpr char kFragShader[] = R"( |
| precision mediump float; |
| uniform int uints[4]; |
| void main() { |
| gl_FragColor = vec4(uints[0], uints[1], uints[2], uints[3]); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Zero(), kFragShader); |
| glUseProgram(program); |
| std::vector<GLint> expected = {{1, 2, 3, 4}}; |
| |
| for (size_t i = 0; i < expected.size(); i++) |
| { |
| std::string locationName = "uints[" + std::to_string(i) + "]"; |
| GLint uniformLocation = glGetUniformLocation(program, locationName.c_str()); |
| glUniform1i(uniformLocation, expected[i]); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_NE(uniformLocation, -1); |
| |
| GLint result = 0; |
| glGetUniformiv(program, uniformLocation, &result); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(result, expected[i]); |
| } |
| } |
| |
| class BasicUniformUsageTest : public ANGLETest<> |
| { |
| protected: |
| BasicUniformUsageTest() |
| { |
| setWindowWidth(128); |
| setWindowHeight(128); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| } |
| |
| void testSetUp() override |
| { |
| |
| constexpr char kFS[] = R"( |
| precision mediump float; |
| uniform float uniF; |
| uniform int uniI; |
| uniform vec4 uniVec4; |
| void main() { |
| gl_FragColor = vec4(uniF + float(uniI)); |
| gl_FragColor += uniVec4; |
| })"; |
| mProgram = CompileProgram(essl1_shaders::vs::Simple(), kFS); |
| ASSERT_NE(mProgram, 0u); |
| |
| mUniformFLocation = glGetUniformLocation(mProgram, "uniF"); |
| ASSERT_NE(mUniformFLocation, -1); |
| |
| mUniformILocation = glGetUniformLocation(mProgram, "uniI"); |
| ASSERT_NE(mUniformILocation, -1); |
| |
| mUniformVec4Location = glGetUniformLocation(mProgram, "uniVec4"); |
| ASSERT_NE(mUniformVec4Location, -1); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| void testTearDown() override { glDeleteProgram(mProgram); } |
| |
| GLuint mProgram = 0; |
| GLint mUniformFLocation = -1; |
| GLint mUniformILocation = -1; |
| GLint mUniformVec4Location = -1; |
| }; |
| |
| // Tests that setting a float uniform with glUniform1f() is actually observable in the shader. |
| TEST_P(BasicUniformUsageTest, Float) |
| { |
| glUseProgram(mProgram); |
| |
| glUniform1f(mUniformFLocation, 1.0f); |
| glUniform1i(mUniformILocation, 0); |
| glUniform4f(mUniformVec4Location, 0.0f, 0.0f, 0.0f, 1.0f); |
| |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| } |
| |
| // Tests that setting an int uniform with glUniform1i() is actually observable in the shader. |
| TEST_P(BasicUniformUsageTest, Integer) |
| { |
| glUseProgram(mProgram); |
| |
| glUniform1f(mUniformFLocation, 0.0f); |
| glUniform1i(mUniformILocation, 1); |
| glUniform4f(mUniformVec4Location, 0.0f, 0.0f, 0.0f, 1.0f); |
| |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| } |
| |
| // Tests that setting a vec4 uniform with glUniform4f() is actually observable in the shader. |
| TEST_P(BasicUniformUsageTest, Vec4) |
| { |
| glUseProgram(mProgram); |
| |
| glUniform1f(mUniformFLocation, 0.0f); |
| glUniform1i(mUniformILocation, 0); |
| // green |
| glUniform4f(mUniformVec4Location, 0.0f, 1.0f, 0.0f, 1.0f); |
| |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| // Tests that setting a vec4 uniform with glUniform4f() is actually observable in the shader, across |
| // multiple draw calls, even without a glFlush() in between the draw calls. |
| TEST_P(BasicUniformUsageTest, Vec4MultipleDraws) |
| { |
| glUseProgram(mProgram); |
| |
| glUniform1f(mUniformFLocation, 0.0f); |
| glUniform1i(mUniformILocation, 0); |
| // green |
| glUniform4f(mUniformVec4Location, 0.0f, 1.0f, 0.0f, 1.0f); |
| |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // readPixels caused a flush, try red now |
| glUniform4f(mUniformVec4Location, 1.0f, 0.0f, 0.0f, 1.0f); |
| |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // green |
| glUniform4f(mUniformVec4Location, 0.0f, 1.0f, 0.0f, 1.0f); |
| // But only draw a quad half the size |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.0f, /*positionAttribXYScale=*/0.5f); |
| // Still red at (0,0) |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| // Green in the middle. |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green); |
| |
| // Now, do a similar thing but no flush in the middle. |
| // Draw the screen green: |
| glUniform4f(mUniformVec4Location, 0.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.0f); |
| // Draw the middle of the screen red: |
| glUniform4f(mUniformVec4Location, 1.0f, 0.0f, 0.0f, 1.0f); |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.0f, /*positionAttribXYScale=*/0.5f); |
| // Still green at (0,0) |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| // Red in the middle. |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red); |
| } |
| |
| // Named differently to instantiate on different backends. |
| using SimpleUniformUsageTest = SimpleUniformTest; |
| |
| // In std140, the member following a struct will need to be aligned to 16. This tests that backends |
| // like WGSL which take std140 buffers correctly align this member. |
| TEST_P(SimpleUniformUsageTest, NestedStructAlignedCorrectly) |
| { |
| constexpr char kFragShader[] = R"(precision mediump float; |
| struct NestedUniforms { |
| float x; |
| }; |
| struct Uniforms { |
| NestedUniforms a; |
| float b; |
| float c; |
| }; |
| uniform Uniforms unis; |
| void main() { |
| gl_FragColor = vec4(unis.a.x, unis.b, unis.c, 1.0); |
| })"; |
| |
| GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kFragShader); |
| ASSERT_NE(program, 0u); |
| glUseProgram(program); |
| GLint uniformAXLocation = glGetUniformLocation(program, "unis.a.x"); |
| ASSERT_NE(uniformAXLocation, -1); |
| GLint uniformBLocation = glGetUniformLocation(program, "unis.b"); |
| ASSERT_NE(uniformBLocation, -1); |
| GLint uniformCLocation = glGetUniformLocation(program, "unis.c"); |
| ASSERT_NE(uniformCLocation, -1); |
| |
| // Set to red |
| glUniform1f(uniformAXLocation, 1.0f); |
| glUniform1f(uniformBLocation, 0.0f); |
| glUniform1f(uniformCLocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Set to green |
| glUniform1f(uniformAXLocation, 0.0f); |
| glUniform1f(uniformBLocation, 1.0f); |
| glUniform1f(uniformCLocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Set to blue |
| glUniform1f(uniformAXLocation, 0.0f); |
| glUniform1f(uniformBLocation, 0.0f); |
| glUniform1f(uniformCLocation, 1.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| |
| glDeleteProgram(program); |
| } |
| |
| // Similarly to the above, tests that structs as array elements are aligned correctly, and nested |
| // structs that follow float members are aligned correctly. |
| TEST_P(SimpleUniformUsageTest, NestedStructAlignedCorrectly2) |
| { |
| constexpr char kFragShader[] = R"(precision mediump float; |
| struct NestedUniforms { |
| float x; |
| }; |
| struct Uniforms { |
| float b; |
| NestedUniforms nested; |
| float c; |
| NestedUniforms[2] arr; |
| float d; |
| }; |
| uniform Uniforms unis; |
| void main() { |
| gl_FragColor = vec4(unis.nested.x, unis.b, unis.c, 1.0); |
| gl_FragColor += vec4(unis.arr[0].x, unis.arr[1].x, unis.d, 1.0); |
| })"; |
| |
| GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kFragShader); |
| ASSERT_NE(program, 0u); |
| glUseProgram(program); |
| |
| GLint uniformNestedXLocation = glGetUniformLocation(program, "unis.nested.x"); |
| ASSERT_NE(uniformNestedXLocation, -1); |
| GLint uniformBLocation = glGetUniformLocation(program, "unis.b"); |
| ASSERT_NE(uniformBLocation, -1); |
| GLint uniformCLocation = glGetUniformLocation(program, "unis.c"); |
| ASSERT_NE(uniformCLocation, -1); |
| GLint uniformArr0Location = glGetUniformLocation(program, "unis.arr[0].x"); |
| ASSERT_NE(uniformArr0Location, -1); |
| GLint uniformArr1Location = glGetUniformLocation(program, "unis.arr[1].x"); |
| ASSERT_NE(uniformArr1Location, -1); |
| GLint uniformDLocation = glGetUniformLocation(program, "unis.d"); |
| ASSERT_NE(uniformDLocation, -1); |
| |
| // Init to 0 |
| glUniform1f(uniformArr0Location, 0.0f); |
| glUniform1f(uniformArr1Location, 0.0f); |
| glUniform1f(uniformDLocation, 0.0f); |
| |
| // Set to red |
| glUniform1f(uniformNestedXLocation, 1.0f); |
| glUniform1f(uniformBLocation, 0.0f); |
| glUniform1f(uniformCLocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Set to green |
| glUniform1f(uniformNestedXLocation, 0.0f); |
| glUniform1f(uniformBLocation, 1.0f); |
| glUniform1f(uniformCLocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Set to blue |
| glUniform1f(uniformNestedXLocation, 0.0f); |
| glUniform1f(uniformBLocation, 0.0f); |
| glUniform1f(uniformCLocation, 1.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| |
| // Zero out |
| glUniform1f(uniformNestedXLocation, 0.0f); |
| glUniform1f(uniformBLocation, 0.0f); |
| glUniform1f(uniformCLocation, 0.0f); |
| // Set to red |
| glUniform1f(uniformArr0Location, 1.0f); |
| glUniform1f(uniformArr1Location, 0.0f); |
| glUniform1f(uniformDLocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Set to green |
| glUniform1f(uniformArr0Location, 0.0f); |
| glUniform1f(uniformArr1Location, 1.0f); |
| glUniform1f(uniformDLocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Set to blue |
| glUniform1f(uniformArr0Location, 0.0f); |
| glUniform1f(uniformArr1Location, 0.0f); |
| glUniform1f(uniformDLocation, 1.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| |
| glDeleteProgram(program); |
| } |
| |
| // Tests that arrays in uniforms function corectly. In particular, WGSL requires arrays in uniforms |
| // to have a stride a multiple of 16, but some arrays (e.g. vec2[N] or float[N]) will not |
| // automatically have stride 16 and need special handling. |
| TEST_P(SimpleUniformUsageTest, ArraysInUniforms) |
| { |
| constexpr char kFragShader[] = R"( |
| precision mediump float; |
| struct NestedUniforms { |
| vec2 x[5]; |
| }; |
| struct Uniforms { |
| NestedUniforms a; |
| float b; |
| float c; |
| float[5] d; |
| float e; |
| vec3 f[7]; |
| }; |
| uniform Uniforms unis; |
| void main() { |
| gl_FragColor = vec4(unis.a.x[2].x, unis.d[1], unis.e, 1.0); |
| gl_FragColor += vec4(unis.f[2], 0.0); |
| })"; |
| |
| GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kFragShader); |
| ASSERT_NE(program, 0u); |
| glUseProgram(program); |
| |
| GLint uniformAXLocation = glGetUniformLocation(program, "unis.a.x[2]"); |
| ASSERT_NE(uniformAXLocation, -1); |
| GLint uniformDLocation = glGetUniformLocation(program, "unis.d[1]"); |
| ASSERT_NE(uniformDLocation, -1); |
| GLint uniformELocation = glGetUniformLocation(program, "unis.e"); |
| ASSERT_NE(uniformELocation, -1); |
| GLint uniformFLocation = glGetUniformLocation(program, "unis.f[2]"); |
| ASSERT_NE(uniformFLocation, -1); |
| |
| // Set to red |
| glUniform2f(uniformAXLocation, 1.0f, 0.0); |
| glUniform1f(uniformDLocation, 0.0f); |
| glUniform1f(uniformELocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Set to green |
| glUniform2f(uniformAXLocation, 0.0f, 0.0f); |
| glUniform1f(uniformDLocation, 1.0f); |
| glUniform1f(uniformELocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Set to blue |
| glUniform2f(uniformAXLocation, 0.0f, 0.0f); |
| glUniform1f(uniformDLocation, 0.0f); |
| glUniform1f(uniformELocation, 1.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| |
| // Set to red |
| glUniform1f(uniformELocation, 0.0f); |
| glUniform3f(uniformFLocation, 1.0f, 0.0f, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| glDeleteProgram(program); |
| } |
| |
| using SimpleUniformUsageTestES3 = SimpleUniformUsageTest; |
| |
| // Tests that making a copy of a struct of uniforms functions correctly. |
| TEST_P(SimpleUniformUsageTestES3, CopyOfUniformsWithArrays) |
| { |
| constexpr char kFragShader[] = R"(#version 300 es |
| precision mediump float; |
| struct NestedUniforms { |
| vec2 x[5]; |
| }; |
| struct Uniforms { |
| NestedUniforms a; |
| float b; |
| float c; |
| float[5] d; |
| float e; |
| vec3 f[7]; |
| }; |
| uniform Uniforms unis; |
| out vec4 fragColor; |
| void main() { |
| Uniforms copy = unis; |
| fragColor = vec4(copy.a.x[2].x, copy.d[1], copy.e, 1.0); |
| fragColor += vec4(copy.f[2], 0.0); |
| })"; |
| |
| GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFragShader); |
| ASSERT_NE(program, 0u); |
| glUseProgram(program); |
| |
| GLint uniformAXLocation = glGetUniformLocation(program, "unis.a.x[2]"); |
| ASSERT_NE(uniformAXLocation, -1); |
| GLint uniformDLocation = glGetUniformLocation(program, "unis.d[1]"); |
| ASSERT_NE(uniformDLocation, -1); |
| GLint uniformELocation = glGetUniformLocation(program, "unis.e"); |
| ASSERT_NE(uniformELocation, -1); |
| GLint uniformFLocation = glGetUniformLocation(program, "unis.f[2]"); |
| ASSERT_NE(uniformFLocation, -1); |
| |
| // Set to red |
| glUniform2f(uniformAXLocation, 1.0f, 0.0); |
| glUniform1f(uniformDLocation, 0.0f); |
| glUniform1f(uniformELocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Set to green |
| glUniform2f(uniformAXLocation, 0.0f, 0.0f); |
| glUniform1f(uniformDLocation, 1.0f); |
| glUniform1f(uniformELocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Set to blue |
| glUniform2f(uniformAXLocation, 0.0f, 0.0f); |
| glUniform1f(uniformDLocation, 0.0f); |
| glUniform1f(uniformELocation, 1.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| |
| // Set to red |
| glUniform1f(uniformELocation, 0.0f); |
| glUniform3f(uniformFLocation, 1.0f, 0.0f, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| glDeleteProgram(program); |
| } |
| |
| // Tests that making a copy of an array from a uniform functions correctly. |
| TEST_P(SimpleUniformUsageTestES3, CopyOfArrayInUniform) |
| { |
| constexpr char kFragShader[] = R"(#version 300 es |
| precision mediump float; |
| struct NestedUniforms { |
| vec2 x[5]; |
| }; |
| struct Uniforms { |
| NestedUniforms a; |
| float b; |
| float c; |
| float[5] d; |
| float[4] d2; |
| float e; |
| vec3 f[7]; |
| }; |
| uniform Uniforms unis; |
| out vec4 fragColor; |
| void main() { |
| float[5] dCopy = unis.d; |
| float[4] d2Copy = unis.d2; |
| fragColor = vec4(dCopy[1], d2Copy[0], 0.0, 1.0); |
| })"; |
| |
| GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFragShader); |
| ASSERT_NE(program, 0u); |
| glUseProgram(program); |
| |
| GLint uniformDLocation = glGetUniformLocation(program, "unis.d[1]"); |
| ASSERT_NE(uniformDLocation, -1); |
| GLint uniformD2Location = glGetUniformLocation(program, "unis.d2[0]"); |
| ASSERT_NE(uniformD2Location, -1); |
| |
| // Set to black |
| glUniform1f(uniformDLocation, 0.0f); |
| glUniform1f(uniformD2Location, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); |
| |
| // Set to red |
| glUniform1f(uniformDLocation, 1.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| glDeleteProgram(program); |
| } |
| |
| // Tests that ternaries function correctly when retrieving an array element from a uniform. |
| TEST_P(SimpleUniformUsageTestES3, TernarySelectAnArrayElement) |
| { |
| |
| // TODO(anglebug.com/42267100): should eventually have a test (for WGSL) where the array is |
| // select by the ternary, and then the element is selected (`(unis.a > 0.5 ? unis.b : |
| // unis.c)[1]`). It doesn't work right now because ternaries are implemented incorrectly in the |
| // translator (translated as select()). |
| constexpr char kFragShader[] = R"(#version 300 es |
| precision mediump float; |
| struct NestedUniforms { |
| vec2 x[5]; |
| }; |
| struct Uniforms { |
| float a; |
| float b[2]; |
| float c[2]; |
| }; |
| uniform Uniforms unis; |
| out vec4 fragColor; |
| void main() { |
| fragColor = vec4((unis.a > 0.5 ? unis.b[1] : unis.c[1]), |
| (unis.a > 0.5 ? unis.c[1] : unis.b[1]), |
| 0.0, 1.0); |
| })"; |
| |
| GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFragShader); |
| ASSERT_NE(program, 0u); |
| glUseProgram(program); |
| |
| GLint uniformALocation = glGetUniformLocation(program, "unis.a"); |
| ASSERT_NE(uniformALocation, -1); |
| GLint uniformBLocation = glGetUniformLocation(program, "unis.b[1]"); |
| ASSERT_NE(uniformBLocation, -1); |
| GLint uniformCLocation = glGetUniformLocation(program, "unis.c[1]"); |
| ASSERT_NE(uniformCLocation, -1); |
| |
| // Set to red |
| glUniform1f(uniformALocation, 1.0f); |
| glUniform1f(uniformBLocation, 1.0f); |
| glUniform1f(uniformCLocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Flip unis.a to set to green |
| glUniform1f(uniformALocation, 0.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Set to red by flipping unis.b[1] and unis.c[1]. |
| glUniform1f(uniformBLocation, 0.0f); |
| glUniform1f(uniformCLocation, 1.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Flip unis.a to set to green |
| glUniform1f(uniformALocation, 1.0f); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| glDeleteProgram(program); |
| } |
| |
| // Tests that a struct used in the uniform address space can also be used outside of the uniform |
| // address space. The WGSL translator changes the type signature of the struct which can cause |
| // problems assigning to fields. |
| TEST_P(SimpleUniformUsageTestES3, UseUniformStructOutsideOfUniformAddressSpace) |
| { |
| constexpr char kFragShader[] = R"(#version 300 es |
| precision mediump float; |
| struct NestedUniforms { |
| float x[3]; |
| }; |
| struct Uniforms { |
| NestedUniforms a; |
| float b; |
| float c; |
| float[5] d; |
| float e; |
| vec3 f[7]; |
| }; |
| uniform Uniforms unis; |
| out vec4 fragColor; |
| void main() { |
| NestedUniforms privUnis; |
| privUnis.x = float[3](1.0, 1.0, 1.0); |
| NestedUniforms privUnis2; |
| privUnis2.x = unis.a.x; |
| Uniforms privUnisWholeStruct; |
| privUnisWholeStruct = unis; |
| fragColor = vec4(privUnis.x[1], privUnis2.x[1], privUnisWholeStruct.a.x[1], 1.0); |
| })"; |
| |
| GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFragShader); |
| ASSERT_NE(program, 0u); |
| glUseProgram(program); |
| |
| GLint uniformAXLocation = glGetUniformLocation(program, "unis.a.x"); |
| ASSERT_NE(uniformAXLocation, -1); |
| |
| GLfloat x[3] = {0.0, 1.0, 0.0}; |
| |
| // Set to white |
| glUniform1fv(uniformAXLocation, 3, x); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| |
| glDeleteProgram(program); |
| } |
| |
| // Tests that matCx2 (matrix with C columns and 2 rows) functions correctly in a |
| // uniform. WGSL's matCx2 does not match std140 layout. |
| TEST_P(SimpleUniformUsageTestES3, MatCx2) |
| { |
| constexpr char kFragShader[] = R"(#version 300 es |
| precision mediump float; |
| struct Uniforms { |
| mat2 a; |
| mat3x2 b; |
| mat4x2 c; |
| |
| mat2[2] aArr; |
| mat3x2[2] bArr; |
| mat4x2[2] cArr; |
| }; |
| uniform Uniforms unis; |
| out vec4 fragColor; |
| void main() { |
| mat2 a = unis.a; |
| mat3x2 b = unis.b; |
| mat4x2 c = unis.c; |
| vec2 aMult = vec2(1.0, 1.0); |
| vec3 bMult = vec3(0.25, 0.25, 0.5); |
| vec4 cMult = vec4(0.25, 0.25, 0.25, 0.25); |
| |
| fragColor = vec4(a * aMult, 0.0, 1.0); |
| fragColor += vec4(b * bMult, 0.0, 1.0); |
| fragColor += vec4(c * cMult, 0.0, 1.0); |
| })"; |
| |
| GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFragShader); |
| ASSERT_NE(program, 0u); |
| glUseProgram(program); |
| |
| GLint uniformALocation = glGetUniformLocation(program, "unis.a"); |
| ASSERT_NE(uniformALocation, -1); |
| GLint uniformBLocation = glGetUniformLocation(program, "unis.b"); |
| ASSERT_NE(uniformBLocation, -1); |
| GLint uniformCLocation = glGetUniformLocation(program, "unis.c"); |
| ASSERT_NE(uniformCLocation, -1); |
| |
| GLfloat a[4] = {1.0, 0.0, 0.0, 1.0}; |
| GLfloat b[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; |
| GLfloat c[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; |
| |
| glUniformMatrix2fv(uniformALocation, 1, GL_FALSE, a); |
| glUniformMatrix3x2fv(uniformBLocation, 1, GL_FALSE, b); |
| glUniformMatrix4x2fv(uniformCLocation, 1, GL_FALSE, c); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); |
| |
| // reset a and test b |
| GLfloat a2[4] = {0.0, 0.0, 0.0, 0.0}; |
| GLfloat b2[6] = {1.0, 0.0, 1.0, 0.0, 1.0, 1.0}; |
| glUniformMatrix2fv(uniformALocation, 1, GL_FALSE, a2); |
| glUniformMatrix3x2fv(uniformBLocation, 1, GL_FALSE, b2); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255u, 127u, 0, 255u), 1.0); |
| |
| // reset a, b and test c |
| GLfloat a3[4] = {0.0, 0.0, 0.0, 0.0}; |
| GLfloat b3[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; |
| GLfloat c3[8] = {1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0}; |
| glUniformMatrix2fv(uniformALocation, 1, GL_FALSE, a3); |
| glUniformMatrix3x2fv(uniformBLocation, 1, GL_FALSE, b3); |
| glUniformMatrix4x2fv(uniformCLocation, 1, GL_FALSE, c3); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255u, 64u, 0, 255u), 1.0); |
| |
| glDeleteProgram(program); |
| } |
| |
| // Tests that matCx2 in an array in a uniform can be used in a shader. |
| TEST_P(SimpleUniformUsageTestES3, MatCx2InArray) |
| { |
| constexpr char kFragShader[] = R"(#version 300 es |
| precision mediump float; |
| struct Uniforms { |
| mat2[2] aArr; |
| mat3x2[2] bArr; |
| mat4x2[2] cArr; |
| }; |
| uniform Uniforms unis; |
| out vec4 fragColor; |
| void main() { |
| mat2[2] aArr = unis.aArr; |
| mat3x2[2] bArr = unis.bArr; |
| mat4x2[2] cArr = unis.cArr; |
| |
| vec2 aMult = vec2(1.0, 1.0); |
| vec3 bMult = vec3(0.25, 0.25, 0.5); |
| vec4 cMult = vec4(0.25, 0.25, 0.25, 0.25); |
| |
| fragColor = vec4(aArr[0] * aMult, 0.0, 1.0); |
| fragColor += vec4(bArr[0] * bMult, 0.0, 1.0); |
| fragColor += vec4(cArr[0] * cMult, 0.0, 1.0); |
| })"; |
| |
| GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFragShader); |
| ASSERT_NE(program, 0u); |
| glUseProgram(program); |
| |
| GLint uniformALocation = glGetUniformLocation(program, "unis.aArr[0]"); |
| ASSERT_NE(uniformALocation, -1); |
| GLint uniformBLocation = glGetUniformLocation(program, "unis.bArr[0]"); |
| ASSERT_NE(uniformBLocation, -1); |
| GLint uniformCLocation = glGetUniformLocation(program, "unis.cArr[0]"); |
| ASSERT_NE(uniformCLocation, -1); |
| |
| GLfloat a[4] = {1.0, 0.0, 0.0, 1.0}; |
| GLfloat b[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; |
| GLfloat c[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; |
| |
| glUniformMatrix2fv(uniformALocation, 1, GL_FALSE, a); |
| glUniformMatrix3x2fv(uniformBLocation, 1, GL_FALSE, b); |
| glUniformMatrix4x2fv(uniformCLocation, 1, GL_FALSE, c); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); |
| |
| // reset a and test b |
| GLfloat a2[4] = {0.0, 0.0, 0.0, 0.0}; |
| GLfloat b2[6] = {1.0, 0.0, 1.0, 0.0, 1.0, 1.0}; |
| glUniformMatrix2fv(uniformALocation, 1, GL_FALSE, a2); |
| glUniformMatrix3x2fv(uniformBLocation, 1, GL_FALSE, b2); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255u, 127u, 0, 255u), 1.0); |
| |
| // reset a, b and test c |
| GLfloat a3[4] = {0.0, 0.0, 0.0, 0.0}; |
| GLfloat b3[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; |
| GLfloat c3[8] = {1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0}; |
| glUniformMatrix2fv(uniformALocation, 1, GL_FALSE, a3); |
| glUniformMatrix3x2fv(uniformBLocation, 1, GL_FALSE, b3); |
| glUniformMatrix4x2fv(uniformCLocation, 1, GL_FALSE, c3); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255u, 64u, 0, 255u), 1.0); |
| |
| glDeleteProgram(program); |
| } |
| |
| // Tests that a uniform array containing matCx2 can be indexed into correctly. |
| // The WGSL translator includes some optimizations around this case.. |
| TEST_P(SimpleUniformUsageTestES3, MatCx2InArrayWithOptimization) |
| { |
| constexpr char kFragShader[] = R"(#version 300 es |
| precision mediump float; |
| struct Uniforms { |
| mat2[2] aArr; |
| mat3x2[2] bArr; |
| mat4x2[2] cArr; |
| }; |
| uniform Uniforms unis; |
| out vec4 fragColor; |
| void main() { |
| mat2 aIndexed = unis.aArr[1]; |
| mat3x2 bIndexed = unis.bArr[1]; |
| mat4x2 cIndexed = unis.cArr[1]; |
| |
| vec2 aMult = vec2(1.0, 1.0); |
| vec3 bMult = vec3(0.25, 0.25, 0.5); |
| vec4 cMult = vec4(0.25, 0.25, 0.25, 0.25); |
| |
| fragColor = vec4(aIndexed * aMult, 0.0, 1.0); |
| fragColor += vec4(bIndexed * bMult, 0.0, 1.0); |
| fragColor += vec4(cIndexed * cMult, 0.0, 1.0); |
| })"; |
| |
| GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFragShader); |
| ASSERT_NE(program, 0u); |
| glUseProgram(program); |
| |
| GLint uniformALocation = glGetUniformLocation(program, "unis.aArr[1]"); |
| ASSERT_NE(uniformALocation, -1); |
| GLint uniformBLocation = glGetUniformLocation(program, "unis.bArr[1]"); |
| ASSERT_NE(uniformBLocation, -1); |
| GLint uniformCLocation = glGetUniformLocation(program, "unis.cArr[1]"); |
| ASSERT_NE(uniformCLocation, -1); |
| |
| GLfloat a[4] = {1.0, 0.0, 0.0, 1.0}; |
| GLfloat b[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; |
| GLfloat c[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; |
| |
| glUniformMatrix2fv(uniformALocation, 1, GL_FALSE, a); |
| glUniformMatrix3x2fv(uniformBLocation, 1, GL_FALSE, b); |
| glUniformMatrix4x2fv(uniformCLocation, 1, GL_FALSE, c); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); |
| |
| // reset a and test b |
| GLfloat a2[4] = {0.0, 0.0, 0.0, 0.0}; |
| GLfloat b2[6] = {1.0, 0.0, 1.0, 0.0, 1.0, 1.0}; |
| glUniformMatrix2fv(uniformALocation, 1, GL_FALSE, a2); |
| glUniformMatrix3x2fv(uniformBLocation, 1, GL_FALSE, b2); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255u, 127u, 0, 255u), 1.0); |
| |
| // reset a, b and test c |
| GLfloat a3[4] = {0.0, 0.0, 0.0, 0.0}; |
| GLfloat b3[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; |
| GLfloat c3[8] = {1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0}; |
| glUniformMatrix2fv(uniformALocation, 1, GL_FALSE, a3); |
| glUniformMatrix3x2fv(uniformBLocation, 1, GL_FALSE, b3); |
| glUniformMatrix4x2fv(uniformCLocation, 1, GL_FALSE, c3); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255u, 64u, 0, 255u), 1.0); |
| |
| glDeleteProgram(program); |
| } |
| |
| // Tests that matCx2 can be used in a uniform at the same time an array of |
| // matCx2s is used in a uniform. (The WGSL translator had trouble with this) |
| TEST_P(SimpleUniformUsageTestES3, MatCx2InArrayAndOutOfArray) |
| { |
| constexpr char kFragShader[] = R"(#version 300 es |
| precision mediump float; |
| struct Uniforms { |
| mat2 a; |
| mat2[2] aArr; |
| mat2[3] aArr2; |
| }; |
| uniform Uniforms unis; |
| out vec4 fragColor; |
| void main() { |
| mat2 aIndexed = unis.aArr[1] + unis.a + unis.aArr2[1]; |
| |
| vec2 aMult = vec2(1.0, 1.0); |
| |
| fragColor = vec4(aIndexed * aMult, 0.0, 1.0); |
| })"; |
| |
| GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFragShader); |
| ASSERT_NE(program, 0u); |
| glUseProgram(program); |
| |
| GLint uniformALocation = glGetUniformLocation(program, "unis.a"); |
| ASSERT_NE(uniformALocation, -1); |
| GLint uniformAArrLocation = glGetUniformLocation(program, "unis.aArr[1]"); |
| ASSERT_NE(uniformAArrLocation, -1); |
| GLint uniformAArr2Location = glGetUniformLocation(program, "unis.aArr2[1]"); |
| ASSERT_NE(uniformAArr2Location, -1); |
| |
| GLfloat a[4] = {0.5, 0.0, 0.0, 0.5}; |
| GLfloat aArr[4] = {0.5, 0.0, 0.0, 0.5}; |
| GLfloat aArr2[4] = {0.0, 0.0, 0.0, 0.0}; |
| |
| glUniformMatrix2fv(uniformALocation, 1, GL_FALSE, a); |
| glUniformMatrix2fv(uniformAArrLocation, 1, GL_FALSE, aArr); |
| glUniformMatrix2fv(uniformAArr2Location, 1, GL_FALSE, aArr2); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); |
| |
| glDeleteProgram(program); |
| } |
| |
| class UniformTest : public ANGLETest<> |
| { |
| protected: |
| UniformTest() |
| { |
| setWindowWidth(128); |
| setWindowHeight(128); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| } |
| |
| void testSetUp() override |
| { |
| // TODO(anglebug.com/40096755): asserting with latest direct-to-Metal compiler |
| // changes. Must skip all tests explicitly. |
| // if (IsMetal()) |
| // return; |
| constexpr char kVS[] = "void main() { gl_Position = vec4(1); }"; |
| |
| constexpr char kFS[] = |
| "precision mediump float;\n" |
| "uniform float uniF;\n" |
| "uniform int uniI;\n" |
| "uniform bool uniB;\n" |
| "uniform bool uniBArr[4];\n" |
| "void main() {\n" |
| " gl_FragColor = vec4(uniF + float(uniI));\n" |
| " gl_FragColor += vec4(uniB ? 1.0 : 0.0);\n" |
| " gl_FragColor += vec4(uniBArr[0] ? 1.0 : 0.0);\n" |
| " gl_FragColor += vec4(uniBArr[1] ? 1.0 : 0.0);\n" |
| " gl_FragColor += vec4(uniBArr[2] ? 1.0 : 0.0);\n" |
| " gl_FragColor += vec4(uniBArr[3] ? 1.0 : 0.0);\n" |
| "}"; |
| |
| mProgram = CompileProgram(kVS, kFS); |
| ASSERT_NE(mProgram, 0u); |
| |
| mUniformFLocation = glGetUniformLocation(mProgram, "uniF"); |
| ASSERT_NE(mUniformFLocation, -1); |
| |
| mUniformILocation = glGetUniformLocation(mProgram, "uniI"); |
| ASSERT_NE(mUniformILocation, -1); |
| |
| mUniformBLocation = glGetUniformLocation(mProgram, "uniB"); |
| ASSERT_NE(mUniformBLocation, -1); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| void testTearDown() override { glDeleteProgram(mProgram); } |
| |
| GLuint mProgram = 0; |
| GLint mUniformFLocation = -1; |
| GLint mUniformILocation = -1; |
| GLint mUniformBLocation = -1; |
| }; |
| |
| TEST_P(UniformTest, GetUniformNoCurrentProgram) |
| { |
| |
| glUseProgram(mProgram); |
| glUniform1f(mUniformFLocation, 1.0f); |
| glUniform1i(mUniformILocation, 1); |
| glUseProgram(0); |
| |
| GLfloat f; |
| glGetnUniformfvEXT(mProgram, mUniformFLocation, 4, &f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_EQ(1.0f, f); |
| |
| glGetUniformfv(mProgram, mUniformFLocation, &f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_EQ(1.0f, f); |
| |
| GLint i; |
| glGetnUniformivEXT(mProgram, mUniformILocation, 4, &i); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_EQ(1, i); |
| |
| glGetUniformiv(mProgram, mUniformILocation, &i); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_EQ(1, i); |
| } |
| |
| TEST_P(UniformTest, UniformArrayLocations) |
| { |
| |
| constexpr char kVS[] = R"(precision mediump float; |
| uniform float uPosition[4]; |
| void main(void) |
| { |
| gl_Position = vec4(uPosition[0], uPosition[1], uPosition[2], uPosition[3]); |
| })"; |
| |
| constexpr char kFS[] = R"(precision mediump float; |
| uniform float uColor[4]; |
| void main(void) |
| { |
| gl_FragColor = vec4(uColor[0], uColor[1], uColor[2], uColor[3]); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| |
| // Array index zero should be equivalent to the un-indexed uniform |
| EXPECT_NE(-1, glGetUniformLocation(program, "uPosition")); |
| EXPECT_EQ(glGetUniformLocation(program, "uPosition"), |
| glGetUniformLocation(program, "uPosition[0]")); |
| |
| EXPECT_NE(-1, glGetUniformLocation(program, "uColor")); |
| EXPECT_EQ(glGetUniformLocation(program, "uColor"), glGetUniformLocation(program, "uColor[0]")); |
| |
| // All array uniform locations should be unique |
| GLint positionLocations[4] = { |
| glGetUniformLocation(program, "uPosition[0]"), |
| glGetUniformLocation(program, "uPosition[1]"), |
| glGetUniformLocation(program, "uPosition[2]"), |
| glGetUniformLocation(program, "uPosition[3]"), |
| }; |
| |
| GLint colorLocations[4] = { |
| glGetUniformLocation(program, "uColor[0]"), |
| glGetUniformLocation(program, "uColor[1]"), |
| glGetUniformLocation(program, "uColor[2]"), |
| glGetUniformLocation(program, "uColor[3]"), |
| }; |
| |
| for (size_t i = 0; i < 4; i++) |
| { |
| EXPECT_NE(-1, positionLocations[i]); |
| EXPECT_NE(-1, colorLocations[i]); |
| |
| for (size_t j = i + 1; j < 4; j++) |
| { |
| EXPECT_NE(positionLocations[i], positionLocations[j]); |
| EXPECT_NE(colorLocations[i], colorLocations[j]); |
| } |
| } |
| |
| glDeleteProgram(program); |
| } |
| |
| // Test that float to integer GetUniform rounds values correctly. |
| TEST_P(UniformTest, FloatUniformStateQuery) |
| { |
| |
| std::vector<double> inValues; |
| std::vector<GLfloat> expectedFValues; |
| std::vector<GLint> expectedIValues; |
| |
| double intMaxD = static_cast<double>(std::numeric_limits<GLint>::max()); |
| double intMinD = static_cast<double>(std::numeric_limits<GLint>::min()); |
| |
| // TODO(jmadill): Investigate rounding of .5 |
| inValues.push_back(-1.0); |
| inValues.push_back(-0.6); |
| // inValues.push_back(-0.5); // undefined behaviour? |
| inValues.push_back(-0.4); |
| inValues.push_back(0.0); |
| inValues.push_back(0.4); |
| // inValues.push_back(0.5); // undefined behaviour? |
| inValues.push_back(0.6); |
| inValues.push_back(1.0); |
| inValues.push_back(999999.2); |
| inValues.push_back(intMaxD * 2.0); |
| inValues.push_back(intMaxD + 1.0); |
| inValues.push_back(intMinD * 2.0); |
| inValues.push_back(intMinD - 1.0); |
| |
| for (double value : inValues) |
| { |
| expectedFValues.push_back(static_cast<GLfloat>(value)); |
| |
| double clampedValue = std::max(intMinD, std::min(intMaxD, value)); |
| double rounded = round(clampedValue); |
| expectedIValues.push_back(static_cast<GLint>(rounded)); |
| } |
| |
| glUseProgram(mProgram); |
| ASSERT_GL_NO_ERROR(); |
| |
| for (size_t index = 0; index < inValues.size(); ++index) |
| { |
| GLfloat inValue = static_cast<GLfloat>(inValues[index]); |
| GLfloat expectedValue = expectedFValues[index]; |
| |
| glUniform1f(mUniformFLocation, inValue); |
| GLfloat testValue; |
| glGetUniformfv(mProgram, mUniformFLocation, &testValue); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_EQ(expectedValue, testValue); |
| } |
| |
| for (size_t index = 0; index < inValues.size(); ++index) |
| { |
| GLfloat inValue = static_cast<GLfloat>(inValues[index]); |
| GLint expectedValue = expectedIValues[index]; |
| |
| glUniform1f(mUniformFLocation, inValue); |
| GLint testValue; |
| glGetUniformiv(mProgram, mUniformFLocation, &testValue); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_EQ(expectedValue, testValue); |
| } |
| } |
| |
| // Test that integer to float GetUniform rounds values correctly. |
| TEST_P(UniformTest, IntUniformStateQuery) |
| { |
| // Qualcomm seems to have a bug where integer uniforms are internally stored as float, and |
| // large values are rounded to the nearest float representation of an integer. |
| // TODO(jmadill): Lift this suppression when/if the bug is fixed. |
| ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES()); |
| |
| std::vector<GLint> inValues; |
| std::vector<GLint> expectedIValues; |
| std::vector<GLfloat> expectedFValues; |
| |
| GLint intMax = std::numeric_limits<GLint>::max(); |
| GLint intMin = std::numeric_limits<GLint>::min(); |
| |
| inValues.push_back(-1); |
| inValues.push_back(0); |
| inValues.push_back(1); |
| inValues.push_back(999999); |
| inValues.push_back(intMax); |
| inValues.push_back(intMax - 1); |
| inValues.push_back(intMin); |
| inValues.push_back(intMin + 1); |
| |
| for (GLint value : inValues) |
| { |
| expectedIValues.push_back(value); |
| expectedFValues.push_back(static_cast<GLfloat>(value)); |
| } |
| |
| glUseProgram(mProgram); |
| ASSERT_GL_NO_ERROR(); |
| |
| for (size_t index = 0; index < inValues.size(); ++index) |
| { |
| GLint inValue = inValues[index]; |
| GLint expectedValue = expectedIValues[index]; |
| |
| glUniform1i(mUniformILocation, inValue); |
| GLint testValue = 1234567; |
| glGetUniformiv(mProgram, mUniformILocation, &testValue); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_EQ(expectedValue, testValue) << " with glGetUniformiv"; |
| } |
| |
| for (size_t index = 0; index < inValues.size(); ++index) |
| { |
| GLint inValue = inValues[index]; |
| GLfloat expectedValue = expectedFValues[index]; |
| |
| glUniform1i(mUniformILocation, inValue); |
| GLfloat testValue = 124567.0; |
| glGetUniformfv(mProgram, mUniformILocation, &testValue); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_EQ(expectedValue, testValue) << " with glGetUniformfv"; |
| } |
| } |
| |
| // Test that queries of boolean uniforms round correctly. |
| TEST_P(UniformTest, BooleanUniformStateQuery) |
| { |
| |
| glUseProgram(mProgram); |
| GLint intValue = 0; |
| GLfloat floatValue = 0.0f; |
| |
| // Calling Uniform1i |
| glUniform1i(mUniformBLocation, GL_FALSE); |
| |
| glGetUniformiv(mProgram, mUniformBLocation, &intValue); |
| EXPECT_EQ(0, intValue); |
| |
| glGetUniformfv(mProgram, mUniformBLocation, &floatValue); |
| EXPECT_EQ(0.0f, floatValue); |
| |
| glUniform1i(mUniformBLocation, GL_TRUE); |
| |
| glGetUniformiv(mProgram, mUniformBLocation, &intValue); |
| EXPECT_EQ(1, intValue); |
| |
| glGetUniformfv(mProgram, mUniformBLocation, &floatValue); |
| EXPECT_EQ(1.0f, floatValue); |
| |
| // Calling Uniform1f |
| glUniform1f(mUniformBLocation, 0.0f); |
| |
| glGetUniformiv(mProgram, mUniformBLocation, &intValue); |
| EXPECT_EQ(0, intValue); |
| |
| glGetUniformfv(mProgram, mUniformBLocation, &floatValue); |
| EXPECT_EQ(0.0f, floatValue); |
| |
| glUniform1f(mUniformBLocation, 1.0f); |
| |
| glGetUniformiv(mProgram, mUniformBLocation, &intValue); |
| EXPECT_EQ(1, intValue); |
| |
| glGetUniformfv(mProgram, mUniformBLocation, &floatValue); |
| EXPECT_EQ(1.0f, floatValue); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test queries for arrays of boolean uniforms. |
| TEST_P(UniformTest, BooleanArrayUniformStateQuery) |
| { |
| |
| glUseProgram(mProgram); |
| GLint boolValuesi[4] = {0, 1, 0, 1}; |
| GLfloat boolValuesf[4] = {0, 1, 0, 1}; |
| |
| GLint locations[4] = { |
| glGetUniformLocation(mProgram, "uniBArr"), |
| glGetUniformLocation(mProgram, "uniBArr[1]"), |
| glGetUniformLocation(mProgram, "uniBArr[2]"), |
| glGetUniformLocation(mProgram, "uniBArr[3]"), |
| }; |
| |
| for (int i = 0; i < 4; ++i) |
| { |
| ASSERT_NE(-1, locations[i]) << " with i=" << i; |
| } |
| |
| // Calling Uniform1iv |
| glUniform1iv(locations[0], 4, boolValuesi); |
| |
| for (unsigned int idx = 0; idx < 4; ++idx) |
| { |
| int value = -1; |
| glGetUniformiv(mProgram, locations[idx], &value); |
| EXPECT_EQ(boolValuesi[idx], value) << " with Uniform1iv/GetUniformiv at " << idx; |
| } |
| |
| for (unsigned int idx = 0; idx < 4; ++idx) |
| { |
| float value = -1.0f; |
| glGetUniformfv(mProgram, locations[idx], &value); |
| EXPECT_EQ(boolValuesf[idx], value) << " with Uniform1iv/GetUniformfv at " << idx; |
| } |
| |
| // Calling Uniform1fv |
| glUniform1fv(locations[0], 4, boolValuesf); |
| |
| for (unsigned int idx = 0; idx < 4; ++idx) |
| { |
| int value = -1; |
| glGetUniformiv(mProgram, locations[idx], &value); |
| EXPECT_EQ(boolValuesi[idx], value) << " with Uniform1fv/GetUniformiv at " << idx; |
| } |
| |
| for (unsigned int idx = 0; idx < 4; ++idx) |
| { |
| float value = -1.0f; |
| glGetUniformfv(mProgram, locations[idx], &value); |
| EXPECT_EQ(boolValuesf[idx], value) << " with Uniform1fv/GetUniformfv at " << idx; |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| class UniformTestES3 : public ANGLETest<> |
| { |
| protected: |
| UniformTestES3() : mProgram(0) {} |
| |
| void testTearDown() override |
| { |
| if (mProgram != 0) |
| { |
| glDeleteProgram(mProgram); |
| mProgram = 0; |
| } |
| } |
| |
| GLuint mProgram; |
| }; |
| |
| // Test that we can get and set an array of matrices uniform. |
| TEST_P(UniformTestES3, MatrixArrayUniformStateQuery) |
| { |
| constexpr char kFragShader[] = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "uniform mat3x4 uniMat3x4[5];\n" |
| "out vec4 fragColor;\n" |
| "void main() {\n" |
| " fragColor = vec4(uniMat3x4[0]);\n" |
| " fragColor += vec4(uniMat3x4[1]);\n" |
| " fragColor += vec4(uniMat3x4[2]);\n" |
| " fragColor += vec4(uniMat3x4[3]);\n" |
| " fragColor += vec4(uniMat3x4[4]);\n" |
| "}\n"; |
| constexpr unsigned int kArrayCount = 5; |
| constexpr unsigned int kMatrixStride = 3 * 4; |
| |
| mProgram = CompileProgram(essl3_shaders::vs::Zero(), kFragShader); |
| ASSERT_NE(mProgram, 0u); |
| |
| glUseProgram(mProgram); |
| GLfloat expected[kArrayCount][kMatrixStride] = { |
| {0.6f, -0.4f, 0.6f, 0.9f, -0.6f, 0.3f, -0.3f, -0.1f, -0.4f, -0.3f, 0.7f, 0.1f}, |
| {-0.4f, -0.4f, -0.5f, -0.7f, 0.1f, -0.5f, 0.0f, -0.9f, -0.4f, 0.8f, -0.6f, 0.9f}, |
| {0.4f, 0.1f, -0.9f, 1.0f, -0.8f, 0.4f, -0.2f, 0.4f, -0.0f, 0.2f, 0.9f, -0.3f}, |
| {0.5f, 0.7f, -0.0f, 1.0f, 0.7f, 0.7f, 0.7f, -0.7f, -0.8f, 0.6f, 0.5f, -0.2f}, |
| {-1.0f, 0.8f, 1.0f, -0.4f, 0.7f, 0.5f, 0.5f, 0.8f, 0.6f, 0.1f, 0.4f, -0.9f}}; |
| |
| GLint baseLocation = glGetUniformLocation(mProgram, "uniMat3x4"); |
| ASSERT_NE(-1, baseLocation); |
| |
| glUniformMatrix3x4fv(baseLocation, kArrayCount, GL_FALSE, &expected[0][0]); |
| |
| for (size_t i = 0; i < kArrayCount; i++) |
| { |
| std::stringstream nameStr; |
| nameStr << "uniMat3x4[" << i << "]"; |
| std::string name = nameStr.str(); |
| GLint location = glGetUniformLocation(mProgram, name.c_str()); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_NE(-1, location); |
| |
| std::vector<GLfloat> results(12, 0); |
| glGetUniformfv(mProgram, location, results.data()); |
| ASSERT_GL_NO_ERROR(); |
| |
| for (size_t compIdx = 0; compIdx < kMatrixStride; compIdx++) |
| { |
| EXPECT_EQ(results[compIdx], expected[i][compIdx]); |
| } |
| } |
| } |
| |
| // Test queries for transposed arrays of non-square matrix uniforms. |
| TEST_P(UniformTestES3, TransposedMatrixArrayUniformStateQuery) |
| { |
| constexpr char kFS[] = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "uniform mat3x2 uniMat3x2[5];\n" |
| "out vec4 color;\n" |
| "void main() {\n" |
| " color = vec4(uniMat3x2[0][0][0]);\n" |
| " color += vec4(uniMat3x2[1][0][0]);\n" |
| " color += vec4(uniMat3x2[2][0][0]);\n" |
| " color += vec4(uniMat3x2[3][0][0]);\n" |
| " color += vec4(uniMat3x2[4][0][0]);\n" |
| "}"; |
| |
| mProgram = CompileProgram(essl3_shaders::vs::Zero(), kFS); |
| ASSERT_NE(mProgram, 0u); |
| |
| glUseProgram(mProgram); |
| |
| std::vector<GLfloat> transposedValues; |
| |
| for (size_t arrayElement = 0; arrayElement < 5; ++arrayElement) |
| { |
| transposedValues.push_back(1.0f + arrayElement); |
| transposedValues.push_back(3.0f + arrayElement); |
| transposedValues.push_back(5.0f + arrayElement); |
| transposedValues.push_back(2.0f + arrayElement); |
| transposedValues.push_back(4.0f + arrayElement); |
| transposedValues.push_back(6.0f + arrayElement); |
| } |
| |
| // Setting as a clump |
| GLint baseLocation = glGetUniformLocation(mProgram, "uniMat3x2"); |
| ASSERT_NE(-1, baseLocation); |
| |
| glUniformMatrix3x2fv(baseLocation, 5, GL_TRUE, &transposedValues[0]); |
| |
| for (size_t arrayElement = 0; arrayElement < 5; ++arrayElement) |
| { |
| std::stringstream nameStr; |
| nameStr << "uniMat3x2[" << arrayElement << "]"; |
| std::string name = nameStr.str(); |
| GLint location = glGetUniformLocation(mProgram, name.c_str()); |
| ASSERT_NE(-1, location); |
| |
| std::vector<GLfloat> sequentialValues(6, 0); |
| glGetUniformfv(mProgram, location, &sequentialValues[0]); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| for (size_t comp = 0; comp < 6; ++comp) |
| { |
| EXPECT_EQ(static_cast<GLfloat>(comp + 1 + arrayElement), sequentialValues[comp]); |
| } |
| } |
| } |
| |
| // Check that trying setting too many elements of an array doesn't overflow |
| TEST_P(UniformTestES3, OverflowArray) |
| { |
| |
| constexpr char kFS[] = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "uniform float uniF[5];\n" |
| "uniform mat3x2 uniMat3x2[5];\n" |
| "out vec4 color;\n" |
| "void main() {\n" |
| " color = vec4(uniMat3x2[0][0][0] + uniF[0]);\n" |
| " color = vec4(uniMat3x2[1][0][0] + uniF[1]);\n" |
| " color = vec4(uniMat3x2[2][0][0] + uniF[2]);\n" |
| " color = vec4(uniMat3x2[3][0][0] + uniF[3]);\n" |
| " color = vec4(uniMat3x2[4][0][0] + uniF[4]);\n" |
| "}"; |
| |
| mProgram = CompileProgram(essl3_shaders::vs::Zero(), kFS); |
| ASSERT_NE(mProgram, 0u); |
| |
| glUseProgram(mProgram); |
| |
| const size_t kOverflowSize = 10000; |
| std::vector<GLfloat> values(10000 * 6); |
| |
| // Setting as a clump |
| GLint floatLocation = glGetUniformLocation(mProgram, "uniF"); |
| ASSERT_NE(-1, floatLocation); |
| GLint matLocation = glGetUniformLocation(mProgram, "uniMat3x2"); |
| ASSERT_NE(-1, matLocation); |
| |
| // Set too many float uniforms |
| glUniform1fv(floatLocation, kOverflowSize, &values[0]); |
| |
| // Set too many matrix uniforms, transposed or not |
| glUniformMatrix3x2fv(matLocation, kOverflowSize, GL_FALSE, &values[0]); |
| glUniformMatrix3x2fv(matLocation, kOverflowSize, GL_TRUE, &values[0]); |
| |
| // Same checks but with offsets |
| GLint floatLocationOffset = glGetUniformLocation(mProgram, "uniF[3]"); |
| ASSERT_NE(-1, floatLocationOffset); |
| GLint matLocationOffset = glGetUniformLocation(mProgram, "uniMat3x2[3]"); |
| ASSERT_NE(-1, matLocationOffset); |
| |
| glUniform1fv(floatLocationOffset, kOverflowSize, &values[0]); |
| glUniformMatrix3x2fv(matLocationOffset, kOverflowSize, GL_FALSE, &values[0]); |
| glUniformMatrix3x2fv(matLocationOffset, kOverflowSize, GL_TRUE, &values[0]); |
| } |
| |
| // Check setting a sampler uniform |
| TEST_P(UniformTest, Sampler) |
| { |
| constexpr char kVS[] = |
| "uniform sampler2D tex2D;\n" |
| "void main() {\n" |
| " gl_Position = vec4(0, 0, 0, 1);\n" |
| "}"; |
| |
| constexpr char kFS[] = |
| "precision mediump float;\n" |
| "uniform sampler2D tex2D;\n" |
| "void main() {\n" |
| " gl_FragColor = texture2D(tex2D, vec2(0, 0));\n" |
| "}"; |
| |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| |
| GLint location = glGetUniformLocation(program, "tex2D"); |
| ASSERT_NE(-1, location); |
| |
| const GLint sampler[] = {0, 0, 0, 0}; |
| |
| // before UseProgram |
| glUniform1i(location, sampler[0]); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| glUseProgram(program); |
| |
| // Uniform1i |
| glUniform1i(location, sampler[0]); |
| glUniform1iv(location, 1, sampler); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Uniform{234}i |
| glUniform2i(location, sampler[0], sampler[0]); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform3i(location, sampler[0], sampler[0], sampler[0]); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform4i(location, sampler[0], sampler[0], sampler[0], sampler[0]); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform2iv(location, 1, sampler); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform3iv(location, 1, sampler); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform4iv(location, 1, sampler); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // Uniform{1234}f |
| const GLfloat f[] = {0, 0, 0, 0}; |
| glUniform1f(location, f[0]); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform2f(location, f[0], f[0]); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform3f(location, f[0], f[0], f[0]); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform4f(location, f[0], f[0], f[0], f[0]); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform1fv(location, 1, f); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform2fv(location, 1, f); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform3fv(location, 1, f); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glUniform4fv(location, 1, f); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // < 0 or >= max |
| GLint tooHigh; |
| glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &tooHigh); |
| constexpr GLint tooLow[] = {-1}; |
| glUniform1i(location, tooLow[0]); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| glUniform1iv(location, 1, tooLow); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| glUniform1i(location, tooHigh); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| glUniform1iv(location, 1, &tooHigh); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| } |
| |
| // Check that sampler uniforms only show up one time in the list |
| TEST_P(UniformTest, SamplerUniformsAppearOnce) |
| { |
| int maxVertexTextureImageUnits = 0; |
| glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextureImageUnits); |
| |
| // Renderer doesn't support vertex texture fetch, skipping test. |
| ANGLE_SKIP_TEST_IF(!maxVertexTextureImageUnits); |
| |
| constexpr char kVS[] = |
| "attribute vec2 position;\n" |
| "uniform sampler2D tex2D;\n" |
| "varying vec4 color;\n" |
| "void main() {\n" |
| " gl_Position = vec4(position, 0, 1);\n" |
| " color = texture2D(tex2D, vec2(0));\n" |
| "}"; |
| |
| constexpr char kFS[] = |
| "precision mediump float;\n" |
| "varying vec4 color;\n" |
| "uniform sampler2D tex2D;\n" |
| "void main() {\n" |
| " gl_FragColor = texture2D(tex2D, vec2(0)) + color;\n" |
| "}"; |
| |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| |
| GLint activeUniformsCount = 0; |
| glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniformsCount); |
| ASSERT_EQ(1, activeUniformsCount); |
| |
| GLint size = 0; |
| GLenum type = GL_NONE; |
| GLchar name[120] = {0}; |
| glGetActiveUniform(program, 0, 100, nullptr, &size, &type, name); |
| EXPECT_EQ(1, size); |
| EXPECT_GLENUM_EQ(GL_SAMPLER_2D, type); |
| EXPECT_STREQ("tex2D", name); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glDeleteProgram(program); |
| } |
| |
| template <typename T, typename GetUniformV> |
| void CheckOneElement(GetUniformV getUniformv, |
| GLuint program, |
| const std::string &name, |
| int components, |
| T canary) |
| { |
| // The buffer getting the results has three chunks |
| // - A chunk to see underflows |
| // - A chunk that will hold the result |
| // - A chunk to see overflows for when components = kChunkSize |
| static const size_t kChunkSize = 4; |
| std::array<T, 3 * kChunkSize> buffer; |
| buffer.fill(canary); |
| |
| GLint location = glGetUniformLocation(program, name.c_str()); |
| ASSERT_NE(location, -1); |
| |
| getUniformv(program, location, &buffer[kChunkSize]); |
| for (size_t i = 0; i < kChunkSize; i++) |
| { |
| ASSERT_EQ(canary, buffer[i]); |
| } |
| for (size_t i = kChunkSize + components; i < buffer.size(); i++) |
| { |
| ASSERT_EQ(canary, buffer[i]); |
| } |
| } |
| |
| // Check that getting an element array doesn't return the whole array. |
| TEST_P(UniformTestES3, ReturnsOnlyOneArrayElement) |
| { |
| |
| static const size_t kArraySize = 4; |
| struct UniformArrayInfo |
| { |
| UniformArrayInfo(std::string type, std::string name, int components) |
| : type(type), name(name), components(components) |
| {} |
| std::string type; |
| std::string name; |
| int components; |
| }; |
| |
| // Check for various number of components and types |
| std::vector<UniformArrayInfo> uniformArrays; |
| uniformArrays.emplace_back("bool", "uBool", 1); |
| uniformArrays.emplace_back("vec2", "uFloat", 2); |
| uniformArrays.emplace_back("ivec3", "uInt", 3); |
| uniformArrays.emplace_back("uvec4", "uUint", 4); |
| |
| std::ostringstream uniformStream; |
| std::ostringstream additionStream; |
| for (const auto &array : uniformArrays) |
| { |
| uniformStream << "uniform " << array.type << " " << array.name << "[" |
| << ToString(kArraySize) << "];\n"; |
| |
| // We need to make use of the uniforms or they get compiled out. |
| for (int i = 0; i < 4; i++) |
| { |
| if (array.components == 1) |
| { |
| additionStream << " + float(" << array.name << "[" << i << "])"; |
| } |
| else |
| { |
| for (int component = 0; component < array.components; component++) |
| { |
| additionStream << " + float(" << array.name << "[" << i << "][" << component |
| << "])"; |
| } |
| } |
| } |
| } |
| |
| const std::string vertexShader = "#version 300 es\n" + uniformStream.str() + |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(1.0" + |
| additionStream.str() + |
| ");\n" |
| "}"; |
| |
| constexpr char kFS[] = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 color;\n" |
| "void main ()\n" |
| "{\n" |
| " color = vec4(1, 0, 0, 1);\n" |
| "}"; |
| |
| mProgram = CompileProgram(vertexShader.c_str(), kFS); |
| ASSERT_NE(0u, mProgram); |
| |
| glUseProgram(mProgram); |
| |
| for (const auto &uniformArray : uniformArrays) |
| { |
| for (size_t index = 0; index < kArraySize; index++) |
| { |
| std::string strIndex = "[" + ToString(index) + "]"; |
| // Check all the different glGetUniformv functions |
| CheckOneElement<float>(glGetUniformfv, mProgram, uniformArray.name + strIndex, |
| uniformArray.components, 42.4242f); |
| CheckOneElement<int>(glGetUniformiv, mProgram, uniformArray.name + strIndex, |
| uniformArray.components, 0x7BADBED5); |
| CheckOneElement<unsigned int>(glGetUniformuiv, mProgram, uniformArray.name + strIndex, |
| uniformArray.components, 0xDEADBEEF); |
| } |
| } |
| } |
| |
| // This test reproduces a regression when Intel windows driver upgrades to 4944. In some situation, |
| // when a boolean uniform with false value is used as the if and for condtions, the bug will be |
| // triggered. It seems that the shader doesn't get a right 'false' value from the uniform. |
| TEST_P(UniformTestES3, BooleanUniformAsIfAndForCondition) |
| { |
| const char kFragShader[] = |
| R"(#version 300 es |
| precision mediump float; |
| uniform bool u; |
| out vec4 result; |
| int sideEffectCounter; |
| |
| bool foo() { |
| ++sideEffectCounter; |
| return true; |
| } |
| |
| void main() { |
| sideEffectCounter = 0; |
| bool condition = u; |
| if (condition) |
| { |
| condition = foo(); |
| } |
| for(int iterations = 0; condition;) { |
| ++iterations; |
| if (iterations >= 10) { |
| break; |
| } |
| |
| if (condition) |
| { |
| condition = foo(); |
| } |
| } |
| |
| bool success = (!u && sideEffectCounter == 0); |
| result = (success) ? vec4(0, 1.0, 0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFragShader); |
| |
| glUseProgram(program); |
| |
| GLint uniformLocation = glGetUniformLocation(program, "u"); |
| ASSERT_NE(uniformLocation, -1); |
| |
| glUniform1i(uniformLocation, GL_FALSE); |
| |
| drawQuad(program, essl3_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| class UniformTestES31 : public ANGLETest<> |
| { |
| protected: |
| UniformTestES31() : mProgram(0) {} |
| |
| void testTearDown() override |
| { |
| if (mProgram != 0) |
| { |
| glDeleteProgram(mProgram); |
| mProgram = 0; |
| } |
| } |
| |
| GLuint mProgram; |
| }; |
| |
| // Test that uniform locations get set correctly for structure members. |
| // ESSL 3.10.4 section 4.4.3. |
| TEST_P(UniformTestES31, StructLocationLayoutQualifier) |
| { |
| constexpr char kFS[] = |
| "#version 310 es\n" |
| "out highp vec4 my_FragColor;\n" |
| "struct S\n" |
| "{\n" |
| " highp float f;\n" |
| " highp float f2;\n" |
| "};\n" |
| "uniform layout(location=12) S uS;\n" |
| "void main()\n" |
| "{\n" |
| " my_FragColor = vec4(uS.f, uS.f2, 0, 1);\n" |
| "}"; |
| |
| ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Zero(), kFS); |
| |
| EXPECT_EQ(12, glGetUniformLocation(program, "uS.f")); |
| EXPECT_EQ(13, glGetUniformLocation(program, "uS.f2")); |
| } |
| |
| // Set uniform location with a layout qualifier in the fragment shader. The same uniform exists in |
| // the vertex shader, but doesn't have a location specified there. |
| TEST_P(UniformTestES31, UniformLocationInFragmentShader) |
| { |
| constexpr char kVS[] = |
| "#version 310 es\n" |
| "uniform highp sampler2D tex2D;\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = texture(tex2D, vec2(0));\n" |
| "}"; |
| |
| constexpr char kFS[] = |
| "#version 310 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "uniform layout(location=12) highp sampler2D tex2D;\n" |
| "void main()\n" |
| "{\n" |
| " my_FragColor = texture(tex2D, vec2(0));\n" |
| "}"; |
| |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| |
| EXPECT_EQ(12, glGetUniformLocation(program, "tex2D")); |
| } |
| |
| // Test two unused uniforms that have the same location. |
| // ESSL 3.10.4 section 4.4.3: "No two default-block uniform variables in the program can have the |
| // same location, even if they are unused, otherwise a compiler or linker error will be generated." |
| TEST_P(UniformTestES31, UnusedUniformsConflictingLocation) |
| { |
| constexpr char kVS[] = |
| "#version 310 es\n" |
| "uniform layout(location=12) highp sampler2D texA;\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(0);\n" |
| "}"; |
| |
| constexpr char kFS[] = |
| "#version 310 es\n" |
| "out highp vec4 my_FragColor;\n" |
| "uniform layout(location=12) highp sampler2D texB;\n" |
| "void main()\n" |
| "{\n" |
| " my_FragColor = vec4(0);\n" |
| "}"; |
| |
| mProgram = CompileProgram(kVS, kFS); |
| EXPECT_EQ(0u, mProgram); |
| } |
| |
| // Test two unused uniforms that have overlapping locations once all array elements are taken into |
| // account. |
| // ESSL 3.10.4 section 4.4.3: "No two default-block uniform variables in the program can have the |
| // same location, even if they are unused, otherwise a compiler or linker error will be generated." |
| TEST_P(UniformTestES31, UnusedUniformArraysConflictingLocation) |
| { |
| constexpr char kVS[] = |
| "#version 310 es\n" |
| "uniform layout(location=11) highp vec4 uA[2];\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(0);\n" |
| "}"; |
| |
| constexpr char kFS[] = |
| "#version 310 es\n" |
| "out highp vec4 my_FragColor;\n" |
| "uniform layout(location=12) highp vec4 uB;\n" |
| "void main()\n" |
| "{\n" |
| " my_FragColor = vec4(0);\n" |
| "}"; |
| |
| mProgram = CompileProgram(kVS, kFS); |
| EXPECT_EQ(0u, mProgram); |
| } |
| |
| // Test a uniform struct containing a non-square matrix and a boolean. |
| // Minimal test case for a bug revealed by dEQP tests. |
| TEST_P(UniformTestES3, StructWithNonSquareMatrixAndBool) |
| { |
| constexpr char kFS[] = |
| "#version 300 es\n" |
| "precision highp float;\n" |
| "out highp vec4 my_color;\n" |
| "struct S\n" |
| "{\n" |
| " mat2x4 m;\n" |
| " bool b;\n" |
| "};\n" |
| "uniform S uni;\n" |
| "void main()\n" |
| "{\n" |
| " my_color = vec4(1.0);\n" |
| " if (!uni.b) { my_color.g = 0.0; }" |
| "}\n"; |
| |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); |
| |
| glUseProgram(program); |
| |
| GLint location = glGetUniformLocation(program, "uni.b"); |
| ASSERT_NE(-1, location); |
| glUniform1i(location, 1); |
| |
| drawQuad(program, essl3_shaders::PositionAttrib(), 0.0f); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| } |
| |
| // Test that matrix uniform upload is correct. |
| TEST_P(UniformTestES3, MatrixUniformUpload) |
| { |
| constexpr size_t kMinDims = 2; |
| constexpr size_t kMaxDims = 4; |
| |
| GLfloat matrixValues[kMaxDims * kMaxDims]; |
| |
| for (size_t i = 0; i < kMaxDims * kMaxDims; ++i) |
| { |
| matrixValues[i] = static_cast<GLfloat>(i); |
| } |
| |
| using UniformMatrixCxRfv = decltype(glUniformMatrix2fv); |
| UniformMatrixCxRfv uniformMatrixCxRfv[kMaxDims + 1][kMaxDims + 1] = { |
| {nullptr, nullptr, nullptr, nullptr, nullptr}, |
| {nullptr, nullptr, nullptr, nullptr, nullptr}, |
| {nullptr, nullptr, glUniformMatrix2fv, glUniformMatrix2x3fv, glUniformMatrix2x4fv}, |
| {nullptr, nullptr, glUniformMatrix3x2fv, glUniformMatrix3fv, glUniformMatrix3x4fv}, |
| {nullptr, nullptr, glUniformMatrix4x2fv, glUniformMatrix4x3fv, glUniformMatrix4fv}, |
| }; |
| |
| for (int transpose = 0; transpose < 2; ++transpose) |
| { |
| for (size_t cols = kMinDims; cols <= kMaxDims; ++cols) |
| { |
| for (size_t rows = kMinDims; rows <= kMaxDims; ++rows) |
| { |
| std::ostringstream shader; |
| shader << "#version 300 es\n" |
| "precision highp float;\n" |
| "out highp vec4 colorOut;\n" |
| "uniform mat" |
| << cols << 'x' << rows |
| << " unused;\n" |
| "uniform mat" |
| << cols << 'x' << rows |
| << " m;\n" |
| "void main()\n" |
| "{\n" |
| " bool isCorrect ="; |
| |
| for (size_t col = 0; col < cols; ++col) |
| { |
| for (size_t row = 0; row < rows; ++row) |
| { |
| size_t value; |
| if (!transpose) |
| { |
| // Matrix data is uploaded column-major. |
| value = col * rows + row; |
| } |
| else |
| { |
| // Matrix data is uploaded row-major. |
| value = row * cols + col; |
| } |
| |
| if (value != 0) |
| { |
| shader << "&&\n "; |
| } |
| |
| shader << "(m[" << col << "][" << row << "] == " << value << ".0)"; |
| } |
| } |
| |
| shader << ";\n colorOut = vec4(isCorrect);\n" |
| "}\n"; |
| |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), shader.str().c_str()); |
| |
| glUseProgram(program); |
| |
| GLint location = glGetUniformLocation(program, "m"); |
| ASSERT_NE(-1, location); |
| |
| uniformMatrixCxRfv[cols][rows](location, 1, transpose != 0, matrixValues); |
| ASSERT_GL_NO_ERROR(); |
| |
| drawQuad(program, essl3_shaders::PositionAttrib(), 0.0f); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white) |
| << " transpose = " << transpose << ", cols = " << cols << ", rows = " << rows; |
| } |
| } |
| } |
| } |
| |
| // Test that uniforms with reserved OpenGL names that aren't reserved in GL ES 2 work correctly. |
| TEST_P(UniformTest, UniformWithReservedOpenGLName) |
| { |
| constexpr char kFS[] = |
| "precision mediump float;\n" |
| "uniform float buffer;" |
| "void main() {\n" |
| " gl_FragColor = vec4(buffer);\n" |
| "}"; |
| |
| mProgram = CompileProgram(essl1_shaders::vs::Simple(), kFS); |
| ASSERT_NE(mProgram, 0u); |
| |
| GLint location = glGetUniformLocation(mProgram, "buffer"); |
| ASSERT_NE(-1, location); |
| |
| glUseProgram(mProgram); |
| glUniform1f(location, 1.0f); |
| |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.0f); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| } |
| |
| // Test that unused sampler array elements do not corrupt used sampler array elements. Checks for a |
| // bug where unused samplers in an array would mark the whole array unused. |
| TEST_P(UniformTest, UnusedUniformsInSamplerArray) |
| { |
| constexpr char kVS[] = R"(precision highp float; |
| attribute vec4 position; |
| varying vec2 texcoord; |
| void main() |
| { |
| gl_Position = position; |
| texcoord = (position.xy * 0.5) + 0.5; |
| })"; |
| constexpr char kFS[] = R"(precision highp float; |
| uniform sampler2D tex[3]; |
| varying vec2 texcoord; |
| void main() |
| { |
| gl_FragColor = texture2D(tex[0], texcoord); |
| })"; |
| |
| mProgram = CompileProgram(kVS, kFS); |
| |
| ASSERT_NE(mProgram, 0u); |
| GLint texLocation = glGetUniformLocation(mProgram, "tex[0]"); |
| ASSERT_NE(-1, texLocation); |
| glUseProgram(mProgram); |
| glUniform1i(texLocation, 0); |
| GLTexture tex; |
| glActiveTexture(GL_TEXTURE0); |
| glBindTexture(GL_TEXTURE_2D, tex); |
| constexpr GLsizei kTextureSize = 2; |
| std::vector<GLColor> textureData(kTextureSize * kTextureSize, GLColor::green); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureSize, kTextureSize, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| drawQuad(mProgram, "position", 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| TEST_P(UniformTest, UnusedStructInlineUniform) |
| { |
| constexpr char kVS[] = R"(precision highp float; |
| attribute vec4 position; |
| void main() |
| { |
| gl_Position = position; |
| })"; |
| |
| constexpr char kFS[] = R"(precision highp float; |
| uniform struct { |
| vec3 aVec3; |
| vec2 aVec2; |
| }aUniform; |
| varying vec2 texcoord; |
| void main() |
| { |
| gl_FragColor = vec4(0,1,0,1); |
| })"; |
| |
| mProgram = CompileProgram(kVS, kFS); |
| ASSERT_NE(mProgram, 0u); |
| drawQuad(mProgram, "position", 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| TEST_P(UniformTest, UnusedStructInlineUniformWithSampler) |
| { |
| constexpr char kVS[] = R"(precision highp float; |
| attribute vec4 position; |
| void main() |
| { |
| gl_Position = position; |
| })"; |
| |
| constexpr char kFS[] = R"(precision highp float; |
| uniform struct { |
| sampler2D aSampler; |
| vec3 aVec3; |
| }aUniform; |
| varying vec2 texcoord; |
| void main() |
| { |
| gl_FragColor = vec4(0,1,0,1); |
| })"; |
| |
| mProgram = CompileProgram(kVS, kFS); |
| ASSERT_NE(mProgram, 0u); |
| drawQuad(mProgram, "position", 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| // Bug: chromium:4210448 : Ensure programs properly |
| // compiles and renders where the uniforms form |
| // a struct with an alignment not matched with |
| // the actual size of the individual members. |
| // (Metal) |
| TEST_P(UniformTest, Vec4Vec2SizeAlignment) |
| { |
| constexpr char kVS[] = R"(precision highp float; |
| attribute vec4 position; |
| uniform vec4 uniformA; |
| uniform vec4 uniformB; |
| uniform vec2 uniformC; |
| void main() |
| { |
| gl_Position = position+uniformA + |
| uniformB + vec4(uniformC.x, uniformC.y, 0, 0); |
| })"; |
| constexpr char kFS[] = R"(precision highp float; |
| void main() |
| { |
| gl_FragColor = vec4(0,1,0,1); |
| })"; |
| mProgram = CompileProgram(kVS, kFS); |
| ASSERT_NE(mProgram, 0u); |
| drawQuad(mProgram, "position", 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| // Regression test for D3D11 packing of 3x3 matrices followed by a single float. The setting of the |
| // matrix would overwrite the float which is packed right after. http://anglebug.com/42266878, |
| // http://crbug.com/345525082 |
| TEST_P(UniformTestES3, ExpandedFloatMatrix3Packing) |
| { |
| constexpr char vs[] = R"(precision highp float; |
| attribute vec4 position; |
| void main() |
| { |
| gl_Position = position; |
| })"; |
| |
| constexpr char fs[] = R"(precision mediump float; |
| struct s |
| { |
| mat3 umat3; |
| float ufloat; |
| }; |
| uniform s u; |
| void main() { |
| gl_FragColor = vec4(u.umat3[0][0], u.ufloat, 1.0, 1.0); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, vs, fs); |
| glUseProgram(program); |
| |
| GLint umat3Location = glGetUniformLocation(program, "u.umat3"); |
| ASSERT_NE(umat3Location, -1); |
| |
| GLint ufloatLocation = glGetUniformLocation(program, "u.ufloat"); |
| ASSERT_NE(ufloatLocation, -1); |
| |
| constexpr GLfloat mat3[9] = { |
| 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, |
| }; |
| |
| glUniform1f(ufloatLocation, 1.0f); |
| glUniformMatrix3fv(umat3Location, 1, GL_FALSE, mat3); |
| drawQuad(program, "position", 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(0, 255, 255, 255)); |
| } |
| |
| // Use this to select which configurations (e.g. which renderer, which GLES major version) these |
| // tests should be run against. |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(SimpleUniformTest); |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(SimpleUniformUsageTest, ES2_WEBGPU()); |
| |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(UniformTest); |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(BasicUniformUsageTest, ES2_WEBGPU()); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniformTestES3); |
| ANGLE_INSTANTIATE_TEST_ES3(UniformTestES3); |
| ANGLE_INSTANTIATE_TEST_ES3_AND(SimpleUniformUsageTestES3, ES3_WEBGPU()); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniformTestES31); |
| ANGLE_INSTANTIATE_TEST_ES31(UniformTestES31); |
| |
| } // namespace |