// // 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; class BlitFramebufferANGLETest : public ANGLETest { protected: BlitFramebufferANGLETest() { setWindowWidth(256); setWindowHeight(256); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); setConfigDepthBits(24); setConfigStencilBits(8); mCheckerProgram = 0; mBlueProgram = 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; mBGRAMultisampledRenderbuffer = 0; mBGRAMultisampledFBO = 0; } virtual void SetUp() { ANGLETest::SetUp(); const std::string passthroughVS = SHADER_SOURCE ( precision highp float; attribute vec4 position; varying vec4 pos; void main() { gl_Position = position; pos = position; } ); const std::string checkeredFS = SHADER_SOURCE ( precision highp float; varying vec4 pos; void main() { if (pos.x * pos.y > 0.0) { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } else { gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); } } ); const std::string blueFS = SHADER_SOURCE ( precision highp float; varying vec4 pos; void main() { gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); } ); mCheckerProgram = CompileProgram(passthroughVS, checkeredFS); mBlueProgram = CompileProgram(passthroughVS, blueFS); if (mCheckerProgram == 0 || mBlueProgram == 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_BGRA8_EXT; glGenFramebuffers(1, &mUserFBO); glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glGenTextures(1, &mUserColorBuffer); glGenRenderbuffers(1, &mUserDepthStencilBuffer); glBindTexture(GL_TEXTURE_2D, mUserColorBuffer); glTexStorage2DEXT(GL_TEXTURE_2D, 1, format, getWindowWidth(), getWindowHeight()); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mUserColorBuffer, 0); 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); glTexStorage2DEXT(GL_TEXTURE_2D, 1, format, getWindowWidth() / 2, getWindowHeight() / 2); 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); glTexStorage2DEXT(GL_TEXTURE_2D, 1, format, getWindowWidth(), getWindowHeight()); 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); glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGB565, getWindowWidth(), getWindowHeight()); 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); glTexStorage2DEXT(GL_TEXTURE_2D, 1, format, getWindowWidth()*2, getWindowHeight()*2); 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 (extensionEnabled("GL_EXT_draw_buffers")) { glGenFramebuffers(1, &mMRTFBO); glBindFramebuffer(GL_FRAMEBUFFER, mMRTFBO); glGenTextures(1, &mMRTColorBuffer0); glGenTextures(1, &mMRTColorBuffer1); glBindTexture(GL_TEXTURE_2D, mMRTColorBuffer0); glTexStorage2DEXT(GL_TEXTURE_2D, 1, format, getWindowWidth(), getWindowHeight()); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, mMRTColorBuffer0, 0); glBindTexture(GL_TEXTURE_2D, mMRTColorBuffer1); glTexStorage2DEXT(GL_TEXTURE_2D, 1, format, getWindowWidth(), getWindowHeight()); 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 (extensionEnabled("GL_ANGLE_framebuffer_multisample")) { // Test blit between RGBA and multisampled BGRA glGenTextures(1, &mRGBAColorbuffer); glBindTexture(GL_TEXTURE_2D, mRGBAColorbuffer); glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8_OES, getWindowWidth(), getWindowHeight()); 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)); 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); } virtual void TearDown() { glDeleteProgram(mCheckerProgram); glDeleteProgram(mBlueProgram); 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 (extensionEnabled("GL_EXT_draw_buffers")) { glDeleteFramebuffers(1, &mMRTFBO); glDeleteTextures(1, &mMRTColorBuffer0); glDeleteTextures(1, &mMRTColorBuffer1); } if (mRGBAColorbuffer != 0) { glDeleteTextures(1, &mRGBAColorbuffer); } if (mRGBAFBO != 0) { glDeleteFramebuffers(1, &mBGRAMultisampledFBO); } if (mBGRAMultisampledRenderbuffer != 0) { glDeleteRenderbuffers(1, &mBGRAMultisampledRenderbuffer); } if (mBGRAMultisampledFBO != 0) { glDeleteFramebuffers(1, &mBGRAMultisampledFBO); } ANGLETest::TearDown(); } GLuint mCheckerProgram; GLuint mBlueProgram; 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 mBGRAMultisampledRenderbuffer; GLuint mBGRAMultisampledFBO; }; // Draw to user-created framebuffer, blit whole-buffer color to original framebuffer. TEST_P(BlitFramebufferANGLETest, BlitColorToDefault) { glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); } // Draw to system framebuffer, blit whole-buffer color to user-created framebuffer. TEST_P(BlitFramebufferANGLETest, ReverseColorBlit) { glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); } // blit from user-created FBO to system framebuffer, with the scissor test enabled. TEST_P(BlitFramebufferANGLETest, ScissoredBlit) { glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 255, 255, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 255, 255, 255); } // blit from system FBO to user-created framebuffer, with the scissor test enabled. TEST_P(BlitFramebufferANGLETest, ReverseScissoredBlit) { // TODO(jmadill): Triage this driver bug. if (IsAMD() && IsD3D11()) { std::cout << "Test skipped on AMD D3D11." << std::endl; return; } glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 255, 255, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 255, 255, 255); } // blit from user-created FBO to system framebuffer, using region larger than buffer. TEST_P(BlitFramebufferANGLETest, OversizedBlit) { glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); } // blit from system FBO to user-created framebuffer, using region larger than buffer. TEST_P(BlitFramebufferANGLETest, ReverseOversizedBlit) { glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); } // blit from user-created FBO to system framebuffer, with depth buffer. TEST_P(BlitFramebufferANGLETest, BlitWithDepth) { glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glDepthMask(GL_TRUE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glEnable(GL_DEPTH_TEST); drawQuad(mCheckerProgram, "position", 0.3f); 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(), 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 not draw, because it is behind the blitted one drawQuad(mBlueProgram, "position", 0.8f); glDisable(GL_DEPTH_TEST); EXPECT_PIXEL_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); } // blit from system FBO to user-created framebuffer, with depth buffer. TEST_P(BlitFramebufferANGLETest, ReverseBlitWithDepth) { glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glEnable(GL_DEPTH_TEST); drawQuad(mCheckerProgram, "position", 0.3f); EXPECT_GL_NO_ERROR(); glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mUserFBO); glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mOriginalFBO); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 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_DEPTH_BUFFER_BIT, GL_NEAREST); EXPECT_GL_NO_ERROR(); glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); // if blit is happening correctly, this quad will not draw, because it is behind the blitted one drawQuad(mBlueProgram, "position", 0.8f); glDisable(GL_DEPTH_TEST); EXPECT_PIXEL_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); } // blit from one region of the system fbo to another-- this should fail. TEST_P(BlitFramebufferANGLETest, BlitSameBufferOriginal) { glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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) { glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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) { glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 255, 255, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 255, 255, 255, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 255, 255, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); } TEST_P(BlitFramebufferANGLETest, BlitDifferentSizes) { glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_GL_NO_ERROR(); } TEST_P(BlitFramebufferANGLETest, BlitWithMissingAttachments) { glBindFramebuffer(GL_FRAMEBUFFER, mColorOnlyFBO); glClear(GL_COLOR_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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); // depth blit request should be silently ignored, because 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(); glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); EXPECT_PIXEL_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); // unlike in the depth blit tests, this *should* draw a blue quad, because depth info // has not been copied glEnable(GL_DEPTH_TEST); drawQuad(mBlueProgram, "position", 0.8f); glDisable(GL_DEPTH_TEST); EXPECT_PIXEL_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 0, 255, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 0, 255, 255); } TEST_P(BlitFramebufferANGLETest, BlitStencil) { // TODO(jmadill): Figure out if we can fix this on D3D9. // https://code.google.com/p/angleproject/issues/detail?id=809 if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE) { std::cout << "Test skipped on Intel D3D9." << std::endl; return; } glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glClear(GL_COLOR_BUFFER_BIT); // fill the stencil buffer with 0x1 glStencilFunc(GL_ALWAYS, 0x1, 0xFF); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); glEnable(GL_STENCIL_TEST); drawQuad(mCheckerProgram, "position", 0.3f); glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO); glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO); glClearColor(1.0, 1.0, 1.0, 1.0); glClearStencil(0x0); glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // depth blit request should be silently ignored, because the read FBO has no depth attachment 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_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); glStencilFunc(GL_EQUAL, 0x1, 0xFF); // only pass if stencil buffer at pixel reads 0x1 drawQuad(mBlueProgram, "position", 0.8f); // blue quad will draw if stencil buffer was copied glDisable(GL_STENCIL_TEST); EXPECT_PIXEL_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 0, 255, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 0, 255, 255); } // make sure that attempting to blit a partial depth buffer issues an error TEST_P(BlitFramebufferANGLETest, BlitPartialDepthStencil) { glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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) { if (!extensionEnabled("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, "position", 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_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); 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_EQ( getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255); EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 255, 0, 0, 255); EXPECT_PIXEL_EQ( getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mMRTColorBuffer0, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, mMRTColorBuffer1, 0); } // Make sure that attempts to stretch in a blit call issue an error TEST_P(BlitFramebufferANGLETest, ErrorStretching) { glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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) { glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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) { glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawQuad(mCheckerProgram, "position", 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); if (extensionEnabled("GL_ANGLE_framebuffer_multisample")) { glBindFramebuffer(GL_READ_FRAMEBUFFER, mBGRAMultisampledFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mRGBAFBO); EXPECT_GL_NO_ERROR(); 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/1289) class BlitFramebufferTest : public ANGLETest { protected: BlitFramebufferTest() { setWindowWidth(256); setWindowHeight(256); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); setConfigDepthBits(24); setConfigStencilBits(8); } }; // Tests resolving a multisample depth buffer. TEST_P(BlitFramebufferTest, MultisampleDepth) { // TODO(jmadill): Triage this driver bug. if (IsAMD() && IsD3D11()) { std::cout << "Test skipped on AMD D3D11." << std::endl; return; } GLRenderbuffer renderbuf; glBindRenderbuffer(GL_RENDERBUFFER, renderbuf.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 2, GL_DEPTH_COMPONENT24, 256, 256); const std::string &vertex = "#version 300 es\n" "in vec2 position;\n" "void main() {\n" " gl_Position = vec4(position, 0.0, 0.5);\n" "}"; const std::string &fragment = "#version 300 es\n" "out mediump vec4 red;\n" "void main() {\n" " red = vec4(1.0, 0.0, 0.0, 1.0);\n" " gl_FragDepth = 0.5;\n" "}"; ANGLE_GL_PROGRAM(drawRed, vertex, fragment); GLFramebuffer framebuffer; glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuf.get()); ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); glClearDepthf(0.5f); glClear(GL_DEPTH_BUFFER_BIT); GLRenderbuffer destRenderbuf; glBindRenderbuffer(GL_RENDERBUFFER, destRenderbuf.get()); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 256, 256); GLFramebuffer resolved; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolved.get()); glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, destRenderbuf.get()); glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer.get()); glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_DEPTH_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_FRAMEBUFFER, resolved.get()); GLTexture colorbuf; glBindTexture(GL_TEXTURE_2D, colorbuf.get()); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuf.get(), 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); // Draw with 0.5f test and the test should pass. glEnable(GL_DEPTH_TEST); glDepthFunc(GL_EQUAL); drawQuad(drawRed.get(), "position", 0.5f); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); ASSERT_GL_NO_ERROR(); } // Test resolving a multisampled stencil buffer. TEST_P(BlitFramebufferTest, MultisampleStencil) { GLRenderbuffer renderbuf; glBindRenderbuffer(GL_RENDERBUFFER, renderbuf.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 2, GL_STENCIL_INDEX8, 256, 256); const std::string &vertex = "#version 300 es\n" "in vec2 position;\n" "void main() {\n" " gl_Position = vec4(position, 0.0, 1.0);\n" "}"; const std::string &fragment = "#version 300 es\n" "out mediump vec4 red;\n" "void main() {\n" " red = vec4(1.0, 0.0, 0.0, 1.0);\n" "}"; ANGLE_GL_PROGRAM(drawRed, vertex, fragment); GLFramebuffer framebuffer; glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuf.get()); 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.get(), "position", 0.5f); GLTexture destColorbuf; glBindTexture(GL_TEXTURE_2D, destColorbuf.get()); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256); GLRenderbuffer destRenderbuf; glBindRenderbuffer(GL_RENDERBUFFER, destRenderbuf.get()); glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, 256, 256); GLFramebuffer resolved; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolved.get()); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destColorbuf.get(), 0); glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, destRenderbuf.get()); glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer.get()); glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_STENCIL_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_FRAMEBUFFER, resolved.get()); 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/resolve. glStencilFunc(GL_EQUAL, 0x1, 0xFF); drawQuad(drawRed.get(), "position", 0.5f); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); ASSERT_GL_NO_ERROR(); } // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. ANGLE_INSTANTIATE_TEST(BlitFramebufferANGLETest, ES2_D3D9(), ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE), ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE)); ANGLE_INSTANTIATE_TEST(BlitFramebufferTest, ES3_D3D11());