blob: 54e32ddcefaad8bc955b6be06add339d0bb1f9e3 [file] [log] [blame]
//
// Copyright 2016 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.
//
// SRGBFramebufferTest.cpp: Tests of sRGB framebuffer functionality.
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
namespace
{
constexpr angle::GLColor linearColor(64, 127, 191, 255);
constexpr angle::GLColor srgbColor(13, 54, 133, 255);
} // namespace
namespace angle
{
class SRGBFramebufferTest : public ANGLETest<>
{
protected:
SRGBFramebufferTest()
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
void testSetUp() override
{
mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
ASSERT_NE(0u, mProgram);
mColorLocation = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
ASSERT_NE(-1, mColorLocation);
}
void testTearDown() override { glDeleteProgram(mProgram); }
GLuint mProgram = 0;
GLint mColorLocation = -1;
};
class SRGBFramebufferTestES3 : public SRGBFramebufferTest
{};
// Test basic validation of GL_EXT_sRGB_write_control
TEST_P(SRGBFramebufferTest, Validation)
{
GLenum expectedError =
IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ? GL_NO_ERROR : GL_INVALID_ENUM;
GLboolean value = GL_FALSE;
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
EXPECT_GL_ERROR(expectedError);
glGetBooleanv(GL_FRAMEBUFFER_SRGB_EXT, &value);
EXPECT_GL_ERROR(expectedError);
if (expectedError == GL_NO_ERROR)
{
EXPECT_GL_TRUE(value);
}
glDisable(GL_FRAMEBUFFER_SRGB_EXT);
EXPECT_GL_ERROR(expectedError);
glGetBooleanv(GL_FRAMEBUFFER_SRGB_EXT, &value);
EXPECT_GL_ERROR(expectedError);
if (expectedError == GL_NO_ERROR)
{
EXPECT_GL_FALSE(value);
}
}
// Test basic functionality of GL_EXT_sRGB_write_control
TEST_P(SRGBFramebufferTest, BasicUsage)
{
if (!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
(!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3))
{
std::cout
<< "Test skipped because GL_EXT_sRGB_write_control and GL_EXT_sRGB are not available."
<< std::endl;
return;
}
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
nullptr);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glUseProgram(mProgram);
glUniform4fv(mColorLocation, 1, srgbColor.toNormalizedVector().data());
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
glDisable(GL_FRAMEBUFFER_SRGB_EXT);
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
}
// Test that GL_EXT_sRGB_write_control state applies to all framebuffers if multiple are used
// 1. disable srgb
// 2. draw to both framebuffers
// 3. enable srgb
// 4. draw to both framebuffers
TEST_P(SRGBFramebufferTest, MultipleFramebuffers)
{
if (!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
(!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3))
{
std::cout
<< "Test skipped because GL_EXT_sRGB_write_control and GL_EXT_sRGB are not available."
<< std::endl;
return;
}
// NVIDIA failures on older drivers
// http://anglebug.com/42264177
ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGLES());
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
nullptr);
GLFramebuffer framebuffer1;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glUseProgram(mProgram);
glUniform4fv(mColorLocation, 1, srgbColor.toNormalizedVector().data());
glDisable(GL_FRAMEBUFFER_SRGB_EXT);
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
GLFramebuffer framebuffer2;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
}
// Test that we behave correctly when we toggle FRAMEBUFFER_SRGB_EXT on a framebuffer that has an
// attachment in linear colorspace
TEST_P(SRGBFramebufferTest, NegativeAlreadyLinear)
{
if (!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
(!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3))
{
std::cout
<< "Test skipped because GL_EXT_sRGB_write_control and GL_EXT_sRGB are not available."
<< std::endl;
return;
}
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glUseProgram(mProgram);
glUniform4fv(mColorLocation, 1, linearColor.toNormalizedVector().data());
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
glDisable(GL_FRAMEBUFFER_SRGB_EXT);
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
}
// Test that lifetimes of internal resources are tracked correctly by deleting a texture and then
// attempting to use it. This is expected to produce a non-fatal error.
TEST_P(SRGBFramebufferTest, NegativeLifetimeTracking)
{
if (!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
(!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3))
{
std::cout
<< "Test skipped because GL_EXT_sRGB_write_control and GL_EXT_sRGB are not available."
<< std::endl;
return;
}
// NVIDIA failures
// http://anglebug.com/42264177
ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGLES());
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
nullptr);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glUseProgram(mProgram);
glUniform4fv(mColorLocation, 1, srgbColor.toNormalizedVector().data());
glDisable(GL_FRAMEBUFFER_SRGB_EXT);
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
// Delete the texture
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
texture.reset();
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
GLColor throwaway_color;
glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &throwaway_color);
EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
}
// Test that glBlitFramebuffer correctly converts colorspaces
TEST_P(SRGBFramebufferTestES3, BlitFramebuffer)
{
// http://anglebug.com/42264326
ANGLE_SKIP_TEST_IF(!IsVulkan());
if (!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
(!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3))
{
std::cout
<< "Test skipped because GL_EXT_sRGB_write_control and GL_EXT_sRGB are not available."
<< std::endl;
return;
}
GLTexture dstTexture;
glBindTexture(GL_TEXTURE_2D, dstTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
nullptr);
GLFramebuffer dstFramebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTexture, 0);
GLTexture srcTexture;
glBindTexture(GL_TEXTURE_2D, srcTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
nullptr);
GLFramebuffer srcFramebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTexture, 0);
glUseProgram(mProgram);
glUniform4fv(mColorLocation, 1, srgbColor.toNormalizedVector().data());
// Draw onto the framebuffer normally
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
// Blit the framebuffer normally
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer);
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer);
glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer);
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
// Blit the framebuffer with forced linear colorspace
glDisable(GL_FRAMEBUFFER_SRGB_EXT);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer);
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer);
glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer);
EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
}
// This test reproduces an issue in the Vulkan backend found in the Chromium CI that
// was caused by enabling the VK_KHR_image_format_list extension on SwiftShader
// which exposed GL_EXT_sRGB_write_control.
TEST_P(SRGBFramebufferTest, DrawToSmallFBOClearLargeFBO)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
(!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3));
// Disabling GL_FRAMEBUFFER_SRGB_EXT caused the issue
glDisable(GL_FRAMEBUFFER_SRGB_EXT);
// The issue involved framebuffers of two different sizes.
// The smaller needed to be drawn to, while the larger one could be just cleared
// to reproduce the issue. These are the smallest tested sizes that generated
// the validation error.
constexpr GLsizei kDimensionsSmall[] = {1, 1};
constexpr GLsizei kDimensionsLarge[] = {2, 2};
{
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kDimensionsSmall[0], kDimensionsSmall[1]);
glBindTexture(GL_TEXTURE_2D, 0);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
unsigned char vertexData[] = {0};
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(char), vertexData, GL_STATIC_DRAW);
unsigned int indexData[] = {0};
GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int), indexData, GL_STATIC_DRAW);
glUseProgram(mProgram);
glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);
EXPECT_GL_NO_ERROR();
}
{
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kDimensionsLarge[0], kDimensionsLarge[1]);
glBindTexture(GL_TEXTURE_2D, 0);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
// Vulkan validation happened to fail here with:
// "Cannot execute a render pass with renderArea not within the bound of the framebuffer"
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_NO_ERROR();
}
}
class SRGBFramebufferDefaultLinearTest : public ANGLETest<>
{
protected:
SRGBFramebufferDefaultLinearTest()
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
void testBasic(bool isSrgb, bool isES3)
{
// Default framebuffer attachment queries require OpenGL ES 3.0
if (isES3)
{
GLint encoding;
glGetFramebufferAttachmentParameteriv(
GL_FRAMEBUFFER, GL_BACK, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &encoding);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(encoding, isSrgb ? GL_SRGB : GL_LINEAR);
}
glClearColor(0.5, 0.5, 0.5, 0.5);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
if (isSrgb)
{
EXPECT_PIXEL_NEAR(0, 0, 188, 188, 188, 127, 1);
}
else
{
EXPECT_PIXEL_NEAR(0, 0, 127, 127, 127, 127, 1);
}
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(program);
const GLint colorUniformLocation =
glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
glUniform4f(colorUniformLocation, 0.25, 0.25, 0.25, 0.25);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
if (isSrgb)
{
EXPECT_PIXEL_NEAR(0, 0, 137, 137, 137, 64, 1);
}
else
{
EXPECT_PIXEL_NEAR(0, 0, 64, 64, 64, 64, 1);
}
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glUniform4f(colorUniformLocation, 0.5, 0.5, 0.5, 0.5);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
if (isSrgb)
{
EXPECT_PIXEL_NEAR(0, 0, 225, 225, 225, 191, 1);
}
else
{
EXPECT_PIXEL_NEAR(0, 0, 191, 191, 191, 191, 1);
}
}
void testBlit(bool isFromFboToSurface, bool isFboSrgb, bool isSurfaceSrgb, bool isES3)
{
PFNGLBLITFRAMEBUFFERPROC blitFramebuffer = isES3 ? glBlitFramebuffer : glBlitFramebufferNV;
GLRenderbuffer rb;
glBindRenderbuffer(GL_RENDERBUFFER, rb);
glRenderbufferStorage(GL_RENDERBUFFER, isFboSrgb ? GL_SRGB8_ALPHA8 : GL_RGBA8, 128, 128);
ASSERT_GL_NO_ERROR();
GLFramebuffer fb;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
// Clear source to 0.5
glBindFramebuffer(GL_FRAMEBUFFER, isFromFboToSurface ? fb : 0);
glClearColor(0.25, 0.5, 0.75, 0.5);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
// Clear destination to 0.0
glBindFramebuffer(GL_FRAMEBUFFER, isFromFboToSurface ? 0 : fb);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, isFromFboToSurface ? fb : 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, isFromFboToSurface ? 0 : fb);
blitFramebuffer(0, 0, 128, 128, 0, 0, 128, 128, GL_COLOR_BUFFER_BIT, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, isFromFboToSurface ? 0 : fb);
if ((isFromFboToSurface && isSurfaceSrgb) || (!isFromFboToSurface && isFboSrgb))
{
EXPECT_PIXEL_NEAR(0, 0, 137, 188, 225, 127, 1);
}
else
{
EXPECT_PIXEL_NEAR(0, 0, 64, 127, 191, 127, 1);
}
// Test linear filtering
if (!isFromFboToSurface)
{
// Prepare the default framebuffer content
std::vector<uint8_t> data(128 * 128 * 4);
for (size_t i = 0; i < data.size(); ++i)
{
data[i] = i & 4 ? 255 : 0;
}
GLTexture tempTex;
glBindTexture(GL_TEXTURE_2D, tempTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE,
data.data());
ASSERT_GL_NO_ERROR();
GLFramebuffer tempFb;
glBindFramebuffer(GL_FRAMEBUFFER, tempFb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tempTex, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, tempFb);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
blitFramebuffer(0, 0, 128, 128, 0, 0, 128, 128, GL_COLOR_BUFFER_BIT, GL_NEAREST);
ASSERT_GL_NO_ERROR();
}
const int fboDim = isFromFboToSurface ? 256 : 64;
std::vector<uint8_t> data(fboDim * fboDim * 4);
if (isFromFboToSurface)
{
// Prepare texture content
for (size_t i = 0; i < data.size(); ++i)
{
data[i] = i & 4 ? 255 : 0;
}
}
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
if (isES3)
{
glTexImage2D(GL_TEXTURE_2D, 0, isFboSrgb ? GL_SRGB8_ALPHA8 : GL_RGBA8, fboDim, fboDim,
0, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
}
else
{
glTexImage2D(GL_TEXTURE_2D, 0, isFboSrgb ? GL_SRGB_ALPHA_EXT : GL_RGBA, fboDim, fboDim,
0, isFboSrgb ? GL_SRGB_ALPHA_EXT : GL_RGBA, GL_UNSIGNED_BYTE, data.data());
}
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
ASSERT_GL_NO_ERROR();
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Clear destination to 0.0
glBindFramebuffer(GL_FRAMEBUFFER, isFromFboToSurface ? 0 : fb);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, isFromFboToSurface ? fb : 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, isFromFboToSurface ? 0 : fb);
if (isFromFboToSurface)
{
blitFramebuffer(0, 0, 256, 256, 0, 0, 128, 128, GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
else
{
blitFramebuffer(0, 0, 128, 128, 0, 0, 64, 64, GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, isFromFboToSurface ? 0 : fb);
if ((isFromFboToSurface && isSurfaceSrgb) || (!isFromFboToSurface && isFboSrgb))
{
EXPECT_PIXEL_NEAR(0, 0, 188, 188, 188, 127, 1);
}
else
{
EXPECT_PIXEL_NEAR(0, 0, 127, 127, 127, 127, 1);
}
}
void testBlitFromLinearSurfaceToLinearFbo(bool isES3) { testBlit(false, false, false, isES3); }
void testBlitFromLinearFboToLinearSurface(bool isES3) { testBlit(true, false, false, isES3); }
void testBlitFromLinearSurfaceToSrgbFbo(bool isES3) { testBlit(false, true, false, isES3); }
void testBlitFromSrgbFboToLinearSurface(bool isES3) { testBlit(true, true, false, isES3); }
void testBlitFromSrgbSurfaceToLinearFbo(bool isES3) { testBlit(false, false, true, isES3); }
void testBlitFromLinearFboToSrgbSurface(bool isES3) { testBlit(true, false, true, isES3); }
void testBlitFromSrgbSurfaceToSrgbFbo(bool isES3) { testBlit(false, true, true, isES3); }
void testBlitFromSrgbFboToSrgbSurface(bool isES3) { testBlit(true, true, true, isES3); }
};
// Test that basic operations are performed with linear encoding.
TEST_P(SRGBFramebufferDefaultLinearTest, ClearAndDrawAndBlend)
{
testBasic(false, getClientMajorVersion() >= 3);
}
// Test blits from the linearly-encoded default framebuffer to a linearly-encoded FBO.
TEST_P(SRGBFramebufferDefaultLinearTest, BlitToLinearFbo)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
(!IsGLExtensionEnabled("GL_OES_rgb8_rgba8") ||
!IsGLExtensionEnabled("GL_NV_framebuffer_blit")));
testBlitFromLinearSurfaceToLinearFbo(getClientMajorVersion() >= 3);
}
// Test blits from a linearly-encoded FBO to the linearly-encoded default framebuffer.
TEST_P(SRGBFramebufferDefaultLinearTest, BlitFromLinearFbo)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
(!IsGLExtensionEnabled("GL_OES_rgb8_rgba8") ||
!IsGLExtensionEnabled("GL_NV_framebuffer_blit")));
testBlitFromLinearFboToLinearSurface(getClientMajorVersion() >= 3);
}
// Test blits from the linearly-encoded default framebuffer to an sRGB-encoded FBO.
TEST_P(SRGBFramebufferDefaultLinearTest, BlitToSrgbFbo)
{
ANGLE_SKIP_TEST_IF(
getClientMajorVersion() < 3 &&
(!IsGLExtensionEnabled("GL_EXT_sRGB") || !IsGLExtensionEnabled("GL_NV_framebuffer_blit")));
testBlitFromLinearSurfaceToSrgbFbo(getClientMajorVersion() >= 3);
}
// Test blits from an sRGB-encoded FBO to the linearly-encoded default framebuffer.
TEST_P(SRGBFramebufferDefaultLinearTest, BlitFromSrgbFbo)
{
ANGLE_SKIP_TEST_IF(
getClientMajorVersion() < 3 &&
(!IsGLExtensionEnabled("GL_EXT_sRGB") || !IsGLExtensionEnabled("GL_NV_framebuffer_blit")));
testBlitFromSrgbFboToLinearSurface(getClientMajorVersion() >= 3);
}
class SRGBFramebufferDefaultSrgbTest : public SRGBFramebufferDefaultLinearTest
{
protected:
SRGBFramebufferDefaultSrgbTest() : SRGBFramebufferDefaultLinearTest()
{
setConfigColorSpace(EGL_GL_COLORSPACE_SRGB);
}
};
// Test that basic operations are performed with sRGB encoding.
TEST_P(SRGBFramebufferDefaultSrgbTest, ClearAndDrawAndBlend)
{
testBasic(true, getClientMajorVersion() >= 3);
}
// Test blits from the sRGB-encoded default framebuffer to a linearly-encoded FBO.
TEST_P(SRGBFramebufferDefaultSrgbTest, BlitToLinearFbo)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
(!IsGLExtensionEnabled("GL_OES_rgb8_rgba8") ||
!IsGLExtensionEnabled("GL_NV_framebuffer_blit")));
testBlitFromSrgbSurfaceToLinearFbo(getClientMajorVersion() >= 3);
}
// Test blits from a linearly-encoded FBO to the sRGB-encoded default framebuffer.
TEST_P(SRGBFramebufferDefaultSrgbTest, BlitFromLinearFbo)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
(!IsGLExtensionEnabled("GL_OES_rgb8_rgba8") ||
!IsGLExtensionEnabled("GL_NV_framebuffer_blit")));
testBlitFromLinearFboToSrgbSurface(getClientMajorVersion() >= 3);
}
// Test blits from the sRGB-encoded default framebuffer to an sRGB-encoded FBO.
TEST_P(SRGBFramebufferDefaultSrgbTest, BlitToSrgbFbo)
{
ANGLE_SKIP_TEST_IF(
getClientMajorVersion() < 3 &&
(!IsGLExtensionEnabled("GL_EXT_sRGB") || !IsGLExtensionEnabled("GL_NV_framebuffer_blit")));
testBlitFromSrgbSurfaceToSrgbFbo(getClientMajorVersion() >= 3);
}
// Test blits from an sRGB-encoded FBO to the sRGB-encoded default framebuffer.
TEST_P(SRGBFramebufferDefaultSrgbTest, BlitFromSrgbFbo)
{
ANGLE_SKIP_TEST_IF(
getClientMajorVersion() < 3 &&
(!IsGLExtensionEnabled("GL_EXT_sRGB") || !IsGLExtensionEnabled("GL_NV_framebuffer_blit")));
testBlitFromSrgbFboToSrgbSurface(getClientMajorVersion() >= 3);
}
// 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(SRGBFramebufferTest);
ANGLE_INSTANTIATE_TEST_ES3(SRGBFramebufferTestES3);
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(SRGBFramebufferDefaultLinearTest);
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(SRGBFramebufferDefaultSrgbTest);
} // namespace angle