Vulkan: Implement scissored clears.

Bug: angleproject:2356

Change-Id: I33888f9b4ebaf4b0b5af4ad59b12ad963325a790
Reviewed-on: https://chromium-review.googlesource.com/921882
Commit-Queue: Luc Ferron <lucferron@chromium.org>
Reviewed-by: Jamie Madill <jmadill@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 8d22dbf..72167da 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -136,7 +136,15 @@
         return gl::NoError();
     }
 
-    // TODO(jmadill): Scissored clears.
+    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();
+    }
+
     const auto *attachment = mState.getFirstNonNullAttachment();
     ASSERT(attachment && attachment->isAttached());
     const auto &size = attachment->getSize();
@@ -461,6 +469,50 @@
     return &mFramebuffer;
 }
 
+gl::Error FramebufferVk::clearColorAttachmentsWithScissorRegion(const gl::Context *context)
+{
+    ContextVk *contextVk = vk::GetImpl(context);
+    RendererVk *renderer = contextVk->getRenderer();
+
+    // This command can only happen inside a render pass, so obtain one if its already happening
+    // or create a new one if not.
+    vk::CommandGraphNode *node       = nullptr;
+    vk::CommandBuffer *commandBuffer = nullptr;
+    ANGLE_TRY(getCommandGraphNodeForDraw(context, &node));
+    if (node->getInsideRenderPassCommands()->valid())
+    {
+        commandBuffer = node->getInsideRenderPassCommands();
+    }
+    else
+    {
+        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())
+    {
+        VkClearAttachment &clearAttachment = clearAttachments[clearAttachmentIndex];
+        clearAttachment.aspectMask         = VK_IMAGE_ASPECT_COLOR_BIT;
+        clearAttachment.colorAttachment    = static_cast<uint32_t>(colorIndex);
+        clearAttachment.clearValue         = contextVk->getClearColorValue();
+        ++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
+    // cube maps, 3d textures and array textures.
+    VkClearRect clearRect;
+    clearRect.baseArrayLayer = 0;
+    clearRect.layerCount     = 1;
+    clearRect.rect           = contextVk->getScissor();
+
+    commandBuffer->clearAttachments(static_cast<uint32_t>(colorAttachments.size()),
+                                    clearAttachments.data(), 1, &clearRect);
+    return gl::NoError();
+}
+
 gl::Error FramebufferVk::getSamplePosition(size_t index, GLfloat *xy) const
 {
     UNIMPLEMENTED();