Vulkan: Depth/stencil scissored clears

- Generalize cmdClearAttachments to be able to clear
depth/stencil/color individually.
- The clear of the stencil part is implemented, but cant be tested
until stencil state support is implemented in the next commit.

Bug: angleproject:2427

Change-Id: Ib1fc7f66b2bd232761d374e217812605d3ff9152
Reviewed-on: https://chromium-review.googlesource.com/992874
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Luc Ferron <lucferron@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index 2d9fdb4..2ac151d 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -132,7 +132,18 @@
     bool clearStencil = (stencilAttachment && (mask & GL_STENCIL_BUFFER_BIT) != 0);
     ASSERT(!clearStencil || stencilAttachment->isAttached());
 
-    // Depth/stencil clear.
+    bool clearColor = IsMaskFlagSet(static_cast<int>(mask), GL_COLOR_BUFFER_BIT);
+
+    if (context->getGLState().isScissorTestEnabled())
+    {
+        // With scissor test enabled, we clear very differently and we don't need to access
+        // the image inside each attachment we can just use clearCmdAttachments with our
+        // scissor region instead.
+        ANGLE_TRY(clearAttachmentsWithScissorRegion(context, clearColor, clearDepth, clearStencil));
+        return gl::NoError();
+    }
+
+    // Standard Depth/stencil clear without scissor.
     if (clearDepth || clearStencil)
     {
         ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
@@ -157,21 +168,13 @@
         commandBuffer->clearSingleDepthStencilImage(renderTarget->image->getImage(), aspectFlags,
                                                     clearDepthStencilValue);
 
-        if ((mask & GL_COLOR_BUFFER_BIT) == 0)
+        if (!clearColor)
         {
             return gl::NoError();
         }
     }
 
-    if (context->getGLState().isScissorTestEnabled())
-    {
-        // With scissor test enabled, we clear very differently and we don't need to access
-        // the image inside each attachment we can just use clearCmdAttachments with our
-        // scissor region instead.
-        ANGLE_TRY(clearColorAttachmentsWithScissorRegion(context));
-        return gl::NoError();
-    }
-
+    ASSERT(clearColor);
     const auto *attachment = mState.getFirstNonNullAttachment();
     ASSERT(attachment && attachment->isAttached());
 
@@ -465,7 +468,10 @@
     return &mFramebuffer;
 }
 
-gl::Error FramebufferVk::clearColorAttachmentsWithScissorRegion(const gl::Context *context)
+gl::Error FramebufferVk::clearAttachmentsWithScissorRegion(const gl::Context *context,
+                                                           bool clearColor,
+                                                           bool clearDepth,
+                                                           bool clearStencil)
 {
     ContextVk *contextVk = vk::GetImpl(context);
     RendererVk *renderer = contextVk->getRenderer();
@@ -484,17 +490,52 @@
         ANGLE_TRY(node->beginInsideRenderPassRecording(renderer, &commandBuffer));
     }
 
-    const std::vector<gl::FramebufferAttachment> &colorAttachments = mState.getColorAttachments();
     gl::AttachmentArray<VkClearAttachment> clearAttachments;
     int clearAttachmentIndex = 0;
-    for (auto colorIndex : mState.getEnabledDrawBuffers())
+
+    if (clearColor)
     {
+        // TODO(jmadill): Support gaps in RenderTargets. http://anglebug.com/2394
+        for (size_t colorIndex : mState.getEnabledDrawBuffers())
+        {
+            VkClearAttachment &clearAttachment = clearAttachments[clearAttachmentIndex];
+            clearAttachment.aspectMask         = VK_IMAGE_ASPECT_COLOR_BIT;
+            clearAttachment.colorAttachment    = static_cast<uint32_t>(colorIndex);
+            clearAttachment.clearValue         = contextVk->getClearColorValue();
+            ++clearAttachmentIndex;
+        }
+    }
+
+    if (clearDepth && clearStencil && mState.getDepthStencilAttachment() != nullptr)
+    {
+        // When we have a packed depth/stencil attachment we can do 1 clear for both when it
+        // applies.
         VkClearAttachment &clearAttachment = clearAttachments[clearAttachmentIndex];
-        clearAttachment.aspectMask         = VK_IMAGE_ASPECT_COLOR_BIT;
-        clearAttachment.colorAttachment    = static_cast<uint32_t>(colorIndex);
-        clearAttachment.clearValue         = contextVk->getClearColorValue();
+        clearAttachment.aspectMask      = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+        clearAttachment.colorAttachment = VK_ATTACHMENT_UNUSED;
+        clearAttachment.clearValue      = contextVk->getClearDepthStencilValue();
         ++clearAttachmentIndex;
     }
+    else
+    {
+        if (clearDepth)
+        {
+            VkClearAttachment &clearAttachment = clearAttachments[clearAttachmentIndex];
+            clearAttachment.aspectMask         = VK_IMAGE_ASPECT_DEPTH_BIT;
+            clearAttachment.colorAttachment    = VK_ATTACHMENT_UNUSED;
+            clearAttachment.clearValue         = contextVk->getClearDepthStencilValue();
+            ++clearAttachmentIndex;
+        }
+
+        if (clearStencil)
+        {
+            VkClearAttachment &clearAttachment = clearAttachments[clearAttachmentIndex];
+            clearAttachment.aspectMask         = VK_IMAGE_ASPECT_STENCIL_BIT;
+            clearAttachment.colorAttachment    = VK_ATTACHMENT_UNUSED;
+            clearAttachment.clearValue         = contextVk->getClearDepthStencilValue();
+            ++clearAttachmentIndex;
+        }
+    }
 
     // We assume for now that we always need to clear only 1 layer starting at the
     // baseArrayLayer 0, this might need to change depending how we'll implement
@@ -504,7 +545,7 @@
     clearRect.layerCount     = 1;
     clearRect.rect           = contextVk->getScissor();
 
-    commandBuffer->clearAttachments(static_cast<uint32_t>(colorAttachments.size()),
+    commandBuffer->clearAttachments(static_cast<uint32_t>(clearAttachmentIndex),
                                     clearAttachments.data(), 1, &clearRect);
     return gl::NoError();
 }