Vulkan/D3D11: Improve blit framebuffer tests and fix bug in D3D11

- Improving the tests revealed a bug in D3D 11 Fast Path rendering.
- These changes here are preliminary to implementing the blit for
depth/stencil in Vulkan when using the viewport flipping.

Bug: angleproject:2673
Bug: angleproject:2719
Change-Id: I6d55084e559d3110c8eeb0e7acb4e6fb09b6c1b5
Reviewed-on: https://chromium-review.googlesource.com/1132125
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Luc Ferron <lucferron@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp
index f6c1242..d7f4f6f 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp
@@ -330,21 +330,37 @@
     {
         const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer();
         ASSERT(readBuffer);
-
         RenderTargetD3D *readRenderTarget = nullptr;
         ANGLE_TRY(readBuffer->getRenderTarget(context, &readRenderTarget));
         ASSERT(readRenderTarget);
 
+        const bool invertSource        = UsePresentPathFast(mRenderer, readBuffer);
+        gl::Rectangle actualSourceArea = sourceArea;
+        if (invertSource)
+        {
+            RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget);
+            actualSourceArea.y                 = readRenderTarget11->getHeight() - sourceArea.y;
+            actualSourceArea.height            = -sourceArea.height;
+        }
+
         const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment();
         ASSERT(drawBuffer);
-
         RenderTargetD3D *drawRenderTarget = nullptr;
         ANGLE_TRY(drawBuffer->getRenderTarget(context, &drawRenderTarget));
         ASSERT(drawRenderTarget);
 
-        ANGLE_TRY(mRenderer->blitRenderbufferRect(context, sourceArea, destArea, readRenderTarget,
-                                                  drawRenderTarget, filter, scissor, false,
-                                                  blitDepth, blitStencil));
+        bool invertDest              = UsePresentPathFast(mRenderer, drawBuffer);
+        gl::Rectangle actualDestArea = destArea;
+        if (invertDest)
+        {
+            RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
+            actualDestArea.y                   = drawRenderTarget11->getHeight() - destArea.y;
+            actualDestArea.height              = -destArea.height;
+        }
+
+        ANGLE_TRY(mRenderer->blitRenderbufferRect(context, actualSourceArea, actualDestArea,
+                                                  readRenderTarget, drawRenderTarget, filter,
+                                                  scissor, false, blitDepth, blitStencil));
     }
 
     ANGLE_TRY(markAttachmentsDirty(context));
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index 85ef146..89f22c3 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -485,6 +485,7 @@
         {
             if (flipSource || contextVk->isViewportFlipEnabledForReadFBO())
             {
+                // TODO(lucferron): Implement this http://anglebug.com/2673
                 // The tests in BlitFramebufferANGLETest are passing, but they are wrong since they
                 // use a single color for the depth / stencil buffers, it looks like its working,
                 // but if it was a gradient or a checked board, you would realize the flip isn't
diff --git a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
index 14a3535..79b8491 100644
--- a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
+++ b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
@@ -25,6 +25,7 @@
 
         mCheckerProgram = 0;
         mBlueProgram = 0;
+        mRedProgram     = 0;
 
         mOriginalFBO = 0;
 
@@ -67,7 +68,8 @@
         mCheckerProgram =
             CompileProgram(essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Checkered());
         mBlueProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
-        if (mCheckerProgram == 0 || mBlueProgram == 0)
+        mRedProgram  = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
+        if (mCheckerProgram == 0 || mBlueProgram == 0 || mRedProgram == 0)
         {
             FAIL() << "shader compilation failed.";
         }
@@ -236,6 +238,7 @@
     {
         glDeleteProgram(mCheckerProgram);
         glDeleteProgram(mBlueProgram);
+        glDeleteProgram(mRedProgram);
 
         glDeleteFramebuffers(1, &mUserFBO);
         glDeleteTextures(1, &mUserColorBuffer);
@@ -337,6 +340,7 @@
 
     GLuint mCheckerProgram;
     GLuint mBlueProgram;
+    GLuint mRedProgram;
 
     GLuint mOriginalFBO;
 
@@ -568,12 +572,8 @@
 }
 
 // blit from user-created FBO to system framebuffer, with depth buffer.
-TEST_P(BlitFramebufferANGLETest, BlitWithDepth)
+TEST_P(BlitFramebufferANGLETest, BlitWithDepthUserToDefault)
 {
-    // TODO(lucferron): Fix this test and the implementation.
-    // http://anglebug.com/2673
-    ANGLE_SKIP_TEST_IF(IsVulkan());
-
     ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_ANGLE_framebuffer_blit"));
 
     glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO);
@@ -583,74 +583,96 @@
 
     glEnable(GL_DEPTH_TEST);
 
-    drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.3f);
-
     EXPECT_GL_NO_ERROR();
 
+    // Clear the first half of the screen
+    glEnable(GL_SCISSOR_TEST);
+    glScissor(0, 0, getWindowWidth(), getWindowHeight() / 2);
+
+    glClearDepthf(0.1f);
+    glClearColor(1.0, 0.0, 0.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    // Scissor the second half of the screen
+    glScissor(0, getWindowHeight() / 2, getWindowWidth(), getWindowHeight() / 2);
+
+    glClearDepthf(0.9f);
+    glClearColor(0.0, 1.0, 0.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glDisable(GL_SCISSOR_TEST);
+
     glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO);
     glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO);
 
-    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, essl1_shaders::PositionAttrib(), 0.8f);
+    // if blit is happening correctly, this quad will draw only on the bottom half since it will be
+    // behind on the first half and in front on the second half.
+    drawQuad(mBlueProgram, essl1_shaders::PositionAttrib(), 0.5f);
 
     glDisable(GL_DEPTH_TEST);
 
