Vulkan: Mask the alpha channel for draw when needed

When the angleFormat we have has no alpha channel, but the actual
texture underneath has one, we shouldn't be drawing over the alpha
channel, so we apply a mask on it when we're in this situation.

Bug: angleproject:2597
Change-Id: Ia7110709e6ee32bb61988d08f5049e4e80e7e24e
Reviewed-on: https://chromium-review.googlesource.com/1106759
Commit-Queue: Luc Ferron <lucferron@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index 59e6662..c22b2f9 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -203,11 +203,21 @@
     const VkClearColorValue &clearColorValue = contextVk->getClearColorValue().color;
     for (size_t colorIndex : mState.getEnabledDrawBuffers())
     {
+        VkClearColorValue modifiedClearColorValue = clearColorValue;
         RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndex];
+
+        // Its possible we're clearing a render target that has no alpha channel but we represent it
+        // with a texture that has one. We must not affect its alpha channel no matter what the
+        // clear value is in that case.
+        if (mEmulatedAlphaAttachmentMask[colorIndex])
+        {
+            modifiedClearColorValue.float32[3] = 1.0;
+        }
+
         ASSERT(colorRenderTarget);
         vk::ImageHelper *image = colorRenderTarget->getImageForWrite(currentSerial, this);
         GLint mipLevelToClear  = (attachment->type() == GL_TEXTURE) ? attachment->mipLevel() : 0;
-        image->clearColor(clearColorValue, mipLevelToClear, 1, commandBuffer);
+        image->clearColor(modifiedClearColorValue, mipLevelToClear, 1, commandBuffer);
     }
 
     return gl::NoError();
@@ -369,9 +379,19 @@
                 RenderTargetVk *renderTarget = mRenderTargetCache.getColors()[colorIndex];
                 if (renderTarget)
                 {
-                    const angle::Format &format = renderTarget->getImageFormat().textureFormat();
-                    updateActiveColorMasks(colorIndex, format.redBits > 0, format.greenBits > 0,
-                                           format.blueBits > 0, format.alphaBits > 0);
+                    const angle::Format &emulatedFormat =
+                        renderTarget->getImageFormat().textureFormat();
+                    updateActiveColorMasks(
+                        colorIndex, emulatedFormat.redBits > 0, emulatedFormat.greenBits > 0,
+                        emulatedFormat.blueBits > 0, emulatedFormat.alphaBits > 0);
+
+                    // TODO(lucferron): Add a test to trigger edge case where the framebuffer
+                    // attachment would change but not the binding.
+                    // http://anglebug.com/2597
+                    const angle::Format &sourceFormat =
+                        renderTarget->getImageFormat().angleFormat();
+                    mEmulatedAlphaAttachmentMask.set(
+                        colorIndex, sourceFormat.alphaBits == 0 && emulatedFormat.alphaBits > 0);
                 }
                 else
                 {
@@ -383,8 +403,8 @@
     }
 
     mActiveColorComponents = gl_vk::GetColorComponentFlags(
-        mActiveColorComponentMasks[0].any(), mActiveColorComponentMasks[1].any(),
-        mActiveColorComponentMasks[2].any(), mActiveColorComponentMasks[3].any());
+        mActiveColorComponentMasksForClear[0].any(), mActiveColorComponentMasksForClear[1].any(),
+        mActiveColorComponentMasksForClear[2].any(), mActiveColorComponentMasksForClear[3].any());
 
     mRenderPassDesc.reset();
     renderer->releaseObject(getStoredQueueSerial(), &mFramebuffer);
@@ -626,7 +646,7 @@
     // This pipeline desc could be cached.
     vk::PipelineDesc pipelineDesc;
     pipelineDesc.initDefaults();
-    pipelineDesc.updateColorWriteMask(colorMaskFlags);
+    pipelineDesc.updateColorWriteMask(colorMaskFlags, getEmulatedAlphaAttachmentMask());
     pipelineDesc.updateRenderPassDesc(getRenderPassDesc());
     pipelineDesc.updateShaders(fullScreenQuad->queueSerial(), pushConstantColor->queueSerial());
     pipelineDesc.updateViewport(renderArea, 0.0f, 1.0f);
@@ -740,10 +760,15 @@
 
 void FramebufferVk::updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a)
 {
-    mActiveColorComponentMasks[0].set(colorIndex, r);
-    mActiveColorComponentMasks[1].set(colorIndex, g);
-    mActiveColorComponentMasks[2].set(colorIndex, b);
-    mActiveColorComponentMasks[3].set(colorIndex, a);
+    mActiveColorComponentMasksForClear[0].set(colorIndex, r);
+    mActiveColorComponentMasksForClear[1].set(colorIndex, g);
+    mActiveColorComponentMasksForClear[2].set(colorIndex, b);
+    mActiveColorComponentMasksForClear[3].set(colorIndex, a);
+}
+
+gl::DrawBufferMask FramebufferVk::getEmulatedAlphaAttachmentMask()
+{
+    return mEmulatedAlphaAttachmentMask;
 }
 
 gl::Error FramebufferVk::readPixelsImpl(const gl::Context *context,