summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/tests/gl_tests/BlitFramebufferANGLETest.cpp')
-rwxr-xr-xgfx/angle/src/tests/gl_tests/BlitFramebufferANGLETest.cpp1070
1 files changed, 1070 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/gl_tests/BlitFramebufferANGLETest.cpp b/gfx/angle/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
new file mode 100755
index 000000000..e40a411db
--- /dev/null
+++ b/gfx/angle/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
@@ -0,0 +1,1070 @@
+//
+// 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()); \ No newline at end of file