Added BlitFramebufferANGLE tests.
TRAC #23776
Signed-off-by: Jamie Madill
Signed-off-by: Shannon Woods
diff --git a/tests/angle_tests/BlitFramebufferANGLETest.cpp b/tests/angle_tests/BlitFramebufferANGLETest.cpp
new file mode 100644
index 0000000..cce73cc
--- /dev/null
+++ b/tests/angle_tests/BlitFramebufferANGLETest.cpp
@@ -0,0 +1,802 @@
+#include "ANGLETest.h"
+
+class BlitFramebufferANGLETest : public ANGLETest
+{
+protected:
+ BlitFramebufferANGLETest()
+ {
+ setWindowWidth(256);
+ setWindowHeight(256);
+ setRedBits(8);
+ setGreenBits(8);
+ setBlueBits(8);
+ setAlphaBits(8);
+ setDepthBits(24);
+
+ 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;
+ }
+
+ 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_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
+ 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_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
+ 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_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
+ 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_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
+ 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_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
+ 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_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
+ ASSERT_GL_NO_ERROR();
+ }
+
+ 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);
+ }
+
+ 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;
+};
+
+// Draw to user-created framebuffer, blit whole-buffer color to original framebuffer.
+TEST_F(BlitFramebufferANGLETest, blit_color_to_default)
+{
+ 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_F(BlitFramebufferANGLETest, reverse_color_blit)
+{
+ 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_F(BlitFramebufferANGLETest, scissored_blit)
+{
+ 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_F(BlitFramebufferANGLETest, reverse_scissored_blit)
+{
+ 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_F(BlitFramebufferANGLETest, oversized_blit)
+{
+ 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_F(BlitFramebufferANGLETest, reverse_oversized_blit)
+{
+ 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_F(BlitFramebufferANGLETest, blit_with_depth)
+{
+ 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_F(BlitFramebufferANGLETest, reverse_blit_with_depth)
+{
+ 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_F(BlitFramebufferANGLETest, blit_same_buffer_original)
+{
+ 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_F(BlitFramebufferANGLETest, blit_same_buffer_user)
+{
+ 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_F(BlitFramebufferANGLETest, blit_partial_color)
+{
+ 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_F(BlitFramebufferANGLETest, blit_different_sizes)
+{
+ 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_F(BlitFramebufferANGLETest, blit_with_missing_attachments)
+{
+ 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_F(BlitFramebufferANGLETest, blit_stencil)
+{
+ 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_F(BlitFramebufferANGLETest, blit_partial_depth_stencil)
+{
+ 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_F(BlitFramebufferANGLETest, blit_mrt)
+{
+ 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_F(BlitFramebufferANGLETest, error_stretching)
+{
+ 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_F(BlitFramebufferANGLETest, error_flipping)
+{
+ 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_F(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);
+}