| // | |
| // 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" | |
| using namespace angle; | |
| class BlendMinMaxTest : public ANGLETest | |
| { | |
| protected: | |
| BlendMinMaxTest() | |
| { | |
| setWindowWidth(128); | |
| setWindowHeight(128); | |
| setConfigRedBits(8); | |
| setConfigGreenBits(8); | |
| setConfigBlueBits(8); | |
| setConfigAlphaBits(8); | |
| setConfigDepthBits(24); | |
| mProgram = 0; | |
| mColorLocation = -1; | |
| mFramebuffer = 0; | |
| mColorRenderbuffer = 0; | |
| } | |
| struct Color | |
| { | |
| float values[4]; | |
| }; | |
| static float getExpected(bool blendMin, float curColor, float prevColor) | |
| { | |
| return blendMin ? std::min(curColor, prevColor) : std::max(curColor, prevColor); | |
| } | |
| void runTest(GLenum colorFormat, GLenum type) | |
| { | |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 && | |
| !IsGLExtensionEnabled("GL_EXT_blend_minmax")); | |
| SetUpFramebuffer(colorFormat); | |
| int minValue = 0; | |
| int maxValue = 1; | |
| if (type == GL_FLOAT) | |
| { | |
| minValue = -1024; | |
| maxValue = 1024; | |
| } | |
| const size_t colorCount = 128; | |
| Color colors[colorCount]; | |
| for (size_t i = 0; i < colorCount; i++) | |
| { | |
| for (size_t j = 0; j < 4; j++) | |
| { | |
| colors[i].values[j] = | |
| static_cast<float>(minValue + (rand() % (maxValue - minValue))); | |
| } | |
| } | |
| float prevColor[4]; | |
| for (size_t i = 0; i < colorCount; i++) | |
| { | |
| const Color &color = colors[i]; | |
| glUseProgram(mProgram); | |
| glUniform4f(mColorLocation, color.values[0], color.values[1], color.values[2], | |
| color.values[3]); | |
| bool blendMin = (rand() % 2 == 0); | |
| glBlendEquation(blendMin ? GL_MIN : GL_MAX); | |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f); | |
| float pixel[4]; | |
| if (type == GL_UNSIGNED_BYTE) | |
| { | |
| GLubyte ubytePixel[4]; | |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, ubytePixel); | |
| for (size_t componentIdx = 0; componentIdx < ArraySize(pixel); componentIdx++) | |
| { | |
| pixel[componentIdx] = ubytePixel[componentIdx] / 255.0f; | |
| } | |
| } | |
| else if (type == GL_FLOAT) | |
| { | |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, pixel); | |
| } | |
| else | |
| { | |
| FAIL() << "Unexpected pixel type"; | |
| } | |
| if (i > 0) | |
| { | |
| const float errorRange = 1.0f / 255.0f; | |
| for (size_t componentIdx = 0; componentIdx < ArraySize(pixel); componentIdx++) | |
| { | |
| EXPECT_NEAR( | |
| getExpected(blendMin, color.values[componentIdx], prevColor[componentIdx]), | |
| pixel[componentIdx], errorRange) | |
| << " blendMin=" << blendMin << " componentIdx=" << componentIdx << std::endl | |
| << " color.values[0]=" << color.values[0] | |
| << " prevColor[0]=" << prevColor[0] << std::endl | |
| << " color.values[1]=" << color.values[1] | |
| << " prevColor[1]=" << prevColor[1] << std::endl | |
| << " color.values[2]=" << color.values[2] | |
| << " prevColor[2]=" << prevColor[2] << std::endl | |
| << " color.values[3]=" << color.values[3] | |
| << " prevColor[3]=" << prevColor[3]; | |
| } | |
| } | |
| memcpy(prevColor, pixel, sizeof(pixel)); | |
| } | |
| } | |
| void testSetUp() override | |
| { | |
| mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); | |
| if (mProgram == 0) | |
| { | |
| FAIL() << "shader compilation failed."; | |
| } | |
| mColorLocation = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform()); | |
| glUseProgram(mProgram); | |
| glClearColor(0, 0, 0, 0); | |
| glClearDepthf(0.0); | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| glEnable(GL_BLEND); | |
| glDisable(GL_DEPTH_TEST); | |
| } | |
| void SetUpFramebuffer(GLenum colorFormat) | |
| { | |
| glGenFramebuffers(1, &mFramebuffer); | |
| glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); | |
| glGenRenderbuffers(1, &mColorRenderbuffer); | |
| glBindRenderbuffer(GL_RENDERBUFFER, mColorRenderbuffer); | |
| glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, getWindowWidth(), getWindowHeight()); | |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, | |
| mColorRenderbuffer); | |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| } | |
| void testTearDown() override | |
| { | |
| glDeleteProgram(mProgram); | |
| glDeleteFramebuffers(1, &mFramebuffer); | |
| glDeleteRenderbuffers(1, &mColorRenderbuffer); | |
| } | |
| GLuint mProgram; | |
| GLint mColorLocation; | |
| GLuint mFramebuffer; | |
| GLuint mColorRenderbuffer; | |
| }; | |
| TEST_P(BlendMinMaxTest, RGBA8) | |
| { | |
| runTest(GL_RGBA8, GL_UNSIGNED_BYTE); | |
| } | |
| TEST_P(BlendMinMaxTest, RGBA32F) | |
| { | |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 || !IsGLExtensionEnabled("GL_EXT_float_blend") || | |
| !IsGLExtensionEnabled("GL_EXT_color_buffer_float")); | |
| // Ignore SDK layers messages on D3D11 FL 9.3 (http://anglebug.com/1284) | |
| ANGLE_SKIP_TEST_IF(IsD3D11_FL93()); | |
| runTest(GL_RGBA32F, GL_FLOAT); | |
| } | |
| TEST_P(BlendMinMaxTest, RGBA16F) | |
| { | |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 && | |
| !IsGLExtensionEnabled("GL_EXT_color_buffer_half_float")); | |
| // http://anglebug.com/4092 | |
| ANGLE_SKIP_TEST_IF((IsAndroid() && IsVulkan()) || isSwiftshader()); | |
| // http://anglebug.com/4185 | |
| ANGLE_SKIP_TEST_IF(IsMetal()); | |
| runTest(GL_RGBA16F, GL_FLOAT); | |
| } | |
| // 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(BlendMinMaxTest); |