| // |
| // 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 <variant> |
| |
| #include "test_utils/ANGLETest.h" |
| |
| #include "test_utils/gl_raii.h" |
| #include "util/random_utils.h" |
| #include "util/shader_utils.h" |
| #include "util/test_utils.h" |
| |
| using namespace angle; |
| |
| namespace |
| { |
| |
| struct FormatTableElement |
| { |
| GLint internalformat; |
| GLenum format; |
| GLenum type; |
| |
| bool isInt() const |
| { |
| return format == GL_RED_INTEGER || format == GL_RG_INTEGER || format == GL_RGB_INTEGER || |
| format == GL_RGBA_INTEGER; |
| } |
| |
| // Call isUInt only if isInt is true. |
| bool isUInt() const |
| { |
| return type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT; |
| } |
| }; |
| |
| using ColorTypes = std::variant<GLColor, |
| GLColorT<int8_t>, |
| GLColor16, |
| GLColorT<int16_t>, |
| GLColor32F, |
| GLColor32I, |
| GLColor32UI, |
| GLushort, |
| GLuint, |
| GLint>; |
| class ClearTestBase : public ANGLETest<> |
| { |
| protected: |
| ClearTestBase() |
| { |
| setWindowWidth(128); |
| setWindowHeight(128); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| setConfigDepthBits(24); |
| setConfigStencilBits(8); |
| } |
| |
| void testSetUp() override |
| { |
| mFBOs.resize(2, 0); |
| glGenFramebuffers(2, mFBOs.data()); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| void testTearDown() override |
| { |
| if (!mFBOs.empty()) |
| { |
| glDeleteFramebuffers(static_cast<GLsizei>(mFBOs.size()), mFBOs.data()); |
| } |
| |
| if (!mTextures.empty()) |
| { |
| glDeleteTextures(static_cast<GLsizei>(mTextures.size()), mTextures.data()); |
| } |
| } |
| |
| std::vector<GLuint> mFBOs; |
| std::vector<GLuint> mTextures; |
| }; |
| |
| class ClearTest : public ClearTestBase |
| {}; |
| |
| class ClearTestES3 : public ClearTestBase |
| { |
| protected: |
| void verifyDepth(float depthValue, uint32_t size) |
| { |
| // Use a small shader to verify depth. |
| ANGLE_GL_PROGRAM(depthTestProgram, essl1_shaders::vs::Passthrough(), |
| essl1_shaders::fs::Blue()); |
| ANGLE_GL_PROGRAM(depthTestProgramFail, essl1_shaders::vs::Passthrough(), |
| essl1_shaders::fs::Red()); |
| |
| GLboolean hasDepthTest = GL_FALSE; |
| GLboolean hasDepthWrite = GL_TRUE; |
| GLint prevDepthFunc = GL_ALWAYS; |
| |
| glGetBooleanv(GL_DEPTH_TEST, &hasDepthTest); |
| glGetBooleanv(GL_DEPTH_WRITEMASK, &hasDepthWrite); |
| glGetIntegerv(GL_DEPTH_FUNC, &prevDepthFunc); |
| |
| if (!hasDepthTest) |
| { |
| glEnable(GL_DEPTH_TEST); |
| } |
| if (hasDepthWrite) |
| { |
| glDepthMask(GL_FALSE); |
| } |
| glDepthFunc(GL_LESS); |
| drawQuad(depthTestProgram, essl1_shaders::PositionAttrib(), depthValue * 2 - 1 - 0.01f); |
| drawQuad(depthTestProgramFail, essl1_shaders::PositionAttrib(), depthValue * 2 - 1 + 0.01f); |
| if (!hasDepthTest) |
| { |
| glDisable(GL_DEPTH_TEST); |
| } |
| if (hasDepthWrite) |
| { |
| glDepthMask(GL_TRUE); |
| } |
| glDepthFunc(prevDepthFunc); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::blue, 1); |
| EXPECT_PIXEL_COLOR_NEAR(size - 1, 0, GLColor::blue, 1); |
| EXPECT_PIXEL_COLOR_NEAR(0, size - 1, GLColor::blue, 1); |
| EXPECT_PIXEL_COLOR_NEAR(size - 1, size - 1, GLColor::blue, 1); |
| } |
| |
| void verifyStencil(uint32_t stencilValue, uint32_t size) |
| { |
| // Use another small shader to verify stencil. |
| ANGLE_GL_PROGRAM(stencilTestProgram, essl1_shaders::vs::Passthrough(), |
| essl1_shaders::fs::Green()); |
| GLboolean hasStencilTest = GL_FALSE; |
| GLint prevStencilFunc = GL_ALWAYS; |
| GLint prevStencilValue = 0xFF; |
| GLint prevStencilRef = 0xFF; |
| GLint prevStencilFail = GL_KEEP; |
| GLint prevStencilDepthFail = GL_KEEP; |
| GLint prevStencilDepthPass = GL_KEEP; |
| |
| glGetBooleanv(GL_STENCIL_TEST, &hasStencilTest); |
| glGetIntegerv(GL_STENCIL_FUNC, &prevStencilFunc); |
| glGetIntegerv(GL_STENCIL_VALUE_MASK, &prevStencilValue); |
| glGetIntegerv(GL_STENCIL_REF, &prevStencilRef); |
| glGetIntegerv(GL_STENCIL_FAIL, &prevStencilFail); |
| glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &prevStencilDepthFail); |
| glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &prevStencilDepthPass); |
| |
| if (!hasStencilTest) |
| { |
| glEnable(GL_STENCIL_TEST); |
| } |
| glStencilFunc(GL_EQUAL, stencilValue, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| drawQuad(stencilTestProgram, essl1_shaders::PositionAttrib(), 0.0f); |
| if (!hasStencilTest) |
| { |
| glDisable(GL_STENCIL_TEST); |
| } |
| glStencilFunc(prevStencilFunc, prevStencilValue, prevStencilRef); |
| glStencilOp(prevStencilFail, prevStencilDepthFail, prevStencilDepthPass); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::green, 1); |
| EXPECT_PIXEL_COLOR_NEAR(size - 1, 0, GLColor::green, 1); |
| EXPECT_PIXEL_COLOR_NEAR(0, size - 1, GLColor::green, 1); |
| EXPECT_PIXEL_COLOR_NEAR(size - 1, size - 1, GLColor::green, 1); |
| } |
| }; |
| |
| class ClearTestES31 : public ClearTestES3 |
| {}; |
| |
| class ClearTestRGB : public ANGLETest<> |
| { |
| protected: |
| ClearTestRGB() |
| { |
| setWindowWidth(128); |
| setWindowHeight(128); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| } |
| }; |
| |
| class ClearTestRGB_ES3 : public ClearTestRGB |
| {}; |
| |
| class ClearTextureEXTTest : public ANGLETest<> |
| { |
| protected: |
| ClearTextureEXTTest() |
| { |
| setWindowWidth(128); |
| setWindowHeight(128); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| } |
| }; |
| |
| class ClearTextureEXTTestES31 : public ANGLETest<> |
| { |
| protected: |
| ClearTextureEXTTestES31() |
| { |
| setWindowWidth(128); |
| setWindowHeight(128); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| |
| angle::RNG rng; |
| mWidth = rng.randomIntBetween(1, 32); |
| mHeight = rng.randomIntBetween(1, 32); |
| mDepth = rng.randomIntBetween(1, 4); |
| |
| mLevels = std::log2(std::max(mWidth, mHeight)) + 1; |
| } |
| |
| // Texture's information. |
| int mWidth; |
| int mHeight; |
| int mDepth; |
| int mLevels; |
| |
| GLenum mTarget; |
| |
| bool mIsArray = true; |
| bool mHasLayer = true; |
| bool mExtraSupport = true; |
| |
| GLColor mFullColorRef = GLColor::red; |
| GLColor mPartialColorRef = GLColor::blue; |
| |
| // Convert the reference color so that it can be suitable for different type of format. |
| ColorTypes convertColorTypeInternal(const GLenum &type, const GLColor &color); |
| ColorTypes convertColorType(const GLenum &format, const GLenum &type, GLColor color); |
| GLColor getClearColor(GLenum format, GLColor full); |
| |
| // Check color results by format type. |
| void colorCheckType(const FormatTableElement &fmt, |
| const int &x, |
| const int &y, |
| const int &width, |
| const int &height, |
| GLColor &color); |
| |
| bool requiredNorm16(GLint internalformat); |
| |
| const std::string getVertexShader(const GLenum &target); |
| const std::string getFragmentShader(const GLenum &target, bool isInteger, bool isUInteger); |
| |
| // Initialize texture. |
| void initTexture(int levelNum, FormatTableElement &fmt, GLTexture &tex); |
| |
| // Clear and check results. |
| void clearCheckRenderable(int level, |
| int width, |
| int height, |
| int depth, |
| const GLTexture &tex, |
| const FormatTableElement &fmt, |
| GLColor &fullColorRef, |
| ColorTypes &fullColor, |
| GLColor &partialColorRef, |
| ColorTypes &partialColor); |
| void clearCheckUnrenderable(int level, |
| int width, |
| int height, |
| int depth, |
| const GLTexture &tex, |
| const FormatTableElement &fmt, |
| GLuint program, |
| const std::vector<int> &loc, |
| GLColor &fullColorRef, |
| ColorTypes &fullColor, |
| GLColor &partialColorRef, |
| ColorTypes &partialColor); |
| }; |
| |
| ColorTypes ClearTextureEXTTestES31::convertColorTypeInternal(const GLenum &type, |
| const GLColor &color) |
| { |
| GLColor32F colorFloat; |
| colorFloat.R = gl::normalizedToFloat<uint8_t>(color.R); |
| colorFloat.G = gl::normalizedToFloat<uint8_t>(color.G); |
| colorFloat.B = gl::normalizedToFloat<uint8_t>(color.B); |
| colorFloat.A = gl::normalizedToFloat<uint8_t>(color.A); |
| |
| switch (type) |
| { |
| case GL_UNSIGNED_BYTE: |
| { |
| return color; |
| } |
| case GL_BYTE: |
| { |
| GLColorT<int8_t> retColorByte; |
| retColorByte.R = gl::floatToNormalized<int8_t>(colorFloat.R); |
| retColorByte.G = gl::floatToNormalized<int8_t>(colorFloat.G); |
| retColorByte.B = gl::floatToNormalized<int8_t>(colorFloat.B); |
| retColorByte.A = gl::floatToNormalized<int8_t>(colorFloat.A); |
| return retColorByte; |
| } |
| case GL_UNSIGNED_SHORT: |
| { |
| GLColor16 retColorUShort; |
| retColorUShort.R = gl::floatToNormalized<uint16_t>(colorFloat.R); |
| retColorUShort.G = gl::floatToNormalized<uint16_t>(colorFloat.G); |
| retColorUShort.B = gl::floatToNormalized<uint16_t>(colorFloat.B); |
| retColorUShort.A = gl::floatToNormalized<uint16_t>(colorFloat.A); |
| return retColorUShort; |
| } |
| case GL_UNSIGNED_SHORT_5_6_5: |
| { |
| GLushort retColor565; |
| retColor565 = gl::shiftData<5, 11>(gl::floatToNormalized<5, uint16_t>(colorFloat.R)) | |
| gl::shiftData<6, 5>(gl::floatToNormalized<6, uint16_t>(colorFloat.G)) | |
| gl::shiftData<5, 0>(gl::floatToNormalized<5, uint16_t>(colorFloat.B)); |
| return retColor565; |
| } |
| case GL_UNSIGNED_SHORT_5_5_5_1: |
| { |
| GLushort retColor5551; |
| retColor5551 = gl::shiftData<5, 11>(gl::floatToNormalized<5, uint16_t>(colorFloat.R)) | |
| gl::shiftData<5, 6>(gl::floatToNormalized<5, uint16_t>(colorFloat.G)) | |
| gl::shiftData<5, 1>(gl::floatToNormalized<5, uint16_t>(colorFloat.B)) | |
| gl::shiftData<1, 0>(gl::floatToNormalized<1, uint16_t>(colorFloat.A)); |
| return retColor5551; |
| } |
| case GL_UNSIGNED_SHORT_4_4_4_4: |
| { |
| GLushort retColor4444; |
| retColor4444 = gl::shiftData<4, 12>(gl::floatToNormalized<4, uint16_t>(colorFloat.R)) | |
| gl::shiftData<4, 8>(gl::floatToNormalized<4, uint16_t>(colorFloat.G)) | |
| gl::shiftData<4, 4>(gl::floatToNormalized<4, uint16_t>(colorFloat.B)) | |
| gl::shiftData<4, 0>(gl::floatToNormalized<4, uint16_t>(colorFloat.A)); |
| return retColor4444; |
| } |
| case GL_SHORT: |
| { |
| GLColorT<int16_t> retColorShort; |
| retColorShort.R = gl::floatToNormalized<int16_t>(colorFloat.R); |
| retColorShort.G = gl::floatToNormalized<int16_t>(colorFloat.G); |
| retColorShort.B = gl::floatToNormalized<int16_t>(colorFloat.B); |
| retColorShort.A = gl::floatToNormalized<int16_t>(colorFloat.A); |
| return retColorShort; |
| } |
| case GL_UNSIGNED_INT: |
| { |
| GLColor32UI retColorUInt; |
| retColorUInt.R = gl::floatToNormalized<uint32_t>(colorFloat.R); |
| retColorUInt.G = gl::floatToNormalized<uint32_t>(colorFloat.G); |
| retColorUInt.B = gl::floatToNormalized<uint32_t>(colorFloat.B); |
| retColorUInt.A = gl::floatToNormalized<uint32_t>(colorFloat.A); |
| return retColorUInt; |
| } |
| case GL_UNSIGNED_INT_10F_11F_11F_REV: |
| { |
| GLuint retColor101011; |
| retColor101011 = (GLuint)gl::float32ToFloat11(colorFloat.R) | |
| (GLuint)(gl::float32ToFloat11(colorFloat.G) << 11) | |
| (GLuint)(gl::float32ToFloat10(colorFloat.B) << 22); |
| return retColor101011; |
| } |
| case GL_UNSIGNED_INT_2_10_10_10_REV: |
| { |
| GLuint retColor1010102; |
| retColor1010102 = gl::floatToNormalized<10, uint32_t>(colorFloat.R) | |
| (gl::floatToNormalized<10, uint32_t>(colorFloat.G) << 10) | |
| (gl::floatToNormalized<10, uint32_t>(colorFloat.B) << 20) | |
| (gl::floatToNormalized<2, uint32_t>(colorFloat.A) << 30); |
| return retColor1010102; |
| } |
| case GL_UNSIGNED_INT_5_9_9_9_REV: |
| { |
| GLuint retColor9995; |
| retColor9995 = gl::convertRGBFloatsTo999E5(colorFloat.R, colorFloat.G, colorFloat.B); |
| return retColor9995; |
| } |
| case GL_INT: |
| { |
| GLColor32I retColorInt; |
| retColorInt.R = gl::floatToNormalized<int32_t>(colorFloat.R); |
| retColorInt.G = gl::floatToNormalized<int32_t>(colorFloat.G); |
| retColorInt.B = gl::floatToNormalized<int32_t>(colorFloat.B); |
| retColorInt.A = gl::floatToNormalized<int32_t>(colorFloat.A); |
| return retColorInt; |
| } |
| case GL_HALF_FLOAT: |
| { |
| GLColor16 retColorHFloat; |
| retColorHFloat.R = gl::float32ToFloat16(colorFloat.R); |
| retColorHFloat.G = gl::float32ToFloat16(colorFloat.G); |
| retColorHFloat.B = gl::float32ToFloat16(colorFloat.B); |
| retColorHFloat.A = gl::float32ToFloat16(colorFloat.A); |
| return retColorHFloat; |
| } |
| case GL_FLOAT: |
| { |
| return colorFloat; |
| } |
| default: |
| { |
| return color; |
| } |
| } |
| } |
| |
| ColorTypes ClearTextureEXTTestES31::convertColorType(const GLenum &format, |
| const GLenum &type, |
| GLColor color) |
| { |
| // LUMINANCE, LUMINANCE_ALPHA and ALPHA are special. |
| switch (format) |
| { |
| case GL_LUMINANCE: |
| { |
| color.G = color.B = color.A = 0; |
| break; |
| } |
| case GL_LUMINANCE_ALPHA: |
| { |
| color.G = color.A; |
| color.B = color.A = 0; |
| break; |
| } |
| case GL_ALPHA: |
| { |
| color.R = color.A; |
| color.G = color.B = color.A = 0; |
| break; |
| } |
| default: |
| { |
| // Other formats do nothing. |
| break; |
| } |
| } |
| return convertColorTypeInternal(type, color); |
| } |
| |
| GLColor ClearTextureEXTTestES31::getClearColor(GLenum format, GLColor full) |
| { |
| switch (format) |
| { |
| case GL_RED_INTEGER: |
| case GL_RED: |
| return GLColor(full.R, 0, 0, 255u); |
| case GL_RG_INTEGER: |
| case GL_RG: |
| return GLColor(full.R, full.G, 0, 255u); |
| case GL_RGB_INTEGER: |
| case GL_RGB: |
| return GLColor(full.R, full.G, full.B, 255u); |
| case GL_RGBA_INTEGER: |
| case GL_RGBA: |
| return full; |
| case GL_LUMINANCE: |
| return GLColor(full.R, full.R, full.R, 255u); |
| case GL_ALPHA: |
| return GLColor(0, 0, 0, full.A); |
| case GL_LUMINANCE_ALPHA: |
| return GLColor(full.R, full.R, full.R, full.A); |
| default: |
| EXPECT_TRUE(false); |
| return GLColor::white; |
| } |
| } |
| |
| void ClearTextureEXTTestES31::colorCheckType(const FormatTableElement &fmt, |
| const int &x, |
| const int &y, |
| const int &width, |
| const int &height, |
| GLColor &color) |
| { |
| if (fmt.isInt()) |
| { |
| GLColor32UI colorUInt; |
| GLColor32I colorInt; |
| switch (fmt.type) |
| { |
| case GL_UNSIGNED_BYTE: |
| { |
| colorUInt.R = static_cast<uint32_t>(color.R); |
| colorUInt.G = static_cast<uint32_t>(color.G); |
| colorUInt.B = static_cast<uint32_t>(color.B); |
| colorUInt.A = static_cast<uint32_t>(color.A); |
| if (fmt.format != GL_RGBA_INTEGER) |
| { |
| colorUInt.A = 1; |
| } |
| EXPECT_PIXEL_RECT32UI_EQ(x, y, width, height, colorUInt); |
| return; |
| } |
| case GL_UNSIGNED_SHORT: |
| { |
| GLColor16 colorUShort = |
| std::get<GLColor16>(convertColorTypeInternal(GL_UNSIGNED_SHORT, color)); |
| colorUInt.R = static_cast<uint32_t>(colorUShort.R); |
| colorUInt.G = static_cast<uint32_t>(colorUShort.G); |
| colorUInt.B = static_cast<uint32_t>(colorUShort.B); |
| colorUInt.A = static_cast<uint32_t>(colorUShort.A); |
| if (fmt.format != GL_RGBA_INTEGER) |
| { |
| colorUInt.A = 1; |
| } |
| EXPECT_PIXEL_RECT32UI_EQ(x, y, width, height, colorUInt); |
| return; |
| } |
| case GL_UNSIGNED_INT: |
| { |
| colorUInt = std::get<GLColor32UI>(convertColorTypeInternal(GL_UNSIGNED_INT, color)); |
| if (fmt.format != GL_RGBA_INTEGER) |
| { |
| colorUInt.A = 1; |
| } |
| EXPECT_PIXEL_RECT32UI_EQ(x, y, width, height, colorUInt); |
| return; |
| } |
| case GL_BYTE: |
| { |
| GLColorT<int8_t> colorByte = |
| std::get<GLColorT<int8_t>>(convertColorTypeInternal(GL_BYTE, color)); |
| colorInt.R = static_cast<int32_t>(colorByte.R); |
| colorInt.G = static_cast<int32_t>(colorByte.G); |
| colorInt.B = static_cast<int32_t>(colorByte.B); |
| colorInt.A = static_cast<int32_t>(colorByte.A); |
| if (fmt.format != GL_RGBA_INTEGER) |
| { |
| colorInt.A = 1; |
| } |
| EXPECT_PIXEL_RECT32I_EQ(x, y, width, height, colorInt); |
| return; |
| } |
| case GL_SHORT: |
| { |
| GLColorT<int16_t> colorShort = |
| std::get<GLColorT<int16_t>>(convertColorTypeInternal(GL_SHORT, color)); |
| colorInt.R = static_cast<int32_t>(colorShort.R); |
| colorInt.G = static_cast<int32_t>(colorShort.G); |
| colorInt.B = static_cast<int32_t>(colorShort.B); |
| colorInt.A = static_cast<int32_t>(colorShort.A); |
| if (fmt.format != GL_RGBA_INTEGER) |
| { |
| colorInt.A = 1; |
| } |
| EXPECT_PIXEL_RECT32I_EQ(x, y, width, height, colorInt); |
| return; |
| } |
| case GL_INT: |
| { |
| colorInt = std::get<GLColor32I>(convertColorTypeInternal(GL_INT, color)); |
| if (fmt.format != GL_RGBA_INTEGER) |
| { |
| colorInt.A = 1; |
| } |
| EXPECT_PIXEL_RECT32I_EQ(x, y, width, height, colorInt); |
| return; |
| } |
| default: |
| { |
| UNREACHABLE(); |
| } |
| } |
| } |
| else |
| { |
| switch (fmt.type) |
| { |
| case GL_UNSIGNED_INT_10F_11F_11F_REV: |
| case GL_HALF_FLOAT: |
| case GL_FLOAT: |
| { |
| GLColor32F colorFloat = |
| std::get<GLColor32F>(convertColorTypeInternal(GL_FLOAT, color)); |
| EXPECT_PIXEL_RECT32F_EQ(x, y, width, height, colorFloat); |
| return; |
| } |
| default: |
| { |
| EXPECT_PIXEL_RECT_EQ(x, y, width, height, color); |
| return; |
| } |
| } |
| } |
| } |
| |
| bool ClearTextureEXTTestES31::requiredNorm16(GLint internalformat) |
| { |
| switch (internalformat) |
| { |
| case GL_R16_EXT: |
| case GL_RG16_EXT: |
| case GL_RGB16_EXT: |
| case GL_RGBA16_EXT: |
| case GL_R16_SNORM_EXT: |
| case GL_RG16_SNORM_EXT: |
| case GL_RGB16_SNORM_EXT: |
| case GL_RGBA16_SNORM_EXT: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| const std::string ClearTextureEXTTestES31::getVertexShader(const GLenum &target) |
| { |
| std::string uniform = ""; |
| std::string texcoord = " texcoord = (a_position.xy * 0.5) + 0.5;\n"; |
| |
| if (target == GL_TEXTURE_2D_MULTISAMPLE || target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) |
| { |
| uniform = "uniform vec2 texsize;\n"; |
| texcoord = |
| " texcoord = (a_position.xy * 0.5) + 0.5;\n" |
| " texcoord.x = texcoord.x * texsize.x;\n" |
| " texcoord.y = texcoord.y * texsize.y;\n"; |
| } |
| |
| return "#version 310 es\n" |
| "out vec2 texcoord;\n" |
| "in vec4 a_position;\n" + |
| uniform + |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(a_position.xy, 0.0, 1.0);\n" + |
| texcoord + "}\n"; |
| } |
| |
| const std::string ClearTextureEXTTestES31::getFragmentShader(const GLenum &target, |
| bool isInteger, |
| bool isUInteger) |
| { |
| std::string version = ""; |
| std::string sampler = ""; |
| std::string uniform = ""; |
| std::string mainCode = ""; |
| std::string ui = ""; |
| if (isInteger) |
| { |
| if (isUInteger) |
| { |
| ui = "u"; |
| } |
| else |
| { |
| ui = "i"; |
| } |
| } |
| switch (target) |
| { |
| case GL_TEXTURE_2D: |
| { |
| sampler = "uniform highp " + ui + "sampler2D tex;\n"; |
| mainCode = " fragColor = vec4(texture(tex, texcoord));\n"; |
| break; |
| } |
| case GL_TEXTURE_2D_ARRAY: |
| { |
| sampler = "uniform highp " + ui + "sampler2DArray tex;\n"; |
| uniform = "uniform int slice;\n"; |
| mainCode = " fragColor = vec4(texture(tex, vec3(texcoord, float(slice))));\n"; |
| break; |
| } |
| case GL_TEXTURE_3D: |
| { |
| sampler = "uniform highp " + ui + "sampler3D tex;\n"; |
| uniform = "uniform float slice;\n"; |
| mainCode = " fragColor = vec4(texture(tex, vec3(texcoord, slice)));\n"; |
| break; |
| } |
| case GL_TEXTURE_CUBE_MAP: |
| { |
| sampler = sampler = "uniform highp " + ui + "samplerCube tex;\n"; |
| uniform = "uniform int cubeFace;\n"; |
| mainCode = |
| " vec2 scaled = texcoord.xy * 2. - 1.;\n" |
| " vec3 cubecoord = vec3(1, -scaled.yx);\n" |
| " if (cubeFace == 1)\n" |
| " cubecoord = vec3(-1, -scaled.y, scaled.x);\n" |
| " if (cubeFace == 2)\n" |
| " cubecoord = vec3(scaled.x, 1, scaled.y);\n" |
| " if (cubeFace == 3)\n" |
| " cubecoord = vec3(scaled.x, -1, -scaled.y);\n" |
| " if (cubeFace == 4)\n" |
| " cubecoord = vec3(scaled.x, -scaled.y, 1);\n" |
| " if (cubeFace == 5)\n" |
| " cubecoord = vec3(-scaled.xy, -1);\n" |
| " fragColor = vec4(texture(tex, cubecoord));\n"; |
| break; |
| } |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| { |
| version = "#extension GL_EXT_texture_cube_map_array : enable\n"; |
| sampler = "uniform highp " + ui + "samplerCubeArray tex;\n"; |
| uniform = |
| "uniform int cubeFace;\n" |
| "uniform int layer;\n"; |
| mainCode = |
| " vec2 scaled = texcoord.xy * 2. - 1.;\n" |
| " vec3 cubecoord = vec3(1, -scaled.yx);\n" |
| " if (cubeFace == 1)\n" |
| " cubecoord = vec3(-1, -scaled.y, scaled.x);\n" |
| " if (cubeFace == 2)\n" |
| " cubecoord = vec3(scaled.x, 1, scaled.y);\n" |
| " if (cubeFace == 3)\n" |
| " cubecoord = vec3(scaled.x, -1, -scaled.y);\n" |
| " if (cubeFace == 4)\n" |
| " cubecoord = vec3(scaled.x, -scaled.y, 1);\n" |
| " if (cubeFace == 5)\n" |
| " cubecoord = vec3(-scaled.xy, -1);\n" |
| " fragColor = vec4(texture(tex, vec4(cubecoord, layer)));\n"; |
| break; |
| } |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| { |
| sampler = "uniform highp " + ui + "sampler2DMS tex;\n"; |
| uniform = "uniform int s;\n"; |
| mainCode = " fragColor = vec4(texelFetch(tex, ivec2(texcoord), s));\n"; |
| break; |
| } |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| { |
| version = "#extension GL_OES_texture_storage_multisample_2d_array : require\n"; |
| sampler = "uniform highp " + ui + "sampler2DMSArray tex;\n"; |
| uniform = |
| "uniform int s;\n" |
| "uniform int slice;\n"; |
| mainCode = " fragColor = vec4(texelFetch(tex, ivec3(texcoord, slice), s));\n"; |
| break; |
| } |
| default: |
| { |
| UNREACHABLE(); |
| } |
| } |
| |
| return "#version 310 es\n" + version + "precision highp float;\n" + sampler + uniform + |
| "in vec2 texcoord;\n" |
| "out vec4 fragColor;\n" |
| "void main()\n" |
| "{\n" + |
| mainCode + "}\n"; |
| } |
| |
| void ClearTextureEXTTestES31::initTexture(int levelNum, FormatTableElement &fmt, GLTexture &tex) |
| { |
| // Create a texture widthxheightxdepth with 0x33. |
| std::vector<uint8_t> initColor(mWidth * mHeight * mDepth * 4 * sizeof(fmt.type), 0x33); |
| |
| glBindTexture(mTarget, tex); |
| if (1 == levelNum) |
| { |
| glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| } |
| else |
| { |
| glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); |
| } |
| glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_NO_ERROR); |
| |
| // For each level, initialize the texture color. |
| for (int level = 0; level < levelNum; ++level) |
| { |
| int w = std::max(mWidth >> level, 1); |
| int h = std::max(mHeight >> level, 1); |
| int d = (mTarget == GL_TEXTURE_3D ? std::max(mDepth >> level, 1) : mDepth); |
| |
| if (mTarget == GL_TEXTURE_2D) |
| { |
| glTexImage2D(mTarget, level, fmt.internalformat, w, h, 0, fmt.format, fmt.type, |
| initColor.data()); |
| } |
| else if (mTarget == GL_TEXTURE_CUBE_MAP) |
| { |
| for (int f = 0; f < 6; ++f) |
| { |
| glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, level, fmt.internalformat, w, h, 0, |
| fmt.format, fmt.type, initColor.data()); |
| } |
| } |
| else |
| { |
| glTexImage3D(mTarget, level, fmt.internalformat, w, h, d, 0, fmt.format, fmt.type, |
| initColor.data()); |
| } |
| } |
| } |
| |
| void ClearTextureEXTTestES31::clearCheckRenderable(int level, |
| int width, |
| int height, |
| int depth, |
| const GLTexture &tex, |
| const FormatTableElement &fmt, |
| GLColor &fullColorRef, |
| ColorTypes &fullColor, |
| GLColor &partialColorRef, |
| ColorTypes &partialColor) |
| { |
| // Clear the entire texture. |
| glClearTexImageEXT(tex, level, fmt.format, fmt.type, &fullColor); |
| |
| for (int z = 0; z < depth; ++z) |
| { |
| if (mHasLayer) |
| { |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, level, z); |
| } |
| else |
| { |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, level); |
| } |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| colorCheckType(fmt, 0, 0, width, height, fullColorRef); |
| } |
| |
| // Partial clear the texture. |
| int clearXOffset = width >> 2; |
| int clearYOffset = height >> 2; |
| int clearZOffset = depth >> 2; |
| int clearWidth = std::max(width >> 1, 1); |
| int clearHeight = std::max(height >> 1, 1); |
| int clearDepth = std::max(depth >> 1, 1); |
| |
| glClearTexSubImageEXT(tex, level, clearXOffset, clearYOffset, clearZOffset, clearWidth, |
| clearHeight, clearDepth, fmt.format, fmt.type, &partialColor); |
| |
| for (int z = 0; z < depth; ++z) |
| { |
| if (mHasLayer) |
| { |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, level, z); |
| } |
| else |
| { |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, level); |
| } |
| |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| if (z >= clearZOffset && z < (clearZOffset + clearDepth)) |
| { |
| colorCheckType(fmt, clearXOffset, clearYOffset, clearWidth, clearHeight, |
| partialColorRef); |
| } |
| else |
| { |
| colorCheckType(fmt, clearXOffset, clearYOffset, clearWidth, clearHeight, fullColorRef); |
| } |
| } |
| } |
| |
| void ClearTextureEXTTestES31::clearCheckUnrenderable(int level, |
| int width, |
| int height, |
| int depth, |
| const GLTexture &tex, |
| const FormatTableElement &fmt, |
| GLuint program, |
| const std::vector<int> &loc, |
| GLColor &fullColorRef, |
| ColorTypes &fullColor, |
| GLColor &partialColorRef, |
| ColorTypes &partialColor) |
| { |
| // Clear the entire texture. |
| glClearTexImageEXT(tex, level, fmt.format, fmt.type, &fullColor); |
| glTexParameteri(mTarget, GL_TEXTURE_BASE_LEVEL, level); |
| |
| int sampleNum = 1; |
| if (mTarget == GL_TEXTURE_2D_MULTISAMPLE || mTarget == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) |
| { |
| glGetInternalformativ(mTarget, fmt.internalformat, GL_SAMPLES, 1, &sampleNum); |
| sampleNum = std::min(sampleNum, 4); |
| } |
| |
| for (int z = 0; z < depth; ++z) |
| { |
| if (mHasLayer) |
| { |
| if (mTarget == GL_TEXTURE_CUBE_MAP_ARRAY) |
| { |
| glUniform1i(loc[0], z % 6); |
| glUniform1i(loc[1], z / 6); |
| } |
| else if (mTarget == GL_TEXTURE_3D) |
| { |
| glUniform1f(loc[0], (z + 0.5f) / depth); |
| } |
| else if (mTarget == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) |
| { |
| glUniform1i(loc[1], z); |
| } |
| else |
| { |
| glUniform1i(loc[0], z); |
| } |
| } |
| |
| for (int sample = 0; sample < sampleNum; ++sample) |
| { |
| if (sampleNum != 1) |
| { |
| glUniform1i(loc[0], sample); |
| } |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), fullColorRef); |
| } |
| } |
| |
| // Partial clear the texture. |
| int clearXOffset = width >> 2; |
| int clearYOffset = height >> 2; |
| int clearZOffset = depth >> 2; |
| int clearWidth = std::max(width >> 1, 1); |
| int clearHeight = std::max(height >> 1, 1); |
| int clearDepth = std::max(depth >> 1, 1); |
| int pixelXOffset = |
| static_cast<int>(clearXOffset * getWindowWidth() / static_cast<float>(width) + 0.5); |
| int pixelYOffset = |
| static_cast<int>(clearYOffset * getWindowHeight() / static_cast<float>(height) + 0.5); |
| int pixelWidth = |
| static_cast<int>( |
| (clearXOffset + clearWidth) * getWindowWidth() / static_cast<float>(width) + 0.5) - |
| pixelXOffset; |
| int pixelHeight = |
| static_cast<int>( |
| (clearYOffset + clearHeight) * getWindowHeight() / static_cast<float>(height) + 0.5) - |
| pixelYOffset; |
| |
| glClearTexSubImageEXT(tex, level, clearXOffset, clearYOffset, clearZOffset, clearWidth, |
| clearHeight, clearDepth, fmt.format, fmt.type, &partialColor); |
| |
| for (int z = 0; z < depth; ++z) |
| { |
| if (mHasLayer) |
| { |
| if (mTarget == GL_TEXTURE_CUBE_MAP_ARRAY) |
| { |
| glUniform1i(loc[0], z % 6); |
| glUniform1i(loc[1], z / 6); |
| } |
| else if (mTarget == GL_TEXTURE_3D) |
| { |
| glUniform1f(loc[0], (z + 0.5f) / depth); |
| } |
| else if (mTarget == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) |
| { |
| glUniform1i(loc[1], z); |
| } |
| else |
| { |
| glUniform1i(loc[0], z); |
| } |
| } |
| |
| for (int sample = 0; sample < sampleNum; ++sample) |
| { |
| if (sampleNum != 1) |
| { |
| glUniform1i(loc[0], sample); |
| } |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| if (z >= clearZOffset && z < (clearZOffset + clearDepth)) |
| { |
| EXPECT_PIXEL_RECT_EQ(pixelXOffset, pixelYOffset, pixelWidth, pixelHeight, |
| partialColorRef); |
| } |
| else |
| { |
| EXPECT_PIXEL_RECT_EQ(pixelXOffset, pixelYOffset, pixelWidth, pixelHeight, |
| fullColorRef); |
| } |
| } |
| } |
| } |
| |
| class ClearTextureEXTTestES31Renderable : public ClearTextureEXTTestES31 |
| { |
| protected: |
| std::vector<FormatTableElement> mFormats = { |
| {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, |
| {GL_R16F, GL_RED, GL_HALF_FLOAT}, |
| {GL_R16F, GL_RED, GL_FLOAT}, |
| {GL_R32F, GL_RED, GL_FLOAT}, |
| {GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, |
| {GL_RG16F, GL_RG, GL_HALF_FLOAT}, |
| {GL_RG16F, GL_RG, GL_FLOAT}, |
| {GL_RG32F, GL_RG, GL_FLOAT}, |
| {GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}, |
| {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, |
| {GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE}, |
| {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV}, |
| {GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT}, |
| {GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT}, |
| {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE}, |
| {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE}, |
| {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, |
| {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, |
| {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, |
| {GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE}, |
| {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}, |
| {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, |
| {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT}, |
| {GL_RGBA16F, GL_RGBA, GL_FLOAT}, |
| {GL_RGBA32F, GL_RGBA, GL_FLOAT}, |
| {GL_R16_EXT, GL_RED, GL_UNSIGNED_SHORT}, |
| {GL_RG16_EXT, GL_RG, GL_UNSIGNED_SHORT}, |
| {GL_RGBA16_EXT, GL_RGBA, GL_UNSIGNED_SHORT}, |
| {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE}, |
| {GL_R8I, GL_RED_INTEGER, GL_BYTE}, |
| {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT}, |
| {GL_R16I, GL_RED_INTEGER, GL_SHORT}, |
| {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, |
| {GL_R32I, GL_RED_INTEGER, GL_INT}, |
| {GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE}, |
| {GL_RG8I, GL_RG_INTEGER, GL_BYTE}, |
| {GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT}, |
| {GL_RG16I, GL_RG_INTEGER, GL_SHORT}, |
| {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT}, |
| {GL_RG32I, GL_RG_INTEGER, GL_INT}, |
| {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE}, |
| {GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE}, |
| {GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT}, |
| {GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT}, |
| {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT}, |
| {GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, |
| }; |
| |
| void testRenderable() |
| { |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 || |
| !IsGLExtensionEnabled("GL_EXT_clear_texture") || !mExtraSupport); |
| |
| const auto test = [&](FormatTableElement &fmt) { |
| // Update MAX level numbers. |
| if (mTarget == GL_TEXTURE_3D) |
| { |
| mLevels = std::max(mLevels, static_cast<int>(std::log2(mDepth)) + 1); |
| } |
| |
| GLTexture tex; |
| initTexture(mLevels, fmt, tex); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| // Calculate specific clear color value. |
| GLColor fullColorRef = getClearColor(fmt.format, mFullColorRef); |
| ColorTypes fullColor = convertColorType(fmt.format, fmt.type, fullColorRef); |
| GLColor partialColorRef = getClearColor(fmt.format, mPartialColorRef); |
| ColorTypes partialColor = convertColorType(fmt.format, fmt.type, partialColorRef); |
| |
| for (int level = 0; level < mLevels; ++level) |
| { |
| int width = std::max(mWidth >> level, 1); |
| int height = std::max(mHeight >> level, 1); |
| int depth = mIsArray ? mDepth : std::max(mDepth >> level, 1); |
| |
| clearCheckRenderable(level, width, height, depth, tex, fmt, fullColorRef, fullColor, |
| partialColorRef, partialColor); |
| } |
| }; |
| |
| bool supportNorm16 = IsGLExtensionEnabled("GL_EXT_texture_norm16"); |
| for (auto fmt : mFormats) |
| { |
| if (!supportNorm16 && requiredNorm16(fmt.internalformat)) |
| { |
| continue; |
| } |
| test(fmt); |
| } |
| } |
| |
| void testMS() |
| { |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 || |
| !IsGLExtensionEnabled("GL_EXT_clear_texture") || !mExtraSupport); |
| |
| const auto test = [&](FormatTableElement &fmt) { |
| // Initialize the texture. |
| GLTexture tex; |
| glBindTexture(mTarget, tex); |
| int sampleNum = 0; |
| glGetInternalformativ(mTarget, fmt.internalformat, GL_SAMPLES, 1, &sampleNum); |
| sampleNum = std::min(sampleNum, 4); |
| if (mIsArray) |
| { |
| glTexStorage3DMultisampleOES(mTarget, sampleNum, fmt.internalformat, mWidth, |
| mHeight, mDepth, GL_TRUE); |
| } |
| else |
| { |
| glTexStorage2DMultisample(mTarget, sampleNum, fmt.internalformat, mWidth, mHeight, |
| GL_TRUE); |
| } |
| EXPECT_GL_ERROR(GL_NO_ERROR); |
| ANGLE_GL_PROGRAM(initProgram, essl31_shaders::vs::Simple(), |
| essl31_shaders::fs::Green()); |
| glUseProgram(initProgram); |
| drawQuad(initProgram, essl31_shaders::PositionAttrib(), 0.5f); |
| |
| // Calculate specific clear color value. |
| GLColor fullColorRef = getClearColor(fmt.format, mFullColorRef); |
| ColorTypes fullColor = convertColorType(fmt.format, fmt.type, fullColorRef); |
| GLColor partialColorRef = getClearColor(fmt.format, mPartialColorRef); |
| ColorTypes partialColor = convertColorType(fmt.format, fmt.type, partialColorRef); |
| |
| ANGLE_GL_PROGRAM(program, getVertexShader(mTarget).c_str(), |
| getFragmentShader(mTarget, fmt.isInt(), fmt.isUInt()).c_str()); |
| glUseProgram(program); |
| |
| std::vector<int> uniformLocs = {0, 0, 0}; |
| |
| uniformLocs[0] = glGetUniformLocation(program, "s"); |
| ASSERT_NE(-1, uniformLocs[0]); |
| uniformLocs[2] = glGetUniformLocation(program, "texsize"); |
| ASSERT_NE(-1, uniformLocs[2]); |
| glUniform2f(uniformLocs[2], static_cast<float>(mWidth), static_cast<float>(mHeight)); |
| if (mIsArray) |
| { |
| uniformLocs[1] = glGetUniformLocation(program, "slice"); |
| ASSERT_NE(-1, uniformLocs[1]); |
| } |
| |
| clearCheckUnrenderable(0, mWidth, mHeight, mDepth, tex, fmt, program, uniformLocs, |
| fullColorRef, fullColor, partialColorRef, partialColor); |
| }; |
| |
| bool supportNorm16 = IsGLExtensionEnabled("GL_EXT_texture_norm16"); |
| for (auto fmt : mFormats) |
| { |
| if (!supportNorm16 && requiredNorm16(fmt.internalformat)) |
| { |
| continue; |
| } |
| test(fmt); |
| } |
| } |
| }; |
| |
| class ClearTextureEXTTestES31Unrenderable : public ClearTextureEXTTestES31 |
| { |
| protected: |
| std::vector<FormatTableElement> mFormats = { |
| {GL_RGB16F, GL_RGB, GL_HALF_FLOAT}, |
| {GL_RGB16F, GL_RGB, GL_FLOAT}, |
| {GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE}, |
| {GL_RGB8I, GL_RGB_INTEGER, GL_BYTE}, |
| {GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT}, |
| {GL_RGB16I, GL_RGB_INTEGER, GL_SHORT}, |
| {GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT}, |
| {GL_RGB32I, GL_RGB_INTEGER, GL_INT}, |
| {GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE}, |
| {GL_R8_SNORM, GL_RED, GL_BYTE}, |
| {GL_RG8_SNORM, GL_RG, GL_BYTE}, |
| {GL_RGB8_SNORM, GL_RGB, GL_BYTE}, |
| {GL_RGB32F, GL_RGB, GL_FLOAT}, |
| {GL_RGBA8_SNORM, GL_RGBA, GL_BYTE}, |
| {GL_RGB16_EXT, GL_RGB, GL_UNSIGNED_SHORT}, |
| {GL_R16_SNORM_EXT, GL_RED, GL_SHORT}, |
| {GL_RG16_SNORM_EXT, GL_RG, GL_SHORT}, |
| {GL_RGBA16_SNORM_EXT, GL_RGBA, GL_SHORT}, |
| {GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE}, |
| {GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE}, |
| {GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE}, |
| }; |
| |
| std::vector<FormatTableElement> mFormatsRGB9E5 = { |
| {GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, |
| {GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT}, |
| {GL_RGB9_E5, GL_RGB, GL_FLOAT}, |
| }; |
| |
| void testUnrenderable(std::vector<FormatTableElement> &formats) |
| { |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 || |
| !IsGLExtensionEnabled("GL_EXT_clear_texture") || !mExtraSupport); |
| |
| const auto test = [&](FormatTableElement &fmt) { |
| // Update MAX level numbers. |
| if (mTarget == GL_TEXTURE_3D) |
| { |
| mLevels = std::max(mLevels, static_cast<int>(std::log2(mDepth)) + 1); |
| } |
| |
| GLTexture tex; |
| initTexture(mLevels, fmt, tex); |
| |
| // Calculate specific clear color value. |
| GLColor fullColorRef = getClearColor(fmt.format, mFullColorRef); |
| ColorTypes fullColor = convertColorType(fmt.format, fmt.type, fullColorRef); |
| GLColor partialColorRef = getClearColor(fmt.format, mPartialColorRef); |
| ColorTypes partialColor = convertColorType(fmt.format, fmt.type, partialColorRef); |
| |
| ANGLE_GL_PROGRAM(program, getVertexShader(mTarget).c_str(), |
| getFragmentShader(mTarget, fmt.isInt(), fmt.isUInt()).c_str()); |
| glUseProgram(program); |
| |
| std::vector<int> uniformLocs = {0, 0}; |
| if (mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_3D) |
| { |
| uniformLocs[0] = glGetUniformLocation(program, "slice"); |
| ASSERT_NE(-1, uniformLocs[0]); |
| } |
| else if (mTarget == GL_TEXTURE_CUBE_MAP) |
| { |
| uniformLocs[0] = glGetUniformLocation(program, "cubeFace"); |
| } |
| else if (mTarget == GL_TEXTURE_CUBE_MAP_ARRAY) |
| { |
| uniformLocs[0] = glGetUniformLocation(program, "cubeFace"); |
| ASSERT_NE(-1, uniformLocs[0]); |
| uniformLocs[1] = glGetUniformLocation(program, "layer"); |
| ASSERT_NE(-1, uniformLocs[1]); |
| } |
| |
| // For each level, clear the texture. |
| for (int level = 0; level < mLevels; ++level) |
| { |
| int width = std::max(mWidth >> level, 1); |
| int height = std::max(mHeight >> level, 1); |
| int depth = mIsArray ? mDepth : std::max(mDepth >> level, 1); |
| |
| clearCheckUnrenderable(level, width, height, depth, tex, fmt, program, uniformLocs, |
| fullColorRef, fullColor, partialColorRef, partialColor); |
| } |
| }; |
| |
| bool supportNorm16 = IsGLExtensionEnabled("GL_EXT_texture_norm16"); |
| for (auto fmt : formats) |
| { |
| if (!supportNorm16 && requiredNorm16(fmt.internalformat)) |
| { |
| continue; |
| } |
| test(fmt); |
| } |
| } |
| }; |
| |
| // Each int parameter can have three values: don't clear, clear, or masked clear. The bool |
| // parameter controls scissor. |
| using MaskedScissoredClearVariationsTestParams = |
| std::tuple<angle::PlatformParameters, int, int, int, bool>; |
| |
| void ParseMaskedScissoredClearVariationsTestParams( |
| const MaskedScissoredClearVariationsTestParams ¶ms, |
| bool *clearColor, |
| bool *clearDepth, |
| bool *clearStencil, |
| bool *maskColor, |
| bool *maskDepth, |
| bool *maskStencil, |
| bool *scissor) |
| { |
| int colorClearInfo = std::get<1>(params); |
| int depthClearInfo = std::get<2>(params); |
| int stencilClearInfo = std::get<3>(params); |
| |
| *clearColor = colorClearInfo > 0; |
| *clearDepth = depthClearInfo > 0; |
| *clearStencil = stencilClearInfo > 0; |
| |
| *maskColor = colorClearInfo > 1; |
| *maskDepth = depthClearInfo > 1; |
| *maskStencil = stencilClearInfo > 1; |
| |
| *scissor = std::get<4>(params); |
| } |
| |
| std::string MaskedScissoredClearVariationsTestPrint( |
| const ::testing::TestParamInfo<MaskedScissoredClearVariationsTestParams> ¶msInfo) |
| { |
| const MaskedScissoredClearVariationsTestParams ¶ms = paramsInfo.param; |
| std::ostringstream out; |
| |
| out << std::get<0>(params); |
| |
| bool clearColor, clearDepth, clearStencil; |
| bool maskColor, maskDepth, maskStencil; |
| bool scissor; |
| |
| ParseMaskedScissoredClearVariationsTestParams(params, &clearColor, &clearDepth, &clearStencil, |
| &maskColor, &maskDepth, &maskStencil, &scissor); |
| |
| if (scissor || clearColor || clearDepth || clearStencil || maskColor || maskDepth || |
| maskStencil) |
| { |
| out << "_"; |
| } |
| |
| if (scissor) |
| { |
| out << "_scissored"; |
| } |
| |
| if (clearColor || clearDepth || clearStencil) |
| { |
| out << "_clear_"; |
| if (clearColor) |
| { |
| out << "c"; |
| } |
| if (clearDepth) |
| { |
| out << "d"; |
| } |
| if (clearStencil) |
| { |
| out << "s"; |
| } |
| } |
| |
| if (maskColor || maskDepth || maskStencil) |
| { |
| out << "_mask_"; |
| if (maskColor) |
| { |
| out << "c"; |
| } |
| if (maskDepth) |
| { |
| out << "d"; |
| } |
| if (maskStencil) |
| { |
| out << "s"; |
| } |
| } |
| |
| return out.str(); |
| } |
| |
| class MaskedScissoredClearTestBase : public ANGLETest<MaskedScissoredClearVariationsTestParams> |
| { |
| protected: |
| MaskedScissoredClearTestBase() |
| { |
| setWindowWidth(128); |
| setWindowHeight(128); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| setConfigDepthBits(24); |
| setConfigStencilBits(8); |
| } |
| |
| void maskedScissoredColorDepthStencilClear( |
| const MaskedScissoredClearVariationsTestParams ¶ms); |
| |
| bool mHasDepth = true; |
| bool mHasStencil = true; |
| }; |
| |
| class MaskedScissoredClearTest : public MaskedScissoredClearTestBase |
| {}; |
| |
| // Overrides a feature to force emulation of stencil-only and depth-only formats with a packed |
| // depth/stencil format |
| class VulkanClearTest : public MaskedScissoredClearTestBase |
| { |
| protected: |
| void testSetUp() override |
| { |
| glBindTexture(GL_TEXTURE_2D, mColorTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| |
| // Setup Color/Stencil FBO with a stencil format that's emulated with packed depth/stencil. |
| glBindFramebuffer(GL_FRAMEBUFFER, mColorStencilFBO); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mColorTexture, |
| 0); |
| glBindRenderbuffer(GL_RENDERBUFFER, mStencilTexture); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, getWindowWidth(), |
| getWindowHeight()); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| mStencilTexture); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Note: GL_DEPTH_COMPONENT24 is not allowed in GLES2. |
| if (getClientMajorVersion() >= 3) |
| { |
| // Setup Color/Depth FBO with a depth format that's emulated with packed depth/stencil. |
| glBindFramebuffer(GL_FRAMEBUFFER, mColorDepthFBO); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| mColorTexture, 0); |
| glBindRenderbuffer(GL_RENDERBUFFER, mDepthTexture); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, getWindowWidth(), |
| getWindowHeight()); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| mDepthTexture); |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| void bindColorStencilFBO() |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, mColorStencilFBO); |
| mHasDepth = false; |
| } |
| |
| void bindColorDepthFBO() |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, mColorDepthFBO); |
| mHasStencil = false; |
| } |
| |
| private: |
| GLFramebuffer mColorStencilFBO; |
| GLFramebuffer mColorDepthFBO; |
| GLTexture mColorTexture; |
| GLRenderbuffer mDepthTexture; |
| GLRenderbuffer mStencilTexture; |
| }; |
| |
| // Test clearing the default framebuffer |
| TEST_P(ClearTest, DefaultFramebuffer) |
| { |
| glClearColor(0.25f, 0.5f, 0.5f, 0.5f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_NEAR(0, 0, 64, 128, 128, 128, 1.0); |
| } |
| |
| // Test clearing the default framebuffer with scissor and mask |
| // This forces down path that uses draw to do clear |
| TEST_P(ClearTest, EmptyScissor) |
| { |
| // These configs have bug that fails this test. |
| // These configs are unmaintained so skipping. |
| ANGLE_SKIP_TEST_IF(IsIntel() && IsD3D9()); |
| ANGLE_SKIP_TEST_IF(IsIntel() && IsMac() && IsOpenGL()); |
| glClearColor(0.25f, 0.5f, 0.5f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(-10, 0, 5, 5); |
| glClearColor(0.5f, 0.25f, 0.75f, 0.5f); |
| glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_TRUE); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glDisable(GL_SCISSOR_TEST); |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| EXPECT_PIXEL_NEAR(0, 0, 64, 128, 128, 255, 1.0); |
| } |
| |
| // Test clearing the RGB default framebuffer and verify that the alpha channel is not cleared |
| TEST_P(ClearTestRGB, DefaultFramebufferRGB) |
| { |
| // Some GPUs don't support RGB format default framebuffer, |
| // so skip if the back buffer has alpha bits. |
| EGLWindow *window = getEGLWindow(); |
| EGLDisplay display = window->getDisplay(); |
| EGLConfig config = window->getConfig(); |
| EGLint backbufferAlphaBits = 0; |
| eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &backbufferAlphaBits); |
| ANGLE_SKIP_TEST_IF(backbufferAlphaBits != 0); |
| |
| glClearColor(0.25f, 0.5f, 0.5f, 0.5f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_NEAR(0, 0, 64, 128, 128, 255, 1.0); |
| } |
| |
| // Invalidate the RGB default framebuffer and verify that the alpha channel is not cleared, and |
| // stays set after drawing. |
| TEST_P(ClearTestRGB_ES3, InvalidateDefaultFramebufferRGB) |
| { |
| ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| |
| // Some GPUs don't support RGB format default framebuffer, |
| // so skip if the back buffer has alpha bits. |
| EGLWindow *window = getEGLWindow(); |
| EGLDisplay display = window->getDisplay(); |
| EGLConfig config = window->getConfig(); |
| EGLint backbufferAlphaBits = 0; |
| eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &backbufferAlphaBits); |
| ANGLE_SKIP_TEST_IF(backbufferAlphaBits != 0); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| // Verify that even though Alpha is cleared to 0.0 for this RGB FBO, it should be read back as |
| // 1.0, since the glReadPixels() is issued with GL_RGBA. |
| // OpenGL ES 3.2 spec: |
| // 16.1.3 Obtaining Pixels from the Framebuffer |
| // If G, B, or A values are not present in the internal format, they are taken to be zero, |
| // zero, and one respectively. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); |
| |
| const GLenum discards[] = {GL_COLOR}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards); |
| |
| // Don't explicitly clear, but draw blue (make sure alpha is not cleared) |
| drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| } |
| |
| // Draw with a shader that outputs alpha=0.5. Readback and ensure that alpha=1. |
| TEST_P(ClearTestRGB_ES3, ShaderOutputsAlphaVerifyReadingAlphaIsOne) |
| { |
| ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(blueProgram); |
| |
| // Some GPUs don't support RGB format default framebuffer, |
| // so skip if the back buffer has alpha bits. |
| EGLWindow *window = getEGLWindow(); |
| EGLDisplay display = window->getDisplay(); |
| EGLConfig config = window->getConfig(); |
| EGLint backbufferAlphaBits = 0; |
| eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &backbufferAlphaBits); |
| ANGLE_SKIP_TEST_IF(backbufferAlphaBits != 0); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); |
| |
| GLint colorUniformLocation = |
| glGetUniformLocation(blueProgram, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Don't explicitly clear, but draw blue (make sure alpha is not cleared) |
| drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| } |
| |
| // Test clearing a RGBA8 Framebuffer |
| TEST_P(ClearTest, RGBA8Framebuffer) |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture texture; |
| |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| |
| glClearColor(0.5f, 0.5f, 0.5f, 0.5f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| EXPECT_PIXEL_NEAR(0, 0, 128, 128, 128, 128, 1.0); |
| } |
| |
| // Test clearing a BGRA8 Framebuffer |
| TEST_P(ClearTest, BGRA8Framebuffer) |
| { |
| ANGLE_SKIP_TEST_IF(getEGLWindow()->isFeatureEnabled(Feature::BgraTexImageFormatsBroken)); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture texture; |
| |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, getWindowWidth(), getWindowHeight(), 0, GL_BGRA_EXT, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| EXPECT_PIXEL_NEAR(0, 0, 0, 255, 0, 255, 1.0); |
| } |
| |
| // Test uploading a texture and then clearing a RGBA8 Framebuffer |
| TEST_P(ClearTest, TextureUploadAndRGBA8Framebuffer) |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture texture; |
| |
| constexpr uint32_t kSize = 16; |
| std::vector<GLColor> pixelData(kSize * kSize, GLColor::blue); |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| pixelData.data()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| |
| EXPECT_PIXEL_NEAR(0, 0, 0, 0, 255, 255, 1.0); |
| |
| glClearColor(0.5f, 0.5f, 0.5f, 0.5f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| EXPECT_PIXEL_NEAR(0, 0, 128, 128, 128, 128, 1.0); |
| } |
| |
| // Test to validate that we can go from an RGBA framebuffer attachment, to an RGB one and still |
| // have a correct behavior after. |
| TEST_P(ClearTest, ChangeFramebufferAttachmentFromRGBAtoRGB) |
| { |
| // http://anglebug.com/40096508 |
| ANGLE_SKIP_TEST_IF(IsAndroid() && IsAdreno() && IsOpenGLES()); |
| |
| // http://anglebug.com/40644765 |
| ANGLE_SKIP_TEST_IF(IsMac() && IsDesktopOpenGL() && IsIntel()); |
| |
| ANGLE_GL_PROGRAM(program, angle::essl1_shaders::vs::Simple(), |
| angle::essl1_shaders::fs::UniformColor()); |
| setupQuadVertexBuffer(0.5f, 1.0f); |
| glUseProgram(program); |
| GLint positionLocation = glGetAttribLocation(program, angle::essl1_shaders::PositionAttrib()); |
| ASSERT_NE(positionLocation, -1); |
| glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| glEnableVertexAttribArray(positionLocation); |
| |
| GLint colorUniformLocation = |
| glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| glUniform4f(colorUniformLocation, 1.0f, 1.0f, 1.0f, 0.5f); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| |
| // Initially clear to black. |
| glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Clear with masked color. |
| glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_TRUE); |
| glClearColor(0.5f, 0.5f, 0.5f, 0.75f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| // So far so good, we have an RGBA framebuffer that we've cleared to 0.5 everywhere. |
| EXPECT_PIXEL_NEAR(0, 0, 128, 0, 128, 192, 1.0); |
| |
| // In the Vulkan backend, RGB textures are emulated with an RGBA texture format |
| // underneath and we keep a special mask to know that we shouldn't touch the alpha |
| // channel when we have that emulated texture. This test exists to validate that |
| // this mask gets updated correctly when the framebuffer attachment changes. |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::magenta); |
| } |
| |
| // Test clearing a RGB8 Framebuffer with a color mask. |
| TEST_P(ClearTest, RGB8WithMaskFramebuffer) |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture texture; |
| |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| |
| glClearColor(0.2f, 0.4f, 0.6f, 0.8f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Since there's no alpha, we expect to get 255 back instead of the clear value (204). |
| EXPECT_PIXEL_NEAR(0, 0, 51, 102, 153, 255, 1.0); |
| |
| glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_TRUE); |
| glClearColor(0.1f, 0.3f, 0.5f, 0.7f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // The blue channel was masked so its value should be unchanged. |
| EXPECT_PIXEL_NEAR(0, 0, 26, 77, 153, 255, 1.0); |
| |
| // Restore default. |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| } |
| |
| TEST_P(ClearTest, ClearIssue) |
| { |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LEQUAL); |
| |
| glClearColor(0.0, 1.0, 0.0, 1.0); |
| glClearDepthf(0.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLRenderbuffer rbo; |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB565, 16, 16); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClearDepthf(1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| // Regression test for a bug where "glClearDepthf"'s argument was not clamped |
| // In GLES 2 they where declared as GLclampf and the behaviour is the same in GLES 3.2 |
| TEST_P(ClearTest, ClearIsClamped) |
| { |
| glClearDepthf(5.0f); |
| |
| GLfloat clear_depth; |
| glGetFloatv(GL_DEPTH_CLEAR_VALUE, &clear_depth); |
| EXPECT_EQ(1.0f, clear_depth); |
| } |
| |
| // Regression test for a bug where "glDepthRangef"'s arguments were not clamped |
| // In GLES 2 they where declared as GLclampf and the behaviour is the same in GLES 3.2 |
| TEST_P(ClearTest, DepthRangefIsClamped) |
| { |
| glDepthRangef(1.1f, -4.0f); |
| |
| GLfloat depth_range[2]; |
| glGetFloatv(GL_DEPTH_RANGE, depth_range); |
| EXPECT_EQ(1.0f, depth_range[0]); |
| EXPECT_EQ(0.0f, depth_range[1]); |
| } |
| |
| // Test scissored clears on Depth16 |
| TEST_P(ClearTest, Depth16Scissored) |
| { |
| GLRenderbuffer renderbuffer; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); |
| constexpr int kRenderbufferSize = 64; |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, kRenderbufferSize, |
| kRenderbufferSize); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer); |
| |
| glClearDepthf(0.0f); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| |
| glEnable(GL_SCISSOR_TEST); |
| constexpr int kNumSteps = 13; |
| for (int ndx = 1; ndx < kNumSteps; ndx++) |
| { |
| float perc = static_cast<float>(ndx) / static_cast<float>(kNumSteps); |
| glScissor(0, 0, static_cast<int>(kRenderbufferSize * perc), |
| static_cast<int>(kRenderbufferSize * perc)); |
| glClearDepthf(perc); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| } |
| } |
| |
| // Test scissored clears on Stencil8 |
| TEST_P(ClearTest, Stencil8Scissored) |
| { |
| GLRenderbuffer renderbuffer; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); |
| constexpr int kRenderbufferSize = 64; |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, kRenderbufferSize, kRenderbufferSize); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer); |
| |
| glClearStencil(0); |
| glClear(GL_STENCIL_BUFFER_BIT); |
| |
| glEnable(GL_SCISSOR_TEST); |
| constexpr int kNumSteps = 13; |
| for (int ndx = 1; ndx < kNumSteps; ndx++) |
| { |
| float perc = static_cast<float>(ndx) / static_cast<float>(kNumSteps); |
| glScissor(0, 0, static_cast<int>(kRenderbufferSize * perc), |
| static_cast<int>(kRenderbufferSize * perc)); |
| glClearStencil(static_cast<int>(perc * 255.0f)); |
| glClear(GL_STENCIL_BUFFER_BIT); |
| } |
| } |
| |
| // Covers a bug in the Vulkan back-end where starting a new command buffer in |
| // the masked clear would not trigger descriptor sets to be re-bound. |
| TEST_P(ClearTest, MaskedClearThenDrawWithUniform) |
| { |
| // Initialize a program with a uniform. |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(program); |
| |
| GLint uniLoc = glGetUniformLocation(program, essl1_shaders::ColorUniform()); |
| ASSERT_NE(-1, uniLoc); |
| glUniform4f(uniLoc, 0.0f, 1.0f, 0.0f, 1.0f); |
| |
| // Initialize position attribute. |
| GLint posLoc = glGetAttribLocation(program, essl1_shaders::PositionAttrib()); |
| ASSERT_NE(-1, posLoc); |
| setupQuadVertexBuffer(0.5f, 1.0f); |
| glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| glEnableVertexAttribArray(posLoc); |
| |
| // Initialize a simple FBO. |
| constexpr GLsizei kSize = 2; |
| GLTexture clearTexture; |
| glBindTexture(GL_TEXTURE_2D, clearTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, clearTexture, 0); |
| |
| glViewport(0, 0, kSize, kSize); |
| |
| // Clear and draw to flush out dirty bits. |
| glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| |
| // Flush to trigger a new serial. |
| glFlush(); |
| |
| // Enable color mask and draw again to trigger the bug. |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); |
| glClearColor(1.0f, 0.0f, 0.0f, 0.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| // Clear with a mask to verify that masked clear is done properly |
| // (can't use inline or RenderOp clear when some color channels are masked) |
| TEST_P(ClearTestES3, ClearPlusMaskDrawAndClear) |
| { |
| // Initialize a program with a uniform. |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(program); |
| |
| GLint uniLoc = glGetUniformLocation(program, essl1_shaders::ColorUniform()); |
| ASSERT_NE(-1, uniLoc); |
| glUniform4f(uniLoc, 0.0f, 1.0f, 0.0f, 1.0f); |
| |
| // Initialize position attribute. |
| GLint posLoc = glGetAttribLocation(program, essl1_shaders::PositionAttrib()); |
| ASSERT_NE(-1, posLoc); |
| setupQuadVertexBuffer(0.5f, 1.0f); |
| glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| glEnableVertexAttribArray(posLoc); |
| |
| // Initialize a simple FBO. |
| constexpr GLsizei kSize = 2; |
| GLTexture clearTexture; |
| glBindTexture(GL_TEXTURE_2D, clearTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, clearTexture, 0); |
| |
| GLRenderbuffer depthStencil; |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencil); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| ASSERT_GL_NO_ERROR(); |
| |
| glViewport(0, 0, kSize, kSize); |
| |
| // Clear and draw to flush out dirty bits. |
| glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| glClearDepthf(1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Draw green rectangle |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| |
| // Enable color mask and draw again to trigger the bug. |
| glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_TRUE); |
| glClearColor(0.5f, 0.5f, 0.5f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Draw purple-ish rectangle, green should be masked off |
| glUniform4f(uniLoc, 1.0f, 0.25f, 1.0f, 1.0f); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| } |
| |
| // Test that clearing all buffers through glClearColor followed by a clear of a specific buffer |
| // clears to the correct values. |
| TEST_P(ClearTestES3, ClearMultipleAttachmentsFollowedBySpecificOne) |
| { |
| constexpr uint32_t kSize = 16; |
| constexpr uint32_t kAttachmentCount = 4; |
| std::vector<unsigned char> pixelData(kSize * kSize * 4, 255); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture textures[kAttachmentCount]; |
| GLenum drawBuffers[kAttachmentCount]; |
| GLColor clearValues[kAttachmentCount]; |
| |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glBindTexture(GL_TEXTURE_2D, textures[i]); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| pixelData.data()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], |
| 0); |
| drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; |
| |
| clearValues[i].R = static_cast<GLubyte>(1 + i * 20); |
| clearValues[i].G = static_cast<GLubyte>(7 + i * 20); |
| clearValues[i].B = static_cast<GLubyte>(12 + i * 20); |
| clearValues[i].A = static_cast<GLubyte>(16 + i * 20); |
| } |
| |
| glDrawBuffers(kAttachmentCount, drawBuffers); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| |
| // Clear all targets. |
| angle::Vector4 clearColor = clearValues[0].toNormalizedVector(); |
| glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); |
| glClear(GL_COLOR_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear odd targets individually. |
| for (uint32_t i = 1; i < kAttachmentCount; i += 2) |
| { |
| clearColor = clearValues[i].toNormalizedVector(); |
| glClearBufferfv(GL_COLOR, i, clearColor.data()); |
| } |
| |
| // Even attachments should be cleared to color 0, while odd attachments are cleared to their |
| // respective color. |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT0 + i); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t clearIndex = i % 2 == 0 ? 0 : i; |
| const GLColor &expect = clearValues[clearIndex]; |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, expect); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, expect); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, expect); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, expect); |
| } |
| } |
| |
| // Test that clearing each render target individually works. In the Vulkan backend, this should be |
| // done in a single render pass. |
| TEST_P(ClearTestES3, ClearMultipleAttachmentsIndividually) |
| { |
| // http://anglebug.com/40096714 |
| ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan()); |
| |
| constexpr uint32_t kSize = 16; |
| constexpr uint32_t kAttachmentCount = 2; |
| constexpr float kDepthClearValue = 0.125f; |
| constexpr int32_t kStencilClearValue = 0x67; |
| std::vector<unsigned char> pixelData(kSize * kSize * 4, 255); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture textures[kAttachmentCount]; |
| GLRenderbuffer depthStencil; |
| GLenum drawBuffers[kAttachmentCount]; |
| GLColor clearValues[kAttachmentCount]; |
| |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glBindTexture(GL_TEXTURE_2D, textures[i]); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| pixelData.data()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], |
| 0); |
| drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; |
| |
| clearValues[i].R = static_cast<GLubyte>(1 + i * 20); |
| clearValues[i].G = static_cast<GLubyte>(7 + i * 20); |
| clearValues[i].B = static_cast<GLubyte>(12 + i * 20); |
| clearValues[i].A = static_cast<GLubyte>(16 + i * 20); |
| } |
| |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencil); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| |
| glDrawBuffers(kAttachmentCount, drawBuffers); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glClearBufferfv(GL_COLOR, i, clearValues[i].toNormalizedVector().data()); |
| } |
| |
| glClearBufferfv(GL_DEPTH, 0, &kDepthClearValue); |
| glClearBufferiv(GL_STENCIL, 0, &kStencilClearValue); |
| ASSERT_GL_NO_ERROR(); |
| |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT0 + i); |
| ASSERT_GL_NO_ERROR(); |
| |
| const GLColor &expect = clearValues[i]; |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, expect); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, expect); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, expect); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, expect); |
| } |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| for (uint32_t i = 1; i < kAttachmentCount; ++i) |
| drawBuffers[i] = GL_NONE; |
| glDrawBuffers(kAttachmentCount, drawBuffers); |
| |
| verifyDepth(kDepthClearValue, kSize); |
| verifyStencil(kStencilClearValue, kSize); |
| } |
| |
| // Test that clearing multiple attachments in the presence of a color mask, scissor or both |
| // correctly clears all the attachments. |
| TEST_P(ClearTestES3, MaskedScissoredClearMultipleAttachments) |
| { |
| constexpr uint32_t kSize = 16; |
| constexpr uint32_t kAttachmentCount = 2; |
| std::vector<unsigned char> pixelData(kSize * kSize * 4, 255); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture textures[kAttachmentCount]; |
| GLenum drawBuffers[kAttachmentCount]; |
| |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glBindTexture(GL_TEXTURE_2D, textures[i]); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| pixelData.data()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], |
| 0); |
| drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; |
| } |
| |
| glDrawBuffers(kAttachmentCount, drawBuffers); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| |
| // Masked clear |
| GLColor clearColorMasked(31, 63, 255, 191); |
| angle::Vector4 clearColor = GLColor(31, 63, 127, 191).toNormalizedVector(); |
| |
| glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_TRUE); |
| glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); |
| glClear(GL_COLOR_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| // All attachments should be cleared, with the blue channel untouched |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT0 + i); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, clearColorMasked); |
| } |
| |
| // Masked scissored clear |
| GLColor clearColorMaskedScissored(63, 127, 255, 31); |
| clearColor = GLColor(63, 127, 191, 31).toNormalizedVector(); |
| |
| glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(kSize / 6, kSize / 6, kSize / 3, kSize / 3); |
| glClear(GL_COLOR_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| // The corners should keep the previous value while the center is cleared, except its blue |
| // channel. |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT0 + i); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 3, 2 * kSize / 3, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3, kSize / 3, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3, 2 * kSize / 3, clearColorMasked); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 3, kSize / 3, clearColorMaskedScissored); |
| } |
| |
| // Scissored clear |
| GLColor clearColorScissored(127, 191, 31, 63); |
| clearColor = GLColor(127, 191, 31, 63).toNormalizedVector(); |
| |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); |
| glClear(GL_COLOR_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| // The corners should keep the old value while all channels of the center are cleared. |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT0 + i); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 3, 2 * kSize / 3, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3, kSize / 3, clearColorMasked); |
| EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3, 2 * kSize / 3, clearColorMasked); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 3, kSize / 3, clearColorScissored); |
| } |
| } |
| |
| // Test clearing multiple attachments in the presence of an indexed color mask. |
| TEST_P(ClearTestES3, MaskedIndexedClearMultipleAttachments) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_draw_buffers_indexed")); |
| |
| constexpr uint32_t kSize = 16; |
| constexpr uint32_t kAttachmentCount = 4; |
| std::vector<unsigned char> pixelData(kSize * kSize * 4, 255); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture textures[kAttachmentCount]; |
| GLenum drawBuffers[kAttachmentCount]; |
| |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glBindTexture(GL_TEXTURE_2D, textures[i]); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| pixelData.data()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], |
| 0); |
| drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; |
| } |
| |
| glDrawBuffers(kAttachmentCount, drawBuffers); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| |
| // Masked clear |
| GLColor clearColorMasked(31, 63, 255, 191); |
| angle::Vector4 clearColor = GLColor(31, 63, 127, 191).toNormalizedVector(); |
| |
| // Block blue channel for all attachements |
| glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_TRUE); |
| |
| // Unblock blue channel for attachments 0 and 1 |
| glColorMaskiOES(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| glColorMaskiOES(1, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| |
| glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); |
| glClear(GL_COLOR_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| // All attachments should be cleared, with the blue channel untouched for all attachments but 1. |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT0 + i); |
| ASSERT_GL_NO_ERROR(); |
| |
| const GLColor attachmentColor = (i > 1) ? clearColorMasked : clearColor; |
| EXPECT_PIXEL_COLOR_EQ(0, 0, attachmentColor); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, attachmentColor); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, attachmentColor); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, attachmentColor); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, attachmentColor); |
| } |
| } |
| |
| // Test that clearing multiple attachments of different nature (float, int and uint) in the |
| // presence of a color mask works correctly. In the Vulkan backend, this exercises clearWithDraw |
| // and the relevant internal shaders. |
| TEST_P(ClearTestES3, MaskedClearHeterogeneousAttachments) |
| { |
| // http://anglebug.com/40096714 |
| ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan()); |
| |
| constexpr uint32_t kSize = 16; |
| constexpr uint32_t kAttachmentCount = 3; |
| constexpr float kDepthClearValue = 0.256f; |
| constexpr int32_t kStencilClearValue = 0x1D; |
| constexpr GLenum kAttachmentFormats[kAttachmentCount] = { |
| GL_RGBA8, |
| GL_RGBA8I, |
| GL_RGBA8UI, |
| }; |
| constexpr GLenum kDataFormats[kAttachmentCount] = { |
| GL_RGBA, |
| GL_RGBA_INTEGER, |
| GL_RGBA_INTEGER, |
| }; |
| constexpr GLenum kDataTypes[kAttachmentCount] = { |
| GL_UNSIGNED_BYTE, |
| GL_BYTE, |
| GL_UNSIGNED_BYTE, |
| }; |
| |
| std::vector<unsigned char> pixelData(kSize * kSize * 4, 0); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture textures[kAttachmentCount]; |
| GLRenderbuffer depthStencil; |
| GLenum drawBuffers[kAttachmentCount]; |
| |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glBindTexture(GL_TEXTURE_2D, textures[i]); |
| glTexImage2D(GL_TEXTURE_2D, 0, kAttachmentFormats[i], kSize, kSize, 0, kDataFormats[i], |
| kDataTypes[i], pixelData.data()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], |
| 0); |
| drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; |
| } |
| |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencil); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| |
| glDrawBuffers(kAttachmentCount, drawBuffers); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0); |
| |
| // Mask out red for all clears |
| glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE); |
| |
| glClearBufferfv(GL_DEPTH, 0, &kDepthClearValue); |
| glClearBufferiv(GL_STENCIL, 0, &kStencilClearValue); |
| |
| GLColor clearValuef = {25, 50, 75, 100}; |
| glClearBufferfv(GL_COLOR, 0, clearValuef.toNormalizedVector().data()); |
| |
| int clearValuei[4] = {10, -20, 30, -40}; |
| glClearBufferiv(GL_COLOR, 1, clearValuei); |
| |
| uint32_t clearValueui[4] = {50, 60, 70, 80}; |
| glClearBufferuiv(GL_COLOR, 2, clearValueui); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| ASSERT_GL_NO_ERROR(); |
| |
| GLColor expect = clearValuef; |
| expect.R = 0; |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, expect); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, expect); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, expect); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, expect); |
| } |
| |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT1); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_8I(0, 0, 0, clearValuei[1], clearValuei[2], clearValuei[3]); |
| EXPECT_PIXEL_8I(0, kSize - 1, 0, clearValuei[1], clearValuei[2], clearValuei[3]); |
| EXPECT_PIXEL_8I(kSize - 1, 0, 0, clearValuei[1], clearValuei[2], clearValuei[3]); |
| EXPECT_PIXEL_8I(kSize - 1, kSize - 1, 0, clearValuei[1], clearValuei[2], clearValuei[3]); |
| } |
| |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT2); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_8UI(0, 0, 0, clearValueui[1], clearValueui[2], clearValueui[3]); |
| EXPECT_PIXEL_8UI(0, kSize - 1, 0, clearValueui[1], clearValueui[2], clearValueui[3]); |
| EXPECT_PIXEL_8UI(kSize - 1, 0, 0, clearValueui[1], clearValueui[2], clearValueui[3]); |
| EXPECT_PIXEL_8UI(kSize - 1, kSize - 1, 0, clearValueui[1], clearValueui[2], |
| clearValueui[3]); |
| } |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| for (uint32_t i = 1; i < kAttachmentCount; ++i) |
| drawBuffers[i] = GL_NONE; |
| glDrawBuffers(kAttachmentCount, drawBuffers); |
| |
| verifyDepth(kDepthClearValue, kSize); |
| verifyStencil(kStencilClearValue, kSize); |
| } |
| |
| // Test that clearing multiple attachments of different nature (float, int and uint) in the |
| // presence of a scissor test works correctly. In the Vulkan backend, this exercises clearWithDraw |
| // and the relevant internal shaders. |
| TEST_P(ClearTestES3, ScissoredClearHeterogeneousAttachments) |
| { |
| // http://anglebug.com/40096714 |
| ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan()); |
| |
| // http://anglebug.com/42263682 |
| ANGLE_SKIP_TEST_IF(IsWindows() && (IsOpenGL() || IsD3D11()) && IsAMD()); |
| |
| // http://anglebug.com/42263790 |
| ANGLE_SKIP_TEST_IF(IsWindows7() && IsD3D11() && IsNVIDIA()); |
| |
| constexpr uint32_t kSize = 16; |
| constexpr uint32_t kHalfSize = kSize / 2; |
| constexpr uint32_t kAttachmentCount = 3; |
| constexpr float kDepthClearValue = 0.256f; |
| constexpr int32_t kStencilClearValue = 0x1D; |
| constexpr GLenum kAttachmentFormats[kAttachmentCount] = { |
| GL_RGBA8, |
| GL_RGBA8I, |
| GL_RGBA8UI, |
| }; |
| constexpr GLenum kDataFormats[kAttachmentCount] = { |
| GL_RGBA, |
| GL_RGBA_INTEGER, |
| GL_RGBA_INTEGER, |
| }; |
| constexpr GLenum kDataTypes[kAttachmentCount] = { |
| GL_UNSIGNED_BYTE, |
| GL_BYTE, |
| GL_UNSIGNED_BYTE, |
| }; |
| |
| std::vector<unsigned char> pixelData(kSize * kSize * 4, 0); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture textures[kAttachmentCount]; |
| GLRenderbuffer depthStencil; |
| GLenum drawBuffers[kAttachmentCount]; |
| |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glBindTexture(GL_TEXTURE_2D, textures[i]); |
| glTexImage2D(GL_TEXTURE_2D, 0, kAttachmentFormats[i], kSize, kSize, 0, kDataFormats[i], |
| kDataTypes[i], pixelData.data()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], |
| 0); |
| drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; |
| } |
| |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencil); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| |
| glDrawBuffers(kAttachmentCount, drawBuffers); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0); |
| |
| // Enable scissor test |
| glScissor(0, 0, kHalfSize, kHalfSize); |
| glEnable(GL_SCISSOR_TEST); |
| |
| GLColor clearValuef = {25, 50, 75, 100}; |
| angle::Vector4 clearValuefv = clearValuef.toNormalizedVector(); |
| |
| glClearColor(clearValuefv.x(), clearValuefv.y(), clearValuefv.z(), clearValuefv.w()); |
| glClearDepthf(kDepthClearValue); |
| |
| // clear stencil. |
| glClearBufferiv(GL_STENCIL, 0, &kStencilClearValue); |
| |
| // clear float color attachment & depth together |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // clear integer attachment. |
| int clearValuei[4] = {10, -20, 30, -40}; |
| glClearBufferiv(GL_COLOR, 1, clearValuei); |
| |
| // clear unsigned integer attachment |
| uint32_t clearValueui[4] = {50, 60, 70, 80}; |
| glClearBufferuiv(GL_COLOR, 2, clearValueui); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| ASSERT_GL_NO_ERROR(); |
| |
| GLColor expect = clearValuef; |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, expect); |
| EXPECT_PIXEL_COLOR_EQ(0, kHalfSize - 1, expect); |
| EXPECT_PIXEL_COLOR_EQ(kHalfSize - 1, 0, expect); |
| EXPECT_PIXEL_COLOR_EQ(kHalfSize - 1, kHalfSize - 1, expect); |
| EXPECT_PIXEL_EQ(kHalfSize + 1, kHalfSize + 1, 0, 0, 0, 0); |
| } |
| |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT1); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_8I(0, 0, clearValuei[0], clearValuei[1], clearValuei[2], clearValuei[3]); |
| EXPECT_PIXEL_8I(0, kHalfSize - 1, clearValuei[0], clearValuei[1], clearValuei[2], |
| clearValuei[3]); |
| EXPECT_PIXEL_8I(kHalfSize - 1, 0, clearValuei[0], clearValuei[1], clearValuei[2], |
| clearValuei[3]); |
| EXPECT_PIXEL_8I(kHalfSize - 1, kHalfSize - 1, clearValuei[0], clearValuei[1], |
| clearValuei[2], clearValuei[3]); |
| EXPECT_PIXEL_8I(kHalfSize + 1, kHalfSize + 1, 0, 0, 0, 0); |
| } |
| |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT2); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_8UI(0, 0, clearValueui[0], clearValueui[1], clearValueui[2], clearValueui[3]); |
| EXPECT_PIXEL_8UI(0, kHalfSize - 1, clearValueui[0], clearValueui[1], clearValueui[2], |
| clearValueui[3]); |
| EXPECT_PIXEL_8UI(kHalfSize - 1, 0, clearValueui[0], clearValueui[1], clearValueui[2], |
| clearValueui[3]); |
| EXPECT_PIXEL_8UI(kHalfSize - 1, kHalfSize - 1, clearValueui[0], clearValueui[1], |
| clearValueui[2], clearValueui[3]); |
| EXPECT_PIXEL_8UI(kHalfSize + 1, kHalfSize + 1, 0, 0, 0, 0); |
| } |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| for (uint32_t i = 1; i < kAttachmentCount; ++i) |
| drawBuffers[i] = GL_NONE; |
| glDrawBuffers(kAttachmentCount, drawBuffers); |
| |
| verifyDepth(kDepthClearValue, kHalfSize); |
| verifyStencil(kStencilClearValue, kHalfSize); |
| } |
| |
| // This tests a bug where in a masked clear when calling "ClearBuffer", we would |
| // mistakenly clear every channel (including the masked-out ones) |
| TEST_P(ClearTestES3, MaskedClearBufferBug) |
| { |
| unsigned char pixelData[] = {255, 255, 255, 255}; |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture textures[2]; |
| |
| glBindTexture(GL_TEXTURE_2D, textures[0]); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0); |
| |
| glBindTexture(GL_TEXTURE_2D, textures[1]); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_EQ(0, 0, 255, 255, 255, 255); |
| |
| float clearValue[] = {0, 0.5f, 0.5f, 1.0f}; |
| GLenum drawBuffers[] = {GL_NONE, GL_COLOR_ATTACHMENT1}; |
| glDrawBuffers(2, drawBuffers); |
| glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_TRUE); |
| glClearBufferfv(GL_COLOR, 1, clearValue); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_EQ(0, 0, 255, 255, 255, 255); |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT1); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_NEAR(0, 0, 0, 127, 255, 255, 1); |
| } |
| |
| // Test that stencil clears works if reference and write mask have no common bits. The write mask |
| // is the only thing that dictates which bits should be written to, and this is a regression test |
| // for a bug where the clear was no-oped if the (reference & writemask) == 0 instead of just |
| // writemask == 0. |
| TEST_P(ClearTestES3, ClearStencilWithNonOverlappingWriteMaskAndReferenceBits) |
| { |
| constexpr uint32_t kSize = 16; |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture textures; |
| GLRenderbuffer depthStencil; |
| |
| glBindTexture(GL_TEXTURE_2D, textures); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures, 0); |
| |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencil); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| // Initialize the stencil buffer. |
| glClearDepthf(0); |
| glClearStencil(0xEC); |
| |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| verifyStencil(0xEC, kSize); |
| |
| // Clear the color buffer again to make sure there are no stale data. |
| glClearColor(0.25, 0.5, 0.75, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_NEAR(0, 0, 63, 127, 191, 255, 1.0); |
| |
| // Set the stencil write mask to 0xF0 |
| glStencilMask(0xF0); |
| |
| // Set the stencil reference to 0x0F. It shouldn't matter |
| glStencilFunc(GL_EQUAL, 0x55, 0x0F); |
| glStencilOp(GL_INCR, GL_INCR, GL_INCR); |
| |
| // Clear stencil again. Only the top four bits should be written. |
| const GLint kStencilClearValue = 0x59; |
| glClearBufferiv(GL_STENCIL, 0, &kStencilClearValue); |
| verifyStencil(0x5C, kSize); |
| } |
| |
| // Regression test for a serial tracking bug. |
| TEST_P(ClearTestES3, BadFBOSerialBug) |
| { |
| // First make a simple framebuffer, and clear it to green |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture textures[2]; |
| |
| glBindTexture(GL_TEXTURE_2D, textures[0]); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0); |
| |
| GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0}; |
| glDrawBuffers(1, drawBuffers); |
| |
| float clearValues1[] = {0.0f, 1.0f, 0.0f, 1.0f}; |
| glClearBufferfv(GL_COLOR, 0, clearValues1); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Next make a second framebuffer, and draw it to red |
| // (Triggers bad applied render target serial) |
| GLFramebuffer fbo2; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo2); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindTexture(GL_TEXTURE_2D, textures[1]); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], 0); |
| |
| glDrawBuffers(1, drawBuffers); |
| |
| ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Check that the first framebuffer is still green. |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| // Test that SRGB framebuffers clear to the linearized clear color |
| TEST_P(ClearTestES3, SRGBClear) |
| { |
| // First make a simple framebuffer, and clear it |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture texture; |
| |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_SRGB8_ALPHA8, getWindowWidth(), getWindowHeight()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| |
| glClearColor(0.5f, 0.5f, 0.5f, 0.5f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| EXPECT_PIXEL_NEAR(0, 0, 188, 188, 188, 128, 1.0); |
| } |
| |
| // Test that framebuffers with mixed SRGB/Linear attachments clear to the correct color for each |
| // attachment |
| TEST_P(ClearTestES3, MixedSRGBClear) |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| |
| GLTexture textures[2]; |
| |
| glBindTexture(GL_TEXTURE_2D, textures[0]); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_SRGB8_ALPHA8, getWindowWidth(), getWindowHeight()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0); |
| |
| glBindTexture(GL_TEXTURE_2D, textures[1]); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0); |
| |
| GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; |
| glDrawBuffers(2, drawBuffers); |
| |
| // Clear both textures |
| glClearColor(0.5f, 0.5f, 0.5f, 0.5f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0); |
| |
| // Check value of texture0 |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0); |
| EXPECT_PIXEL_NEAR(0, 0, 188, 188, 188, 128, 1.0); |
| |
| // Check value of texture1 |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], 0); |
| EXPECT_PIXEL_NEAR(0, 0, 128, 128, 128, 128, 1.0); |
| } |
| |
| // This test covers a D3D11 bug where calling ClearRenderTargetView sometimes wouldn't sync |
| // before a draw call. The test draws small quads to a larger FBO (the default back buffer). |
| // Before each blit to the back buffer it clears the quad to a certain color using |
| // ClearBufferfv to give a solid color. The sync problem goes away if we insert a call to |
| // flush or finish after ClearBufferfv or each draw. |
| TEST_P(ClearTestES3, RepeatedClear) |
| { |
| // Fails on 431.02 driver. http://anglebug.com/40644697 |
| ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsVulkan()); |
| ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D()); |
| |
| constexpr char kVS[] = |
| "#version 300 es\n" |
| "in highp vec2 position;\n" |
| "out highp vec2 v_coord;\n" |
| "void main(void)\n" |
| "{\n" |
| " gl_Position = vec4(position, 0, 1);\n" |
| " vec2 texCoord = (position * 0.5) + 0.5;\n" |
| " v_coord = texCoord;\n" |
| "}\n"; |
| |
| constexpr char kFS[] = |
| "#version 300 es\n" |
| "in highp vec2 v_coord;\n" |
| "out highp vec4 color;\n" |
| "uniform sampler2D tex;\n" |
| "void main()\n" |
| "{\n" |
| " color = texture(tex, v_coord);\n" |
| "}\n"; |
| |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| |
| mTextures.resize(1, 0); |
| glGenTextures(1, mTextures.data()); |
| |
| GLenum format = GL_RGBA8; |
| const int numRowsCols = 3; |
| const int cellSize = 32; |
| const int fboSize = cellSize; |
| const int backFBOSize = cellSize * numRowsCols; |
| const float fmtValueMin = 0.0f; |
| const float fmtValueMax = 1.0f; |
| |
| glBindTexture(GL_TEXTURE_2D, mTextures[0]); |
| glTexStorage2D(GL_TEXTURE_2D, 1, format, fboSize, fboSize); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| |
| // larger fbo bound -- clear to transparent black |
| glUseProgram(program); |
| GLint uniLoc = glGetUniformLocation(program, "tex"); |
| ASSERT_NE(-1, uniLoc); |
| glUniform1i(uniLoc, 0); |
| glBindTexture(GL_TEXTURE_2D, mTextures[0]); |
| |
| GLint positionLocation = glGetAttribLocation(program, "position"); |
| ASSERT_NE(-1, positionLocation); |
| |
| glUseProgram(program); |
| |
| for (int cellY = 0; cellY < numRowsCols; cellY++) |
| { |
| for (int cellX = 0; cellX < numRowsCols; cellX++) |
| { |
| int seed = cellX + cellY * numRowsCols; |
| const Vector4 color = RandomVec4(seed, fmtValueMin, fmtValueMax); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| glClearBufferfv(GL_COLOR, 0, color.data()); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| // Method 1: Set viewport and draw full-viewport quad |
| glViewport(cellX * cellSize, cellY * cellSize, cellSize, cellSize); |
| drawQuad(program, "position", 0.5f); |
| |
| // Uncommenting the glFinish call seems to make the test pass. |
| // glFinish(); |
| } |
| } |
| |
| std::vector<GLColor> pixelData(backFBOSize * backFBOSize); |
| glReadPixels(0, 0, backFBOSize, backFBOSize, GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data()); |
| |
| for (int cellY = 0; cellY < numRowsCols; cellY++) |
| { |
| for (int cellX = 0; cellX < numRowsCols; cellX++) |
| { |
| int seed = cellX + cellY * numRowsCols; |
| const Vector4 color = RandomVec4(seed, fmtValueMin, fmtValueMax); |
| GLColor expectedColor(color); |
| |
| int testN = cellX * cellSize + cellY * backFBOSize * cellSize + backFBOSize + 1; |
| GLColor actualColor = pixelData[testN]; |
| EXPECT_NEAR(expectedColor.R, actualColor.R, 1); |
| EXPECT_NEAR(expectedColor.G, actualColor.G, 1); |
| EXPECT_NEAR(expectedColor.B, actualColor.B, 1); |
| EXPECT_NEAR(expectedColor.A, actualColor.A, 1); |
| } |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that clearing RGB8 attachments work when verified through sampling. |
| TEST_P(ClearTestES3, ClearRGB8) |
| { |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, 1, 1); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the texture through framebuffer. |
| const GLubyte kClearColor[] = {63, 127, 191, 55}; |
| glClearColor(kClearColor[0] / 255.0f, kClearColor[1] / 255.0f, kClearColor[2] / 255.0f, |
| kClearColor[3] / 255.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| // Sample from it and verify clear is done. |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Texture2DLod(), essl3_shaders::fs::Texture2DLod()); |
| glUseProgram(program); |
| GLint textureLocation = glGetUniformLocation(program, essl3_shaders::Texture2DUniform()); |
| ASSERT_NE(-1, textureLocation); |
| GLint lodLocation = glGetUniformLocation(program, essl3_shaders::LodUniform()); |
| ASSERT_NE(-1, lodLocation); |
| |
| glUniform1i(textureLocation, 0); |
| glUniform1f(lodLocation, 0); |
| |
| drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| EXPECT_PIXEL_NEAR(0, 0, kClearColor[0], kClearColor[1], kClearColor[2], 255, 1); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that clearing RGB8 attachments from a 2D texture array does not cause |
| // VUID-VkImageMemoryBarrier-oldLayout-01197 |
| TEST_P(ClearTestES3, TextureArrayRGB8) |
| { |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, tex); |
| glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGB8, 1, 1, 2); |
| glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 0); |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, tex, 0, 1); |
| |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| GLenum bufs[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; |
| glDrawBuffers(2, &bufs[0]); |
| |
| glClearColor(1.0, 0.0, 1.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fb); |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta); |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT1); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta); |
| |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| void MaskedScissoredClearTestBase::maskedScissoredColorDepthStencilClear( |
| const MaskedScissoredClearVariationsTestParams ¶ms) |
| { |
| // Flaky on Android Nexus 5x and Pixel 2, possible Qualcomm driver bug. |
| // TODO(jmadill): Re-enable when possible. http://anglebug.com/42261257 |
| ANGLE_SKIP_TEST_IF(IsOpenGLES() && IsAndroid()); |
| |
| const int w = getWindowWidth(); |
| const int h = getWindowHeight(); |
| const int wthird = w / 3; |
| const int hthird = h / 3; |
| |
| constexpr float kPreClearDepth = 0.9f; |
| constexpr float kClearDepth = 0.5f; |
| constexpr uint8_t kPreClearStencil = 0xFF; |
| constexpr uint8_t kClearStencil = 0x16; |
| constexpr uint8_t kStencilMask = 0x59; |
| constexpr uint8_t kMaskedClearStencil = |
| (kPreClearStencil & ~kStencilMask) | (kClearStencil & kStencilMask); |
| |
| bool clearColor, clearDepth, clearStencil; |
| bool maskColor, maskDepth, maskStencil; |
| bool scissor; |
| |
| ParseMaskedScissoredClearVariationsTestParams(params, &clearColor, &clearDepth, &clearStencil, |
| &maskColor, &maskDepth, &maskStencil, &scissor); |
| |
| // Clear to a random color, 0.9 depth and 0x00 stencil |
| Vector4 color1(0.1f, 0.2f, 0.3f, 0.4f); |
| GLColor color1RGB(color1); |
| |
| glClearColor(color1[0], color1[1], color1[2], color1[3]); |
| glClearDepthf(kPreClearDepth); |
| glClearStencil(kPreClearStencil); |
| |
| if (!clearColor) |
| { |
| // If not asked to clear color, clear it anyway, but individually. The clear value is |
| // still used to verify that the depth/stencil clear happened correctly. This allows |
| // testing for depth/stencil-only clear implementations. |
| glClear(GL_COLOR_BUFFER_BIT); |
| } |
| |
| glClear((clearColor ? GL_COLOR_BUFFER_BIT : 0) | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) | |
| (clearStencil ? GL_STENCIL_BUFFER_BIT : 0)); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify color was cleared correctly. |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1); |
| |
| if (scissor) |
| { |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(wthird / 2, hthird / 2, wthird, hthird); |
| } |
| |
| // Use color and stencil masks to clear to a second color, 0.5 depth and 0x59 stencil. |
| Vector4 color2(0.2f, 0.4f, 0.6f, 0.8f); |
| GLColor color2RGB(color2); |
| glClearColor(color2[0], color2[1], color2[2], color2[3]); |
| glClearDepthf(kClearDepth); |
| glClearStencil(kClearStencil); |
| if (maskColor) |
| { |
| glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE); |
| } |
| if (maskDepth) |
| { |
| glDepthMask(GL_FALSE); |
| } |
| if (maskStencil) |
| { |
| glStencilMask(kStencilMask); |
| } |
| glClear((clearColor ? GL_COLOR_BUFFER_BIT : 0) | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) | |
| (clearStencil ? GL_STENCIL_BUFFER_BIT : 0)); |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| glDepthMask(GL_TRUE); |
| glStencilMask(0xFF); |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| glDisable(GL_SCISSOR_TEST); |
| ASSERT_GL_NO_ERROR(); |
| |
| GLColor color2MaskedRGB(color2RGB[0], color1RGB[1], color2RGB[2], color1RGB[3]); |
| |
| // If not clearing color, the original color should be left both in the center and corners. If |
| // using a scissor, the corners should be left to the original color, while the center is |
| // possibly changed. If using a mask, the center (and corners if not scissored), changes to |
| // the masked results. |
| GLColor expectedCenterColorRGB = !clearColor ? color1RGB |
| : maskColor ? color2MaskedRGB |
| : color2RGB; |
| GLColor expectedCornerColorRGB = scissor ? color1RGB : expectedCenterColorRGB; |
| |
| // Verify second clear color mask worked as expected. |
| EXPECT_PIXEL_COLOR_NEAR(wthird, hthird, expectedCenterColorRGB, 1); |
| |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(0, h - 1, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(wthird, 2 * hthird, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(2 * wthird, hthird, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(2 * wthird, 2 * hthird, expectedCornerColorRGB, 1); |
| |
| // If there is depth, but depth is not asked to be cleared, the depth buffer contains garbage, |
| // so no particular behavior can be expected. |
| if (clearDepth || !mHasDepth) |
| { |
| // We use a small shader to verify depth. |
| ANGLE_GL_PROGRAM(depthTestProgram, essl1_shaders::vs::Passthrough(), |
| essl1_shaders::fs::Blue()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(maskDepth ? GL_GREATER : GL_EQUAL); |
| // - If depth is cleared, but it's masked, kPreClearDepth should be in the depth buffer. |
| // - If depth is cleared, but it's not masked, kClearDepth should be in the depth buffer. |
| // - If depth is not cleared, the if above ensures there is no depth buffer at all, |
| // which means depth test will always pass. |
| drawQuad(depthTestProgram, essl1_shaders::PositionAttrib(), maskDepth ? 1.0f : 0.0f); |
| glDisable(GL_DEPTH_TEST); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Either way, we expect blue to be written to the center. |
| expectedCenterColorRGB = GLColor::blue; |
| // If there is no depth, depth test always passes so the whole image must be blue. Same if |
| // depth write is masked. |
| expectedCornerColorRGB = |
| mHasDepth && scissor && !maskDepth ? expectedCornerColorRGB : GLColor::blue; |
| |
| EXPECT_PIXEL_COLOR_NEAR(wthird, hthird, expectedCenterColorRGB, 1); |
| |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(0, h - 1, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(wthird, 2 * hthird, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(2 * wthird, hthird, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(2 * wthird, 2 * hthird, expectedCornerColorRGB, 1); |
| } |
| |
| // If there is stencil, but it's not asked to be cleared, there is similarly no expectation. |
| if (clearStencil || !mHasStencil) |
| { |
| // And another small shader to verify stencil. |
| ANGLE_GL_PROGRAM(stencilTestProgram, essl1_shaders::vs::Passthrough(), |
| essl1_shaders::fs::Green()); |
| glEnable(GL_STENCIL_TEST); |
| // - If stencil is cleared, but it's masked, kMaskedClearStencil should be in the stencil |
| // buffer. |
| // - If stencil is cleared, but it's not masked, kClearStencil should be in the stencil |
| // buffer. |
| // - If stencil is not cleared, the if above ensures there is no stencil buffer at all, |
| // which means stencil test will always pass. |
| glStencilFunc(GL_EQUAL, maskStencil ? kMaskedClearStencil : kClearStencil, 0xFF); |
| drawQuad(stencilTestProgram, essl1_shaders::PositionAttrib(), 0.0f); |
| glDisable(GL_STENCIL_TEST); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Either way, we expect green to be written to the center. |
| expectedCenterColorRGB = GLColor::green; |
| // If there is no stencil, stencil test always passes so the whole image must be green. |
| expectedCornerColorRGB = mHasStencil && scissor ? expectedCornerColorRGB : GLColor::green; |
| |
| EXPECT_PIXEL_COLOR_NEAR(wthird, hthird, expectedCenterColorRGB, 1); |
| |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(0, h - 1, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(wthird, 2 * hthird, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(2 * wthird, hthird, expectedCornerColorRGB, 1); |
| EXPECT_PIXEL_COLOR_NEAR(2 * wthird, 2 * hthird, expectedCornerColorRGB, 1); |
| } |
| } |
| |
| // Tests combinations of color, depth, stencil clears with or without masks or scissor. |
| TEST_P(MaskedScissoredClearTest, Test) |
| { |
| maskedScissoredColorDepthStencilClear(GetParam()); |
| } |
| |
| // Tests combinations of color, depth, stencil clears with or without masks or scissor. |
| // |
| // This uses depth/stencil attachments that are single-channel, but are emulated with a format |
| // that has both channels. |
| TEST_P(VulkanClearTest, Test) |
| { |
| bool clearColor, clearDepth, clearStencil; |
| bool maskColor, maskDepth, maskStencil; |
| bool scissor; |
| |
| ParseMaskedScissoredClearVariationsTestParams(GetParam(), &clearColor, &clearDepth, |
| &clearStencil, &maskColor, &maskDepth, |
| &maskStencil, &scissor); |
| |
| // We only care about clearing depth xor stencil. |
| if (clearDepth == clearStencil) |
| { |
| return; |
| } |
| |
| if (clearDepth) |
| { |
| // Creating a depth-only renderbuffer is an ES3 feature. |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| bindColorDepthFBO(); |
| } |
| else |
| { |
| bindColorStencilFBO(); |
| } |
| |
| maskedScissoredColorDepthStencilClear(GetParam()); |
| } |
| |
| // Tests that clearing a non existing attachment works. |
| TEST_P(ClearTest, ClearColorThenClearNonExistingDepthStencil) |
| { |
| constexpr GLsizei kSize = 16; |
| |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear color. |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Clear depth/stencil. |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Read back color. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| } |
| |
| // Tests that clearing a non existing attachment works. |
| TEST_P(ClearTestES3, ClearDepthStencilThenClearNonExistingColor) |
| { |
| constexpr GLsizei kSize = 16; |
| |
| GLRenderbuffer depth; |
| glBindRenderbuffer(GL_RENDERBUFFER, depth); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depth); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear depth/stencil. |
| glClearDepthf(1.0f); |
| glClearStencil(0xAA); |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear color. |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that just clearing a nonexistent drawbuffer of the default framebuffer doesn't cause an |
| // assert. |
| TEST_P(ClearTestES3, ClearBuffer1OnDefaultFramebufferNoAssert) |
| { |
| std::vector<GLuint> testUint(4); |
| glClearBufferuiv(GL_COLOR, 1, testUint.data()); |
| std::vector<GLint> testInt(4); |
| glClearBufferiv(GL_COLOR, 1, testInt.data()); |
| std::vector<GLfloat> testFloat(4); |
| glClearBufferfv(GL_COLOR, 1, testFloat.data()); |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Clears many small concentric rectangles using scissor regions. |
| TEST_P(ClearTest, InceptionScissorClears) |
| { |
| angle::RNG rng; |
| |
| constexpr GLuint kSize = 16; |
| |
| // Create a square user FBO so we have more control over the dimensions. |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| GLRenderbuffer rbo; |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glViewport(0, 0, kSize, kSize); |
| |
| // Draw small concentric squares using scissor. |
| std::vector<GLColor> expectedColors; |
| for (GLuint index = 0; index < (kSize - 1) / 2; index++) |
| { |
| // Do the first clear without the scissor. |
| if (index > 0) |
| { |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(index, index, kSize - (index * 2), kSize - (index * 2)); |
| } |
| |
| GLColor color = RandomColor(&rng); |
| expectedColors.push_back(color); |
| Vector4 floatColor = color.toNormalizedVector(); |
| glClearColor(floatColor[0], floatColor[1], floatColor[2], floatColor[3]); |
| glClear(GL_COLOR_BUFFER_BIT); |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| std::vector<GLColor> actualColors(expectedColors.size()); |
| glReadPixels(0, kSize / 2, actualColors.size(), 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| actualColors.data()); |
| |
| EXPECT_EQ(expectedColors, actualColors); |
| } |
| |
| // Clears many small concentric rectangles using scissor regions. |
| TEST_P(ClearTest, DrawThenInceptionScissorClears) |
| { |
| angle::RNG rng; |
| |
| constexpr GLuint kSize = 16; |
| |
| // Create a square user FBO so we have more control over the dimensions. |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| GLRenderbuffer rbo; |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glViewport(0, 0, kSize, kSize); |
| |
| ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Draw small concentric squares using scissor. |
| std::vector<GLColor> expectedColors; |
| for (GLuint index = 0; index < (kSize - 1) / 2; index++) |
| { |
| // Do the first clear without the scissor. |
| if (index > 0) |
| { |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(index, index, kSize - (index * 2), kSize - (index * 2)); |
| } |
| |
| GLColor color = RandomColor(&rng); |
| expectedColors.push_back(color); |
| Vector4 floatColor = color.toNormalizedVector(); |
| glClearColor(floatColor[0], floatColor[1], floatColor[2], floatColor[3]); |
| glClear(GL_COLOR_BUFFER_BIT); |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| std::vector<GLColor> actualColors(expectedColors.size()); |
| glReadPixels(0, kSize / 2, actualColors.size(), 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| actualColors.data()); |
| |
| EXPECT_EQ(expectedColors, actualColors); |
| } |
| |
| // Test that clearBuffer with disabled non-zero drawbuffer or disabled read source doesn't cause an |
| // assert. |
| TEST_P(ClearTestES3, ClearDisabledNonZeroAttachmentNoAssert) |
| { |
| // http://anglebug.com/40644728 |
| ANGLE_SKIP_TEST_IF(IsMac() && IsDesktopOpenGL()); |
| |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| |
| GLRenderbuffer rb; |
| glBindRenderbuffer(GL_RENDERBUFFER, rb); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 16, 16); |
| |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rb); |
| glDrawBuffers(0, nullptr); |
| glReadBuffer(GL_NONE); |
| |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| float clearColorf[4] = {0.5, 0.5, 0.5, 0.5}; |
| glClearBufferfv(GL_COLOR, 1, clearColorf); |
| |
| GLuint clearColorui[4] = {255, 255, 255, 255}; |
| glClearBufferuiv(GL_COLOR, 1, clearColorui); |
| |
| GLint clearColori[4] = {-127, -127, -127, -127}; |
| glClearBufferiv(GL_COLOR, 1, clearColori); |
| |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Test that having a framebuffer with maximum number of attachments and clearing color, depth and |
| // stencil works. |
| TEST_P(ClearTestES3, ClearMaxAttachments) |
| { |
| // http://anglebug.com/40644728 |
| ANGLE_SKIP_TEST_IF(IsMac() && IsDesktopOpenGL()); |
| // http://anglebug.com/42263935 |
| ANGLE_SKIP_TEST_IF(IsAMD() && IsD3D11()); |
| |
| constexpr GLsizei kSize = 16; |
| |
| GLint maxDrawBuffers = 0; |
| glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| ASSERT_GE(maxDrawBuffers, 4); |
| |
| // Setup framebuffer. |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| |
| std::vector<GLRenderbuffer> color(maxDrawBuffers); |
| std::vector<GLenum> drawBuffers(maxDrawBuffers); |
| |
| for (GLint colorIndex = 0; colorIndex < maxDrawBuffers; ++colorIndex) |
| { |
| glBindRenderbuffer(GL_RENDERBUFFER, color[colorIndex]); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorIndex, |
| GL_RENDERBUFFER, color[colorIndex]); |
| |
| drawBuffers[colorIndex] = GL_COLOR_ATTACHMENT0 + colorIndex; |
| } |
| |
| GLRenderbuffer depthStencil; |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencil); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| |
| EXPECT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glDrawBuffers(maxDrawBuffers, drawBuffers.data()); |
| |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClearDepthf(1.0f); |
| glClearStencil(0x55); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Verify that every color attachment is cleared correctly. |
| for (GLint colorIndex = 0; colorIndex < maxDrawBuffers; ++colorIndex) |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT0 + colorIndex); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::red); |
| } |
| |
| // Verify that depth and stencil attachments are cleared correctly. |
| GLFramebuffer fbVerify; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbVerify); |
| |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color[0]); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| |
| // If depth is not cleared to 1, rendering would fail. |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| |
| // If stencil is not cleared to 0x55, rendering would fail. |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_EQUAL, 0x55, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| glStencilMask(0xFF); |
| |
| // Draw green. |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.95f); |
| |
| // Verify that green was drawn. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::green); |
| } |
| |
| // Test that having a framebuffer with maximum number of attachments and clearing color, depth and |
| // stencil after a draw call works. |
| TEST_P(ClearTestES3, ClearMaxAttachmentsAfterDraw) |
| { |
| // http://anglebug.com/40644728 |
| ANGLE_SKIP_TEST_IF(IsMac() && IsDesktopOpenGL()); |
| |
| constexpr GLsizei kSize = 16; |
| |
| GLint maxDrawBuffers = 0; |
| glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| ASSERT_GE(maxDrawBuffers, 4); |
| |
| // Setup framebuffer. |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| |
| std::vector<GLRenderbuffer> color(maxDrawBuffers); |
| std::vector<GLenum> drawBuffers(maxDrawBuffers); |
| |
| for (GLint colorIndex = 0; colorIndex < maxDrawBuffers; ++colorIndex) |
| { |
| glBindRenderbuffer(GL_RENDERBUFFER, color[colorIndex]); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorIndex, |
| GL_RENDERBUFFER, color[colorIndex]); |
| |
| drawBuffers[colorIndex] = GL_COLOR_ATTACHMENT0 + colorIndex; |
| } |
| |
| GLRenderbuffer depthStencil; |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencil); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| |
| EXPECT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glDrawBuffers(maxDrawBuffers, drawBuffers.data()); |
| |
| // Issue a draw call to render blue, depth=0 and stencil 0x3C to the attachments. |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_ALWAYS); |
| |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_ALWAYS, 0x3C, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glStencilMask(0xFF); |
| |
| // Generate shader for this framebuffer. |
| std::stringstream strstr; |
| strstr << "#version 300 es\n" |
| "precision highp float;\n"; |
| for (GLint colorIndex = 0; colorIndex < maxDrawBuffers; ++colorIndex) |
| { |
| strstr << "layout(location = " << colorIndex << ") out vec4 value" << colorIndex << ";\n"; |
| } |
| strstr << "void main()\n" |
| "{\n"; |
| for (GLint colorIndex = 0; colorIndex < maxDrawBuffers; ++colorIndex) |
| { |
| strstr << "value" << colorIndex << " = vec4(0.0f, 0.0f, 1.0f, 1.0f);\n"; |
| } |
| strstr << "}\n"; |
| |
| ANGLE_GL_PROGRAM(drawMRT, essl3_shaders::vs::Simple(), strstr.str().c_str()); |
| drawQuad(drawMRT, essl3_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClearDepthf(1.0f); |
| glClearStencil(0x55); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Verify that every color attachment is cleared correctly. |
| for (GLint colorIndex = 0; colorIndex < maxDrawBuffers; ++colorIndex) |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT0 + colorIndex); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red) << colorIndex; |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::red) << colorIndex; |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::red) << colorIndex; |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::red) << colorIndex; |
| } |
| |
| // Verify that depth and stencil attachments are cleared correctly. |
| GLFramebuffer fbVerify; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbVerify); |
| |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color[0]); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| |
| // If depth is not cleared to 1, rendering would fail. |
| glDepthFunc(GL_LESS); |
| |
| // If stencil is not cleared to 0x55, rendering would fail. |
| glStencilFunc(GL_EQUAL, 0x55, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| |
| // Draw green. |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.95f); |
| |
| // Verify that green was drawn. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::green); |
| } |
| |
| // Test that mixed masked clear works after clear. |
| TEST_P(ClearTestES3, ClearThenMixedMaskedClear) |
| { |
| constexpr GLsizei kSize = 16; |
| |
| // Setup framebuffer. |
| GLRenderbuffer color; |
| glBindRenderbuffer(GL_RENDERBUFFER, color); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| |
| GLRenderbuffer depthStencil; |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencil); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| EXPECT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear color and depth/stencil |
| glClearColor(0.1f, 1.0f, 0.0f, 0.7f); |
| glClearDepthf(0.0f); |
| glClearStencil(0x55); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Clear again, but with color and stencil masked |
| glClearColor(1.0f, 0.2f, 0.6f, 1.0f); |
| glClearDepthf(1.0f); |
| glClearStencil(0x3C); |
| glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE); |
| glStencilMask(0xF0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Issue a draw call to verify color, depth and stencil. |
| |
| // If depth is not cleared to 1, rendering would fail. |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| |
| // If stencil is not cleared to 0x35, rendering would fail. |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_EQUAL, 0x35, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| glStencilMask(0xFF); |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| // Blend half-transparent blue into the color buffer. |
| glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 0.5f); |
| glEnable(GL_BLEND); |
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify that the color buffer is now gray |
| const GLColor kExpected(127, 127, 127, 191); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, kExpected, 1); |
| EXPECT_PIXEL_COLOR_NEAR(0, kSize - 1, kExpected, 1); |
| EXPECT_PIXEL_COLOR_NEAR(kSize - 1, 0, kExpected, 1); |
| EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1); |
| } |
| |
| // Test that clearing stencil after a draw call works. |
| TEST_P(ClearTestES3, ClearStencilAfterDraw) |
| { |
| // http://anglebug.com/40644728 |
| ANGLE_SKIP_TEST_IF(IsMac() && IsDesktopOpenGL()); |
| |
| constexpr GLsizei kSize = 16; |
| |
| GLint maxDrawBuffers = 0; |
| glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| ASSERT_GE(maxDrawBuffers, 4); |
| |
| // Setup framebuffer. |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| |
| std::vector<GLRenderbuffer> color(maxDrawBuffers); |
| std::vector<GLenum> drawBuffers(maxDrawBuffers); |
| |
| for (GLint colorIndex = 0; colorIndex < maxDrawBuffers; ++colorIndex) |
| { |
| glBindRenderbuffer(GL_RENDERBUFFER, color[colorIndex]); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorIndex, |
| GL_RENDERBUFFER, color[colorIndex]); |
| |
| drawBuffers[colorIndex] = GL_COLOR_ATTACHMENT0 + colorIndex; |
| } |
| |
| GLRenderbuffer depthStencil; |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencil); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| |
| EXPECT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glDrawBuffers(maxDrawBuffers, drawBuffers.data()); |
| |
| // Issue a draw call to render blue and stencil 0x3C to the attachments. |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_ALWAYS, 0x3C, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glStencilMask(0xFF); |
| |
| // Generate shader for this framebuffer. |
| std::stringstream strstr; |
| strstr << "#version 300 es\n" |
| "precision highp float;\n"; |
| for (GLint colorIndex = 0; colorIndex < maxDrawBuffers; ++colorIndex) |
| { |
| strstr << "layout(location = " << colorIndex << ") out vec4 value" << colorIndex << ";\n"; |
| } |
| strstr << "void main()\n" |
| "{\n"; |
| for (GLint colorIndex = 0; colorIndex < maxDrawBuffers; ++colorIndex) |
| { |
| strstr << "value" << colorIndex << " = vec4(0.0f, 0.0f, 1.0f, 1.0f);\n"; |
| } |
| strstr << "}\n"; |
| |
| ANGLE_GL_PROGRAM(drawMRT, essl3_shaders::vs::Simple(), strstr.str().c_str()); |
| drawQuad(drawMRT, essl3_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClearStencil(0x55); |
| glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Verify that every color attachment is cleared correctly. |
| for (GLint colorIndex = 0; colorIndex < maxDrawBuffers; ++colorIndex) |
| { |
| glReadBuffer(GL_COLOR_ATTACHMENT0 + colorIndex); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::red); |
| } |
| |
| // Verify that depth and stencil attachments are cleared correctly. |
| GLFramebuffer fbVerify; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbVerify); |
| |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color[0]); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencil); |
| |
| // If stencil is not cleared to 0x55, rendering would fail. |
| glStencilFunc(GL_EQUAL, 0x55, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| |
| // Draw green. |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.95f); |
| |
| // Verify that green was drawn. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::green); |
| } |
| |
| // Test that mid-render pass clearing of mixed used and unused color attachments works. |
| TEST_P(ClearTestES3, MixedRenderPassClearMixedUsedUnusedAttachments) |
| { |
| // http://anglebug.com/40644728 |
| ANGLE_SKIP_TEST_IF(IsMac() && IsDesktopOpenGL()); |
| |
| constexpr GLsizei kSize = 16; |
| |
| // Setup framebuffer. |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| |
| GLRenderbuffer color[2]; |
| |
| for (GLint colorIndex = 0; colorIndex < 2; ++colorIndex) |
| { |
| glBindRenderbuffer(GL_RENDERBUFFER, color[colorIndex]); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorIndex, |
| GL_RENDERBUFFER, color[colorIndex]); |
| } |
| EXPECT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Disable color attachment 0. |
| GLenum drawBuffers[] = {GL_NONE, GL_COLOR_ATTACHMENT1}; |
| glDrawBuffers(2, drawBuffers); |
| |
| // Draw into color attachment 1 |
| constexpr char kFS[] = R"(#version 300 es |
| precision highp float; |
| layout(location = 0) out vec4 color0; |
| layout(location = 1) out vec4 color1; |
| void main() |
| { |
| color0 = vec4(0, 0, 1, 1); |
| color1 = vec4(1, 0, 0, 1); |
| })"; |
| |
| ANGLE_GL_PROGRAM(drawMRT, essl3_shaders::vs::Simple(), kFS); |
| drawQuad(drawMRT, essl3_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Color attachment 0 is now uninitialized, while color attachment 1 is red. |
| // Re-enable color attachment 0 and clear both attachments to green. |
| drawBuffers[0] = GL_COLOR_ATTACHMENT0; |
| glDrawBuffers(2, drawBuffers); |
| |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Verify that both color attachments are now green. |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| glReadBuffer(GL_COLOR_ATTACHMENT1); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Test that draw without state change after masked clear works |
| TEST_P(ClearTestES3, DrawClearThenDrawWithoutStateChange) |
| { |
| swapBuffers(); |
| constexpr GLsizei kSize = 16; |
| |
| // Setup framebuffer. |
| GLRenderbuffer color; |
| glBindRenderbuffer(GL_RENDERBUFFER, color); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color); |
| EXPECT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear color initially. |
| glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Mask color. |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); |
| |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| // Initialize position attribute. |
| GLint posLoc = glGetAttribLocation(drawColor, essl1_shaders::PositionAttrib()); |
| ASSERT_NE(-1, posLoc); |
| setupQuadVertexBuffer(0.5f, 1.0f); |
| glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| glEnableVertexAttribArray(posLoc); |
| |
| // Draw red. |
| glViewport(0, 0, kSize, kSize); |
| glClearColor(0.0f, 1.0f, 0.0f, 0.0f); |
| glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 0.5f); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| |
| // Clear to green without any state change. |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Draw red again without any state change. |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| |
| // Verify that the color buffer is now red |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::red); |
| } |
| |
| // Test that clear stencil value is correctly masked to 8 bits. |
| TEST_P(ClearTest, ClearStencilMask) |
| { |
| GLint stencilBits = 0; |
| glGetIntegerv(GL_STENCIL_BITS, &stencilBits); |
| EXPECT_EQ(stencilBits, 8); |
| |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| glUseProgram(drawColor); |
| |
| glClearColor(0, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); |
| |
| // Clear stencil value must be masked to 0x42 |
| glClearStencil(0x142); |
| glClear(GL_STENCIL_BUFFER_BIT); |
| |
| // Check that the stencil test works as expected |
| glEnable(GL_STENCIL_TEST); |
| |
| // Negative case |
| glStencilFunc(GL_NOTEQUAL, 0x42, 0xFF); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); |
| |
| // Positive case |
| glStencilFunc(GL_EQUAL, 0x42, 0xFF); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that glClearBufferiv correctly masks the clear stencil value. |
| TEST_P(ClearTestES3, ClearBufferivStencilMask) |
| { |
| GLint stencilBits = 0; |
| glGetIntegerv(GL_STENCIL_BITS, &stencilBits); |
| EXPECT_EQ(stencilBits, 8); |
| |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| glUseProgram(drawColor); |
| |
| glClearColor(0, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); |
| |
| // Clear stencil value must be masked to 0x42 |
| const GLint kStencilClearValue = 0x142; |
| glClearBufferiv(GL_STENCIL, 0, &kStencilClearValue); |
| |
| // Check that the stencil test works as expected |
| glEnable(GL_STENCIL_TEST); |
| |
| // Negative case |
| glStencilFunc(GL_NOTEQUAL, 0x42, 0xFF); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); |
| |
| // Positive case |
| glStencilFunc(GL_EQUAL, 0x42, 0xFF); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that glClearBufferfi correctly masks the clear stencil value. |
| TEST_P(ClearTestES3, ClearBufferfiStencilMask) |
| { |
| GLint stencilBits = 0; |
| glGetIntegerv(GL_STENCIL_BITS, &stencilBits); |
| EXPECT_EQ(stencilBits, 8); |
| |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| glUseProgram(drawColor); |
| |
| glClearColor(0, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); |
| |
| // Clear stencil value must be masked to 0x42 |
| glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.5f, 0x142); |
| |
| // Check that the stencil test works as expected |
| glEnable(GL_STENCIL_TEST); |
| |
| // Negative case |
| glStencilFunc(GL_NOTEQUAL, 0x42, 0xFF); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); |
| |
| // Positive case |
| glStencilFunc(GL_EQUAL, 0x42, 0xFF); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that glClearBufferfi works when stencil attachment is not present. |
| TEST_P(ClearTestES3, ClearBufferfiNoStencilAttachment) |
| { |
| constexpr GLsizei kSize = 16; |
| |
| GLRenderbuffer color; |
| glBindRenderbuffer(GL_RENDERBUFFER, color); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| |
| GLRenderbuffer depth; |
| glBindRenderbuffer(GL_RENDERBUFFER, depth); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, kSize, kSize); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); |
| EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Clear depth/stencil with glClearBufferfi. Note that the stencil attachment doesn't exist. |
| glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.5f, 0x55); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Verify depth is cleared correctly. |
| verifyDepth(0.5f, kSize); |
| } |
| |
| // Test that scissored clear followed by non-scissored draw works. Ensures that when scissor size |
| // is expanded, the clear operation remains limited to the scissor region. Written to catch |
| // potential future bugs if loadOp=CLEAR is used in the Vulkan backend for a small render pass and |
| // then the render area is mistakenly enlarged. |
| TEST_P(ClearTest, ScissoredClearThenNonScissoredDraw) |
| { |
| constexpr GLsizei kSize = 16; |
| const std::vector<GLColor> kInitialData(kSize * kSize, GLColor::red); |
| |
| // Setup framebuffer. Initialize color with red. |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kInitialData.data()); |
| |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| EXPECT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Issue a scissored clear to green. |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glScissor(kSize / 2, 0, kSize / 2, kSize); |
| glEnable(GL_SCISSOR_TEST); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Expand the scissor and blend blue into the framebuffer. |
| glScissor(0, 0, kSize, kSize); |
| glEnable(GL_BLEND); |
| glBlendFunc(GL_ONE, GL_ONE); |
| |
| ANGLE_GL_PROGRAM(drawBlue, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| drawQuad(drawBlue, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify that the left half is magenta, and the right half is cyan. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2 - 1, 0, GLColor::magenta); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::magenta); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2 - 1, kSize - 1, GLColor::magenta); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, 0, GLColor::cyan); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize - 1, GLColor::cyan); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::cyan); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::cyan); |
| } |
| |
| // Test that clear followed by a scissored masked clear works. |
| TEST_P(ClearTest, ClearThenScissoredMaskedClear) |
| { |
| constexpr GLsizei kSize = 16; |
| |
| // Setup framebuffer |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| EXPECT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear to red. |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Mask red and clear to green with a scissor |
| glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE); |
| glScissor(0, 0, kSize / 2, kSize); |
| glEnable(GL_SCISSOR_TEST); |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Verify that the left half is yellow, and the right half is red. |
| EXPECT_PIXEL_RECT_EQ(0, 0, kSize / 2, kSize, GLColor::yellow); |
| EXPECT_PIXEL_RECT_EQ(kSize / 2, 0, kSize / 2, kSize, GLColor::red); |
| } |
| |
| // Test that a scissored stencil clear followed by a full clear works. |
| TEST_P(ClearTestES3, StencilScissoredClearThenFullClear) |
| { |
| constexpr GLsizei kSize = 128; |
| |
| GLint stencilBits = 0; |
| glGetIntegerv(GL_STENCIL_BITS, &stencilBits); |
| EXPECT_EQ(stencilBits, 8); |
| |
| // Clear stencil value must be masked to 0x42 |
| glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.5f, 0x142); |
| |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Shrink the render area. |
| glScissor(kSize / 2, 0, kSize / 2, kSize); |
| glEnable(GL_SCISSOR_TEST); |
| |
| // Clear stencil. |
| glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.5f, 0x64); |
| |
| // Grow the render area. |
| glScissor(0, 0, kSize, kSize); |
| glEnable(GL_SCISSOR_TEST); |
| |
| // Check that the stencil test works as expected |
| glEnable(GL_STENCIL_TEST); |
| |
| // Scissored region is green, outside is red (clear color) |
| glStencilFunc(GL_EQUAL, 0x64, 0xFF); |
| ANGLE_GL_PROGRAM(drawGreen, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green()); |
| glUseProgram(drawGreen); |
| drawQuad(drawGreen, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kSize / 2, kSize, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(kSize / 2, 0, kSize / 2, kSize, GLColor::green); |
| |
| // Outside scissored region is blue. |
| glStencilFunc(GL_EQUAL, 0x42, 0xFF); |
| ANGLE_GL_PROGRAM(drawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue()); |
| glUseProgram(drawBlue); |
| drawQuad(drawBlue, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kSize / 2, kSize, GLColor::blue); |
| EXPECT_PIXEL_RECT_EQ(kSize / 2, 0, kSize / 2, kSize, GLColor::green); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // This is a test that must be verified visually. |
| // |
| // Tests that clear of the default framebuffer applies to the window. |
| TEST_P(ClearTest, DISABLED_ClearReachesWindow) |
| { |
| ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| |
| // Draw blue. |
| drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| swapBuffers(); |
| |
| // Use glClear to clear to red. Regression test for the Vulkan backend where this clear |
| // remained "deferred" and didn't make it to the window on swap. |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| swapBuffers(); |
| |
| // Wait for visual verification. |
| angle::Sleep(2000); |
| } |
| |
| // Tests that masked clear after a no-op framebuffer binding change with an open render pass works. |
| TEST_P(ClearTest, DrawThenChangeFBOBindingAndBackThenMaskedClear) |
| { |
| ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| |
| // Draw blue. |
| drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| // Change framebuffer and back |
| glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]); |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| // Masked clear |
| glColorMask(1, 0, 0, 1); |
| glClearColor(1.0f, 0.5f, 0.5f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta); |
| } |
| |
| // Test that clearing slices of a 3D texture and reading them back works. |
| TEST_P(ClearTestES3, ClearAndReadPixels3DTexture) |
| { |
| constexpr uint32_t kWidth = 128; |
| constexpr uint32_t kHeight = 128; |
| constexpr uint32_t kDepth = 7; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_3D, texture); |
| glTexStorage3D(GL_TEXTURE_3D, 1, GL_RGBA8, kWidth, kHeight, kDepth); |
| glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); |
| |
| std::array<GLColor, kDepth> clearColors = { |
| GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow, |
| GLColor::cyan, GLColor::magenta, GLColor::white, |
| }; |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| |
| for (uint32_t z = 0; z < kDepth; ++z) |
| { |
| glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, z); |
| glClearBufferfv(GL_COLOR, 0, clearColors[z].toNormalizedVector().data()); |
| } |
| |
| for (uint32_t z = 0; z < kDepth; ++z) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, z); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, clearColors[z]); |
| } |
| } |
| |
| // Test that clearing stencil with zero first byte in mask doesn't crash. |
| TEST_P(ClearTestES3, ClearStencilZeroFirstByteMask) |
| { |
| glStencilMask(0xe7d6a900); |
| glClear(GL_STENCIL_BUFFER_BIT); |
| } |
| |
| // Same test as ClearStencilZeroFirstByteMask, but using glClearBufferiv. |
| TEST_P(ClearTestES3, ClearBufferStencilZeroFirstByteMask) |
| { |
| glStencilMask(0xe7d6a900); |
| const GLint kStencilClearValue = 0x55; |
| glClearBufferiv(GL_STENCIL, 0, &kStencilClearValue); |
| } |
| |
| // Test that mid render pass clear after draw sets the render pass size correctly. |
| TEST_P(ClearTestES3, ScissoredDrawThenFullClear) |
| { |
| const int w = getWindowWidth(); |
| const int h = getWindowHeight(); |
| |
| // Use viewport to imply scissor on the draw call |
| glViewport(w / 4, h / 4, w / 2, h / 2); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| |
| // Mid-render-pass clear without scissor or viewport change, which covers the whole framebuffer. |
| glClearColor(1, 1, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| EXPECT_PIXEL_RECT_EQ(0, 0, w, h, GLColor::yellow); |
| } |
| |
| // Test that mid render pass clear after masked clear sets the render pass size correctly. |
| TEST_P(ClearTestES3, MaskedScissoredClearThenFullClear) |
| { |
| const int w = getWindowWidth(); |
| const int h = getWindowHeight(); |
| |
| // Use viewport to imply a small scissor on (non-existing) draw calls. This is important to |
| // make sure render area that's derived from scissor+viewport for draw calls doesn't |
| // accidentally fix render area derived from scissor for clear calls. |
| glViewport(w / 2, h / 2, 1, 1); |
| |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(w / 4, h / 4, w / 2, h / 2); |
| glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE); |
| glClearColor(0.13, 0.38, 0.87, 0.65); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Mid-render-pass clear without scissor, which covers the whole framebuffer. |
| glDisable(GL_SCISSOR_TEST); |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| glClearColor(1, 1, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| EXPECT_PIXEL_RECT_EQ(0, 0, w, h, GLColor::yellow); |
| } |
| |
| // Test that mid render pass masked clear after masked clear sets the render pass size correctly. |
| TEST_P(ClearTestES3, MaskedScissoredClearThenFullMaskedClear) |
| { |
| const int w = getWindowWidth(); |
| const int h = getWindowHeight(); |
| |
| // Make sure the framebuffer is initialized. |
| glClearColor(0, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); |
| |
| // Use viewport to imply a small scissor on (non-existing) draw calls This is important to |
| // make sure render area that's derived from scissor+viewport for draw calls doesn't |
| // accidentally fix render area derived from scissor for clear calls. |
| glViewport(w / 2, h / 2, 1, 1); |
| |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(w / 4, h / 4, w / 2, h / 2); |
| glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE); |
| glClearColor(1, 1, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Mid-render-pass clear without scissor, which covers the whole framebuffer. |
| glDisable(GL_SCISSOR_TEST); |
| glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE); |
| glClearColor(1, 1, 1, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| EXPECT_PIXEL_RECT_EQ(0, 0, w / 4, h, GLColor::green); |
| EXPECT_PIXEL_RECT_EQ(w / 4, 0, w / 2, h / 4, GLColor::green); |
| EXPECT_PIXEL_RECT_EQ(w / 4, 3 * h / 4, w / 2, h / 4, GLColor::green); |
| EXPECT_PIXEL_RECT_EQ(3 * w / 4, 0, w / 4, h, GLColor::green); |
| |
| EXPECT_PIXEL_RECT_EQ(w / 4, h / 4, w / 2, h / 2, GLColor::yellow); |
| } |
| |
| // Test that reclearing color to the same value works. |
| TEST_P(ClearTestES3, RepeatedColorClear) |
| { |
| glClearColor(1, 1, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that reclearing depth to the same value works. |
| TEST_P(ClearTestES3, RepeatedDepthClear) |
| { |
| glClearDepthf(0.25f); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| |
| verifyDepth(0.25f, 1); |
| |
| glClear(GL_DEPTH_BUFFER_BIT); |
| |
| verifyDepth(0.25f, 1); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that reclearing stencil to the same value works. |
| TEST_P(ClearTestES3, RepeatedStencilClear) |
| { |
| glClearStencil(0xE4); |
| glClear(GL_STENCIL_BUFFER_BIT); |
| verifyStencil(0xE4, 1); |
| |
| glClear(GL_STENCIL_BUFFER_BIT); |
| verifyStencil(0xE4, 1); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that reclearing color to the same value works if color was written to in between with a draw |
| // call. |
| TEST_P(ClearTestES3, RepeatedColorClearWithDrawInBetween) |
| { |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| glEnable(GL_BLEND); |
| glBlendFunc(GL_ONE, GL_ONE); |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Green()); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that reclearing depth to the same value works if depth was written to in between with a draw |
| // call. |
| TEST_P(ClearTestES3, RepeatedDepthClearWithDrawInBetween) |
| { |
| glClearDepthf(0.25f); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Green()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_ALWAYS); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.75f); |
| |
| glClear(GL_DEPTH_BUFFER_BIT); |
| glDepthMask(GL_FALSE); |
| verifyDepth(0.25f, 1); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that reclearing stencil to the same value works if stencil was written to in between with a |
| // draw call. |
| TEST_P(ClearTestES3, RepeatedStencilClearWithDrawInBetween) |
| { |
| glClearStencil(0xE4); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glStencilFunc(GL_ALWAYS, 0x3C, 0xFF); |
| glEnable(GL_STENCIL_TEST); |
| |
| glClear(GL_STENCIL_BUFFER_BIT); |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Green()); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.75f); |
| |
| glClear(GL_STENCIL_BUFFER_BIT); |
| verifyStencil(0xE4, 1); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that reclearing color to the same value works if color was written to in between with |
| // glCopyTexSubImage2D. |
| TEST_P(ClearTestES3, RepeatedColorClearWithCopyInBetween) |
| { |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the texture |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Replace the framebuffer texture |
| GLTexture color2; |
| glBindTexture(GL_TEXTURE_2D, color2); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color2, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the new texture and copy it to the old texture |
| glClearColor(0, 1, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glBindTexture(GL_TEXTURE_2D, color); |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, getWindowWidth(), getWindowHeight()); |
| |
| // Attach the original texture back to the framebuffer and verify the copy. |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Clear to the original value and make sure it's applied. |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that reclearing color to the same value works if color was written to in between with a |
| // blit. |
| TEST_P(ClearTestES3, RepeatedColorClearWithBlitInBetween) |
| { |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the texture |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Create another framebuffer as blit src |
| GLTexture color2; |
| glBindTexture(GL_TEXTURE_2D, color2); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| |
| GLFramebuffer fbo2; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo2); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color2, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the new framebuffer and blit it to the old one |
| glClearColor(0, 1, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| // Verify the copy is done correctly. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Clear to the original value and make sure it's applied. |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that reclearing depth to the same value works if depth was written to in between with a |
| // blit. |
| TEST_P(ClearTestES3, RepeatedDepthClearWithBlitInBetween) |
| { |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| |
| GLRenderbuffer depth; |
| glBindRenderbuffer(GL_RENDERBUFFER, depth); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, getWindowWidth(), |
| getWindowHeight()); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear depth |
| glClearDepthf(0.25f); |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| verifyDepth(0.25f, 1); |
| |
| // Create another framebuffer as blit src |
| GLRenderbuffer depth2; |
| glBindRenderbuffer(GL_RENDERBUFFER, depth2); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, getWindowWidth(), |
| getWindowHeight()); |
| |
| GLFramebuffer fbo2; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo2); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth2); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the new framebuffer and blit it to the old one |
| glClearDepthf(0.75f); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); |
| |
| // Verify the copy is done correctly. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| verifyDepth(0.75f, 1); |
| |
| // Clear to the original value and make sure it's applied. |
| glClearDepthf(0.25f); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| verifyDepth(0.25f, 1); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that reclearing stencil to the same value works if stencil was written to in between with a |
| // blit. |
| TEST_P(ClearTestES3, RepeatedStencilClearWithBlitInBetween) |
| { |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| |
| GLRenderbuffer stencil; |
| glBindRenderbuffer(GL_RENDERBUFFER, stencil); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, getWindowWidth(), getWindowHeight()); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear stencil |
| glClearStencil(0xE4); |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| verifyStencil(0xE4, 1); |
| |
| // Create another framebuffer as blit src |
| GLRenderbuffer stencil2; |
| glBindRenderbuffer(GL_RENDERBUFFER, stencil2); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, getWindowWidth(), getWindowHeight()); |
| |
| GLFramebuffer fbo2; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo2); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil2); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the new framebuffer and blit it to the old one |
| glClearStencil(0x35); |
| glClear(GL_STENCIL_BUFFER_BIT); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| // Verify the copy is done correctly. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| verifyStencil(0x35, 1); |
| |
| // Clear to the original value and make sure it's applied. |
| glClearStencil(0xE4); |
| glClear(GL_STENCIL_BUFFER_BIT); |
| verifyStencil(0xE4, 1); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that reclearing color to the same value works if color was written to in between with a |
| // compute shader. |
| TEST_P(ClearTestES31, RepeatedColorClearWithDispatchInBetween) |
| { |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the texture |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Write to the texture with a compute shader. |
| constexpr char kCS[] = R"(#version 310 es |
| layout(local_size_x=1, local_size_y=1, local_size_z=1) in; |
| layout(rgba8) uniform highp writeonly image2D imageOut; |
| void main() |
| { |
| imageStore(imageOut, ivec2(gl_GlobalInvocationID.xy), vec4(0, 1, 0, 1)); |
| })"; |
| |
| ANGLE_GL_COMPUTE_PROGRAM(program, kCS); |
| glUseProgram(program); |
| glBindImageTexture(0, color, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8); |
| |
| glDispatchCompute(getWindowWidth(), getWindowHeight(), 1); |
| EXPECT_GL_NO_ERROR(); |
| |
| glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); |
| |
| // Verify the compute shader overwrites the image correctly. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Clear to the original value and make sure it's applied. |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that clearing a 3D image bound to a layered framebuffer works using only attachment 0. |
| TEST_P(ClearTestES31, Bind3DTextureAndClearUsingAttachment0) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader")); |
| |
| constexpr uint32_t kSize = 16; |
| constexpr uint32_t kAttachmentCount = 4; |
| std::vector<GLColor> pixelData(kSize * kSize * kAttachmentCount, GLColor::white); |
| |
| GLTexture texture3D; |
| glBindTexture(GL_TEXTURE_3D, texture3D); |
| glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, kSize, kSize, kAttachmentCount, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, pixelData.data()); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, kAttachmentCount); |
| glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture3D, 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| glClearColor(1.0, 0.0, 0.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture3D, 0, i); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| ASSERT_GL_NO_ERROR(); |
| } |
| } |
| |
| // Test that clearing a 3D image bound to a layered framebuffer works using multiple attachments. |
| TEST_P(ClearTestES31, Bind3DTextureAndClearUsingMultipleAttachments) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader")); |
| |
| constexpr uint32_t kSize = 16; |
| constexpr uint32_t kAttachmentCount = 4; |
| std::vector<GLColor> pixelData(kSize * kSize * kAttachmentCount, GLColor::white); |
| |
| GLTexture texture3D; |
| glBindTexture(GL_TEXTURE_3D, texture3D); |
| glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, kSize, kSize, kAttachmentCount, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, pixelData.data()); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, kAttachmentCount); |
| glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture3D, 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| glClearColor(1.0, 0.0, 0.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| const GLenum usedAttachment[kAttachmentCount] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, |
| GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT1}; |
| for (uint32_t i = 0; i < kAttachmentCount; ++i) |
| { |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, usedAttachment[i], texture3D, 0, i); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| ASSERT_GL_NO_ERROR(); |
| } |
| } |
| |
| // Test that reclearing depth to the same value works if depth is blit after clear, and depth is |
| // modified in between with a draw call. |
| TEST_P(ClearTestES3, RepeatedDepthClearWithBlitAfterClearAndDrawInBetween) |
| { |
| glClearDepthf(0.25f); |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Make sure clear is flushed. |
| GLRenderbuffer depth; |
| glBindRenderbuffer(GL_RENDERBUFFER, depth); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, getWindowWidth(), |
| getWindowHeight()); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER); |
| |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); |
| |
| // Draw to depth, and break the render pass. |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Green()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_ALWAYS); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.75f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Clear back to the original value |
| glClear(GL_DEPTH_BUFFER_BIT); |
| |
| // Blit again. |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); |
| |
| // Make sure the cleared value is in destination, not the modified value. |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER); |
| verifyDepth(0.25f, 1); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that gaps in framebuffer attachments do not cause race |
| // conditions when a clear op is followed by a draw call. |
| TEST_P(ClearTestES3, DrawAfterClearWithGaps) |
| { |
| constexpr char kVS[] = R"(#version 300 es |
| precision highp float; |
| void main() { |
| vec2 offset = vec2((gl_VertexID & 1) == 0 ? -1.0 : 1.0, (gl_VertexID & 2) == 0 ? -1.0 : 1.0); |
| gl_Position = vec4(offset * 0.125 - 0.5, 0.0, 1.0); |
| })"; |
| |
| constexpr char kFS[] = R"(#version 300 es |
| precision mediump float; |
| layout(location=0) out vec4 color0; |
| layout(location=2) out vec4 color2; |
| void main() { |
| color0 = vec4(1, 0, 1, 1); |
| color2 = vec4(1, 1, 0, 1); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| glUseProgram(program); |
| |
| constexpr int kSize = 1024; |
| |
| GLRenderbuffer rb0; |
| glBindRenderbuffer(GL_RENDERBUFFER, rb0); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| |
| GLRenderbuffer rb2; |
| glBindRenderbuffer(GL_RENDERBUFFER, rb2); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb0); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER, rb2); |
| |
| GLenum bufs[3] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_COLOR_ATTACHMENT2}; |
| glDrawBuffers(3, bufs); |
| glReadBuffer(GL_COLOR_ATTACHMENT2); |
| |
| glClearColor(0, 1, 0, 1); |
| glViewport(0, 0, kSize, kSize); |
| |
| // Draw immediately after clear |
| glClear(GL_COLOR_BUFFER_BIT); |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| |
| std::vector<GLColor> pixels(kSize * kSize, GLColor::transparentBlack); |
| glReadPixels(0, 0, kSize, kSize, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); |
| ASSERT_GL_NO_ERROR(); |
| |
| for (int y = 0; y < kSize; ++y) |
| { |
| for (int x = 0; x < kSize; ++x) |
| { |
| const GLColor color = pixels[y * kSize + x]; |
| if (x > 192 && x < 319 && y > 192 && y < 319) |
| { |
| EXPECT_EQ(color, GLColor::yellow) << "at " << x << ", " << y; |
| } |
| else if (x < 191 || x > 320 || y < 191 || y > 320) |
| { |
| EXPECT_EQ(color, GLColor::green) << "at " << x << ", " << y; |
| } |
| } |
| } |
| } |
| |
| // Test that mid render pass clears work with gaps in locations. |
| TEST_P(ClearTestES3, MidRenderPassClearWithGaps) |
| { |
| constexpr char kVS[] = R"(#version 300 es |
| precision highp float; |
| void main() { |
| // gl_VertexID x y |
| // 0 -1 -1 |
| // 1 1 -1 |
| // 2 -1 1 |
| // 3 1 1 |
| int bit0 = gl_VertexID & 1; |
| int bit1 = gl_VertexID >> 1; |
| gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, gl_VertexID % 2 == 0 ? -1 : 1, 1); |
| })"; |
| |
| constexpr char kFS[] = R"(#version 300 es |
| precision mediump float; |
| layout(location=0) out vec4 color0; |
| layout(location=2) out vec4 color2; |
| uniform vec4 color0in; |
| uniform vec4 color1in; |
| void main() { |
| color0 = color0in; |
| color2 = color1in; |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| glUseProgram(program); |
| |
| const GLint color0InLoc = glGetUniformLocation(program, "color0in"); |
| const GLint color1InLoc = glGetUniformLocation(program, "color1in"); |
| ASSERT_NE(color0InLoc, -1); |
| ASSERT_NE(color1InLoc, -1); |
| |
| constexpr int kSize = 23; |
| |
| GLRenderbuffer rb0; |
| glBindRenderbuffer(GL_RENDERBUFFER, rb0); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| |
| GLRenderbuffer rb2; |
| glBindRenderbuffer(GL_RENDERBUFFER, rb2); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| |
| GLFramebuffer fb; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb0); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER, rb2); |
| |
| GLenum bufs[3] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_COLOR_ATTACHMENT2}; |
| glDrawBuffers(3, bufs); |
| |
| glViewport(0, 0, kSize, kSize); |
| |
| // Start with a draw call |
| glUniform4f(color0InLoc, 0.1, 0.2, 0.3, 0.4); |
| glUniform4f(color1InLoc, 0.05, 0.15, 0.25, 0.35); |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| |
| // Clear in the middle of the render pass |
| glClearColor(1, 0, 0, 0.6); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Draw with blend, and verify results |
| glEnable(GL_BLEND); |
| glBlendFunc(GL_ONE, GL_ONE); |
| glUniform4f(color0InLoc, 0, 1, 0, 0.5); |
| glUniform4f(color1InLoc, 0, 0, 1, 0.5); |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::yellow); |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT2); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::magenta); |
| } |
| |
| // Test that reclearing stencil to the same value works if stencil is blit after clear, and stencil |
| // is modified in between with a draw call. |
| TEST_P(ClearTestES3, RepeatedStencilClearWithBlitAfterClearAndDrawInBetween) |
| { |
| glClearStencil(0xE4); |
| glClear(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Make sure clear is flushed. |
| GLRenderbuffer stencil; |
| glBindRenderbuffer(GL_RENDERBUFFER, stencil); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, getWindowWidth(), |
| getWindowHeight()); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER); |
| |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| // Draw to stencil, and break the render pass. |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Green()); |
| glEnable(GL_STENCIL_TEST); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glStencilFunc(GL_ALWAYS, 0x3C, 0xFF); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.75f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Clear back to the original value |
| glClear(GL_STENCIL_BUFFER_BIT); |
| |
| // Blit again. |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| // Make sure the cleared value is in destination, not the modified value. |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight()); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER); |
| verifyStencil(0xE4, 1); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test basic functionality of clearing a 2D texture with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, Clear2D) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with no data. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the entire texture |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| |
| // Clear each corner to a different color |
| glClearTexSubImageEXT(tex, 0, 0, 0, 0, 8, 8, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexSubImageEXT(tex, 0, 8, 0, 0, 8, 8, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue); |
| glClearTexSubImageEXT(tex, 0, 0, 8, 0, 8, 8, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::cyan); |
| glClearTexSubImageEXT(tex, 0, 8, 8, 0, 8, 8, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::yellow); |
| |
| EXPECT_PIXEL_RECT_EQ(0, 0, 8, 8, GLColor::transparentBlack); |
| EXPECT_PIXEL_RECT_EQ(8, 0, 8, 8, GLColor::blue); |
| EXPECT_PIXEL_RECT_EQ(0, 8, 8, 8, GLColor::cyan); |
| EXPECT_PIXEL_RECT_EQ(8, 8, 8, 8, GLColor::yellow); |
| } |
| |
| // Test basic functionality of clearing a 2D RGB texture with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, Clear2DRGB) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with no data. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the entire texture |
| glClearTexImageEXT(tex, 0, GL_RGB, GL_UNSIGNED_BYTE, &GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| |
| // Clear each corner to a different color |
| glClearTexSubImageEXT(tex, 0, 0, 0, 0, 8, 8, 1, GL_RGB, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexSubImageEXT(tex, 0, 8, 0, 0, 8, 8, 1, GL_RGB, GL_UNSIGNED_BYTE, &GLColor::blue); |
| glClearTexSubImageEXT(tex, 0, 0, 8, 0, 8, 8, 1, GL_RGB, GL_UNSIGNED_BYTE, &GLColor::cyan); |
| glClearTexSubImageEXT(tex, 0, 8, 8, 0, 8, 8, 1, GL_RGB, GL_UNSIGNED_BYTE, &GLColor::yellow); |
| |
| EXPECT_PIXEL_RECT_EQ(0, 0, 8, 8, GLColor::black); |
| EXPECT_PIXEL_RECT_EQ(8, 0, 8, 8, GLColor::blue); |
| EXPECT_PIXEL_RECT_EQ(0, 8, 8, 8, GLColor::cyan); |
| EXPECT_PIXEL_RECT_EQ(8, 8, 8, 8, GLColor::yellow); |
| } |
| |
| // Test basic functionality of clearing a part of a 2D texture with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, Clear2DSubImage) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with no data. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the center to a different color |
| glClearTexSubImageEXT(tex, 0, 4, 4, 0, 8, 8, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::cyan); |
| EXPECT_PIXEL_RECT_EQ(4, 4, 8, 8, GLColor::cyan); |
| } |
| |
| // Test clearing a 2D RGBA4 texture with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, Clear2DRGBA4) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with no data. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 16, 16, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, |
| nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the entire texture, then clear each corner to a different color. |
| GLushort colorRed = 0xF00F; |
| GLushort colorGreen = 0x0F0F; |
| GLushort colorBlue = 0x00FF; |
| GLushort colorYellow = 0xFF0F; |
| |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, &colorGreen); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::green); |
| |
| glClearTexSubImageEXT(tex, 0, 0, 0, 0, 8, 8, 1, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, nullptr); |
| glClearTexSubImageEXT(tex, 0, 8, 0, 0, 8, 8, 1, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, &colorBlue); |
| glClearTexSubImageEXT(tex, 0, 0, 8, 0, 8, 8, 1, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, &colorRed); |
| glClearTexSubImageEXT(tex, 0, 8, 8, 0, 8, 8, 1, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, |
| &colorYellow); |
| |
| EXPECT_PIXEL_RECT_EQ(0, 0, 8, 8, GLColor::transparentBlack); |
| EXPECT_PIXEL_RECT_EQ(8, 0, 8, 8, GLColor::blue); |
| EXPECT_PIXEL_RECT_EQ(0, 8, 8, 8, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(8, 8, 8, 8, GLColor::yellow); |
| } |
| |
| // Test clearing a 2D RGB8 Snorm texture with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, Clear2DRGB8Snorm) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with no data. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8_SNORM, 16, 16, 0, GL_RGB, GL_BYTE, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| |
| // Clear the entire texture. |
| GLint colorGreenRGBSnorm = 0x007F00; |
| glClearTexImageEXT(tex, 0, GL_RGB, GL_BYTE, &colorGreenRGBSnorm); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green); |
| } |
| |
| // Test clearing a corner of a 2D RGB8 Snorm texture with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, Clear2DRGB8SnormCorner) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 4x4 texture with no data. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8_SNORM, 4, 4, 0, GL_RGB, GL_BYTE, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| |
| // Clear one corner of the texture. |
| GLint colorGreenRGBSnorm = 0x007F00; |
| glClearTexSubImageEXT(tex, 0, 0, 0, 0, 2, 2, 1, GL_RGB, GL_BYTE, &colorGreenRGBSnorm); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green); |
| } |
| |
| // Test basic functionality of clearing 2D textures with GL_EXT_clear_texture using nullptr. |
| TEST_P(ClearTextureEXTTest, Clear2DWithNull) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create two 16x16 textures with prior data. |
| std::vector<GLColor> redBlock(16 * 16, GLColor::red); |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, redBlock.data()); |
| |
| GLTexture tex2; |
| glBindTexture(GL_TEXTURE_2D, tex2); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, redBlock.data()); |
| |
| // Clear the RGB texture. |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| GLColor outputColor; |
| glClearTexImageEXT(tex, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); |
| glReadPixels(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &outputColor); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::black); |
| |
| // Clear the RGBA texture. |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex2, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glClearTexImageEXT(tex2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &outputColor); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::transparentBlack); |
| } |
| |
| // Test basic functionality of clearing a 2D texture while bound to another. |
| TEST_P(ClearTextureEXTTest, Clear2DDifferentBinding) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create two 16x16 textures with no data. |
| GLTexture tex1; |
| glBindTexture(GL_TEXTURE_2D, tex1); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLTexture tex2; |
| glBindTexture(GL_TEXTURE_2D, tex2); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| // Use clear on both textures while none are bound. |
| glBindTexture(GL_TEXTURE_2D, 0); |
| glClearTexImageEXT(tex1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| glClearTexImageEXT(tex2, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue); |
| |
| // Bind to one texture while clearing the other. |
| glBindTexture(GL_TEXTURE_2D, tex2); |
| glClearTexImageEXT(tex1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex1, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::green); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex2, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| } |
| |
| // Test basic functionality of clearing 2D textures without binding to them. |
| TEST_P(ClearTextureEXTTest, Clear2DNoBinding) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create two 16x16 textures with no data. |
| GLTexture tex1; |
| glBindTexture(GL_TEXTURE_2D, tex1); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLTexture tex2; |
| glBindTexture(GL_TEXTURE_2D, tex2); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| // Use clear on both textures while bound to neither. |
| glBindTexture(GL_TEXTURE_2D, 0); |
| glClearTexImageEXT(tex1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| glClearTexImageEXT(tex2, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex1, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex2, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| } |
| |
| // Test basic functionality of clearing a 2D texture with prior staged update. |
| TEST_P(ClearTextureEXTTest, Clear2DOverwritePriorContent) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with some data. |
| std::vector<GLColor> redBlock(16 * 16, GLColor::red); |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, redBlock.data()); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear the entire texture. |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| } |
| |
| // Test clearing a 2D texture using a depth of zero. |
| TEST_P(ClearTextureEXTTest, Clear2DWithZeroDepth) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture and fully clear it. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); |
| |
| // Clear the 2D texture using depth of zero. |
| glClearTexSubImageEXT(tex, 0, 0, 0, 0, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::green); |
| } |
| |
| // Test basic functionality of clearing a 2D texture defined using glTexStorage(). |
| TEST_P(ClearTextureEXTTest, Clear2DTexStorage) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 mipmap texture. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexStorage2D(GL_TEXTURE_2D, 5, GL_RGBA8, 16, 16); |
| |
| // Define texture mip levels by clearing them. |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| glClearTexImageEXT(tex, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); |
| glClearTexImageEXT(tex, 2, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue); |
| glClearTexImageEXT(tex, 3, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::magenta); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Bind to framebuffer and verify. |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 8, 8, GLColor::green); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 2); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::blue); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 3); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 2, 2, GLColor::magenta); |
| } |
| |
| // Test that a single full clear for the 3D texture works. |
| TEST_P(ClearTextureEXTTest, Clear3DSingleFull) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| constexpr uint32_t kWidth = 4; |
| constexpr uint32_t kHeight = 4; |
| constexpr uint32_t kDepth = 4; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_3D, texture); |
| glTexStorage3D(GL_TEXTURE_3D, 1, GL_RGBA8, kWidth, kHeight, kDepth); |
| glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); |
| |
| glClearTexImageEXT(texture, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::white); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| for (uint32_t z = 0; z < kDepth; ++z) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, z); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::white); |
| } |
| } |
| |
| // Test that a simple clear for the entire texture works. |
| TEST_P(ClearTextureEXTTest, Clear3DWhole) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| constexpr uint32_t kWidth = 4; |
| constexpr uint32_t kHeight = 4; |
| constexpr uint32_t kDepth = 4; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_3D, texture); |
| glTexStorage3D(GL_TEXTURE_3D, 1, GL_RGBA8, kWidth, kHeight, kDepth); |
| glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); |
| |
| glClearTexImageEXT(texture, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::white); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| for (uint32_t z = 0; z < kDepth; ++z) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, z); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::white); |
| } |
| |
| glClearTexSubImageEXT(texture, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RGBA, GL_UNSIGNED_BYTE, |
| &GLColor::green); |
| for (uint32_t z = 0; z < kDepth; ++z) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, z); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::green); |
| } |
| } |
| |
| // Test that clearing slices of a 3D texture and reading them back works. |
| TEST_P(ClearTextureEXTTest, Clear3DLayers) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| constexpr uint32_t kWidth = 128; |
| constexpr uint32_t kHeight = 128; |
| constexpr uint32_t kDepth = 7; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_3D, texture); |
| glTexStorage3D(GL_TEXTURE_3D, 1, GL_RGBA8, kWidth, kHeight, kDepth); |
| glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); |
| |
| std::array<GLColor, kDepth> clearColors = { |
| GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow, |
| GLColor::cyan, GLColor::magenta, GLColor::white, |
| }; |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| glClearTexImageEXT(texture, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| for (uint32_t z = 0; z < kDepth; ++z) |
| { |
| glClearTexSubImageEXT(texture, 0, 0, 0, z, kWidth, kHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| &clearColors[z]); |
| } |
| |
| for (uint32_t z = 0; z < kDepth; ++z) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, z); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, clearColors[z]); |
| } |
| } |
| |
| // Test that clearing slices of a 3D texture with dimensions of zero does not change it. |
| TEST_P(ClearTextureEXTTest, Clear3DZeroDims) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| constexpr uint32_t kWidth = 4; |
| constexpr uint32_t kHeight = 4; |
| constexpr uint32_t kDepth = 4; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_3D, texture); |
| glTexStorage3D(GL_TEXTURE_3D, 1, GL_RGBA8, kWidth, kHeight, kDepth); |
| glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); |
| glClearTexImageEXT(texture, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::white); |
| |
| // Dimensions of zero for clear are valid. However, they should not change the texture. |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| glClearTexSubImageEXT(texture, 0, 0, 0, 0, 0, kHeight, kDepth, GL_RGBA, GL_UNSIGNED_BYTE, |
| &GLColor::red); |
| ASSERT_GL_NO_ERROR(); |
| glClearTexSubImageEXT(texture, 0, 0, 0, 0, kWidth, 0, kDepth, GL_RGBA, GL_UNSIGNED_BYTE, |
| &GLColor::green); |
| ASSERT_GL_NO_ERROR(); |
| glClearTexSubImageEXT(texture, 0, 0, 0, 0, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| &GLColor::blue); |
| ASSERT_GL_NO_ERROR(); |
| glClearTexSubImageEXT(texture, 0, 0, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| ASSERT_GL_NO_ERROR(); |
| |
| for (uint32_t z = 0; z < kDepth; ++z) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, z); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::white); |
| } |
| } |
| |
| // Test that clearing blocks of a 3D texture and reading them back works. |
| TEST_P(ClearTextureEXTTest, Clear3DBlocks) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| constexpr uint32_t kWidth = 16; |
| constexpr uint32_t kHeight = 16; |
| constexpr uint32_t kDepth = 16; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_3D, texture); |
| glTexStorage3D(GL_TEXTURE_3D, 1, GL_RGBA8, kWidth, kHeight, kDepth); |
| glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); |
| |
| std::array<GLColor, 8> clearColors = {GLColor::red, GLColor::green, GLColor::blue, |
| GLColor::yellow, GLColor::cyan, GLColor::magenta, |
| GLColor::white, GLColor::red}; |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| for (uint32_t k = 0; k < 2; ++k) |
| { |
| for (uint32_t j = 0; j < 2; ++j) |
| { |
| for (uint32_t i = 0; i < 2; ++i) |
| { |
| glClearTexSubImageEXT(texture, 0, i * kWidth / 2, j * kHeight / 2, k * kDepth / 2, |
| kWidth / 2, kHeight / 2, kDepth / 2, GL_RGBA, |
| GL_UNSIGNED_BYTE, &clearColors[(k << 2) + (j << 1) + i]); |
| } |
| } |
| } |
| |
| for (uint32_t z = 0; z < kDepth / 2; ++z) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, z); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth / 2, kHeight / 2, clearColors[0]); |
| EXPECT_PIXEL_RECT_EQ(kWidth / 2, 0, kWidth / 2, kHeight / 2, clearColors[1]); |
| EXPECT_PIXEL_RECT_EQ(0, kHeight / 2, kWidth / 2, kHeight / 2, clearColors[2]); |
| EXPECT_PIXEL_RECT_EQ(kWidth / 2, kHeight / 2, kWidth / 2, kHeight / 2, clearColors[3]); |
| } |
| for (uint32_t z = kDepth / 2; z < kDepth; ++z) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, z); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth / 2, kHeight / 2, clearColors[4]); |
| EXPECT_PIXEL_RECT_EQ(kWidth / 2, 0, kWidth / 2, kHeight / 2, clearColors[5]); |
| EXPECT_PIXEL_RECT_EQ(0, kHeight / 2, kWidth / 2, kHeight / 2, clearColors[6]); |
| EXPECT_PIXEL_RECT_EQ(kWidth / 2, kHeight / 2, kWidth / 2, kHeight / 2, clearColors[7]); |
| } |
| } |
| |
| // Test that clearing slices of a 3D texture and reading them back works. |
| TEST_P(ClearTextureEXTTest, Clear2DArray) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| constexpr uint32_t kWidth = 64; |
| constexpr uint32_t kHeight = 64; |
| constexpr uint32_t kDepth = 4; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, kWidth, kHeight, kDepth); |
| |
| std::array<GLColor, kDepth> clearColors = {GLColor::red, GLColor::green, GLColor::blue, |
| GLColor::yellow}; |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| glClearTexImageEXT(texture, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| for (uint32_t z = 0; z < kDepth; ++z) |
| { |
| glClearTexSubImageEXT(texture, 0, 0, 0, z, kWidth, kHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| &clearColors[z]); |
| } |
| |
| for (uint32_t z = 0; z < kDepth; ++z) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, z); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, clearColors[z]); |
| } |
| } |
| |
| // Test that luminance alpha textures are cleared correctly with GL_EXT_clear_texture. Regression |
| // test for emulated luma formats. |
| TEST_P(ClearTextureEXTTest, Luma) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with no data. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| |
| // Clear the entire texture to transparent black and test |
| GLubyte luminanceClearValue = 192; |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 16, 16, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, |
| nullptr); |
| glClearTexImageEXT(tex, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &luminanceClearValue); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ( |
| 0, 0, getWindowWidth(), getWindowHeight(), |
| GLColor(luminanceClearValue, luminanceClearValue, luminanceClearValue, 255)); |
| |
| GLubyte lumaClearValue[2] = {128, 64}; |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, 16, 16, 0, GL_LUMINANCE_ALPHA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glClearTexImageEXT(tex, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, &lumaClearValue); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ( |
| 0, 0, getWindowWidth(), getWindowHeight(), |
| GLColor(lumaClearValue[0], lumaClearValue[0], lumaClearValue[0], lumaClearValue[1])); |
| } |
| |
| // Test that luminance alpha float textures are cleared correctly with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, LumaAlphaFloat) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with no data. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| |
| GLfloat lumaClearValue[2] = {0.5, 0.25}; |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, 16, 16, 0, GL_LUMINANCE_ALPHA, GL_FLOAT, |
| nullptr); |
| glClearTexImageEXT(tex, 0, GL_LUMINANCE_ALPHA, GL_FLOAT, &lumaClearValue); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, |
| GLColor(lumaClearValue[0] * 255, lumaClearValue[0] * 255, |
| lumaClearValue[0] * 255, lumaClearValue[1] * 255), |
| 1); |
| } |
| |
| // Test that interleaving glClearTexImageEXT and glTexSubImage2D calls produces the correct texture |
| // data. |
| TEST_P(ClearTextureEXTTest, InterleavedUploads) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with no data. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| |
| // Clear the entire texture to transparent black and test |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::transparentBlack); |
| |
| // TexSubImage a corner |
| std::vector<GLColor> redBlock(8 * 8, GLColor::red); |
| glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RGBA, GL_UNSIGNED_BYTE, redBlock.data()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red); |
| |
| // Clear and tex sub image together |
| glClearTexSubImageEXT(tex, 0, 0, 0, 0, 8, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue); |
| glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RGBA, GL_UNSIGNED_BYTE, redBlock.data()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(0, getWindowHeight() / 2, getWindowWidth() / 2, getWindowHeight() / 2, |
| GLColor::blue); |
| } |
| |
| // Test clearing integer textures with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, IntegerTexture) |
| { |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| |
| GLColor32I rgba32iTestValue(-128, 256, -512, 1024); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32I, 16, 16, 0, GL_RGBA_INTEGER, GL_INT, nullptr); |
| glClearTexImageEXT(tex, 0, GL_RGBA_INTEGER, GL_INT, &rgba32iTestValue); |
| EXPECT_GL_NO_ERROR(); |
| EXPECT_PIXEL_32I_COLOR(0, 0, rgba32iTestValue); |
| |
| GLColor32UI rgba32uiTestValue(128, 256, 512, 1024); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32UI, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, |
| nullptr); |
| glClearTexImageEXT(tex, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &rgba32uiTestValue); |
| EXPECT_GL_NO_ERROR(); |
| EXPECT_PIXEL_32UI_COLOR(0, 0, rgba32uiTestValue); |
| } |
| |
| // Test clearing float32 textures with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, Float32Texture) |
| { |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| |
| GLColor32F rgba32fTestValue(0.1, 0.2, 0.3, 0.4); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 16, 16, 0, GL_RGBA, GL_FLOAT, nullptr); |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_FLOAT, &rgba32fTestValue); |
| EXPECT_GL_NO_ERROR(); |
| EXPECT_PIXEL_32F_EQ(0, 0, rgba32fTestValue.R, rgba32fTestValue.G, rgba32fTestValue.B, |
| rgba32fTestValue.A); |
| } |
| |
| // Test clearing depth textures with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, DepthTexture) |
| { |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| GLTexture colorTex; |
| glBindTexture(GL_TEXTURE_2D, colorTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| |
| GLTexture depthTex; |
| glBindTexture(GL_TEXTURE_2D, depthTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 16, 16, 0, GL_DEPTH_COMPONENT, |
| GL_UNSIGNED_INT, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTex, 0); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| |
| const GLuint depthClearZero = 0; |
| const GLuint depthClearOne = std::numeric_limits<GLuint>::max(); |
| |
| // Draw doesn't pass the depth test. Texture has 0.0. |
| glClearTexImageEXT(depthTex, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &depthClearZero); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| |
| // Draw passes the depth test. Texture has 1.0. |
| glClearTexImageEXT(depthTex, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &depthClearOne); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| |
| // Left side passes, right side fails |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| glClearTexSubImageEXT(depthTex, 0, 0, 0, 0, 8, 16, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, |
| &depthClearZero); |
| glClearTexSubImageEXT(depthTex, 0, 8, 0, 0, 8, 16, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, |
| &depthClearOne); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 8, 16, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(8, 0, 8, 16, GLColor::blue); |
| } |
| |
| // Test clearing float depth textures (32-bit) with GL_EXT_clear_texture |
| TEST_P(ClearTextureEXTTest, Depth32FTexture) |
| { |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| GLTexture colorTex; |
| glBindTexture(GL_TEXTURE_2D, colorTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| |
| GLTexture depthTex; |
| glBindTexture(GL_TEXTURE_2D, depthTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, 16, 16, 0, GL_DEPTH_COMPONENT, GL_FLOAT, |
| nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTex, 0); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| |
| const GLfloat depthClearZero = 0.0; |
| const GLfloat depthClearOne = 1.0; |
| |
| // Draw doesn't pass the depth test. Texture has 0.0. |
| glClearTexImageEXT(depthTex, 0, GL_DEPTH_COMPONENT, GL_FLOAT, &depthClearZero); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| |
| // Draw passes the depth test. Texture has 1.0. |
| glClearTexImageEXT(depthTex, 0, GL_DEPTH_COMPONENT, GL_FLOAT, &depthClearOne); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| |
| // Left side passes, right side fails |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| glClearTexSubImageEXT(depthTex, 0, 0, 0, 0, 8, 16, 1, GL_DEPTH_COMPONENT, GL_FLOAT, |
| &depthClearZero); |
| glClearTexSubImageEXT(depthTex, 0, 8, 0, 0, 8, 16, 1, GL_DEPTH_COMPONENT, GL_FLOAT, |
| &depthClearOne); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 8, 16, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(8, 0, 8, 16, GLColor::blue); |
| } |
| |
| // Test clearing 16-bit depth textures with GL_EXT_clear_texture |
| TEST_P(ClearTextureEXTTest, Depth16Texture) |
| { |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| GLTexture colorTex; |
| glBindTexture(GL_TEXTURE_2D, colorTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| |
| GLTexture depthTex; |
| glBindTexture(GL_TEXTURE_2D, depthTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 16, 16, 0, GL_DEPTH_COMPONENT, |
| GL_UNSIGNED_SHORT, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTex, 0); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| |
| const GLushort depthClearZero = 0; |
| const GLushort depthClearOne = std::numeric_limits<GLushort>::max(); |
| |
| // Draw doesn't pass the depth test. Texture has 0.0. |
| glClearTexImageEXT(depthTex, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, &depthClearZero); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| |
| // Draw passes the depth test. Texture has 1.0. |
| glClearTexImageEXT(depthTex, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, &depthClearOne); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| |
| // Left side passes, right side fails |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| glClearTexSubImageEXT(depthTex, 0, 0, 0, 0, 8, 16, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, |
| &depthClearZero); |
| glClearTexSubImageEXT(depthTex, 0, 8, 0, 0, 8, 16, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, |
| &depthClearOne); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 8, 16, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(8, 0, 8, 16, GLColor::blue); |
| } |
| |
| // Test clearing stencil textures with GL_EXT_clear_texture |
| TEST_P(ClearTextureEXTTest, StencilTexture) |
| { |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_stencil8")); |
| |
| GLTexture colorTex; |
| glBindTexture(GL_TEXTURE_2D, colorTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| |
| GLTexture stencilTex; |
| glBindTexture(GL_TEXTURE_2D, stencilTex); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_STENCIL_INDEX8, 16, 16); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTex, 0); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue()); |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_LESS, 0xCC, 0xFF); |
| |
| const GLint stencilClearAA = 0xAA; |
| const GLint stencilClearEE = 0xEE; |
| |
| // Draw doesn't pass the stencil test. |
| glClearTexImageEXT(stencilTex, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &stencilClearAA); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| |
| // Draw passes the stencil test. |
| glClearTexImageEXT(stencilTex, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &stencilClearEE); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| |
| // Left side passes, right side fails |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| glClearTexSubImageEXT(stencilTex, 0, 0, 0, 0, 8, 16, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, |
| &stencilClearAA); |
| glClearTexSubImageEXT(stencilTex, 0, 8, 0, 0, 8, 16, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, |
| &stencilClearEE); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 8, 16, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(8, 0, 8, 16, GLColor::blue); |
| } |
| |
| // Test clearing depth24/stencil8 textures with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, Depth24Stencil8Texture) |
| { |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| GLTexture colorTex; |
| glBindTexture(GL_TEXTURE_2D, colorTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| |
| GLTexture dsTex; |
| glBindTexture(GL_TEXTURE_2D, dsTex); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, 16, 16); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, dsTex, 0); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_LESS, 0xCC, 0xFF); |
| |
| GLuint dsValue0 = 0x000000AA; |
| GLuint dsValue1 = 0x000000EE; |
| GLuint dsValue2 = 0xFFFFFFAA; |
| GLuint dsValue3 = 0xFFFFFFEE; |
| |
| // Draw doesn't pass the test. |
| glClearTexImageEXT(dsTex, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, &dsValue0); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| |
| // Draw passes the stencil test. |
| glClearTexImageEXT(dsTex, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, &dsValue3); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| |
| // Left side fails the depth test. Top side fails the stencil test. |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| |
| glClearTexSubImageEXT(dsTex, 0, 0, 0, 0, 8, 8, 1, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, |
| &dsValue0); |
| glClearTexSubImageEXT(dsTex, 0, 0, 8, 0, 8, 8, 1, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, |
| &dsValue1); |
| glClearTexSubImageEXT(dsTex, 0, 8, 0, 0, 8, 8, 1, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, |
| &dsValue2); |
| glClearTexSubImageEXT(dsTex, 0, 8, 8, 0, 8, 8, 1, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, |
| &dsValue3); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 8, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 8, 16, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(8, 8, 8, 8, GLColor::blue); |
| } |
| |
| // Test clearing depth32/stencil textures with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, Depth32FStencilTexture) |
| { |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| GLTexture colorTex; |
| glBindTexture(GL_TEXTURE_2D, colorTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| |
| GLTexture dsTex; |
| glBindTexture(GL_TEXTURE_2D, dsTex); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH32F_STENCIL8, 16, 16); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, dsTex, 0); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_LESS, 0xCC, 0xFF); |
| |
| struct DSClearValue |
| { |
| GLfloat depth; |
| GLuint stencil; |
| }; |
| |
| DSClearValue dsValue0 = {0, 0xAA}; |
| DSClearValue dsValue1 = {0, 0xEE}; |
| DSClearValue dsValue2 = {1, 0xAA}; |
| DSClearValue dsValue3 = {1, 0xEE}; |
| |
| // Draw doesn't pass the test. |
| glClearTexImageEXT(dsTex, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, &dsValue0); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| |
| // Draw passes the stencil test. |
| glClearTexImageEXT(dsTex, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, &dsValue3); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| |
| // Left side fails the depth test. Top side fails the stencil test. |
| glClearTexImageEXT(colorTex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| |
| glClearTexSubImageEXT(dsTex, 0, 0, 0, 0, 8, 8, 1, GL_DEPTH_STENCIL, |
| GL_FLOAT_32_UNSIGNED_INT_24_8_REV, &dsValue0); |
| glClearTexSubImageEXT(dsTex, 0, 0, 8, 0, 8, 8, 1, GL_DEPTH_STENCIL, |
| GL_FLOAT_32_UNSIGNED_INT_24_8_REV, &dsValue1); |
| glClearTexSubImageEXT(dsTex, 0, 8, 0, 0, 8, 8, 1, GL_DEPTH_STENCIL, |
| GL_FLOAT_32_UNSIGNED_INT_24_8_REV, &dsValue2); |
| glClearTexSubImageEXT(dsTex, 0, 8, 8, 0, 8, 8, 1, GL_DEPTH_STENCIL, |
| GL_FLOAT_32_UNSIGNED_INT_24_8_REV, &dsValue3); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 8, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 8, 16, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(8, 8, 8, 8, GLColor::blue); |
| } |
| |
| // Test clearing different sets of cube map texture faces with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, ClearCubeFaces) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with no data. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_CUBE_MAP, tex); |
| for (size_t i = 0; i < 6; i++) |
| { |
| glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, 16, 16, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| } |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| // Clear the entire texture |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| for (size_t i = 0; i < 6; i++) |
| { |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, tex, 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| } |
| |
| // Clear different ranges of faces to different colors: |
| |
| // [0, 1] -> green |
| glClearTexSubImageEXT(tex, 0, 0, 0, 0, 16, 16, 2, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); |
| |
| // [1, 2] -> blue (partially overlaps previous clear) |
| glClearTexSubImageEXT(tex, 0, 0, 0, 1, 16, 16, 2, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue); |
| |
| // [3, 5] -> cyan |
| glClearTexSubImageEXT(tex, 0, 0, 0, 3, 16, 16, 3, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::cyan); |
| |
| // Test the colors |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + 0, |
| tex, 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::green); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + 1, |
| tex, 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + 2, |
| tex, 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + 3, |
| tex, 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::cyan); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + 4, |
| tex, 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::cyan); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + 5, |
| tex, 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::cyan); |
| } |
| |
| // Test clearing different sets of cube map array texture layer-faces with GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, ClearCubeMapArray) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_cube_map_array")); |
| |
| // Create a 16x16 texture with no data. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex); |
| glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_RGBA, 16, 16, 24, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| // Clear the entire texture |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| for (size_t i = 0; i < 24; i++) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, i); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::red); |
| } |
| |
| // Clear different ranges of faces to different colors: |
| |
| // [0, 4] -> green |
| glClearTexSubImageEXT(tex, 0, 0, 0, 0, 16, 16, 5, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); |
| |
| // [4, 6] -> blue (partially overlaps previous clear) |
| glClearTexSubImageEXT(tex, 0, 0, 0, 4, 16, 16, 3, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue); |
| |
| // [12, 17] -> cyan |
| glClearTexSubImageEXT(tex, 0, 0, 0, 12, 16, 16, 6, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::cyan); |
| |
| // Test the colors |
| for (size_t i = 0; i < 4; i++) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, i); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::green); |
| } |
| for (size_t i = 4; i < 7; i++) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, i); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::blue); |
| } |
| for (size_t i = 12; i < 18; i++) |
| { |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, i); |
| EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::cyan); |
| } |
| } |
| |
| // Test clearing one level, then uploading an update to the same level and then drawing. |
| TEST_P(ClearTextureEXTTest, ClearOneLevelThenPartialUpdateAndDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with prior data. |
| std::vector<GLColor> redBlock(16 * 16, GLColor::red); |
| std::vector<GLColor> greenBlock(16 * 16, GLColor::green); |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, redBlock.data()); |
| glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, redBlock.data()); |
| |
| // Clear one level and add another update on top of it. |
| glClearTexImageEXT(tex, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue); |
| glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, greenBlock.data()); |
| |
| // Draw. |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green); |
| EXPECT_PIXEL_RECT_EQ(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight(), |
| GLColor::blue); |
| EXPECT_PIXEL_RECT_EQ(0, getWindowHeight() / 2, getWindowWidth(), getWindowHeight() / 2, |
| GLColor::blue); |
| } |
| |
| // Test drawing, then partially clearing the texture and drawing again. |
| TEST_P(ClearTextureEXTTest, DrawThenClearPartiallyThenDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with prior data. |
| std::vector<GLColor> redBlock(16 * 16, GLColor::red); |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, redBlock.data()); |
| |
| // Draw. |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::red); |
| |
| // Clear a portion of the texture and draw again. |
| glClearTexSubImageEXT(tex, 0, 0, 0, 0, 8, 8, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::yellow); |
| |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth() / 2, getWindowHeight() / 2, GLColor::yellow); |
| EXPECT_PIXEL_RECT_EQ(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight(), |
| GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(0, getWindowHeight() / 2, getWindowWidth(), getWindowHeight() / 2, |
| GLColor::red); |
| } |
| |
| // Test partially clearing a mip level, applying an overlapping update and then drawing with it. |
| TEST_P(ClearTextureEXTTest, PartialClearThenOverlappingUploadThenDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with prior data. |
| std::vector<GLColor> redBlock(16 * 16, GLColor::red); |
| std::vector<GLColor> greenBlock(16 * 16, GLColor::green); |
| std::vector<GLColor> blueBlock(16 * 16, GLColor::blue); |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, blueBlock.data()); |
| glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, redBlock.data()); |
| |
| // Clear one level and add another update on top of it. |
| glClearTexSubImageEXT(tex, 1, 2, 2, 0, 4, 4, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::yellow); |
| glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, greenBlock.data()); |
| |
| // Draw and verify. |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green); |
| EXPECT_PIXEL_RECT_EQ(getWindowWidth() / 4, getWindowWidth() / 2, getWindowWidth() / 2, |
| getWindowHeight() / 4, GLColor::yellow); |
| EXPECT_PIXEL_RECT_EQ(getWindowWidth() / 2, getWindowWidth() / 4, getWindowWidth() / 4, |
| getWindowHeight() / 2, GLColor::yellow); |
| EXPECT_PIXEL_RECT_EQ((3 * getWindowWidth()) / 4, 0, getWindowWidth() / 4, getWindowHeight(), |
| GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(0, (3 * getWindowHeight()) / 4, getWindowWidth(), getWindowHeight() / 4, |
| GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight() / 4, |
| GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(0, getWindowHeight() / 2, getWindowWidth() / 4, getWindowHeight() / 2, |
| GLColor::red); |
| } |
| |
| // Test clearing a mip level and generating mipmap based on its previous level and draw. |
| TEST_P(ClearTextureEXTTest, ClearLevelThenGenerateMipmapOnBaseThenDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with prior data. |
| std::vector<GLColor> redBlock(16 * 16, GLColor::red); |
| std::vector<GLColor> greenBlock(16 * 16, GLColor::green); |
| std::vector<GLColor> blueBlock(16 * 16, GLColor::blue); |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, redBlock.data()); |
| glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, greenBlock.data()); |
| glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, blueBlock.data()); |
| |
| // Clear level 1 and then generate mipmap for the texture. |
| glClearTexImageEXT(tex, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::yellow); |
| glGenerateMipmap(GL_TEXTURE_2D); |
| |
| // Draw. |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::red); |
| } |
| |
| // Test clearing a mip level and generating mipmap based on that level and draw. |
| TEST_P(ClearTextureEXTTest, ClearLevelThenGenerateMipmapOnLevelThenDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Create a 16x16 texture with prior data. |
| std::vector<GLColor> redBlock(16 * 16, GLColor::red); |
| std::vector<GLColor> greenBlock(16 * 16, GLColor::green); |
| std::vector<GLColor> blueBlock(16 * 16, GLColor::blue); |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, redBlock.data()); |
| glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, greenBlock.data()); |
| glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, blueBlock.data()); |
| |
| // Clear level 1 and then generate mipmap for the texture based on level 1. |
| glClearTexImageEXT(tex, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::yellow); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| glGenerateMipmap(GL_TEXTURE_2D); |
| |
| // Draw. |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow); |
| } |
| |
| // Test clearing a large 2D texture. |
| TEST_P(ClearTextureEXTTest, LargeTexture) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| constexpr GLsizei kTexWidth = 2048; |
| constexpr GLsizei kTexHeight = 2048; |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTexWidth, kTexHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kTexWidth, kTexHeight, GLColor::red); |
| } |
| |
| // Test that clearing works correctly after swizzling the texture components. |
| TEST_P(ClearTextureEXTTest, ClearDrawSwizzleClearDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Initialize texture and draw. |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::cyan); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::cyan); |
| |
| // Change swizzling; left rotation of the RGB components. |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_GREEN); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_BLUE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA); |
| |
| // Clear again and draw. |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::yellow); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::magenta); |
| } |
| |
| // Test validation of GL_EXT_clear_texture. |
| TEST_P(ClearTextureEXTTest, Validation) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Texture 0 is invalid |
| glClearTexImageEXT(0, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // Texture is not the name of a texture object |
| glClearTexImageEXT(1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| GLTexture tex2D; |
| glBindTexture(GL_TEXTURE_2D, tex2D); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| // Out of bounds |
| glClearTexSubImageEXT(tex2D, 0, 1, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| glClearTexSubImageEXT(tex2D, 0, 0, 1, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| glClearTexSubImageEXT(tex2D, 1, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| glClearTexSubImageEXT(tex2D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| glClearTexSubImageEXT(tex2D, 0, 0, 0, 0, 16, 16, 2, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // Negative offsets |
| glClearTexSubImageEXT(tex2D, 0, 4, 4, 0, -2, -2, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| GLTexture texCube; |
| glBindTexture(GL_TEXTURE_CUBE_MAP, texCube); |
| |
| // First and third cube faces are specified |
| glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 0, 0, GL_RGBA, 16, 16, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 2, 0, GL_RGBA, 16, 16, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| |
| // Unspecified cube face |
| glClearTexSubImageEXT(texCube, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| &GLColor::green); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // Cube range with an unspecified face |
| glClearTexSubImageEXT(texCube, 0, 0, 0, 0, 16, 16, 3, GL_RGBA, GL_UNSIGNED_BYTE, |
| &GLColor::green); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // Undefined level |
| GLTexture tex1Level; |
| glBindTexture(GL_TEXTURE_2D, tex1Level); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexImageEXT(tex1Level, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // Compressed texture |
| GLTexture tex2DCompressed; |
| glBindTexture(GL_TEXTURE_2D, tex2DCompressed); |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB8_ETC2, 16, 16, 0, 128, nullptr); |
| glClearTexImageEXT(tex2DCompressed, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // Buffer texture |
| if (IsGLExtensionEnabled("GL_EXT_texture_buffer")) |
| { |
| GLTexture texBuffer; |
| glBindTexture(GL_TEXTURE_BUFFER_EXT, texBuffer); |
| glClearTexImageEXT(texBuffer, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| // internal format is integer and format does not specify integer data |
| GLTexture texInt; |
| glBindTexture(GL_TEXTURE_2D, texInt); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glClearTexImageEXT(texInt, 0, GL_RGBA, GL_FLOAT, &GLColor::red); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // internal format is not integer and format does specify integer data |
| GLTexture texFloat; |
| glBindTexture(GL_TEXTURE_2D, texFloat); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 16, 16, 0, GL_RGBA, GL_FLOAT, nullptr); |
| glClearTexImageEXT(texFloat, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &GLColor::red); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // internal format is DEPTH_COMPONENT and format is not DEPTH_COMPONENT |
| GLTexture texDepth; |
| glBindTexture(GL_TEXTURE_2D, texDepth); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, 16, 16, 0, GL_DEPTH_COMPONENT, GL_FLOAT, |
| nullptr); |
| glClearTexImageEXT(texDepth, 0, GL_RGBA, GL_FLOAT, &GLColor::red); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // internal format is DEPTH_STENCIL and format is not DEPTH_STENCIL |
| GLTexture texDepthStencil; |
| glBindTexture(GL_TEXTURE_2D, texDepthStencil); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 16, 16, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8, nullptr); |
| glClearTexImageEXT(texDepthStencil, 0, GL_RGBA, GL_UNSIGNED_INT_24_8, &GLColor::red); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // internal format is STENCIL_INDEX and format is not STENCIL_INDEX |
| GLTexture texStencil; |
| glBindTexture(GL_TEXTURE_2D, texStencil); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_STENCIL_INDEX8, 16, 16, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, |
| nullptr); |
| glClearTexImageEXT(texStencil, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| // internal format is RGBA and the <format> is DEPTH_COMPONENT, STENCIL_INDEX, or DEPTH_STENCIL |
| GLTexture texRGBA; |
| glBindTexture(GL_TEXTURE_2D, texRGBA); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 16, 16, 0, GL_RGBA, GL_FLOAT, nullptr); |
| glClearTexImageEXT(texRGBA, 0, GL_DEPTH_COMPONENT, GL_FLOAT, &GLColor::red); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glClearTexImageEXT(texRGBA, 0, GL_STENCIL_INDEX, GL_FLOAT, &GLColor::red); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| glClearTexImageEXT(texRGBA, 0, GL_DEPTH_STENCIL, GL_FLOAT, &GLColor::red); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| // Covers a driver bug that leaks color mask state into clear texture ops. |
| TEST_P(ClearTextureEXTTest, ClearTextureAfterMaskedClearBug) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_clear_texture")); |
| |
| // Perform a masked clear |
| { |
| glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
| glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| } |
| |
| // Create a new texture with data, clear it, and sample |
| { |
| constexpr uint32_t kSize = 16; |
| std::vector<unsigned char> pixelData(kSize * kSize * 4, 255); |
| |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| pixelData.data()); |
| glClearTexImageEXT(tex, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack); |
| } |
| } |
| |
| // Test clearing renderable format textures with GL_EXT_clear_texture for TEXTURE_2D. |
| TEST_P(ClearTextureEXTTestES31Renderable, Clear2D) |
| { |
| mDepth = 1; |
| mTarget = GL_TEXTURE_2D; |
| mIsArray = mHasLayer = false; |
| testRenderable(); |
| } |
| |
| // Test clearing unrenderable format textures with GL_EXT_clear_texture for TEXTURE_2D. |
| TEST_P(ClearTextureEXTTestES31Unrenderable, Clear2D) |
| { |
| mDepth = 1; |
| mTarget = GL_TEXTURE_2D; |
| mIsArray = mHasLayer = false; |
| testUnrenderable(mFormats); |
| } |
| |
| // Test clearing renderable format textures with GL_EXT_clear_texture for TEXTURE_2D_ARRAY. |
| TEST_P(ClearTextureEXTTestES31Renderable, Clear2DArray) |
| { |
| mTarget = GL_TEXTURE_2D_ARRAY; |
| testRenderable(); |
| } |
| |
| // Test clearing unrenderable format textures with GL_EXT_clear_texture for TEXTURE_2D_ARRAY. |
| TEST_P(ClearTextureEXTTestES31Unrenderable, Clear2DArray) |
| { |
| mTarget = GL_TEXTURE_2D_ARRAY; |
| testUnrenderable(mFormats); |
| } |
| |
| // Test clearing renderable format textures with GL_EXT_clear_texture for TEXTURE_3D. |
| TEST_P(ClearTextureEXTTestES31Renderable, Clear3D) |
| { |
| mTarget = GL_TEXTURE_3D; |
| mIsArray = false; |
| testRenderable(); |
| } |
| |
| // Test clearing unrenderable format textures with GL_EXT_clear_texture for TEXTURE_3D. |
| TEST_P(ClearTextureEXTTestES31Unrenderable, Clear3D) |
| { |
| mTarget = GL_TEXTURE_3D; |
| mIsArray = false; |
| testUnrenderable(mFormats); |
| } |
| |
| // Test clearing renderable format textures with GL_EXT_clear_texture for TEXTURE_CUBE_MAP. |
| TEST_P(ClearTextureEXTTestES31Renderable, ClearCubeMap) |
| { |
| mHeight = mWidth; |
| mDepth = 6; |
| mLevels = std::log2(mWidth) + 1; |
| mTarget = GL_TEXTURE_CUBE_MAP; |
| testRenderable(); |
| } |
| |
| // Test clearing unrenderable format textures with GL_EXT_clear_texture for TEXTURE_CUBE_MAP. |
| TEST_P(ClearTextureEXTTestES31Unrenderable, ClearCubeMap) |
| { |
| mHeight = mWidth; |
| mDepth = 6; |
| mLevels = std::log2(mWidth) + 1; |
| mTarget = GL_TEXTURE_CUBE_MAP; |
| testUnrenderable(mFormats); |
| } |
| |
| // Test clearing renderable format textures with GL_EXT_clear_texture for |
| // TEXTURE_CUBE_MAP_ARRAY. |
| TEST_P(ClearTextureEXTTestES31Renderable, ClearCubeMapArray) |
| { |
| mHeight = mWidth; |
| mDepth = 2 * 6; |
| mLevels = std::log2(mWidth) + 1; |
| mTarget = GL_TEXTURE_CUBE_MAP_ARRAY; |
| mExtraSupport = IsGLExtensionEnabled("GL_EXT_texture_cube_map_array"); |
| testRenderable(); |
| } |
| |
| // Test clearing unrenderable format textures with GL_EXT_clear_texture for |
| // TEXTURE_CUBE_MAP_ARRAY. |
| TEST_P(ClearTextureEXTTestES31Unrenderable, ClearCubeMapArray) |
| { |
| mHeight = mWidth; |
| mDepth = 2 * 6; |
| mLevels = std::log2(mWidth) + 1; |
| mTarget = GL_TEXTURE_CUBE_MAP_ARRAY; |
| mExtraSupport = IsGLExtensionEnabled("GL_EXT_texture_cube_map_array"); |
| testUnrenderable(mFormats); |
| } |
| |
| // Test clearing GL_RGB9_E5 format. |
| TEST_P(ClearTextureEXTTestES31Unrenderable, ClearRGB9E5) |
| { |
| // Test for TEXTURE_2D_ARRAY. |
| mTarget = GL_TEXTURE_2D_ARRAY; |
| testUnrenderable(mFormatsRGB9E5); |
| |
| // Test for TEXTURE_3D. |
| mTarget = GL_TEXTURE_3D; |
| mIsArray = false; |
| testUnrenderable(mFormatsRGB9E5); |
| |
| // Test for TEXTURE_2D. |
| mDepth = 1; |
| mLevels = std::log2(std::max(mWidth, mHeight)) + 1; |
| mTarget = GL_TEXTURE_2D; |
| mIsArray = mHasLayer = false; |
| testUnrenderable(mFormatsRGB9E5); |
| |
| // Test for TEXTURE_CUBE_MAP. |
| mHeight = mWidth; |
| mDepth = 6; |
| mLevels = std::log2(mWidth) + 1; |
| mTarget = GL_TEXTURE_CUBE_MAP; |
| mIsArray = mHasLayer = true; |
| testUnrenderable(mFormatsRGB9E5); |
| |
| // Test for TEXTURE_CUBE_MAP_ARRAY. |
| mDepth = 2 * 6; |
| mTarget = GL_TEXTURE_CUBE_MAP_ARRAY; |
| mExtraSupport = IsGLExtensionEnabled("GL_EXT_texture_cube_map_array"); |
| testUnrenderable(mFormatsRGB9E5); |
| } |
| |
| // Test clearing unrenderable format textures with GL_EXT_clear_texture for TEXTURE_2D_MULTISAMPLE. |
| TEST_P(ClearTextureEXTTestES31Renderable, ClearMultisample) |
| { |
| mDepth = 1; |
| mTarget = GL_TEXTURE_2D_MULTISAMPLE; |
| mIsArray = mHasLayer = false; |
| testMS(); |
| } |
| |
| // Test clearing unrenderable format textures with GL_EXT_clear_texture for |
| // TEXTURE_2D_MULTISAMPLE_ARRAY. |
| TEST_P(ClearTextureEXTTestES31Renderable, ClearMultisampleArray) |
| { |
| mTarget = GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES; |
| mExtraSupport = EnsureGLExtensionEnabled("GL_OES_texture_storage_multisample_2d_array"); |
| testMS(); |
| } |
| |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND( |
| ClearTest, |
| ES3_VULKAN().enable(Feature::ForceFallbackFormat), |
| ES3_VULKAN().enable(Feature::PreferDrawClearOverVkCmdClearAttachments), |
| ES2_WEBGPU()); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ClearTestES3); |
| ANGLE_INSTANTIATE_TEST_ES3_AND( |
| ClearTestES3, |
| ES3_VULKAN().enable(Feature::ForceFallbackFormat), |
| ES3_VULKAN().enable(Feature::PreferDrawClearOverVkCmdClearAttachments)); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ClearTestES31); |
| ANGLE_INSTANTIATE_TEST_ES31_AND( |
| ClearTestES31, |
| ES31_VULKAN().enable(Feature::ForceFallbackFormat), |
| ES31_VULKAN().enable(Feature::PreferDrawClearOverVkCmdClearAttachments)); |
| |
| ANGLE_INSTANTIATE_TEST_COMBINE_4(MaskedScissoredClearTest, |
| MaskedScissoredClearVariationsTestPrint, |
| testing::Range(0, 3), |
| testing::Range(0, 3), |
| testing::Range(0, 3), |
| testing::Bool(), |
| ANGLE_ALL_TEST_PLATFORMS_ES2, |
| ANGLE_ALL_TEST_PLATFORMS_ES3, |
| ES3_VULKAN() |
| .disable(Feature::SupportsExtendedDynamicState) |
| .disable(Feature::SupportsExtendedDynamicState2), |
| ES3_VULKAN().disable(Feature::SupportsExtendedDynamicState2)); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VulkanClearTest); |
| ANGLE_INSTANTIATE_TEST_COMBINE_4(VulkanClearTest, |
| MaskedScissoredClearVariationsTestPrint, |
| testing::Range(0, 3), |
| testing::Range(0, 3), |
| testing::Range(0, 3), |
| testing::Bool(), |
| ES2_VULKAN().enable(Feature::ForceFallbackFormat), |
| ES2_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat), |
| ES3_VULKAN().enable(Feature::ForceFallbackFormat), |
| ES3_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat)); |
| |
| // Not all ANGLE backends support RGB backbuffers |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ClearTestRGB); |
| ANGLE_INSTANTIATE_TEST(ClearTestRGB, |
| ES2_D3D11(), |
| ES3_D3D11(), |
| ES2_VULKAN(), |
| ES3_VULKAN(), |
| ES2_METAL(), |
| ES3_METAL()); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ClearTestRGB_ES3); |
| ANGLE_INSTANTIATE_TEST(ClearTestRGB_ES3, ES3_D3D11(), ES3_VULKAN(), ES3_METAL()); |
| |
| ANGLE_INSTANTIATE_TEST_ES3(ClearTextureEXTTest); |
| ANGLE_INSTANTIATE_TEST_ES31(ClearTextureEXTTestES31Renderable); |
| ANGLE_INSTANTIATE_TEST_ES31(ClearTextureEXTTestES31Unrenderable); |
| |
| } // anonymous namespace |