-    EXPECT_PIXEL_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);
+    EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255);
+    EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 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);
 }
 
 // blit from system FBO to user-created framebuffer, with depth buffer.
-TEST_P(BlitFramebufferANGLETest, ReverseBlitWithDepth)
+TEST_P(BlitFramebufferANGLETest, BlitWithDepthDefaultToUser)
 {
-    // TODO(lucferron): Fix this test and the implementation.
-    // http://anglebug.com/2673
-    ANGLE_SKIP_TEST_IF(IsVulkan());
-
     ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_ANGLE_framebuffer_blit"));
 
     glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO);
 
+    glDepthMask(GL_TRUE);
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 
     glEnable(GL_DEPTH_TEST);
 
-    drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.3f);
-
     EXPECT_GL_NO_ERROR();
 
+    // Clear the first half of the screen
+    glEnable(GL_SCISSOR_TEST);
+    glScissor(0, 0, getWindowWidth(), getWindowHeight() / 2);
+
+    glClearDepthf(0.1f);
+    glClearColor(1.0, 0.0, 0.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    // Scissor the second half of the screen
+    glScissor(0, getWindowHeight() / 2, getWindowWidth(), getWindowHeight() / 2);
+
+    glClearDepthf(0.9f);
+    glClearColor(0.0, 1.0, 0.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glDisable(GL_SCISSOR_TEST);
+
     glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mUserFBO);
     glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mOriginalFBO);
 
-    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, essl1_shaders::PositionAttrib(), 0.8f);
+    // if blit is happening correctly, this quad will draw only on the bottom half since it will be
+    // behind on the first half and in front on the second half.
+    drawQuad(mBlueProgram, essl1_shaders::PositionAttrib(), 0.5f);
 
     glDisable(GL_DEPTH_TEST);
 
-    EXPECT_PIXEL_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);
+    EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255);
+    EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 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);
 }
 
 // blit from one region of the system fbo to another-- this should fail.
@@ -789,10 +811,6 @@
 
 TEST_P(BlitFramebufferANGLETest, BlitStencil)
 {
-    // TODO(lucferron): Fix this test and the implementation.
-    // http://anglebug.com/2673
-    ANGLE_SKIP_TEST_IF(IsVulkan());
-
     ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_ANGLE_framebuffer_blit"));
 
     // TODO(jmadill): Figure out if we can fix this on D3D9.
@@ -804,16 +822,27 @@
 
     glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO);
 
-    glClear(GL_COLOR_BUFFER_BIT);
+    glClearColor(0.0, 1.0, 0.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+    glClearStencil(0x0);
+
+    // Scissor half the screen so we fill the stencil only halfway
+    glScissor(0, 0, getWindowWidth(), getWindowHeight() / 2);
+    glEnable(GL_SCISSOR_TEST);
+
     // fill the stencil buffer with 0x1
     glStencilFunc(GL_ALWAYS, 0x1, 0xFF);
     glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
     glEnable(GL_STENCIL_TEST);
-    drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.3f);
+    drawQuad(mRedProgram, essl1_shaders::PositionAttrib(), 0.3f);
+
+    glDisable(GL_SCISSOR_TEST);
 
     glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO);
     glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO);
 
+    // These clears are not useful in theory because we're copying over them, but its
+    // helpful in debugging if we see white in any result.
     glClearColor(1.0, 1.0, 1.0, 1.0);
     glClearStencil(0x0);
     glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
@@ -827,19 +856,21 @@
     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(3 * getWindowWidth() / 4, getWindowHeight() / 4, 255, 0, 0, 255);
+    EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255);
     EXPECT_PIXEL_EQ(    getWindowWidth() / 4, 3 * getWindowHeight() / 4,   0, 255,   0, 255);
 
     glStencilFunc(GL_EQUAL, 0x1, 0xFF); // only pass if stencil buffer at pixel reads 0x1
+
     drawQuad(mBlueProgram, essl1_shaders::PositionAttrib(),
              0.8f);  // blue quad will draw if stencil buffer was copied
+
     glDisable(GL_STENCIL_TEST);
 
     EXPECT_PIXEL_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);
+    EXPECT_PIXEL_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255);
+    EXPECT_PIXEL_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 255, 0, 255);
 }
 
 // make sure that attempting to blit a partial depth buffer issues an error