| // |
| // Copyright 2015 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/gl_raii.h" |
| |
| using namespace angle; |
| |
| namespace |
| { |
| class BlitFramebufferANGLETest : public ANGLETest<> |
| { |
| protected: |
| BlitFramebufferANGLETest() |
| { |
| setWindowWidth(64); |
| setWindowHeight(32); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| setConfigDepthBits(24); |
| setConfigStencilBits(8); |
| |
| mCheckerProgram = 0; |
| mBlueProgram = 0; |
| mRedProgram = 0; |
| |
| mOriginalFBO = 0; |
| |
| mUserFBO = 0; |
| mUserColorBuffer = 0; |
| mUserDepthStencilBuffer = 0; |
| |
| mSmallFBO = 0; |
| mSmallColorBuffer = 0; |
| mSmallDepthStencilBuffer = 0; |
| |
| mColorOnlyFBO = 0; |
| mColorOnlyColorBuffer = 0; |
| |
| mDiffFormatFBO = 0; |
| mDiffFormatColorBuffer = 0; |
| |
| mDiffSizeFBO = 0; |
| mDiffSizeColorBuffer = 0; |
| |
| mMRTFBO = 0; |
| mMRTColorBuffer0 = 0; |
| mMRTColorBuffer1 = 0; |
| |
| mRGBAColorbuffer = 0; |
| mRGBAFBO = 0; |
| mRGBAMultisampledRenderbuffer = 0; |
| mRGBAMultisampledFBO = 0; |
| |
| mBGRAColorbuffer = 0; |
| mBGRAFBO = 0; |
| mBGRAMultisampledRenderbuffer = 0; |
| mBGRAMultisampledFBO = 0; |
| } |
| |
| void testSetUp() override |
| { |
| mCheckerProgram = |
| CompileProgram(essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Checkered()); |
| mBlueProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| mRedProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| if (mCheckerProgram == 0 || mBlueProgram == 0 || mRedProgram == 0) |
| { |
| FAIL() << "shader compilation failed."; |
| } |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| GLint originalFBO; |
| glGetIntegerv(GL_FRAMEBUFFER_BINDING, &originalFBO); |
| if (originalFBO >= 0) |
| { |
| mOriginalFBO = (GLuint)originalFBO; |
| } |
| |
| GLenum format = GL_RGBA; |
| |
| glGenFramebuffers(1, &mUserFBO); |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| glGenTextures(1, &mUserColorBuffer); |
| glGenRenderbuffers(1, &mUserDepthStencilBuffer); |
| glBindTexture(GL_TEXTURE_2D, mUserColorBuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| mUserColorBuffer, 0); |
| glTexImage2D(GL_TEXTURE_2D, 0, format, getWindowWidth(), getWindowHeight(), 0, format, |
| GL_UNSIGNED_BYTE, nullptr); |
| glBindRenderbuffer(GL_RENDERBUFFER, mUserDepthStencilBuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, getWindowWidth(), |
| getWindowHeight()); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| mUserDepthStencilBuffer); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| mUserDepthStencilBuffer); |
| |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| ASSERT_GL_NO_ERROR(); |
| |
| glGenFramebuffers(1, &mSmallFBO); |
| glBindFramebuffer(GL_FRAMEBUFFER, mSmallFBO); |
| glGenTextures(1, &mSmallColorBuffer); |
| glGenRenderbuffers(1, &mSmallDepthStencilBuffer); |
| glBindTexture(GL_TEXTURE_2D, mSmallColorBuffer); |
| glTexImage2D(GL_TEXTURE_2D, 0, format, getWindowWidth() / 2, getWindowHeight() / 2, 0, |
| format, GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| mSmallColorBuffer, 0); |
| glBindRenderbuffer(GL_RENDERBUFFER, mSmallDepthStencilBuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, getWindowWidth() / 2, |
| getWindowHeight() / 2); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| mSmallDepthStencilBuffer); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| mSmallDepthStencilBuffer); |
| |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| ASSERT_GL_NO_ERROR(); |
| |
| glGenFramebuffers(1, &mColorOnlyFBO); |
| glBindFramebuffer(GL_FRAMEBUFFER, mColorOnlyFBO); |
| glGenTextures(1, &mColorOnlyColorBuffer); |
| glBindTexture(GL_TEXTURE_2D, mColorOnlyColorBuffer); |
| glTexImage2D(GL_TEXTURE_2D, 0, format, getWindowWidth(), getWindowHeight(), 0, format, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| mColorOnlyColorBuffer, 0); |
| |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| ASSERT_GL_NO_ERROR(); |
| |
| glGenFramebuffers(1, &mDiffFormatFBO); |
| glBindFramebuffer(GL_FRAMEBUFFER, mDiffFormatFBO); |
| glGenTextures(1, &mDiffFormatColorBuffer); |
| glBindTexture(GL_TEXTURE_2D, mDiffFormatColorBuffer); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, |
| GL_UNSIGNED_SHORT_5_6_5, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| mDiffFormatColorBuffer, 0); |
| |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| ASSERT_GL_NO_ERROR(); |
| |
| glGenFramebuffers(1, &mDiffSizeFBO); |
| glBindFramebuffer(GL_FRAMEBUFFER, mDiffSizeFBO); |
| glGenTextures(1, &mDiffSizeColorBuffer); |
| glBindTexture(GL_TEXTURE_2D, mDiffSizeColorBuffer); |
| glTexImage2D(GL_TEXTURE_2D, 0, format, getWindowWidth() * 2, getWindowHeight() * 2, 0, |
| format, GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| mDiffSizeColorBuffer, 0); |
| |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| ASSERT_GL_NO_ERROR(); |
| |
| if (IsGLExtensionEnabled("GL_EXT_draw_buffers")) |
| { |
| glGenFramebuffers(1, &mMRTFBO); |
| glBindFramebuffer(GL_FRAMEBUFFER, mMRTFBO); |
| glGenTextures(1, &mMRTColorBuffer0); |
| glGenTextures(1, &mMRTColorBuffer1); |
| glBindTexture(GL_TEXTURE_2D, mMRTColorBuffer0); |
| glTexImage2D(GL_TEXTURE_2D, 0, format, getWindowWidth(), getWindowHeight(), 0, format, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, |
| mMRTColorBuffer0, 0); |
| glBindTexture(GL_TEXTURE_2D, mMRTColorBuffer1); |
| glTexImage2D(GL_TEXTURE_2D, 0, format, getWindowWidth(), getWindowHeight(), 0, format, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, |
| mMRTColorBuffer1, 0); |
| |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| if (IsGLExtensionEnabled("GL_ANGLE_framebuffer_multisample") && |
| IsGLExtensionEnabled("GL_OES_rgb8_rgba8")) |
| { |
| // RGBA single-sampled framebuffer |
| glGenTextures(1, &mRGBAColorbuffer); |
| glBindTexture(GL_TEXTURE_2D, mRGBAColorbuffer); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| |
| glGenFramebuffers(1, &mRGBAFBO); |
| glBindFramebuffer(GL_FRAMEBUFFER, mRGBAFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| mRGBAColorbuffer, 0); |
| |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| |
| // RGBA multisampled framebuffer |
| glGenRenderbuffers(1, &mRGBAMultisampledRenderbuffer); |
| glBindRenderbuffer(GL_RENDERBUFFER, mRGBAMultisampledRenderbuffer); |
| glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, 1, GL_RGBA8, getWindowWidth(), |
| getWindowHeight()); |
| |
| glGenFramebuffers(1, &mRGBAMultisampledFBO); |
| glBindFramebuffer(GL_FRAMEBUFFER, mRGBAMultisampledFBO); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| mRGBAMultisampledRenderbuffer); |
| |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| |
| if (IsGLExtensionEnabled("GL_EXT_texture_format_BGRA8888")) |
| { |
| // BGRA single-sampled framebuffer |
| glGenTextures(1, &mBGRAColorbuffer); |
| glBindTexture(GL_TEXTURE_2D, mBGRAColorbuffer); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, getWindowWidth(), getWindowHeight(), 0, |
| GL_BGRA_EXT, GL_UNSIGNED_BYTE, nullptr); |
| |
| glGenFramebuffers(1, &mBGRAFBO); |
| glBindFramebuffer(GL_FRAMEBUFFER, mBGRAFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| mBGRAColorbuffer, 0); |
| |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| |
| // BGRA multisampled framebuffer |
| glGenRenderbuffers(1, &mBGRAMultisampledRenderbuffer); |
| glBindRenderbuffer(GL_RENDERBUFFER, mBGRAMultisampledRenderbuffer); |
| glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, 1, GL_BGRA8_EXT, |
| getWindowWidth(), getWindowHeight()); |
| |
| glGenFramebuffers(1, &mBGRAMultisampledFBO); |
| glBindFramebuffer(GL_FRAMEBUFFER, mBGRAMultisampledFBO); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| mBGRAMultisampledRenderbuffer); |
| |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| } |
| } |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| } |
| |
| void testTearDown() override |
| { |
| glDeleteProgram(mCheckerProgram); |
| glDeleteProgram(mBlueProgram); |
| glDeleteProgram(mRedProgram); |
| |
| glDeleteFramebuffers(1, &mUserFBO); |
| glDeleteTextures(1, &mUserColorBuffer); |
| glDeleteRenderbuffers(1, &mUserDepthStencilBuffer); |
| |
| glDeleteFramebuffers(1, &mSmallFBO); |
| glDeleteTextures(1, &mSmallColorBuffer); |
| glDeleteRenderbuffers(1, &mSmallDepthStencilBuffer); |
| |
| glDeleteFramebuffers(1, &mColorOnlyFBO); |
| glDeleteTextures(1, &mSmallDepthStencilBuffer); |
| |
| glDeleteFramebuffers(1, &mDiffFormatFBO); |
| glDeleteTextures(1, &mDiffFormatColorBuffer); |
| |
| glDeleteFramebuffers(1, &mDiffSizeFBO); |
| glDeleteTextures(1, &mDiffSizeColorBuffer); |
| |
| if (IsGLExtensionEnabled("GL_EXT_draw_buffers")) |
| { |
| glDeleteFramebuffers(1, &mMRTFBO); |
| glDeleteTextures(1, &mMRTColorBuffer0); |
| glDeleteTextures(1, &mMRTColorBuffer1); |
| } |
| |
| if (mRGBAColorbuffer != 0) |
| { |
| glDeleteTextures(1, &mRGBAColorbuffer); |
| } |
| |
| if (mRGBAFBO != 0) |
| { |
| glDeleteFramebuffers(1, &mRGBAFBO); |
| } |
| |
| if (mRGBAMultisampledRenderbuffer != 0) |
| { |
| glDeleteRenderbuffers(1, &mRGBAMultisampledRenderbuffer); |
| } |
| |
| if (mRGBAMultisampledFBO != 0) |
| { |
| glDeleteFramebuffers(1, &mRGBAMultisampledFBO); |
| } |
| |
| if (mBGRAColorbuffer != 0) |
| { |
| glDeleteTextures(1, &mBGRAColorbuffer); |
| } |
| |
| if (mBGRAFBO != 0) |
| { |
| glDeleteFramebuffers(1, &mBGRAFBO); |
| } |
| |
| if (mBGRAMultisampledRenderbuffer != 0) |
| { |
| glDeleteRenderbuffers(1, &mBGRAMultisampledRenderbuffer); |
| } |
| |
| if (mBGRAMultisampledFBO != 0) |
| { |
| glDeleteFramebuffers(1, &mBGRAMultisampledFBO); |
| } |
| } |
| |
| void multisampleTestHelper(GLuint readFramebuffer, GLuint drawFramebuffer) |
| { |
| glClearColor(0.0, 1.0, 0.0, 1.0); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, readFramebuffer); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, readFramebuffer); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFramebuffer); |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, drawFramebuffer); |
| EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); |
| EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); |
| EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); |
| EXPECT_PIXEL_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); |
| } |
| |
| bool checkExtension(const std::string &extension) |
| { |
| if (!IsGLExtensionEnabled(extension)) |
| { |
| std::cout << "Test skipped because " << extension << " not supported." << std::endl; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void BlitStencilTestHelper(bool mesaYFlip) |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| if (mesaYFlip) |
| { |
| ASSERT_TRUE(IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| } |
| |
| glClearColor(0.0, 1.0, 0.0, 1.0); |
| glClearStencil(0x0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Scissor half the screen so we fill the stencil only halfway |
| glScissor(0, 0, getWindowWidth(), getWindowHeight() / 2); |
| glEnable(GL_SCISSOR_TEST); |
| |
| // fill the stencil buffer with 0x1 |
| glStencilFunc(GL_ALWAYS, 0x1, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glEnable(GL_STENCIL_TEST); |
| drawQuad(mRedProgram, essl1_shaders::PositionAttrib(), 0.3f); |
| |
| glDisable(GL_SCISSOR_TEST); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| // These clears are not useful in theory because we're copying over them, but its |
| // helpful in debugging if we see white in any result. |
| glClearColor(1.0, 1.0, 1.0, 1.0); |
| glClearStencil(0x0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, |
| GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| |
| glStencilFunc(GL_EQUAL, 0x1, 0xFF); // only pass if stencil buffer at pixel reads 0x1 |
| |
| drawQuad(mBlueProgram, essl1_shaders::PositionAttrib(), |
| 0.8f); // blue quad will draw if stencil buffer was copied |
| |
| glDisable(GL_STENCIL_TEST); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| } |
| |
| GLuint mCheckerProgram; |
| GLuint mBlueProgram; |
| GLuint mRedProgram; |
| |
| GLuint mOriginalFBO; |
| |
| GLuint mUserFBO; |
| GLuint mUserColorBuffer; |
| GLuint mUserDepthStencilBuffer; |
| |
| GLuint mSmallFBO; |
| GLuint mSmallColorBuffer; |
| GLuint mSmallDepthStencilBuffer; |
| |
| GLuint mColorOnlyFBO; |
| GLuint mColorOnlyColorBuffer; |
| |
| GLuint mDiffFormatFBO; |
| GLuint mDiffFormatColorBuffer; |
| |
| GLuint mDiffSizeFBO; |
| GLuint mDiffSizeColorBuffer; |
| |
| GLuint mMRTFBO; |
| GLuint mMRTColorBuffer0; |
| GLuint mMRTColorBuffer1; |
| |
| GLuint mRGBAColorbuffer; |
| GLuint mRGBAFBO; |
| GLuint mRGBAMultisampledRenderbuffer; |
| GLuint mRGBAMultisampledFBO; |
| |
| GLuint mBGRAColorbuffer; |
| GLuint mBGRAFBO; |
| GLuint mBGRAMultisampledRenderbuffer; |
| GLuint mBGRAMultisampledFBO; |
| }; |
| |
| // Draw to user-created framebuffer, blit whole-buffer color to original framebuffer. |
| TEST_P(BlitFramebufferANGLETest, BlitColorToDefault) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow); |
| } |
| |
| // Blit color to/from default framebuffer with Flip-X/Flip-Y. |
| TEST_P(BlitFramebufferANGLETest, BlitColorWithFlip) |
| { |
| // OpenGL ES 3.0 / GL_NV_framebuffer_blit required for flip. |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 && |
| !IsGLExtensionEnabled("GL_NV_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| // Blit to default with x-flip. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), getWindowWidth(), 0, 0, |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| |
| // Blit to default with y-flip. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, getWindowHeight(), |
| getWindowWidth(), 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::blue); |
| |
| // Blit from default with x-flip. |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), getWindowWidth(), 0, 0, |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::red); |
| |
| // Blit from default with y-flip. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, getWindowHeight(), |
| getWindowWidth(), 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow); |
| } |
| |
| // Blit color to default framebuffer from another framebuffer with GL_MESA_framebuffer_flip_y. |
| TEST_P(BlitFramebufferANGLETest, BlitColorWithMesaYFlipSrc) |
| { |
| // OpenGL ES 3.0 / GL_NV_framebuffer_blit required for flip. |
| ANGLE_SKIP_TEST_IF( |
| (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_NV_framebuffer_blit")) || |
| !IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| // Blit to default from y-flipped. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| |
| const int fboTargetWidth = getWindowHeight() / 2; |
| const int fboTargetHeight = getWindowHeight() / 2; |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, fboTargetWidth, |
| fboTargetHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, fboTargetHeight / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, fboTargetHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::yellow); |
| } |
| |
| // Blit color to y-flipped with GL_MESA_framebuffer_flip_y framebuffer from normal framebuffer. |
| TEST_P(BlitFramebufferANGLETest, BlitColorWithMesaYFlipDst) |
| { |
| // OpenGL ES 3.0 / GL_NV_framebuffer_blit required for flip. |
| ANGLE_SKIP_TEST_IF( |
| (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_NV_framebuffer_blit")) || |
| !IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| // Blit to default from y-flipped. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| |
| const int fboTargetWidth = getWindowWidth() / 2; |
| const int fboTargetHeight = getWindowHeight(); |
| |
| glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, fboTargetWidth, |
| fboTargetHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), getWindowWidth() / 2, 0, |
| getWindowWidth(), getWindowHeight() / 2, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 0); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| // Left side have inverted checker pattern. |
| EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, fboTargetHeight / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, fboTargetHeight / 4, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::blue); |
| |
| // Right side is split to 2 parts where upper part have non y-flipped checker pattern and the |
| // bottom one has white color. |
| EXPECT_PIXEL_COLOR_EQ(5 * getWindowWidth() / 8, 5 * getWindowHeight() / 8, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(5 * getWindowWidth() / 8, 7 * getWindowHeight() / 8, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(7 * getWindowWidth() / 8, 5 * getWindowHeight() / 8, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(7 * getWindowWidth() / 8, 7 * getWindowHeight() / 8, GLColor::blue); |
| |
| EXPECT_PIXEL_RECT_EQ(4 * getWindowWidth() / 8, 0, getWindowWidth() / 4, getWindowHeight() / 2, |
| GLColor::white); |
| } |
| |
| // Blit color to/from y-flipped with GL_MESA_framebuffer_flip_y framebuffers where dst framebuffer |
| // have different size. |
| TEST_P(BlitFramebufferANGLETest, BlitColorWithMesaYFlipSrcDst) |
| { |
| // OpenGL ES 3.0 / GL_NV_framebuffer_blit required for flip. |
| ANGLE_SKIP_TEST_IF( |
| (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_NV_framebuffer_blit")) || |
| !IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| |
| // Create a custom framebuffer as the default one cannot be flipped. |
| GLTexture tex0; |
| glBindTexture(GL_TEXTURE_2D, tex0); |
| const int fb0Width = getWindowWidth() / 2; |
| const int fb0Height = getWindowHeight() / 2; |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fb0Width, fb0Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| nullptr); |
| |
| GLFramebuffer fb0; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| // Blit to default from y-flipped. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, fb0); |
| |
| glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| glFramebufferParameteriMESA(GL_READ_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| |
| const int fboTargetWidth = fb0Width / 2; |
| const int fboTargetHeight = fb0Height; |
| |
| glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, fboTargetWidth, |
| fboTargetHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), fb0Width / 2, 0, fb0Width, |
| fb0Height / 2, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fb0); |
| |
| glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 0); |
| |
| // Left side have inverted checker pattern. |
| EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, fboTargetHeight / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, fboTargetHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::yellow); |
| |
| // Right side is split to 2 parts where upper part have y-flipped checker pattern and the |
| // bottom one has white color. |
| EXPECT_PIXEL_COLOR_EQ(5 * fb0Width / 8, 5 * fb0Height / 8, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(5 * fb0Width / 8, 7 * fb0Height / 8, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(7 * fb0Width / 8, 5 * fb0Height / 8, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(7 * fb0Width / 8, 7 * fb0Height / 8, GLColor::yellow); |
| |
| EXPECT_PIXEL_RECT_EQ(4 * fb0Width / 8, 0, fb0Width / 4, fb0Height / 2, GLColor::white); |
| } |
| |
| // Same as BlitColorWithMesaYFlip but uses an integer buffer format. |
| TEST_P(BlitFramebufferANGLETest, BlitColorWithMesaYFlipInteger) |
| { |
| // OpenGL ES 3.0 / GL_NV_framebuffer_blit required for flip. |
| ANGLE_SKIP_TEST_IF( |
| (getClientMajorVersion() < 3 || !IsGLExtensionEnabled("GL_NV_framebuffer_blit")) || |
| !IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| |
| GLTexture tex0; |
| glBindTexture(GL_TEXTURE_2D, tex0); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8I, getWindowWidth(), getWindowHeight(), 0, |
| GL_RGBA_INTEGER, GL_BYTE, nullptr); |
| |
| GLFramebuffer fb0; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| GLTexture tex1; |
| glBindTexture(GL_TEXTURE_2D, tex1); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8I, getWindowWidth(), getWindowHeight(), 0, |
| GL_RGBA_INTEGER, GL_BYTE, nullptr); |
| |
| GLFramebuffer fb1; |
| glBindFramebuffer(GL_FRAMEBUFFER, fb1); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex1, 0); |
| |
| // Blit to default from y-flipped. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fb0); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, fb1); |
| |
| const int fb1_target_width = getWindowHeight() / 3; |
| const int fb1_target_height = getWindowHeight() / 3; |
| |
| glClearColor(0.0f, 1.0f, 1.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, fb1_target_width, |
| fb1_target_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fb1); |
| |
| // The colors outside the target must remain the same. |
| EXPECT_PIXEL_8I(getWindowWidth() - 1, getWindowHeight() - 1, 0, 127, 127, 127); |
| EXPECT_PIXEL_8I(getWindowWidth() - 1, 0, 0, 127, 127, 127); |
| EXPECT_PIXEL_8I(0, getWindowHeight() - 1, 0, 127, 127, 127); |
| EXPECT_PIXEL_8I(fb1_target_width, fb1_target_height, 0, 127, 127, 127); |
| |
| // While inside must change. |
| EXPECT_PIXEL_8I(fb1_target_width / 4, fb1_target_height / 4, 127, 0, 0, 127); |
| EXPECT_PIXEL_8I(fb1_target_width / 4, 3 * fb1_target_height / 4, 0, 127, 0, 127); |
| EXPECT_PIXEL_8I(3 * fb1_target_width / 4, fb1_target_height / 4, 0, 0, 127, 127); |
| EXPECT_PIXEL_8I(3 * fb1_target_width / 4, 3 * fb1_target_height / 4, 127, 127, 0, 127); |
| |
| // Blit from y-flipped to default. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fb1); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, fb0); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Set y-flip flag so that y-flipped frame buffer blit to the original fbo in reverse. This |
| // should result in flipping y back. |
| glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| glBlitFramebuffer(0, 0, fb1_target_width, fb1_target_height, 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| // And explicitly disable y-flip so that read does not implicitly use this flag. |
| glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 0); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fb0); |
| |
| EXPECT_PIXEL_8I(getWindowWidth() / 4, getWindowHeight() / 4, 0, 127, 0, 127); |
| EXPECT_PIXEL_8I(getWindowWidth() / 4, 3 * getWindowHeight() / 4, 127, 0, 0, 127); |
| EXPECT_PIXEL_8I(3 * getWindowWidth() / 4, getWindowHeight() / 4, 127, 127, 0, 127); |
| EXPECT_PIXEL_8I(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 0, 127, 127); |
| } |
| |
| // Draw to system framebuffer, blit whole-buffer color to user-created framebuffer. |
| TEST_P(BlitFramebufferANGLETest, ReverseColorBlit) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| // TODO(jmadill): Fix this. http://anglebug.com/42261451 |
| ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid()); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow); |
| } |
| |
| // blit from user-created FBO to system framebuffer, with the scissor test enabled. |
| TEST_P(BlitFramebufferANGLETest, ScissoredBlit) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glClearColor(1.0, 1.0, 1.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glScissor(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight()); |
| glEnable(GL_SCISSOR_TEST); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glDisable(GL_SCISSOR_TEST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow); |
| } |
| |
| // blit from system FBO to user-created framebuffer, with the scissor test enabled. |
| TEST_P(BlitFramebufferANGLETest, ReverseScissoredBlit) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mUserFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| |
| glClearColor(1.0, 1.0, 1.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glScissor(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight()); |
| glEnable(GL_SCISSOR_TEST); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glDisable(GL_SCISSOR_TEST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow); |
| } |
| |
| // blit from user-created FBO to system framebuffer, using region larger than buffer. |
| TEST_P(BlitFramebufferANGLETest, OversizedBlit) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glClearColor(1.0, 1.0, 1.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth() * 2, getWindowHeight() * 2, 0, 0, |
| getWindowWidth() * 2, getWindowHeight() * 2, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow); |
| } |
| |
| // blit from system FBO to user-created framebuffer, using region larger than buffer. |
| TEST_P(BlitFramebufferANGLETest, ReverseOversizedBlit) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mUserFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| |
| glClearColor(1.0, 1.0, 1.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth() * 2, getWindowHeight() * 2, 0, 0, |
| getWindowWidth() * 2, getWindowHeight() * 2, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow); |
| } |
| |
| // blit from user-created FBO to system framebuffer, with depth buffer. |
| TEST_P(BlitFramebufferANGLETest, BlitWithDepthUserToDefault) |
| { |
| // TODO(http://anglebug.com/42264679): glBlitFramebufferANGLE() generates GL_INVALID_OPERATION |
| // for the ES2_OpenGL backend. |
| ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsOpenGL()); |
| |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glDepthMask(GL_TRUE); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glEnable(GL_DEPTH_TEST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| // Clear the first half of the screen |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(0, 0, getWindowWidth(), getWindowHeight() / 2); |
| |
| glClearDepthf(0.1f); |
| glClearColor(1.0, 0.0, 0.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Scissor the second half of the screen |
| glScissor(0, getWindowHeight() / 2, getWindowWidth(), getWindowHeight() / 2); |
| |
| glClearDepthf(0.9f); |
| glClearColor(0.0, 1.0, 0.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| glDisable(GL_SCISSOR_TEST); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| // if blit is happening correctly, this quad will draw only on the bottom half since it will |
| // be behind on the first half and in front on the second half. |
| drawQuad(mBlueProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| glDisable(GL_DEPTH_TEST); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::blue); |
| } |
| |
| // blit from system FBO to user-created framebuffer, with depth buffer. |
| TEST_P(BlitFramebufferANGLETest, BlitWithDepthDefaultToUser) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| glDepthMask(GL_TRUE); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glEnable(GL_DEPTH_TEST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| // Clear the first half of the screen |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(0, 0, getWindowWidth(), getWindowHeight() / 2); |
| |
| glClearDepthf(0.1f); |
| glClearColor(1.0, 0.0, 0.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Scissor the second half of the screen |
| glScissor(0, getWindowHeight() / 2, getWindowWidth(), getWindowHeight() / 2); |
| |
| glClearDepthf(0.9f); |
| glClearColor(0.0, 1.0, 0.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| glDisable(GL_SCISSOR_TEST); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mUserFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| // if blit is happening correctly, this quad will draw only on the bottom half since it will be |
| // behind on the first half and in front on the second half. |
| drawQuad(mBlueProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| glDisable(GL_DEPTH_TEST); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::blue); |
| } |
| |
| // blit from one region of the system fbo to another-- this should fail. |
| TEST_P(BlitFramebufferANGLETest, BlitSameBufferOriginal) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.3f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth() / 2, getWindowHeight(), getWindowWidth() / 2, 0, |
| getWindowWidth(), getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| // blit from one region of the system fbo to another. |
| TEST_P(BlitFramebufferANGLETest, BlitSameBufferUser) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.3f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth() / 2, getWindowHeight(), getWindowWidth() / 2, 0, |
| getWindowWidth(), getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| TEST_P(BlitFramebufferANGLETest, BlitPartialColor) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glClearColor(1.0, 1.0, 1.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth() / 2, getWindowHeight() / 2, 0, |
| getWindowHeight() / 2, getWindowWidth() / 2, getWindowHeight(), |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::white); |
| } |
| |
| TEST_P(BlitFramebufferANGLETest, BlitDifferentSizes) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mSmallFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glClearColor(1.0, 1.0, 1.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mSmallFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Test that blit with missing attachments is ignored. |
| TEST_P(BlitFramebufferANGLETest, BlitWithMissingAttachments) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mColorOnlyFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.3f); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mColorOnlyFBO); |
| |
| glClearColor(1.0, 1.0, 1.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // No error if the read FBO has no depth attachment |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| // No error if the read FBO has no stencil attachment |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| // No error if we read from a missing color attachment. Create a temp attachment as |
| // attachment1, then remove attachment 0. |
| // |
| // The same could be done with glReadBuffer, which requires ES3 (this test runs on ES2). |
| GLTexture tempColor; |
| glBindTexture(GL_TEXTURE_2D, tempColor); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tempColor, 0); |
| glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| TEST_P(BlitFramebufferANGLETest, BlitStencil) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| // http://anglebug.com/40096473 |
| ANGLE_SKIP_TEST_IF(IsIntel() && IsD3D9()); |
| |
| // http://anglebug.com/42263934 |
| ANGLE_SKIP_TEST_IF(IsAMD() && IsD3D9()); |
| |
| BlitStencilTestHelper(false /* mesaFlipY */); |
| } |
| |
| // Same as BlitStencil, but with y-flip flag set. |
| TEST_P(BlitFramebufferANGLETest, BlitStencilWithMesaYFlip) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit") || |
| !IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| |
| // http://anglebug.com/40096473 |
| ANGLE_SKIP_TEST_IF(IsIntel() && IsD3D9()); |
| |
| // http://anglebug.com/42263934 |
| ANGLE_SKIP_TEST_IF(IsAMD() && IsD3D9()); |
| |
| BlitStencilTestHelper(true /* mesaFlipY */); |
| } |
| |
| // make sure that attempting to blit a partial depth buffer issues an error |
| TEST_P(BlitFramebufferANGLETest, BlitPartialDepthStencil) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, |
| getWindowWidth() / 2, getWindowHeight() / 2, GL_DEPTH_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| // Test blit with MRT framebuffers |
| TEST_P(BlitFramebufferANGLETest, BlitMRT) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| if (!IsGLExtensionEnabled("GL_EXT_draw_buffers")) |
| { |
| return; |
| } |
| |
| GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT}; |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mMRTFBO); |
| glDrawBuffersEXT(2, drawBuffers); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mColorOnlyFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mColorOnlyFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mMRTFBO); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mMRTFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, 0, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mMRTColorBuffer0, |
| 0); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mMRTColorBuffer0, |
| 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, |
| mMRTColorBuffer1, 0); |
| } |
| |
| // Test multisampled framebuffer blits if supported |
| TEST_P(BlitFramebufferANGLETest, MultisampledRGBAToRGBA) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| if (!checkExtension("GL_ANGLE_framebuffer_multisample")) |
| return; |
| |
| if (!checkExtension("GL_OES_rgb8_rgba8")) |
| return; |
| |
| multisampleTestHelper(mRGBAMultisampledFBO, mRGBAFBO); |
| } |
| |
| TEST_P(BlitFramebufferANGLETest, MultisampledRGBAToBGRA) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| if (!checkExtension("GL_ANGLE_framebuffer_multisample")) |
| return; |
| |
| if (!checkExtension("GL_OES_rgb8_rgba8")) |
| return; |
| |
| if (!checkExtension("GL_EXT_texture_format_BGRA8888")) |
| return; |
| |
| multisampleTestHelper(mRGBAMultisampledFBO, mBGRAFBO); |
| } |
| |
| TEST_P(BlitFramebufferANGLETest, MultisampledBGRAToRGBA) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| if (!checkExtension("GL_ANGLE_framebuffer_multisample")) |
| return; |
| |
| if (!checkExtension("GL_OES_rgb8_rgba8")) |
| return; |
| |
| if (!checkExtension("GL_EXT_texture_format_BGRA8888")) |
| return; |
| |
| multisampleTestHelper(mBGRAMultisampledFBO, mRGBAFBO); |
| } |
| |
| TEST_P(BlitFramebufferANGLETest, MultisampledBGRAToBGRA) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| if (!checkExtension("GL_ANGLE_framebuffer_multisample")) |
| return; |
| |
| if (!checkExtension("GL_OES_rgb8_rgba8")) |
| return; |
| |
| if (!checkExtension("GL_EXT_texture_format_BGRA8888")) |
| return; |
| |
| multisampleTestHelper(mBGRAMultisampledFBO, mBGRAFBO); |
| } |
| |
| // Make sure that attempts to stretch in a blit call issue an error |
| TEST_P(BlitFramebufferANGLETest, ErrorStretching) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, |
| getWindowWidth(), getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| // Make sure that attempts to flip in a blit call issue an error |
| TEST_P(BlitFramebufferANGLETest, ErrorFlipping) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth() / 2, getWindowHeight() / 2, getWindowWidth() / 2, |
| getWindowHeight() / 2, 0, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| TEST_P(BlitFramebufferANGLETest, Errors) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_LINEAR); |
| EXPECT_GL_ERROR(GL_INVALID_ENUM); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT | 234, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mDiffFormatFBO); |
| |
| glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| // TODO(geofflang): Fix the dependence on glBlitFramebufferANGLE without checks and assuming the |
| // default framebuffer is BGRA to enable the GL and GLES backends. (http://anglebug.com/42260299) |
| |
| class BlitFramebufferTest : public ANGLETest<> |
| { |
| protected: |
| BlitFramebufferTest() |
| { |
| setWindowWidth(256); |
| setWindowHeight(256); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| setConfigDepthBits(24); |
| setConfigStencilBits(8); |
| } |
| |
| void initColorFBO(GLFramebuffer *fbo, |
| GLRenderbuffer *rbo, |
| GLenum rboFormat, |
| GLsizei width, |
| GLsizei height) |
| { |
| glBindRenderbuffer(GL_RENDERBUFFER, *rbo); |
| glRenderbufferStorage(GL_RENDERBUFFER, rboFormat, width, height); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, *fbo); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *rbo); |
| } |
| |
| void initColorFBOWithCheckerPattern(GLFramebuffer *fbo, |
| GLRenderbuffer *rbo, |
| GLenum rboFormat, |
| GLsizei width, |
| GLsizei height) |
| { |
| initColorFBO(fbo, rbo, rboFormat, width, height); |
| |
| ANGLE_GL_PROGRAM(checkerProgram, essl1_shaders::vs::Passthrough(), |
| essl1_shaders::fs::Checkered()); |
| glViewport(0, 0, width, height); |
| glBindFramebuffer(GL_FRAMEBUFFER, *fbo); |
| drawQuad(checkerProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| } |
| |
| void BlitDepthStencilPixelByPixelTestHelper(bool mesaYFlip) |
| { |
| if (mesaYFlip) |
| ASSERT_TRUE(IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| |
| glViewport(0, 0, 128, 1); |
| glEnable(GL_DEPTH_TEST); |
| |
| GLFramebuffer srcFramebuffer; |
| GLRenderbuffer srcRenderbuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer); |
| if (mesaYFlip) |
| glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| glBindRenderbuffer(GL_RENDERBUFFER, srcRenderbuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 128, 1); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| srcRenderbuffer); |
| glClearDepthf(1.0f); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| |
| drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f, 0.5f); |
| glViewport(0, 0, 256, 2); |
| |
| GLFramebuffer dstFramebuffer; |
| GLRenderbuffer dstRenderbuffer; |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer); |
| glBindRenderbuffer(GL_RENDERBUFFER, dstRenderbuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 256, 2); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| dstRenderbuffer); |
| |
| GLTexture dstColor; |
| glBindTexture(GL_TEXTURE_2D, dstColor); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 2); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstColor, 0); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer); |
| glBlitFramebuffer(0, 0, 128, 1, 0, 0, 256, 2, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, |
| GL_NEAREST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glDepthMask(false); |
| glDepthFunc(GL_LESS); |
| drawQuad(drawRed, essl1_shaders::PositionAttrib(), -0.01f, 0.5f); |
| EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::red); |
| |
| ANGLE_GL_PROGRAM(drawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthMask(false); |
| glDepthFunc(GL_GREATER); |
| if (mesaYFlip) |
| glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| drawQuad(drawBlue, essl1_shaders::PositionAttrib(), 0.01f, 0.5f); |
| if (mesaYFlip) |
| EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::green); |
| else |
| EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::blue); |
| } |
| |
| // Test blitting between 3D textures and 2D array textures |
| void test3DBlit(GLenum sourceTarget, GLenum destTarget) |
| { |
| |
| constexpr int kTexWidth = 4; |
| constexpr int kTexHeight = 3; |
| constexpr int kTexDepth = 2; |
| glViewport(0, 0, kTexWidth, kTexHeight); |
| |
| size_t size = kTexWidth * kTexHeight * kTexDepth; |
| std::vector<uint32_t> sourceData(size); |
| std::vector<uint32_t> destData(size); |
| for (size_t i = 0; i < size; ++i) |
| { |
| sourceData[i] = i; |
| destData[i] = size - i; |
| } |
| |
| // Create a source 3D texture and FBO. |
| GLTexture sourceTexture; |
| glBindTexture(sourceTarget, sourceTexture); |
| glTexImage3D(sourceTarget, 0, GL_RGBA8, kTexWidth, kTexHeight, kTexDepth, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, sourceData.data()); |
| |
| // Create a dest texture and FBO. |
| GLTexture destTexture; |
| glBindTexture(destTarget, destTexture); |
| glTexImage3D(destTarget, 0, GL_RGBA8, kTexWidth, kTexHeight, kTexDepth, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, destData.data()); |
| |
| for (int z = 0; z < kTexDepth; ++z) |
| { |
| ASSERT_GL_NO_ERROR(); |
| GLFramebuffer sourceFBO; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO); |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, sourceTexture, 0, |
| z); |
| ASSERT_GL_NO_ERROR(); |
| |
| GLFramebuffer destFBO; |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destFBO); |
| glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, destTexture, 0, z); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBlitFramebuffer(0, 0, kTexWidth, kTexHeight, 0, 0, kTexWidth, kTexHeight, |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| for (int z = 0; z < kTexDepth; ++z) |
| { |
| GLFramebuffer readFBO; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO); |
| glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, destTexture, 0, z); |
| ASSERT_GL_NO_ERROR(); |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| for (int y = 0; y < kTexHeight; ++y) |
| { |
| for (int x = 0; x < kTexWidth; ++x) |
| { |
| int index = x + kTexWidth * (y + z * kTexHeight); |
| EXPECT_PIXEL_COLOR_EQ(x, y, index); |
| } |
| } |
| } |
| } |
| |
| void initFBOWithProgramAndDepth(GLFramebuffer *fbo, |
| GLRenderbuffer *colorRenderBuffer, |
| GLenum colorFormat, |
| GLRenderbuffer *depthRenderBuffer, |
| GLenum depthFormat, |
| GLsizei width, |
| GLsizei height, |
| GLuint program, |
| float depthValue) |
| { |
| if (fbo != nullptr) |
| { |
| // Create renderbuffer |
| glBindRenderbuffer(GL_RENDERBUFFER, *colorRenderBuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, width, height); |
| glBindRenderbuffer(GL_RENDERBUFFER, *depthRenderBuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, depthFormat, width, height); |
| |
| // Create fbo |
| glBindFramebuffer(GL_FRAMEBUFFER, *fbo); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| *colorRenderBuffer); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| *depthRenderBuffer); |
| } |
| else |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| } |
| |
| // draw with program |
| glUseProgram(program); |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glClearDepthf(1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| glEnable(GL_DEPTH_TEST); |
| glDepthMask(true); |
| drawQuad(program, essl1_shaders::PositionAttrib(), depthValue); |
| } |
| |
| void drawWithDepthValue(std::array<Vector3, 6> &quadVertices, float depth) |
| { |
| for (Vector3 &vertice : quadVertices) |
| { |
| vertice[2] = depth; |
| } |
| glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(quadVertices[0]) * quadVertices.size(), |
| quadVertices.data()); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| } |
| |
| void BlitSampleStencilToDefault(GLsizei samples) |
| { |
| GLsizei w = 3, h = 2; |
| GLint stencilValue = 1; |
| glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| GLRenderbuffer colorbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, colorbuf); |
| if (samples != 0) |
| { |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, w, h); |
| } |
| else |
| { |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, w, h); |
| } |
| |
| GLRenderbuffer depthstencilbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, depthstencilbuf); |
| if (samples != 0) |
| { |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, w, h); |
| } |
| else |
| { |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h); |
| } |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| depthstencilbuf); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthstencilbuf); |
| glCheckFramebufferStatus(GL_FRAMEBUFFER); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| glFlush(); |
| |
| // Clear the stencil of each pixel to a different value. |
| glEnable(GL_STENCIL_TEST); |
| glEnable(GL_SCISSOR_TEST); |
| glViewport(0, 0, w, h); |
| for (GLsizei y = 0; y < h; y++) |
| { |
| for (GLsizei x = 0; x < w; x++) |
| { |
| glScissor(x, y, 1, 1); |
| glClearStencil(stencilValue); |
| glClear(GL_STENCIL_BUFFER_BIT); |
| stencilValue += 1; |
| } |
| } |
| glDisable(GL_SCISSOR_TEST); |
| |
| // Blit stencil buffer to default framebuffer. |
| GLenum attachments1[] = {GL_COLOR_ATTACHMENT0}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments1); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, |
| GL_NEAREST); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| |
| // Disable stencil and draw full_screen green color. |
| ANGLE_GL_PROGRAM(drawGreen, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green()); |
| glDisable(GL_STENCIL_TEST); |
| drawQuad(drawGreen, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| // Get the stencil through drawQuad. |
| // If the blit finished successfully, the stencil test should all pass. |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| glUseProgram(drawColor); |
| glEnable(GL_STENCIL_TEST); |
| for (GLsizei i = 1; i <= 6; i++) |
| { |
| glStencilFunc(GL_EQUAL, i, 255); |
| glUniform4f(colorUniformLocation, i * 1.0f / 255, 0.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 1.0f); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Check the result. |
| std::vector<GLColor> pixels(w * h); |
| GLuint color_ref = 1; |
| glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); |
| for (GLsizei y = 0; y < h; y++) |
| { |
| for (GLsizei x = 0; x < w; x++) |
| { |
| const int curPos = y * w + x; |
| EXPECT_COLOR_NEAR(GLColor(color_ref, 0, 0, 255), pixels[curPos], 1); |
| color_ref += 1; |
| } |
| } |
| } |
| }; |
| |
| class BlitFramebufferTestES31 : public BlitFramebufferTest |
| {}; |
| |
| // Tests resolving a multisample depth buffer. |
| TEST_P(BlitFramebufferTest, MultisampleDepth) |
| { |
| // TODO([email protected]): http://crbug.com/837717 |
| ANGLE_SKIP_TEST_IF(IsOpenGL() && IsMac()); |
| |
| GLRenderbuffer renderbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuf); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 2, GL_DEPTH_COMPONENT24, 256, 256); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuf); |
| |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| |
| glClearDepthf(0.5f); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| |
| GLRenderbuffer destRenderbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, destRenderbuf); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 256, 256); |
| |
| GLFramebuffer resolved; |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolved); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| destRenderbuf); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); |
| glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_DEPTH_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, resolved); |
| |
| // Immediately destroy the framebuffer and the associated textures for additional cleanup |
| // ordering testing. |
| framebuffer.reset(); |
| renderbuf.reset(); |
| |
| GLTexture colorbuf; |
| glBindTexture(GL_TEXTURE_2D, colorbuf); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuf, 0); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear to green |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Make sure resulting depth is near 0.5f. |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthMask(false); |
| glDepthFunc(GL_LESS); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), -0.01f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(255, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(0, 255, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(255, 255, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(127, 127, GLColor::red); |
| |
| ANGLE_GL_PROGRAM(drawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthMask(false); |
| glDepthFunc(GL_GREATER); |
| drawQuad(drawBlue, essl3_shaders::PositionAttrib(), 0.01f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(255, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(0, 255, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(255, 255, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(127, 127, GLColor::blue); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Blit stencil buffer to default framebuffer with prerotaion. |
| TEST_P(BlitFramebufferTest, BlitStencilToDefault) |
| { |
| BlitSampleStencilToDefault(0); |
| } |
| |
| // Blit multisample stencil buffer to default framebuffer with prerotaion. |
| TEST_P(BlitFramebufferTest, BlitMultisampleStencilToDefault) |
| { |
| BlitSampleStencilToDefault(4); |
| } |
| |
| // Test blit multisampled framebuffer to MRT framebuffer |
| TEST_P(BlitFramebufferTest, BlitMultisampledFramebufferToMRT) |
| { |
| // https://issues.angleproject.org/issues/361369302 |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Prepare multisampled framebuffer to blit from. |
| GLRenderbuffer multiSampleColorbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, multiSampleColorbuf); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, getWindowWidth(), |
| getWindowHeight()); |
| |
| GLFramebuffer multiSampleFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, multiSampleFramebuffer); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| multiSampleColorbuf); |
| glCheckFramebufferStatus(GL_FRAMEBUFFER); |
| |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.8f); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Prepare mrt framebuffer with two attachments to blit to. |
| GLFramebuffer MRTFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, MRTFBO); |
| GLTexture MRTColorBuffer0; |
| GLTexture MRTColorBuffer1; |
| glBindTexture(GL_TEXTURE_2D, MRTColorBuffer0); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, MRTColorBuffer0, 0); |
| glBindTexture(GL_TEXTURE_2D, MRTColorBuffer1); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, MRTColorBuffer1, 0); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, multiSampleFramebuffer); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, MRTFBO); |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; |
| glDrawBuffers(2, drawBuffers); |
| |
| glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(), |
| getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Check results |
| glBindFramebuffer(GL_FRAMEBUFFER, MRTFBO); |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::red); |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT1); |
| EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::red); |
| } |
| |
| // Tests clearing a multisampled depth buffer. |
| TEST_P(BlitFramebufferTest, MultisampleDepthClear) |
| { |
| // http://anglebug.com/40096654 |
| ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES()); |
| |
| GLRenderbuffer depthMS; |
| glBindRenderbuffer(GL_RENDERBUFFER, depthMS); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 2, GL_DEPTH_COMPONENT24, 256, 256); |
| |
| GLRenderbuffer colorMS; |
| glBindRenderbuffer(GL_RENDERBUFFER, colorMS); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 2, GL_RGBA8, 256, 256); |
| |
| GLRenderbuffer colorResolved; |
| glBindRenderbuffer(GL_RENDERBUFFER, colorResolved); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 256, 256); |
| |
| GLFramebuffer framebufferMS; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebufferMS); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthMS); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorMS); |
| |
| // Clear depth buffer to 0.5 and color to green. |
| glClearDepthf(0.5f); |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); |
| |
| glFlush(); |
| |
| // Draw red into the multisampled color buffer. |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_EQUAL); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.0f); |
| |
| // Resolve the color buffer to make sure the above draw worked correctly, which in turn implies |
| // that the multisampled depth clear worked. |
| GLFramebuffer framebufferResolved; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebufferResolved); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorResolved); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferMS); |
| glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, framebufferResolved); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(255, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(0, 255, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(255, 255, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(127, 127, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Tests clearing a multisampled depth buffer with a glFenceSync in between. |
| TEST_P(BlitFramebufferTest, MultisampleDepthClearWithFenceSync) |
| { |
| // http://anglebug.com/40096654 |
| ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES()); |
| |
| GLRenderbuffer depthMS; |
| glBindRenderbuffer(GL_RENDERBUFFER, depthMS); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 2, GL_DEPTH_COMPONENT24, 256, 256); |
| |
| GLRenderbuffer colorMS; |
| glBindRenderbuffer(GL_RENDERBUFFER, colorMS); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 2, GL_RGBA8, 256, 256); |
| |
| GLRenderbuffer colorResolved; |
| glBindRenderbuffer(GL_RENDERBUFFER, colorResolved); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 256, 256); |
| |
| GLFramebuffer framebufferMS; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebufferMS); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthMS); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorMS); |
| |
| // Clear depth buffer to 0.5 and color to green. |
| glClearDepthf(0.5f); |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); |
| |
| glFlush(); |
| |
| // Draw red into the multisampled color buffer. |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_EQUAL); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.0f); |
| |
| // This should trigger a deferred renderPass end |
| GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Resolve the color buffer to make sure the above draw worked correctly, which in turn implies |
| // that the multisampled depth clear worked. |
| GLFramebuffer framebufferResolved; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebufferResolved); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorResolved); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferMS); |
| glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, framebufferResolved); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(255, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(0, 255, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(255, 255, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(127, 127, GLColor::red); |
| |
| glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test resolving a multisampled stencil buffer. |
| TEST_P(BlitFramebufferTest, MultisampleStencil) |
| { |
| GLRenderbuffer renderbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuf); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 2, GL_STENCIL_INDEX8, 256, 256); |
| |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuf); |
| |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| |
| // fill the stencil buffer with 0x1 |
| glStencilFunc(GL_ALWAYS, 0x1, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glEnable(GL_STENCIL_TEST); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| GLTexture destColorbuf; |
| glBindTexture(GL_TEXTURE_2D, destColorbuf); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256); |
| |
| GLRenderbuffer destRenderbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, destRenderbuf); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, 256, 256); |
| |
| GLFramebuffer resolved; |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolved); |
| glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destColorbuf, |
| 0); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| destRenderbuf); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); |
| glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| // Immediately destroy the framebuffer and the associated textures for additional cleanup |
| // ordering testing. |
| framebuffer.reset(); |
| renderbuf.reset(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, resolved); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear to green |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Draw red if the stencil is 0x1, which should be true after the resolve. |
| glStencilFunc(GL_EQUAL, 0x1, 0xFF); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test resolving a multisampled stencil buffer with scissor. |
| TEST_P(BlitFramebufferTest, ScissoredMultisampleStencil) |
| { |
| constexpr GLuint kSize = 256; |
| |
| // Create the resolve framebuffer. |
| GLTexture destColorbuf; |
| glBindTexture(GL_TEXTURE_2D, destColorbuf); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize); |
| |
| GLRenderbuffer destRenderbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, destRenderbuf); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, kSize, kSize); |
| |
| GLFramebuffer resolved; |
| glBindFramebuffer(GL_FRAMEBUFFER, resolved); |
| glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destColorbuf, |
| 0); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| destRenderbuf); |
| |
| // Clear the resolved buffer with gray and 0x10 stencil. |
| GLColor gray(127, 127, 127, 255); |
| glClearStencil(0x10); |
| glClearColor(0.499f, 0.499f, 0.499f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, gray); |
| |
| // Create the multisampled framebuffer. |
| GLRenderbuffer renderbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuf); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 2, GL_STENCIL_INDEX8, kSize, kSize); |
| |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| ANGLE_GL_PROGRAM(drawGreen, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green()); |
| ANGLE_GL_PROGRAM(drawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue()); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuf); |
| |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| |
| // Fill the stencil buffer with 0x1. |
| glClearStencil(0x1); |
| glClear(GL_STENCIL_BUFFER_BIT); |
| |
| // Fill a smaller region of the buffer with 0x2. |
| glEnable(GL_SCISSOR_TEST); |
| glEnable(GL_STENCIL_TEST); |
| glScissor(kSize / 4, kSize / 4, kSize / 2, kSize / 2); |
| glStencilFunc(GL_ALWAYS, 0x2, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| // Blit into the resolved framebuffer (with scissor still enabled). |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolved); |
| glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, resolved); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw blue if the stencil is 0x1, which should never be true. |
| glDisable(GL_SCISSOR_TEST); |
| glStencilMask(0); |
| glStencilFunc(GL_EQUAL, 0x1, 0xFF); |
| drawQuad(drawBlue, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, gray); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, gray); |
| |
| // Draw red if the stencil is 0x2, which should be true in the middle after the blit/resolve. |
| glStencilFunc(GL_EQUAL, 0x2, 0xFF); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, gray); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::red); |
| |
| // Draw green if the stencil is 0x10, which should be left untouched in the outer regions. |
| glStencilFunc(GL_EQUAL, 0x10, 0xFF); |
| drawQuad(drawGreen, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test blitting from a texture with non-zero base. The blit is non-stretching and between |
| // identical formats so that the path that uses vkCmdBlitImage is taken. |
| TEST_P(BlitFramebufferTest, NonZeroBaseSource) |
| { |
| // http://anglebug.com/40644751 |
| ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsMac()); |
| |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| |
| // Create a framebuffer for source data. It usea a non-zero base. |
| GLTexture srcColor; |
| glBindTexture(GL_TEXTURE_2D, srcColor); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| |
| GLFramebuffer srcFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcColor, 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // fill the color buffer with red. |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| // Create a framebuffer for blit destination. |
| GLTexture dstColor; |
| glBindTexture(GL_TEXTURE_2D, dstColor); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer dstFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstColor, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Blit. Note: no stretching is done so that vkCmdBlitImage can be used. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer); |
| glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Make sure the blit is done. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test blitting to a texture with non-zero base. The blit is non-stretching and between |
| // identical formats so that the path that uses vkCmdBlitImage is taken. |
| TEST_P(BlitFramebufferTest, NonZeroBaseDestination) |
| { |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| |
| // Create a framebuffer for source data. It usea a non-zero base. |
| GLTexture srcColor; |
| glBindTexture(GL_TEXTURE_2D, srcColor); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer srcFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcColor, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // fill the color buffer with red. |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| // Create a framebuffer for blit destination. |
| GLTexture dstColor; |
| glBindTexture(GL_TEXTURE_2D, dstColor); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| |
| GLFramebuffer dstFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstColor, 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Blit. Note: no stretching is done so that vkCmdBlitImage can be used. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer); |
| glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Make sure the blit is done. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test blitting from a stencil buffer with non-zero base. |
| TEST_P(BlitFramebufferTest, NonZeroBaseSourceStencil) |
| { |
| // http://anglebug.com/40644751 |
| ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsMac()); |
| |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| |
| // Create a framebuffer with an attachment that has non-zero base |
| GLTexture stencilTexture; |
| glBindTexture(GL_TEXTURE_2D, stencilTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 256, 256, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8, nullptr); |
| glTexImage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, 256, 256, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| |
| GLFramebuffer srcFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTexture, 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // fill the stencil buffer with 0x1 |
| glStencilFunc(GL_ALWAYS, 0x1, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glEnable(GL_STENCIL_TEST); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| // Create a framebuffer with an attachment that has non-zero base |
| GLTexture colorTexture; |
| glBindTexture(GL_TEXTURE_2D, colorTexture); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256); |
| |
| GLRenderbuffer renderbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuf); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 256, 256); |
| |
| GLFramebuffer dstFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuf); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Blit stencil. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer); |
| glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear to green |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Draw red if the stencil is 0x1, which should be true after the blit. |
| glStencilFunc(GL_EQUAL, 0x1, 0xFF); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test blitting to a stencil buffer with non-zero base. |
| TEST_P(BlitFramebufferTest, NonZeroBaseDestinationStencil) |
| { |
| // http://anglebug.com/40644751 |
| ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsMac()); |
| |
| // http://anglebug.com/42263576 |
| ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows()); |
| |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| |
| // Create a framebuffer for source data. |
| GLRenderbuffer renderbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuf); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 256, 256); |
| |
| GLFramebuffer srcFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuf); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // fill the stencil buffer with 0x1 |
| glStencilFunc(GL_ALWAYS, 0x1, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glEnable(GL_STENCIL_TEST); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| // Create a framebuffer with an attachment that has non-zero base |
| GLTexture colorTexture; |
| glBindTexture(GL_TEXTURE_2D, colorTexture); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256); |
| |
| GLTexture stencilTexture; |
| glBindTexture(GL_TEXTURE_2D, stencilTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 256, 256, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8, nullptr); |
| glTexImage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, 256, 256, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| |
| GLFramebuffer dstFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTexture, 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Blit stencil. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer); |
| glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear to green |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Draw red if the stencil is 0x1, which should be true after the blit. |
| glStencilFunc(GL_EQUAL, 0x1, 0xFF); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test blitting to a stencil buffer with non-zero base. Exercises the compute path in the Vulkan |
| // backend if stencil export is not supported. The blit is not 1-to-1 for this path to be taken. |
| TEST_P(BlitFramebufferTest, NonZeroBaseDestinationStencilStretch) |
| { |
| // http://anglebug.com/40644750 |
| ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows()); |
| |
| // http://anglebug.com/40644751 |
| ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsMac()); |
| |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| |
| // Create a framebuffer for source data. |
| GLRenderbuffer renderbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuf); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 256, 256); |
| |
| GLFramebuffer srcFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuf); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // fill the stencil buffer with 0x1 |
| glStencilFunc(GL_ALWAYS, 0x1, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glEnable(GL_STENCIL_TEST); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| // Create a framebuffer with an attachment that has non-zero base |
| GLTexture colorTexture; |
| glBindTexture(GL_TEXTURE_2D, colorTexture); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256); |
| |
| GLTexture stencilTexture; |
| glBindTexture(GL_TEXTURE_2D, stencilTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 256, 256, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8, nullptr); |
| glTexImage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, 256, 256, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| |
| GLFramebuffer dstFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTexture, 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Blit stencil. Note: stretch is intentional so vkCmdBlitImage cannot be used in the Vulkan |
| // backend. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer); |
| glBlitFramebuffer(0, 0, 256, 256, -256, -256, 512, 512, GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear to green |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Draw red if the stencil is 0x1, which should be true after the blit. |
| glStencilFunc(GL_EQUAL, 0x1, 0xFF); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Blit an SRGB framebuffer and scale it. |
| TEST_P(BlitFramebufferTest, BlitSRGBToRGBAndScale) |
| { |
| constexpr const GLsizei kWidth = 256; |
| constexpr const GLsizei kHeight = 256; |
| |
| GLRenderbuffer sourceRBO, targetRBO; |
| GLFramebuffer sourceFBO, targetFBO; |
| initColorFBOWithCheckerPattern(&sourceFBO, &sourceRBO, GL_SRGB8_ALPHA8, kWidth * 2, |
| kHeight * 2); |
| initColorFBO(&targetFBO, &targetRBO, GL_RGBA8, kWidth, kHeight); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO); |
| |
| glViewport(0, 0, kWidth, kHeight); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Scale down without flipping. |
| glBlitFramebuffer(0, 0, kWidth * 2, kHeight * 2, 0, 0, kWidth, kHeight, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, targetFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, kHeight / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, kHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, 3 * kHeight / 4, GLColor::yellow); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Scale down and flip in the X direction. |
| glBlitFramebuffer(0, 0, kWidth * 2, kHeight * 2, kWidth, 0, 0, kHeight, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, targetFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, kHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, kHeight / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, 3 * kHeight / 4, GLColor::green); |
| } |
| |
| // Blit stencil, with scissor and scale it. |
| TEST_P(BlitFramebufferTest, BlitStencilScissoredScaled) |
| { |
| constexpr GLint kSize = 256; |
| |
| // Create the destination framebuffer. |
| GLTexture destColorbuf; |
| glBindTexture(GL_TEXTURE_2D, destColorbuf); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize); |
| |
| GLRenderbuffer destRenderbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, destRenderbuf); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, kSize, kSize); |
| |
| GLFramebuffer destFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, destFBO); |
| glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destColorbuf, |
| 0); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| destRenderbuf); |
| |
| // Clear the destination buffer with gray and 0x10 stencil. |
| GLColor gray(127, 127, 127, 255); |
| glClearStencil(0x10); |
| glClearColor(0.499f, 0.499f, 0.499f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, gray); |
| |
| // Create the source framebuffer. |
| GLRenderbuffer renderbuf; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuf); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, kSize, kSize); |
| |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| ANGLE_GL_PROGRAM(drawGreen, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green()); |
| ANGLE_GL_PROGRAM(drawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue()); |
| |
| GLFramebuffer sourceFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, sourceFBO); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuf); |
| |
| ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| |
| // Fill the stencil buffer with 0x1. |
| glClearStencil(0x1); |
| glClear(GL_STENCIL_BUFFER_BIT); |
| |
| // Fill a smaller region of the buffer with 0x2. |
| glEnable(GL_SCISSOR_TEST); |
| glEnable(GL_STENCIL_TEST); |
| glScissor(kSize / 4, kSize / 4, kSize / 2, kSize / 2); |
| glStencilFunc(GL_ALWAYS, 0x2, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| // Blit and scale down into the destination framebuffer (with scissor still enabled). |
| // |
| // Source looks like this: |
| // |
| // +----|----|----|----+ |
| // | | |
| // | 0x1 | |
| // - +---------+ - |
| // | | | | |
| // | | | | |
| // - | 0x2 | - |
| // | | | | |
| // | | | | |
| // - +---------+ - |
| // | | |
| // | | |
| // +----|----|----|----+ |
| // |
| // We want the destination to look like this: |
| // |
| // +----|----|----|----+ |
| // | | |
| // | 0x10 | |
| // - +---------+ - |
| // | | 0x1 | | |
| // | | +------+ | |
| // - | | | - |
| // | | | 0x2 | | |
| // | | | | | |
| // - +--+------+ - |
| // | | |
| // | | |
| // +----|----|----|----+ |
| // |
| // The corresponding blit would be: (0, 0, 3/4, 3/4) -> (1/4, 1/4, 3/4, 3/4). For testing, we |
| // would like to avoid having the destination area and scissor to match. Using destination |
| // area as (0, 0, 1, 1), and keeping the same scaling, the source area should be |
| // (-3/8, -3/8, 9/8, 9/8). |
| // |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destFBO); |
| constexpr GLint kBlitSrc[2] = {-3 * kSize / 8, 9 * kSize / 8}; |
| glBlitFramebuffer(kBlitSrc[0], kBlitSrc[0], kBlitSrc[1], kBlitSrc[1], 0, 0, kSize, kSize, |
| GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, destFBO); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw blue if the stencil is 0x1, which should be true only in the top and left of the inner |
| // square. |
| glDisable(GL_SCISSOR_TEST); |
| glStencilMask(0); |
| glStencilFunc(GL_EQUAL, 0x1, 0xFF); |
| drawQuad(drawBlue, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, gray); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, gray); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 4, kSize / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 4, 3 * kSize / 4 - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, kSize / 4, GLColor::blue); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, gray); |
| EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, 3 * kSize / 4 - 1, gray); |
| |
| // Draw red if the stencil is 0x2, which should be true in the bottom/right of the middle |
| // square after the blit. |
| glStencilFunc(GL_EQUAL, 0x2, 0xFF); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, gray); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, gray); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, gray); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 4, kSize / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 4, 3 * kSize / 4 - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, kSize / 4, GLColor::blue); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, 3 * kSize / 4 - 1, GLColor::red); |
| |
| // Draw green if the stencil is 0x10, which should be left untouched in the outer regions. |
| glStencilFunc(GL_EQUAL, 0x10, 0xFF); |
| drawQuad(drawGreen, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::green); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 4, kSize / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 4, 3 * kSize / 4 - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, kSize / 4, GLColor::blue); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, 3 * kSize / 4 - 1, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Blit a subregion of an SRGB framebuffer to an RGB framebuffer. |
| TEST_P(BlitFramebufferTest, PartialBlitSRGBToRGB) |
| { |
| constexpr const GLsizei kWidth = 256; |
| constexpr const GLsizei kHeight = 256; |
| |
| GLRenderbuffer sourceRBO, targetRBO; |
| GLFramebuffer sourceFBO, targetFBO; |
| initColorFBOWithCheckerPattern(&sourceFBO, &sourceRBO, GL_SRGB8_ALPHA8, kWidth * 2, |
| kHeight * 2); |
| initColorFBO(&targetFBO, &targetRBO, GL_RGBA8, kWidth, kHeight); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO); |
| |
| glViewport(0, 0, kWidth, kHeight); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Blit a part of the source FBO without flipping. |
| glBlitFramebuffer(kWidth, kHeight, kWidth * 2, kHeight * 2, 0, 0, kWidth, kHeight, |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, targetFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, kHeight / 4, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, kHeight / 4, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, 3 * kHeight / 4, GLColor::yellow); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Blit a part of the source FBO and flip in the X direction. |
| glBlitFramebuffer(kWidth * 2, 0, kWidth, kHeight, kWidth, 0, 0, kHeight, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, targetFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, kHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, kHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, 3 * kHeight / 4, GLColor::blue); |
| } |
| |
| // Blit an SRGB framebuffer with an oversized source area (parts outside the source area should be |
| // clipped out). |
| TEST_P(BlitFramebufferTest, BlitSRGBToRGBOversizedSourceArea) |
| { |
| constexpr const GLsizei kWidth = 256; |
| constexpr const GLsizei kHeight = 256; |
| |
| GLRenderbuffer sourceRBO, targetRBO; |
| GLFramebuffer sourceFBO, targetFBO; |
| initColorFBOWithCheckerPattern(&sourceFBO, &sourceRBO, GL_SRGB8_ALPHA8, kWidth, kHeight); |
| initColorFBO(&targetFBO, &targetRBO, GL_RGBA8, kWidth, kHeight); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glViewport(0, 0, kWidth, kHeight); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO); |
| |
| glClearColor(0.0f, 0.0f, 1.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Blit so that the source area gets placed at the center of the target FBO. |
| // The width of the source area is 1/4 of the width of the target FBO. |
| glBlitFramebuffer(-3 * kWidth / 2, -3 * kHeight / 2, 5 * kWidth / 2, 5 * kHeight / 2, 0, 0, |
| kWidth, kHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, targetFBO); |
| |
| // Source FBO colors can be found in the middle of the target FBO. |
| EXPECT_PIXEL_COLOR_EQ(7 * kWidth / 16, 7 * kHeight / 16, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(7 * kWidth / 16, 9 * kHeight / 16, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(9 * kWidth / 16, 7 * kHeight / 16, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(9 * kWidth / 16, 9 * kHeight / 16, GLColor::yellow); |
| |
| // Clear color should remain around the edges of the target FBO (WebGL 2.0 spec explicitly |
| // requires this and ANGLE is expected to follow that). |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, kHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, kHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, 3 * kHeight / 4, GLColor::blue); |
| } |
| |
| // Blit an SRGB framebuffer with an oversized dest area (even though the result is clipped, it |
| // should be scaled as if the whole dest area was used). |
| TEST_P(BlitFramebufferTest, BlitSRGBToRGBOversizedDestArea) |
| { |
| constexpr const GLsizei kWidth = 256; |
| constexpr const GLsizei kHeight = 256; |
| |
| GLRenderbuffer sourceRBO, targetRBO; |
| GLFramebuffer sourceFBO, targetFBO; |
| initColorFBOWithCheckerPattern(&sourceFBO, &sourceRBO, GL_SRGB8_ALPHA8, kWidth, kHeight); |
| initColorFBO(&targetFBO, &targetRBO, GL_RGBA8, kWidth, kHeight); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glViewport(0, 0, kWidth, kHeight); |
| |
| glClearColor(0.0f, 0.0f, 1.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Dest is oversized but centered the same as source |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO); |
| |
| glBlitFramebuffer(0, 0, kWidth, kHeight, -kWidth / 2, -kHeight / 2, 3 * kWidth / 2, |
| 3 * kHeight / 2, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, targetFBO); |
| |
| // Expected result: |
| // |
| // +-------+-------+ |
| // | | | |
| // | R | B | |
| // | | | |
| // +-------+-------+ |
| // | | | |
| // | G | Y | |
| // | | | |
| // +-------+-------+ |
| // |
| EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, kHeight / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 2 - 1, kHeight / 2 - 1, GLColor::red); |
| |
| EXPECT_PIXEL_COLOR_EQ(1, kWidth - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 2 - 1, kHeight / 2 + 1, GLColor::green); |
| |
| EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, kHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 2 + 1, kHeight / 2 - 1, GLColor::blue); |
| |
| EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, 3 * kHeight / 4, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 2 + 1, kHeight / 2 + 1, GLColor::yellow); |
| |
| // Dest is oversized in the negative direction |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO); |
| |
| glBlitFramebuffer(0, 0, kWidth, kHeight, -kWidth / 2, -kHeight / 2, kWidth, kHeight, |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, targetFBO); |
| |
| // Expected result: |
| // |
| // Width / 4 |
| // | |
| // V |
| // +---+-----------+ |
| // | R | B | |
| // +---+-----------+ <- Height / 4 |
| // | | | |
| // | | | |
| // | G | Y | |
| // | | | |
| // | | | |
| // +---+-----------+ |
| // |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(0, kHeight / 4 - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4 - 1, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4 - 1, kHeight / 4 - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 8, kHeight / 8, GLColor::red); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, kHeight / 4 + 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4 - 1, kHeight / 4 + 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4 - 1, kHeight - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 8, kHeight / 2, GLColor::green); |
| |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4 + 1, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4 + 1, kHeight / 4 - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight / 4 - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 8, GLColor::blue); |
| |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4 + 1, kHeight / 4 + 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4 + 1, kHeight - 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight / 4 + 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::yellow); |
| |
| // Dest is oversized in the positive direction |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO); |
| |
| glBlitFramebuffer(0, 0, kWidth, kHeight, 0, 0, 3 * kWidth / 2, 3 * kHeight / 2, |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, targetFBO); |
| |
| // Expected result: |
| // |
| // 3 * Width / 4 |
| // | |
| // V |
| // +-----------+---+ |
| // | | | |
| // | | | |
| // | R | B | |
| // | | | |
| // | | | |
| // +-----------+---+ <- 3 * Height / 4 |
| // | G | Y | |
| // +-----------+---+ |
| // |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(0, 3 * kHeight / 4 - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4 - 1, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4 - 1, 3 * kHeight / 4 - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::red); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 3 * kHeight / 4 + 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4 - 1, 3 * kHeight / 4 + 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4 - 1, kHeight - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 2, 7 * kHeight / 8, GLColor::green); |
| |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4 + 1, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4 + 1, 3 * kHeight / 4 - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 3 * kHeight / 4 - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(7 * kWidth / 8, kHeight / 2, GLColor::blue); |
| |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4 + 1, 3 * kHeight / 4 + 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4 + 1, kHeight - 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 3 * kHeight / 4 + 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(7 * kWidth / 8, 7 * kHeight / 8, GLColor::yellow); |
| } |
| |
| // This test is to demonstrate a bug that when a program is created and used and then destroyed, we |
| // should not have a dangling PipelineHelper pointer in the context point to the already destroyed |
| // object. |
| TEST_P(BlitFramebufferTest, useAndDestroyProgramThenBlit) |
| { |
| constexpr const GLsizei kWidth = 256; |
| constexpr const GLsizei kHeight = 256; |
| |
| GLRenderbuffer sourceRBO, targetRBO; |
| GLFramebuffer sourceFBO, targetFBO; |
| |
| { |
| initColorFBO(&sourceFBO, &sourceRBO, GL_SRGB8_ALPHA8, kWidth, kHeight); |
| // checkerProgram will be created and destroyed in this code block |
| ANGLE_GL_PROGRAM(checkerProgram, essl1_shaders::vs::Passthrough(), |
| essl1_shaders::fs::Checkered()); |
| glViewport(0, 0, kWidth, kHeight); |
| glBindFramebuffer(GL_FRAMEBUFFER, sourceFBO); |
| drawQuad(checkerProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red); |
| } |
| initColorFBO(&targetFBO, &targetRBO, GL_RGBA8, kWidth, kHeight); |
| EXPECT_GL_NO_ERROR(); |
| |
| glViewport(0, 0, kWidth, kHeight); |
| glClearColor(0.0f, 0.0f, 1.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Blit call should not crash or assert |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO); |
| glBlitFramebuffer(0, 0, kWidth, kHeight, -kWidth / 2, -kHeight / 2, 3 * kWidth / 2, |
| 3 * kHeight / 2, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // This test is to ensure the draw after blit without any state change works properly |
| TEST_P(BlitFramebufferTest, drawBlitAndDrawAgain) |
| { |
| constexpr const GLsizei kWidth = 256; |
| constexpr const GLsizei kHeight = 256; |
| |
| GLRenderbuffer srcColorRB, srcDepthRB; |
| GLFramebuffer srcFBO; |
| |
| ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Red()); |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Green()); |
| ANGLE_GL_PROGRAM(drawBlue, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue()); |
| |
| // Initialize source FBO with red color and depth==0.8f |
| initFBOWithProgramAndDepth(&srcFBO, &srcColorRB, GL_RGBA8, &srcDepthRB, GL_DEPTH24_STENCIL8_OES, |
| kWidth, kHeight, drawRed, 0.8f); |
| EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red); |
| |
| // Initialize destination FBO and initialize to green and depth==0.7 |
| initFBOWithProgramAndDepth(nullptr, nullptr, 0, nullptr, 0, kWidth, kHeight, drawGreen, 0.7f); |
| EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green); |
| |
| // Setup for draw-blit-draw use pattern |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| std::array<Vector3, 6> quadVertices = GetQuadVertices(); |
| constexpr size_t kBufferSize = sizeof(quadVertices[0]) * quadVertices.size(); |
| GLBuffer vertexBuffer; |
| glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); |
| glBufferData(GL_ARRAY_BUFFER, kBufferSize, nullptr, GL_STATIC_DRAW); |
| glUseProgram(drawBlue); |
| const GLint positionLocation = glGetAttribLocation(drawBlue, essl1_shaders::PositionAttrib()); |
| ASSERT_NE(-1, positionLocation); |
| glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0); |
| glEnableVertexAttribArray(positionLocation); |
| |
| // Draw with depth=0.75, should fail depth test |
| drawWithDepthValue(quadVertices, 0.75f); |
| // Now blit depth buffer from source FBO to the right half of destination FBO, so left half has |
| // depth 0.7f and right half has 0.8f |
| glBlitFramebuffer(kWidth / 2, 0, kWidth, kHeight, kWidth / 2, 0, kWidth, kHeight, |
| GL_DEPTH_BUFFER_BIT, GL_NEAREST); |
| // Continue draw without state change and depth==0.75f, now it should pass depth test on right |
| // half |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| |
| // Now verify dstFBO |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 2 + 1, 1, GLColor::blue); |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // This test is to ensure the scissored draw after blit without any state change works properly |
| TEST_P(BlitFramebufferTest, scissorDrawBlitAndDrawAgain) |
| { |
| constexpr const GLsizei kWidth = 256; |
| constexpr const GLsizei kHeight = 256; |
| |
| GLRenderbuffer srcColorRB, srcDepthRB; |
| GLFramebuffer srcFBO; |
| |
| ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Red()); |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Green()); |
| ANGLE_GL_PROGRAM(drawBlue, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue()); |
| |
| // Initialize source FBO with red color and depth==0.8f |
| initFBOWithProgramAndDepth(&srcFBO, &srcColorRB, GL_RGBA8, &srcDepthRB, GL_DEPTH24_STENCIL8_OES, |
| kWidth, kHeight, drawRed, 0.8f); |
| EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red); |
| |
| // Initialize destination FBO and initialize to green and depth==0.7 |
| initFBOWithProgramAndDepth(nullptr, nullptr, 0, nullptr, 0, kWidth, kHeight, drawGreen, 0.7f); |
| EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green); |
| |
| // Setup for draw-blit-draw use pattern |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| std::array<Vector3, 6> quadVertices = GetQuadVertices(); |
| constexpr size_t kBufferSize = sizeof(quadVertices[0]) * quadVertices.size(); |
| GLBuffer vertexBuffer; |
| glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); |
| glBufferData(GL_ARRAY_BUFFER, kBufferSize, nullptr, GL_STATIC_DRAW); |
| glUseProgram(drawBlue); |
| const GLint positionLocation = glGetAttribLocation(drawBlue, essl1_shaders::PositionAttrib()); |
| ASSERT_NE(-1, positionLocation); |
| glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0); |
| glEnableVertexAttribArray(positionLocation); |
| |
| // Scissored draw with depth=0.75, should fail depth test |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(0, 0, kWidth, kHeight / 2); |
| drawWithDepthValue(quadVertices, 0.75f); |
| // Now blit depth buffer from source FBO to the right half of destination FBO, so left half has |
| // depth 0.7f and right half has 0.8f |
| glBlitFramebuffer(kWidth / 2, 0, kWidth, kHeight, kWidth / 2, 0, kWidth, kHeight, |
| GL_DEPTH_BUFFER_BIT, GL_NEAREST); |
| // Continue draw without state change and depth==0.75f, now it should pass depth test on right |
| // half |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| |
| // Now verify dstFBO |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 2 + 1, 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(1, kHeight - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 2 + 1, kHeight - 1, GLColor::green); |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Test blitFramebuffer size overflow checks. WebGL 2.0 spec section 5.41. We do validation for |
| // overflows also in non-WebGL mode to avoid triggering driver bugs. |
| TEST_P(BlitFramebufferTest, BlitFramebufferSizeOverflow) |
| { |
| GLTexture textures[2]; |
| glBindTexture(GL_TEXTURE_2D, textures[0]); |
| glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4); |
| glBindTexture(GL_TEXTURE_2D, textures[1]); |
| glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4); |
| |
| GLFramebuffer framebuffers[2]; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], |
| 0); |
| glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], |
| 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| // srcX |
| glBlitFramebuffer(-1, 0, std::numeric_limits<GLint>::max(), 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| glBlitFramebuffer(std::numeric_limits<GLint>::max(), 0, -1, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| // srcY |
| glBlitFramebuffer(0, -1, 4, std::numeric_limits<GLint>::max(), 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| glBlitFramebuffer(0, std::numeric_limits<GLint>::max(), 4, -1, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| // dstX |
| glBlitFramebuffer(0, 0, 4, 4, -1, 0, std::numeric_limits<GLint>::max(), 4, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| glBlitFramebuffer(0, 0, 4, 4, std::numeric_limits<GLint>::max(), 0, -1, 4, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| // dstY |
| glBlitFramebuffer(0, 0, 4, 4, 0, -1, 4, std::numeric_limits<GLint>::max(), GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| glBlitFramebuffer(0, 0, 4, 4, 0, std::numeric_limits<GLint>::max(), 4, -1, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| } |
| |
| // Test blitFramebuffer size overflow checks. WebGL 2.0 spec section 5.41. Similar to above test, |
| // but this test more accurately duplicates the behavior of the WebGL test |
| // conformance2/rendering/blitframebuffer-size-overflow.html, which covers a few more edge cases. |
| TEST_P(BlitFramebufferTest, BlitFramebufferSizeOverflow2) |
| { |
| GLTexture textures[2]; |
| glBindTexture(GL_TEXTURE_2D, textures[0]); |
| glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4); |
| glBindTexture(GL_TEXTURE_2D, textures[1]); |
| glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4); |
| |
| GLFramebuffer framebuffers[2]; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], |
| 0); |
| glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], |
| 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| GLint width = 8; |
| GLint height = 8; |
| |
| GLTexture tex0; |
| glBindTexture(GL_TEXTURE_2D, tex0); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); |
| |
| GLFramebuffer fb0; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fb0); |
| glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0, 0); |
| |
| GLTexture tex1; |
| glBindTexture(GL_TEXTURE_2D, tex1); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); |
| |
| GLFramebuffer fb1; |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb1); |
| glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex1, 0); |
| |
| GLint max = std::numeric_limits<GLint>::max(); |
| // Using max 32-bit integer as blitFramebuffer parameter should succeed. |
| glBlitFramebuffer(0, 0, max, max, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| glBlitFramebuffer(0, 0, width, height, 0, 0, max, max, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| glBlitFramebuffer(0, 0, max, max, 0, 0, max, max, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Using blitFramebuffer parameters where calculated width/height matches max 32-bit integer |
| // should succeed |
| glBlitFramebuffer(-1, -1, max - 1, max - 1, 0, 0, width, height, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| glBlitFramebuffer(0, 0, width, height, -1, -1, max - 1, max - 1, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| glBlitFramebuffer(-1, -1, max - 1, max - 1, -1, -1, max - 1, max - 1, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Using source width/height greater than max 32-bit integer should fail. |
| glBlitFramebuffer(-1, -1, max, max, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| // Using source width/height greater than max 32-bit integer should fail. |
| glBlitFramebuffer(max, max, -1, -1, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| // Using destination width/height greater than max 32-bit integer should fail. |
| glBlitFramebuffer(0, 0, width, height, -1, -1, max, max, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| // Using destination width/height greater than max 32-bit integer should fail. |
| glBlitFramebuffer(0, 0, width, height, max, max, -1, -1, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| // Using both source and destination width/height greater than max 32-bit integer should fail. |
| glBlitFramebuffer(-1, -1, max, max, -1, -1, max, max, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| // Using minimum and maximum integers for all boundaries should fail. |
| glBlitFramebuffer(-max - 1, -max - 1, max, max, -max - 1, -max - 1, max, max, |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| } |
| |
| // Test an edge case in D3D11 stencil blitting on the CPU that does not properly clip the |
| // destination regions |
| TEST_P(BlitFramebufferTest, BlitFramebufferStencilClipNoIntersection) |
| { |
| GLFramebuffer framebuffers[2]; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]); |
| |
| GLRenderbuffer renderbuffers[2]; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[0]); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4); |
| glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| renderbuffers[0]); |
| |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[1]); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| renderbuffers[1]); |
| |
| glBlitFramebuffer(0, 0, 4, 4, 1 << 24, 1 << 24, 1 << 25, 1 << 25, GL_STENCIL_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Test that blit with FBOs with multiple color attachments of different size. |
| TEST_P(BlitFramebufferTest, BlitWithDifferentSizesColorAttachments) |
| { |
| GLFramebuffer srcFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer); |
| constexpr GLint kWidth = 32; |
| constexpr GLint kHeight = 48; |
| GLColor texture_pattern[kWidth * kHeight]; |
| |
| // Prepare texture pattern |
| for (int y = 0; y < kHeight; y++) |
| { |
| for (int x = 0; x < kWidth; x++) |
| { |
| switch ((x + 2 * y) % 3) |
| { |
| case 0: |
| texture_pattern[y * kWidth + x] = GLColor::red; |
| break; |
| case 1: |
| texture_pattern[y * kWidth + x] = GLColor::green; |
| break; |
| case 2: |
| texture_pattern[y * kWidth + x] = GLColor::blue; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| GLTexture largeColorBuffer; |
| glBindTexture(GL_TEXTURE_2D, largeColorBuffer); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| texture_pattern); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, largeColorBuffer, |
| 0); |
| EXPECT_GL_NO_ERROR(); |
| |
| GLTexture smallColorBuffer; |
| glBindTexture(GL_TEXTURE_2D, smallColorBuffer); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth / 2, kHeight / 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, smallColorBuffer, |
| 0); |
| EXPECT_GL_NO_ERROR(); |
| |
| GLFramebuffer dstFramebuffer; |
| GLRenderbuffer dstRenderbuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| glBindRenderbuffer(GL_RENDERBUFFER, dstRenderbuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kWidth, kHeight); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| dstRenderbuffer); |
| glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer); |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| glBlitFramebuffer(0, 0, kWidth / 2 + 1, kHeight / 2 + 1, 0, 0, kWidth / 2 + 1, kHeight / 2 + 1, |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| |
| for (int x = 0; x < kWidth / 2; x++) |
| { |
| for (int y = 0; y < kHeight / 2; y++) |
| { |
| switch ((x + 2 * y) % 3) |
| { |
| case 0: |
| EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::red) << x << " " << y; |
| break; |
| case 1: |
| EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green) << x << " " << y; |
| break; |
| case 2: |
| EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::blue) << x << " " << y; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Test that blit with FBOs with large color attachment and small depth attachment. |
| TEST_P(BlitFramebufferTest, BlitLargeColorSmallDepthAttachments) |
| { |
| constexpr GLint kWidth = 32; |
| constexpr GLint kHeight = 48; |
| GLFramebuffer srcFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer); |
| glDisable(GL_DEPTH_TEST); |
| |
| GLTexture srcLargeColorBuffer; |
| glBindTexture(GL_TEXTURE_2D, srcLargeColorBuffer); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcLargeColorBuffer, |
| 0); |
| EXPECT_GL_NO_ERROR(); |
| |
| GLRenderbuffer srcSmallDepthBuffer; |
| glBindRenderbuffer(GL_RENDERBUFFER, srcSmallDepthBuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kWidth / 2, kHeight / 2); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| srcSmallDepthBuffer); |
| ANGLE_GL_PROGRAM(drawGreen, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green()); |
| drawQuad(drawGreen, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| GLFramebuffer dstFramebuffer; |
| GLRenderbuffer dstColorBuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| glBindRenderbuffer(GL_RENDERBUFFER, dstColorBuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kWidth, kHeight); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| dstColorBuffer); |
| GLRenderbuffer dstDepthBuffer; |
| glBindRenderbuffer(GL_RENDERBUFFER, dstDepthBuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kWidth, kHeight); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, dstDepthBuffer); |
| glClearDepthf(1.0f); |
| glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer); |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| // The blit is larger than the size of srcFramebuffer, so the actual blit area is (kWidth / 2) * |
| // (kHeight / 2) |
| glBlitFramebuffer(0, 0, kWidth / 2 + 1, kHeight / 2 + 1, 0, 0, kWidth / 2 + 1, kHeight / 2 + 1, |
| GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| |
| for (int x = 0; x < kWidth / 2; x++) |
| { |
| for (int y = 0; y < kHeight / 2; y++) |
| { |
| EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green) << x << " " << y; |
| } |
| } |
| |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthMask(false); |
| glDepthFunc(GL_LESS); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.7f); |
| |
| for (int x = 0; x < kWidth / 2; x++) |
| { |
| for (int y = 0; y < kHeight / 2; y++) |
| { |
| EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green) << x << " " << y; |
| } |
| } |
| |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Test that blit with FBOs with small color attachment and large depth attachment. |
| TEST_P(BlitFramebufferTest, BlitSmallColorLargeDepthAttachments) |
| { |
| constexpr GLint kWidth = 32; |
| constexpr GLint kHeight = 48; |
| GLFramebuffer srcFramebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer); |
| glDisable(GL_DEPTH_TEST); |
| |
| GLTexture srcSmallColorBuffer; |
| glBindTexture(GL_TEXTURE_2D, srcSmallColorBuffer); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth / 2, kHeight / 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcSmallColorBuffer, |
| 0); |
| EXPECT_GL_NO_ERROR(); |
| |
| GLRenderbuffer srcLargeDepthBuffer; |
| glBindRenderbuffer(GL_RENDERBUFFER, srcLargeDepthBuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kWidth, kHeight); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| srcLargeDepthBuffer); |
| ANGLE_GL_PROGRAM(drawGreen, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green()); |
| drawQuad(drawGreen, essl3_shaders::PositionAttrib(), 0.5f); |
| |
| GLFramebuffer dstFramebuffer; |
| GLRenderbuffer dstColorBuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| glBindRenderbuffer(GL_RENDERBUFFER, dstColorBuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kWidth, kHeight); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| dstColorBuffer); |
| GLRenderbuffer dstDepthBuffer; |
| glBindRenderbuffer(GL_RENDERBUFFER, dstDepthBuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kWidth, kHeight); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, dstDepthBuffer); |
| glClearDepthf(1.0f); |
| glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer); |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| // The blit is larger than the size of srcFramebuffer, so the actual blit area is (kWidth / 2) * |
| // (kHeight / 2) |
| glBlitFramebuffer(0, 0, kWidth / 2 + 1, kHeight / 2 + 1, 0, 0, kWidth / 2 + 1, kHeight / 2 + 1, |
| GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer); |
| for (int x = 0; x < kWidth / 2; x++) |
| { |
| for (int y = 0; y < kHeight / 2; y++) |
| { |
| EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green) << x << " " << y; |
| } |
| } |
| |
| ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| glEnable(GL_DEPTH_TEST); |
| glDepthMask(false); |
| glDepthFunc(GL_LESS); |
| drawQuad(drawRed, essl3_shaders::PositionAttrib(), 0.7f); |
| |
| for (int x = 0; x < kWidth / 2; x++) |
| { |
| for (int y = 0; y < kHeight / 2; y++) |
| { |
| EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green) << x << " " << y; |
| } |
| } |
| |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Covers an edge case with blitting borderline values. |
| TEST_P(BlitFramebufferTest, OOBWrite) |
| { |
| constexpr size_t length = 0x100000; |
| GLFramebuffer rfb; |
| GLFramebuffer dfb; |
| GLRenderbuffer rb1; |
| GLRenderbuffer rb2; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, rfb); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dfb); |
| glBindRenderbuffer(GL_RENDERBUFFER, rb1); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 0x1000, 2); |
| glBindRenderbuffer(GL_RENDERBUFFER, rb2); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 2, 2); |
| glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| rb1); |
| glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| rb2); |
| glBlitFramebuffer(1, 0, 0, 1, 1, 0, (2147483648 / 2) - (length / 4) + 1, 1, |
| GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that flipped blits don't have off-by-one errors |
| TEST_P(BlitFramebufferTest, FlippedBlits) |
| { |
| constexpr const GLsizei kWidth = 11; |
| constexpr const GLsizei kHeight = 19; |
| glViewport(0, 0, kWidth, kHeight); |
| |
| GLRenderbuffer srcColorRB, srcDepthRB, dstColorRB, dstDepthRB; |
| GLFramebuffer srcFBO, dstFBO; |
| |
| ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Red()); |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Green()); |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorLoc = glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorLoc, -1); |
| |
| // Create source and dest FBOs |
| glBindRenderbuffer(GL_RENDERBUFFER, srcColorRB); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kWidth, kHeight); |
| glBindRenderbuffer(GL_RENDERBUFFER, srcDepthRB); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, kWidth, kHeight); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFBO); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, srcColorRB); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| srcDepthRB); |
| |
| glBindRenderbuffer(GL_RENDERBUFFER, dstColorRB); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kWidth, kHeight); |
| glBindRenderbuffer(GL_RENDERBUFFER, dstDepthRB); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, kWidth, kHeight); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFBO); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, dstColorRB); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| dstDepthRB); |
| |
| // Fill the source framebuffer with differring values per pixel, so off-by-one errors are more |
| // easily found. |
| glEnable(GL_SCISSOR_TEST); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_ALWAYS); |
| glDepthMask(GL_TRUE); |
| glEnable(GL_STENCIL_TEST); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glStencilMask(0xFF); |
| |
| auto makeColor = [](GLsizei row, GLsizei col) -> GLColor { |
| return GLColor(row * 255 / kHeight, col * 255 / kWidth, (row * 7 + col * 11) % 256, 255); |
| }; |
| auto makeDepth = [](GLsizei row, GLsizei col) -> float { |
| return 1.8f * ((row * kWidth + col) % 33 / 32.0f) - 0.9f; |
| }; |
| auto makeStencil = [](GLsizei row, GLsizei col) -> uint8_t { |
| return (col * kHeight + row) & 0xFF; |
| }; |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFBO); |
| glUseProgram(drawColor); |
| for (GLsizei row = 0; row < kHeight; ++row) |
| { |
| for (GLsizei col = 0; col < kWidth; ++col) |
| { |
| glScissor(col, row, 1, 1); |
| |
| glUniform4fv(colorLoc, 1, makeColor(row, col).toNormalizedVector().data()); |
| glStencilFunc(GL_ALWAYS, makeStencil(row, col), 0xFF); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), makeDepth(row, col)); |
| } |
| } |
| |
| glDepthFunc(GL_LESS); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| |
| auto test = [&](int testIndex, bool flipX, bool flipY, GLint srcOffsetX, GLint srcOffsetY, |
| GLint dstOffsetX, GLint dstOffsetY, GLint width, GLint height) { |
| glDisable(GL_SCISSOR_TEST); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFBO); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFBO); |
| |
| const GLint srcX0 = srcOffsetX; |
| const GLint srcY0 = srcOffsetY; |
| const GLint srcX1 = srcOffsetX + width; |
| const GLint srcY1 = srcOffsetY + height; |
| |
| const GLint dstX0 = flipX ? dstOffsetX + width : dstOffsetX; |
| const GLint dstY0 = flipY ? dstOffsetY + height : dstOffsetY; |
| const GLint dstX1 = flipX ? dstOffsetX : dstOffsetX + width; |
| const GLint dstY1 = flipY ? dstOffsetY : dstOffsetY + height; |
| |
| glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, |
| GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, |
| GL_NEAREST); |
| |
| // Verify results |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, dstFBO); |
| |
| for (GLsizei row = 0; row < height; ++row) |
| { |
| for (GLsizei col = 0; col < width; ++col) |
| { |
| const GLint srcPixelX = col + srcOffsetX; |
| const GLint srcPixelY = row + srcOffsetY; |
| const GLint dstPixelX = dstOffsetX + (flipX ? width - 1 - col : col); |
| const GLint dstPixelY = dstOffsetY + (flipY ? height - 1 - row : row); |
| |
| const GLColor expectColor = makeColor(srcPixelY, srcPixelX); |
| const float expectDepth = makeDepth(srcPixelY, srcPixelX); |
| const uint8_t expectStencil = makeStencil(srcPixelY, srcPixelX); |
| |
| // Verify color |
| EXPECT_PIXEL_COLOR_EQ(dstPixelX, dstPixelY, expectColor) |
| << testIndex << " " << flipX << " " << flipY << " " << row << " " << col; |
| |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(dstPixelX, dstPixelY, 1, 1); |
| |
| // Verify depth and stencil |
| glStencilFunc(GL_EQUAL, expectStencil, 0xFF); |
| drawQuad(drawRed, essl1_shaders::PositionAttrib(), expectDepth - 0.05); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), expectDepth + 0.05); |
| |
| EXPECT_PIXEL_COLOR_EQ(dstPixelX, dstPixelY, GLColor::red) |
| << testIndex << " " << flipX << " " << flipY << " " << row << " " << col; |
| } |
| } |
| }; |
| |
| for (int flipX = 0; flipX < 2; ++flipX) |
| { |
| for (int flipY = 0; flipY < 2; ++flipY) |
| { |
| // Test 0, full sized blit |
| test(0, flipX != 0, flipY != 0, 0, 0, 0, 0, kWidth, kHeight); |
| // Test 1, blit only one pixel |
| test(1, flipX != 0, flipY != 0, kWidth / 3, kHeight / 7, 2 * kWidth / 5, |
| 3 * kHeight / 4, 1, 1); |
| // Test 2, random region |
| test(2, flipX != 0, flipY != 0, kWidth / 5, 2 * kHeight / 7, kWidth / 6, kHeight / 4, |
| kWidth / 2, kHeight / 2); |
| } |
| } |
| } |
| |
| // Test blitting a depthStencil buffer with multiple depth values to a larger size. |
| TEST_P(BlitFramebufferTest, BlitDepthStencilPixelByPixel) |
| { |
| BlitDepthStencilPixelByPixelTestHelper(false /* mesaYFlip */); |
| } |
| |
| // Same as BlitDepthStencilPixelByPixel, but with y-flip flag set. |
| TEST_P(BlitFramebufferTest, BlitDepthStencilPixelByPixelMesaYFlip) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| |
| BlitDepthStencilPixelByPixelTestHelper(true /* mesaYFlip */); |
| } |
| |
| // Regression test for a bug in the Vulkan backend where vkCmdResolveImage was used with |
| // out-of-bounds regions. |
| TEST_P(BlitFramebufferTestES31, OOBResolve) |
| { |
| constexpr GLint kWidth = 16; |
| constexpr GLint kHeight = 32; |
| |
| // Read framebuffer is multisampled. |
| GLTexture readTexture; |
| glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, readTexture); |
| glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kWidth, kHeight, GL_TRUE); |
| |
| GLFramebuffer readFbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, readFbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, |
| readTexture, 0); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Draw framebuffer is single sampled. |
| GLTexture drawTexture; |
| glBindTexture(GL_TEXTURE_2D, drawTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| nullptr); |
| glGenerateMipmap(GL_TEXTURE_2D); |
| |
| GLFramebuffer drawFbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, drawFbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, drawTexture, 0); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glClearColor(0, 1, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::green); |
| |
| // Resolve the read framebuffer, using bounds that are outside the size of the image. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo); |
| glBlitFramebuffer(-kWidth * 2, -kHeight * 3, kWidth * 11, kHeight * 8, -kWidth * 2, |
| -kHeight * 3, kWidth * 11, kHeight * 8, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, drawFbo); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::red); |
| } |
| |
| // Regression test for a bug in the Vulkan backend where vkCmdResolveImage was using the src extents |
| // as the resolve area instead of the area passed to glBlitFramebuffer. |
| TEST_P(BlitFramebufferTestES31, PartialResolve) |
| { |
| constexpr GLint kWidth = 16; |
| constexpr GLint kHeight = 32; |
| |
| // Read framebuffer is multisampled. |
| GLTexture readTexture; |
| glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, readTexture); |
| glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kWidth, kHeight, GL_TRUE); |
| |
| GLFramebuffer readFbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, readFbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, |
| readTexture, 0); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Draw framebuffer is single sampled. It's bound to a texture with base level the same size as |
| // the read framebuffer, but it's bound to mip 1. |
| GLTexture drawTexture; |
| glBindTexture(GL_TEXTURE_2D, drawTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| nullptr); |
| glGenerateMipmap(GL_TEXTURE_2D); |
| |
| GLFramebuffer drawFbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, drawFbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, drawTexture, 1); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glClearColor(0, 1, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth / 2, kHeight / 2, GLColor::green); |
| |
| constexpr GLint kResolveX0 = 1; |
| constexpr GLint kResolveY0 = 2; |
| constexpr GLint kResolveX1 = 4; |
| constexpr GLint kResolveY1 = 6; |
| |
| // Resolve only a portion of the read framebuffer. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo); |
| glBlitFramebuffer(kResolveX0, kResolveY0, kResolveX1, kResolveY1, kResolveX0, kResolveY0, |
| kResolveX1, kResolveY1, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, drawFbo); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kWidth / 2, kResolveY0, GLColor::green); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kResolveX0, kHeight / 2, GLColor::green); |
| EXPECT_PIXEL_RECT_EQ(kResolveX1, 0, kWidth / 2 - kResolveX1, kHeight / 2, GLColor::green); |
| EXPECT_PIXEL_RECT_EQ(0, kResolveY1, kWidth / 2, kHeight / 2 - kResolveY1, GLColor::green); |
| |
| EXPECT_PIXEL_RECT_EQ(kResolveX0, kResolveY0, kResolveX1 - kResolveX0, kResolveY1 - kResolveY0, |
| GLColor::red); |
| } |
| |
| // Test that a draw call to a small FBO followed by a resolve of a large FBO works. |
| TEST_P(BlitFramebufferTestES31, DrawToSmallFBOThenResolveLargeFBO) |
| { |
| GLFramebuffer fboMS[2]; |
| GLTexture textureMS[2]; |
| GLFramebuffer fboSS; |
| GLTexture textureSS; |
| |
| // A bug in the Vulkan backend grew the render area of the previous render pass on blit, even |
| // though the previous render pass belonged to an unrelated framebuffer. This test only needs |
| // to make sure that the FBO being resolved is not strictly smaller than the previous FBO which |
| // was drawn to. |
| constexpr GLsizei kLargeWidth = 127; |
| constexpr GLsizei kLargeHeight = 54; |
| constexpr GLsizei kSmallWidth = 37; |
| constexpr GLsizei kSmallHeight = 79; |
| |
| ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| |
| // Create resolve target. |
| glBindTexture(GL_TEXTURE_2D, textureSS); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kLargeWidth, kLargeHeight); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fboSS); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureSS, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Create multisampled framebuffers and draw into them one by one. |
| for (size_t fboIndex = 0; fboIndex < 2; ++fboIndex) |
| { |
| const GLsizei width = fboIndex == 0 ? kLargeWidth : kSmallWidth; |
| const GLsizei height = fboIndex == 0 ? kLargeHeight : kSmallHeight; |
| |
| glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureMS[fboIndex]); |
| glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, width, height, GL_TRUE); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fboMS[fboIndex]); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, |
| textureMS[fboIndex], 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glViewport(0, 0, width, height); |
| drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.8f); |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Resolve the first FBO |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboSS); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fboMS[0]); |
| |
| glViewport(0, 0, kLargeWidth, kLargeHeight); |
| glBlitFramebuffer(0, 0, kLargeWidth, kLargeHeight, 0, 0, kLargeWidth, kLargeHeight, |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Verify the resolve |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fboSS); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kLargeWidth - 1, kLargeHeight - 1, GLColor::red); |
| } |
| |
| // Blit a multisampled RGBX8 framebuffer to an RGB8 framebuffer. |
| TEST_P(BlitFramebufferTestES31, BlitMultisampledRGBX8ToRGB8) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_rgbx_internal_format")); |
| |
| constexpr const GLsizei kWidth = 256; |
| constexpr const GLsizei kHeight = 256; |
| |
| GLTexture textureMS; |
| GLRenderbuffer targetRBO; |
| GLFramebuffer sourceFBO, targetFBO; |
| |
| // Initialize a source multisampled FBO with checker pattern |
| glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureMS); |
| glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBX8_ANGLE, kWidth, kHeight, |
| GL_TRUE); |
| EXPECT_GL_NO_ERROR(); |
| glBindFramebuffer(GL_FRAMEBUFFER, sourceFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, |
| textureMS, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| ANGLE_GL_PROGRAM(checkerProgram, essl1_shaders::vs::Passthrough(), |
| essl1_shaders::fs::Checkered()); |
| glViewport(0, 0, kWidth, kHeight); |
| glBindFramebuffer(GL_FRAMEBUFFER, sourceFBO); |
| drawQuad(checkerProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Initialize the destination FBO |
| initColorFBO(&targetFBO, &targetRBO, GL_RGB8, kWidth, kHeight); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO); |
| EXPECT_GL_NO_ERROR(); |
| |
| glViewport(0, 0, kWidth, kHeight); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Scale down without flipping. |
| glBlitFramebuffer(0, 0, kWidth, kHeight, 0, 0, kWidth, kHeight, GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| EXPECT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, targetFBO); |
| |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, kHeight / 4, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, kHeight / 4, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, 3 * kHeight / 4, GLColor::yellow); |
| } |
| |
| // Test resolving a multisampled texture with blit. Draw flipped, resolve with read fbo flipped. |
| TEST_P(BlitFramebufferTestES31, MultisampleFlippedResolveReadWithBlitAndFlippedDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| |
| constexpr int kSize = 16; |
| glViewport(0, 0, kSize, kSize); |
| |
| GLFramebuffer msaaFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO); |
| |
| glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture); |
| glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false); |
| ASSERT_GL_NO_ERROR(); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texture, |
| 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(), |
| essl31_shaders::fs::RedGreenGradient()); |
| drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Create another FBO to resolve the multisample buffer into. |
| GLTexture resolveTexture; |
| GLFramebuffer resolveFBO; |
| glBindTexture(GL_TEXTURE_2D, resolveTexture); |
| constexpr int kResolveFBOWidth = kSize - 3; |
| constexpr int kResolveFBOHeight = kSize - 2; |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kResolveFBOWidth, kResolveFBOHeight, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO); |
| glFramebufferParameteriMESA(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO); |
| glBlitFramebuffer(0, 0, kResolveFBOWidth, kResolveFBOHeight, 0, 0, kResolveFBOWidth, |
| kResolveFBOHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO); |
| constexpr uint8_t kHalfPixelGradient = 256 / kSize / 2; |
| EXPECT_PIXEL_NEAR(0, 0, kHalfPixelGradient, kHalfPixelGradient, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, 0, 199, kHalfPixelGradient, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(0, kResolveFBOHeight - 1, kHalfPixelGradient, 215, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, kResolveFBOHeight - 1, 199, 215, 0, 255, 1.0); |
| } |
| |
| // Test resolving a multisampled texture with blit. Draw non-flipped, resolve with read fbo flipped. |
| TEST_P(BlitFramebufferTestES31, MultisampleFlippedResolveReadWithBlitAndNonFlippedDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| |
| constexpr int kSize = 16; |
| glViewport(0, 0, kSize, kSize); |
| |
| GLFramebuffer msaaFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO); |
| |
| // Draw non-flipped - explicitly set y-flip to 0. |
| glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 0); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture); |
| glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false); |
| ASSERT_GL_NO_ERROR(); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texture, |
| 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(), |
| essl31_shaders::fs::RedGreenGradient()); |
| drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Create another FBO to resolve the multisample buffer into. |
| GLTexture resolveTexture; |
| GLFramebuffer resolveFBO; |
| glBindTexture(GL_TEXTURE_2D, resolveTexture); |
| constexpr int kResolveFBOWidth = kSize - 3; |
| constexpr int kResolveFBOHeight = kSize - 2; |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kResolveFBOWidth, kResolveFBOHeight, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO); |
| // Resolve with read fbo flipped and draw fbo non-flipped |
| glFramebufferParameteriMESA(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO); |
| glBlitFramebuffer(0, 0, kResolveFBOWidth, kResolveFBOHeight, 0, 0, kResolveFBOWidth, |
| kResolveFBOHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO); |
| constexpr uint8_t kHalfPixelGradient = 256 / kSize / 2; |
| EXPECT_PIXEL_NEAR(0, 0, kHalfPixelGradient, 255 - kHalfPixelGradient, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, 0, 199, 255 - kHalfPixelGradient, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(0, kResolveFBOHeight - 1, kHalfPixelGradient, 40, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, kResolveFBOHeight - 1, 199, 40, 0, 255, 1.0); |
| } |
| |
| // Test resolving a multisampled texture with blit. Draw non-flipped, resolve with draw fbo flipped |
| TEST_P(BlitFramebufferTestES31, MultisampleFlippedResolveDrawWithBlitAndNonFlippedDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| |
| constexpr int kSize = 16; |
| glViewport(0, 0, kSize, kSize); |
| |
| GLFramebuffer msaaFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO); |
| |
| // Draw non-flipped - explicitly set y-flip to 0. |
| glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 0); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture); |
| glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false); |
| ASSERT_GL_NO_ERROR(); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texture, |
| 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(), |
| essl31_shaders::fs::RedGreenGradient()); |
| drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Create another FBO to resolve the multisample buffer into. |
| GLTexture resolveTexture; |
| GLFramebuffer resolveFBO; |
| glBindTexture(GL_TEXTURE_2D, resolveTexture); |
| constexpr int kResolveFBOWidth = kSize - 3; |
| constexpr int kResolveFBOHeight = kSize - 2; |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kResolveFBOWidth, kResolveFBOHeight, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO); |
| // Resolve with draw fbo flipped and read fbo non-flipped. |
| glFramebufferParameteriMESA(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 0); |
| glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| glBlitFramebuffer(0, 0, kResolveFBOWidth, kResolveFBOHeight, 0, 0, kResolveFBOWidth, |
| kResolveFBOHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO); |
| constexpr uint8_t kHalfPixelGradient = 256 / kSize / 2; |
| EXPECT_PIXEL_NEAR(0, 0, kHalfPixelGradient, kHalfPixelGradient, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, 0, 199, kHalfPixelGradient, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(0, kResolveFBOHeight - 1, kHalfPixelGradient, 215, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, kResolveFBOHeight - 1, 199, 215, 0, 255, 1.0); |
| } |
| |
| // Test resolving a multisampled texture with blit. Draw non-flipped, resolve with both read and |
| // draw fbos flipped |
| TEST_P(BlitFramebufferTestES31, MultisampleFlippedResolveWithBlitAndNonFlippedDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y")); |
| |
| constexpr int kSize = 16; |
| glViewport(0, 0, kSize, kSize); |
| |
| GLFramebuffer msaaFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO); |
| |
| // Draw non-flipped - explicitly set y-flip to 0. |
| glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 0); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture); |
| glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false); |
| ASSERT_GL_NO_ERROR(); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texture, |
| 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(), |
| essl31_shaders::fs::RedGreenGradient()); |
| drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Create another FBO to resolve the multisample buffer into. |
| GLTexture resolveTexture; |
| GLFramebuffer resolveFBO; |
| constexpr int kResolveFBOWidth = kSize - 3; |
| constexpr int kResolveFBOHeight = kSize - 2; |
| glBindTexture(GL_TEXTURE_2D, resolveTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kResolveFBOWidth, kResolveFBOHeight, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO); |
| // Resolve with draw and read fbo flipped. |
| glFramebufferParameteriMESA(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| glBlitFramebuffer(0, 0, kResolveFBOWidth, kResolveFBOHeight, 0, 0, kResolveFBOWidth, |
| kResolveFBOHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO); |
| constexpr uint8_t kHalfPixelGradient = 256 / kSize / 2; |
| EXPECT_PIXEL_NEAR(0, 0, kHalfPixelGradient, 255 - kHalfPixelGradient, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, 0, 199, 255 - kHalfPixelGradient, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(0, kResolveFBOHeight - 1, kHalfPixelGradient, 40, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, kResolveFBOHeight - 1, 199, 40, 0, 255, 1.0); |
| } |
| |
| // Test resolving into smaller framebuffer. |
| TEST_P(BlitFramebufferTest, ResolveIntoSmallerFramebuffer) |
| { |
| constexpr GLuint kSize[2] = {40, 32}; |
| glViewport(0, 0, kSize[0], kSize[0]); |
| |
| GLRenderbuffer rbo[2]; |
| GLFramebuffer fbo[2]; |
| |
| for (int i = 0; i < 2; ++i) |
| { |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo[i]); |
| if (i == 0) |
| { |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, kSize[i], kSize[i]); |
| } |
| else |
| { |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize[i], kSize[i]); |
| } |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo[i]); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo[i]); |
| } |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| glUseProgram(program); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.3f); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[1]); |
| glBlitFramebuffer(0, 0, kSize[1], kSize[1], 0, 0, kSize[1], kSize[1], GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[1]); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kSize[1], kSize[1], GLColor::red); |
| } |
| |
| // Test resolving into bigger framebuffer. |
| TEST_P(BlitFramebufferTest, ResolveIntoBiggerFramebuffer) |
| { |
| constexpr GLuint kSize[2] = {32, 40}; |
| glViewport(0, 0, kSize[0], kSize[0]); |
| |
| GLRenderbuffer rbo[2]; |
| GLFramebuffer fbo[2]; |
| |
| for (int i = 0; i < 2; ++i) |
| { |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo[i]); |
| if (i == 0) |
| { |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, kSize[i], kSize[i]); |
| } |
| else |
| { |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize[i], kSize[i]); |
| } |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo[i]); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo[i]); |
| } |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| glUseProgram(program); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.3f); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[1]); |
| glBlitFramebuffer(0, 0, kSize[1], kSize[1], 0, 0, kSize[1], kSize[1], GL_COLOR_BUFFER_BIT, |
| GL_NEAREST); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[1]); |
| EXPECT_PIXEL_RECT_EQ(0, 0, kSize[0], kSize[0], GLColor::red); |
| } |
| |
| // Test resolving into a rotated framebuffer |
| TEST_P(BlitFramebufferTest, ResolveWithRotation) |
| { |
| const GLint w = getWindowWidth(); |
| const GLint h = getWindowHeight(); |
| |
| glViewport(0, 0, w, h); |
| |
| GLRenderbuffer rbo; |
| GLFramebuffer fbo; |
| |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, w, h); |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Checkered()); |
| glUseProgram(program); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.3f); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| EXPECT_PIXEL_RECT_EQ(0, 0, w / 2, h / 2, GLColor::red); |
| EXPECT_PIXEL_RECT_EQ(w / 2, 0, w / 2, h / 2, GLColor::blue); |
| EXPECT_PIXEL_RECT_EQ(0, h / 2, w / 2, h / 2, GLColor::green); |
| EXPECT_PIXEL_RECT_EQ(w / 2, h / 2, w / 2, h / 2, GLColor::yellow); |
| } |
| |
| // Test blitting a 3D texture to a 3D texture |
| TEST_P(BlitFramebufferTest, Blit3D) |
| { |
| test3DBlit(GL_TEXTURE_3D, GL_TEXTURE_3D); |
| } |
| |
| // Test blitting a 2D array texture to a 2D array texture |
| TEST_P(BlitFramebufferTest, Blit2DArray) |
| { |
| test3DBlit(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_2D_ARRAY); |
| } |
| |
| // Test blitting a 3D texture to a 2D array texture |
| TEST_P(BlitFramebufferTest, Blit3DTo2DArray) |
| { |
| test3DBlit(GL_TEXTURE_3D, GL_TEXTURE_2D_ARRAY); |
| } |
| |
| // Test blitting a 2D array texture to a 3D texture |
| TEST_P(BlitFramebufferTest, Blit2DArrayTo3D) |
| { |
| test3DBlit(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D); |
| } |
| |
| // Use this to select which configurations (e.g. which renderer, which GLES major version) these |
| // tests should be run against. |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BlitFramebufferANGLETest); |
| ANGLE_INSTANTIATE_TEST(BlitFramebufferANGLETest, |
| ES2_D3D9(), |
| ES2_D3D11(), |
| ES2_D3D11_PRESENT_PATH_FAST(), |
| ES2_OPENGL(), |
| ES3_OPENGL(), |
| ES2_VULKAN(), |
| ES3_VULKAN(), |
| ES3_VULKAN().enable(Feature::EmulatedPrerotation90), |
| ES3_VULKAN().enable(Feature::EmulatedPrerotation180), |
| ES3_VULKAN().enable(Feature::EmulatedPrerotation270), |
| ES3_VULKAN() |
| .disable(Feature::SupportsExtendedDynamicState) |
| .disable(Feature::SupportsExtendedDynamicState2), |
| ES3_VULKAN().disable(Feature::SupportsExtendedDynamicState2), |
| ES2_METAL(), |
| ES2_METAL().disable(Feature::HasShaderStencilOutput)); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BlitFramebufferTest); |
| ANGLE_INSTANTIATE_TEST_ES3_AND(BlitFramebufferTest, |
| ES3_VULKAN().enable(Feature::EmulatedPrerotation90), |
| ES3_VULKAN().enable(Feature::EmulatedPrerotation180), |
| ES3_VULKAN().enable(Feature::EmulatedPrerotation270), |
| ES3_VULKAN() |
| .disable(Feature::SupportsExtendedDynamicState) |
| .disable(Feature::SupportsExtendedDynamicState2), |
| ES3_VULKAN().disable(Feature::SupportsExtendedDynamicState2), |
| ES3_VULKAN().enable(Feature::DisableFlippingBlitWithCommand), |
| ES3_METAL().disable(Feature::HasShaderStencilOutput)); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BlitFramebufferTestES31); |
| ANGLE_INSTANTIATE_TEST_ES31(BlitFramebufferTestES31); |
| } // namespace |