Subclass GrVkCommandBuffer into Primary and Secondary CommandBuffers.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2019723002

Review-Url: https://codereview.chromium.org/2019723002
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index bc8c20f..9604355 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -16,24 +16,6 @@
 #include "GrVkTransferBuffer.h"
 #include "GrVkUtil.h"
 
-GrVkCommandBuffer* GrVkCommandBuffer::Create(const GrVkGpu* gpu, VkCommandPool cmdPool) {
-    const VkCommandBufferAllocateInfo cmdInfo = {
-        VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,   // sType
-        NULL,                                             // pNext
-        cmdPool,                                          // commandPool
-        VK_COMMAND_BUFFER_LEVEL_PRIMARY,                  // level
-        1                                                 // bufferCount
-    };
-
-    VkCommandBuffer cmdBuffer;
-    VkResult err = GR_VK_CALL(gpu->vkInterface(), AllocateCommandBuffers(gpu->device(),
-                                                                         &cmdInfo,
-                                                                         &cmdBuffer));
-    if (err) {
-        return nullptr;
-    }
-    return new GrVkCommandBuffer(cmdBuffer);
-}
 
 GrVkCommandBuffer::~GrVkCommandBuffer() {
     // Should have ended any render pass we're in the middle of
@@ -79,112 +61,6 @@
     }
 }
 
-void GrVkCommandBuffer::begin(const GrVkGpu* gpu) {
-    SkASSERT(!fIsActive);
-    VkCommandBufferBeginInfo cmdBufferBeginInfo;
-    memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
-    cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-    cmdBufferBeginInfo.pNext = nullptr;
-    cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
-    cmdBufferBeginInfo.pInheritanceInfo = nullptr;
-
-    GR_VK_CALL_ERRCHECK(gpu->vkInterface(), BeginCommandBuffer(fCmdBuffer,
-                                                               &cmdBufferBeginInfo));
-    fIsActive = true;
-}
-
-void GrVkCommandBuffer::end(const GrVkGpu* gpu) {
-    SkASSERT(fIsActive);
-    SkASSERT(!fActiveRenderPass);
-    GR_VK_CALL_ERRCHECK(gpu->vkInterface(), EndCommandBuffer(fCmdBuffer));
-    this->invalidateState();
-    fIsActive = false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-void GrVkCommandBuffer::beginRenderPass(const GrVkGpu* gpu,
-                                        const GrVkRenderPass* renderPass,
-                                        const GrVkRenderTarget& target) {
-    SkASSERT(fIsActive);
-    SkASSERT(!fActiveRenderPass);
-    VkRenderPassBeginInfo beginInfo;
-    VkSubpassContents contents;
-    renderPass->getBeginInfo(target, &beginInfo, &contents);
-    GR_VK_CALL(gpu->vkInterface(), CmdBeginRenderPass(fCmdBuffer, &beginInfo, contents));
-    fActiveRenderPass = renderPass;
-    this->addResource(renderPass);
-    target.addResources(*this);
-}
-
-void GrVkCommandBuffer::endRenderPass(const GrVkGpu* gpu) {
-    SkASSERT(fIsActive);
-    SkASSERT(fActiveRenderPass);
-    GR_VK_CALL(gpu->vkInterface(), CmdEndRenderPass(fCmdBuffer));
-    fActiveRenderPass = nullptr;
-}
-
-void GrVkCommandBuffer::submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync) {
-    SkASSERT(!fIsActive);
-
-    VkResult err;
-    VkFenceCreateInfo fenceInfo;
-    memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
-    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
-    err = GR_VK_CALL(gpu->vkInterface(), CreateFence(gpu->device(), &fenceInfo, nullptr,
-                                                     &fSubmitFence));
-    SkASSERT(!err);
-
-    VkSubmitInfo submitInfo;
-    memset(&submitInfo, 0, sizeof(VkSubmitInfo));
-    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-    submitInfo.pNext = nullptr;
-    submitInfo.waitSemaphoreCount = 0;
-    submitInfo.pWaitSemaphores = nullptr;
-    submitInfo.pWaitDstStageMask = 0;
-    submitInfo.commandBufferCount = 1;
-    submitInfo.pCommandBuffers = &fCmdBuffer;
-    submitInfo.signalSemaphoreCount = 0;
-    submitInfo.pSignalSemaphores = nullptr;
-    GR_VK_CALL_ERRCHECK(gpu->vkInterface(), QueueSubmit(queue, 1, &submitInfo, fSubmitFence));
-
-    if (GrVkGpu::kForce_SyncQueue == sync) {
-        err = GR_VK_CALL(gpu->vkInterface(),
-                         WaitForFences(gpu->device(), 1, &fSubmitFence, true, UINT64_MAX));
-        if (VK_TIMEOUT == err) {
-            SkDebugf("Fence failed to signal: %d\n", err);
-            SkFAIL("failing");
-        }
-        SkASSERT(!err);
-
-        // Destroy the fence
-        GR_VK_CALL(gpu->vkInterface(), DestroyFence(gpu->device(), fSubmitFence, nullptr));
-        fSubmitFence = VK_NULL_HANDLE;
-    }
-}
-
-bool GrVkCommandBuffer::finished(const GrVkGpu* gpu) const {
-    if (VK_NULL_HANDLE == fSubmitFence) {
-        return true;
-    }
-
-    VkResult err = GR_VK_CALL(gpu->vkInterface(), GetFenceStatus(gpu->device(), fSubmitFence));
-    switch (err) {
-        case VK_SUCCESS:
-            return true;
-
-        case VK_NOT_READY:
-            return false;
-
-        default:
-            SkDebugf("Error getting fence status: %d\n", err);
-            SkFAIL("failing");
-            break;
-    }
-
-    return false;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // CommandBuffer commands
 ////////////////////////////////////////////////////////////////////////////////
@@ -239,118 +115,6 @@
 
 }
 
-void GrVkCommandBuffer::copyImage(const GrVkGpu* gpu,
-                                  GrVkImage* srcImage,
-                                  VkImageLayout srcLayout,
-                                  GrVkImage* dstImage,
-                                  VkImageLayout dstLayout,
-                                  uint32_t copyRegionCount,
-                                  const VkImageCopy* copyRegions) {
-    SkASSERT(fIsActive);
-    SkASSERT(!fActiveRenderPass);
-    this->addResource(srcImage->resource());
-    this->addResource(dstImage->resource());
-    GR_VK_CALL(gpu->vkInterface(), CmdCopyImage(fCmdBuffer,
-                                                srcImage->image(),
-                                                srcLayout,
-                                                dstImage->image(),
-                                                dstLayout,
-                                                copyRegionCount,
-                                                copyRegions));
-}
-
-void GrVkCommandBuffer::blitImage(const GrVkGpu* gpu,
-                                  const GrVkResource* srcResource,
-                                  VkImage srcImage,
-                                  VkImageLayout srcLayout,
-                                  const GrVkResource* dstResource,
-                                  VkImage dstImage,
-                                  VkImageLayout dstLayout,
-                                  uint32_t blitRegionCount,
-                                  const VkImageBlit* blitRegions,
-                                  VkFilter filter) {
-    SkASSERT(fIsActive);
-    SkASSERT(!fActiveRenderPass);
-    this->addResource(srcResource);
-    this->addResource(dstResource);
-    GR_VK_CALL(gpu->vkInterface(), CmdBlitImage(fCmdBuffer,
-                                                srcImage,
-                                                srcLayout,
-                                                dstImage,
-                                                dstLayout,
-                                                blitRegionCount,
-                                                blitRegions,
-                                                filter));
-}
-
-void GrVkCommandBuffer::copyImageToBuffer(const GrVkGpu* gpu,
-                                          GrVkImage* srcImage,
-                                          VkImageLayout srcLayout,
-                                          GrVkTransferBuffer* dstBuffer,
-                                          uint32_t copyRegionCount,
-                                          const VkBufferImageCopy* copyRegions) {
-    SkASSERT(fIsActive);
-    SkASSERT(!fActiveRenderPass);
-    this->addResource(srcImage->resource());
-    this->addResource(dstBuffer->resource());
-    GR_VK_CALL(gpu->vkInterface(), CmdCopyImageToBuffer(fCmdBuffer,
-                                                        srcImage->image(),
-                                                        srcLayout,
-                                                        dstBuffer->buffer(),
-                                                        copyRegionCount,
-                                                        copyRegions));
-}
-
-void GrVkCommandBuffer::copyBufferToImage(const GrVkGpu* gpu,
-                                          GrVkTransferBuffer* srcBuffer,
-                                          GrVkImage* dstImage,
-                                          VkImageLayout dstLayout,
-                                          uint32_t copyRegionCount,
-                                          const VkBufferImageCopy* copyRegions) {
-    SkASSERT(fIsActive);
-    SkASSERT(!fActiveRenderPass);
-    this->addResource(srcBuffer->resource());
-    this->addResource(dstImage->resource());
-    GR_VK_CALL(gpu->vkInterface(), CmdCopyBufferToImage(fCmdBuffer,
-                                                        srcBuffer->buffer(),
-                                                        dstImage->image(),
-                                                        dstLayout,
-                                                        copyRegionCount,
-                                                        copyRegions));
-}
-
-void GrVkCommandBuffer::clearColorImage(const GrVkGpu* gpu,
-                                        GrVkImage* image,
-                                        const VkClearColorValue* color,
-                                        uint32_t subRangeCount,
-                                        const VkImageSubresourceRange* subRanges) {
-    SkASSERT(fIsActive);
-    SkASSERT(!fActiveRenderPass);
-    this->addResource(image->resource());
-    GR_VK_CALL(gpu->vkInterface(), CmdClearColorImage(fCmdBuffer,
-                                                      image->image(),
-                                                      image->currentLayout(),
-                                                      color,
-                                                      subRangeCount,
-                                                      subRanges));
-}
-
-void GrVkCommandBuffer::clearDepthStencilImage(const GrVkGpu* gpu,
-                                               GrVkImage* image,
-                                               const VkClearDepthStencilValue* color,
-                                               uint32_t subRangeCount,
-                                               const VkImageSubresourceRange* subRanges) {
-    SkASSERT(fIsActive);
-    SkASSERT(!fActiveRenderPass);
-    this->addResource(image->resource());
-    GR_VK_CALL(gpu->vkInterface(), CmdClearDepthStencilImage(fCmdBuffer,
-                                                             image->image(),
-                                                             image->currentLayout(),
-                                                             color,
-                                                             subRangeCount,
-                                                             subRanges));
-}
-
 void GrVkCommandBuffer::clearAttachments(const GrVkGpu* gpu,
                                          int numAttachments,
                                          const VkClearAttachment* attachments,
@@ -472,3 +236,317 @@
         memcpy(fCachedBlendConstant, blendConstants, 4 * sizeof(float));
     }
 }
+
+///////////////////////////////////////////////////////////////////////////////
+// PrimaryCommandBuffer
+////////////////////////////////////////////////////////////////////////////////
+GrVkPrimaryCommandBuffer* GrVkPrimaryCommandBuffer::Create(const GrVkGpu* gpu,
+                                                           VkCommandPool cmdPool) {
+    const VkCommandBufferAllocateInfo cmdInfo = {
+        VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,   // sType
+        NULL,                                             // pNext
+        cmdPool,                                          // commandPool
+        VK_COMMAND_BUFFER_LEVEL_PRIMARY,                  // level
+        1                                                 // bufferCount
+    };
+
+    VkCommandBuffer cmdBuffer;
+    VkResult err = GR_VK_CALL(gpu->vkInterface(), AllocateCommandBuffers(gpu->device(),
+                                                                         &cmdInfo,
+                                                                         &cmdBuffer));
+    if (err) {
+        return nullptr;
+    }
+    return new GrVkPrimaryCommandBuffer(cmdBuffer);
+}
+
+void GrVkPrimaryCommandBuffer::begin(const GrVkGpu* gpu) {
+    SkASSERT(!fIsActive);
+    VkCommandBufferBeginInfo cmdBufferBeginInfo;
+    memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
+    cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    cmdBufferBeginInfo.pNext = nullptr;
+    cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+    cmdBufferBeginInfo.pInheritanceInfo = nullptr;
+
+    GR_VK_CALL_ERRCHECK(gpu->vkInterface(), BeginCommandBuffer(fCmdBuffer,
+                                                               &cmdBufferBeginInfo));
+    fIsActive = true;
+}
+
+void GrVkPrimaryCommandBuffer::end(const GrVkGpu* gpu) {
+    SkASSERT(fIsActive);
+    SkASSERT(!fActiveRenderPass);
+    GR_VK_CALL_ERRCHECK(gpu->vkInterface(), EndCommandBuffer(fCmdBuffer));
+    this->invalidateState();
+    fIsActive = false;
+}
+
+void GrVkPrimaryCommandBuffer::beginRenderPass(const GrVkGpu* gpu,
+                                        const GrVkRenderPass* renderPass,
+                                        const GrVkRenderTarget& target) {
+    SkASSERT(fIsActive);
+    SkASSERT(!fActiveRenderPass);
+    VkRenderPassBeginInfo beginInfo;
+    VkSubpassContents contents;
+    renderPass->getBeginInfo(target, &beginInfo, &contents);
+    GR_VK_CALL(gpu->vkInterface(), CmdBeginRenderPass(fCmdBuffer, &beginInfo, contents));
+    fActiveRenderPass = renderPass;
+    this->addResource(renderPass);
+    target.addResources(*this);
+}
+
+void GrVkPrimaryCommandBuffer::endRenderPass(const GrVkGpu* gpu) {
+    SkASSERT(fIsActive);
+    SkASSERT(fActiveRenderPass);
+    GR_VK_CALL(gpu->vkInterface(), CmdEndRenderPass(fCmdBuffer));
+    fActiveRenderPass = nullptr;
+}
+
+void GrVkPrimaryCommandBuffer::executeCommands(const GrVkGpu* gpu,
+                                               const GrVkSecondaryCommandBuffer* buffer) {
+    SkASSERT(fIsActive);
+    SkASSERT(fActiveRenderPass);
+    SkASSERT(fActiveRenderPass->isCompatible(*buffer->fActiveRenderPass));
+
+    GR_VK_CALL(gpu->vkInterface(), CmdExecuteCommands(fCmdBuffer, 1, &buffer->fCmdBuffer));
+    this->addResource(buffer);
+}
+
+void GrVkPrimaryCommandBuffer::submitToQueue(const GrVkGpu* gpu,
+                                             VkQueue queue,
+                                             GrVkGpu::SyncQueue sync) {
+    SkASSERT(!fIsActive);
+
+    VkResult err;
+    VkFenceCreateInfo fenceInfo;
+    memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
+    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+    err = GR_VK_CALL(gpu->vkInterface(), CreateFence(gpu->device(), &fenceInfo, nullptr,
+                                                     &fSubmitFence));
+    SkASSERT(!err);
+
+    VkSubmitInfo submitInfo;
+    memset(&submitInfo, 0, sizeof(VkSubmitInfo));
+    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submitInfo.pNext = nullptr;
+    submitInfo.waitSemaphoreCount = 0;
+    submitInfo.pWaitSemaphores = nullptr;
+    submitInfo.pWaitDstStageMask = 0;
+    submitInfo.commandBufferCount = 1;
+    submitInfo.pCommandBuffers = &fCmdBuffer;
+    submitInfo.signalSemaphoreCount = 0;
+    submitInfo.pSignalSemaphores = nullptr;
+    GR_VK_CALL_ERRCHECK(gpu->vkInterface(), QueueSubmit(queue, 1, &submitInfo, fSubmitFence));
+
+    if (GrVkGpu::kForce_SyncQueue == sync) {
+        err = GR_VK_CALL(gpu->vkInterface(),
+                         WaitForFences(gpu->device(), 1, &fSubmitFence, true, UINT64_MAX));
+        if (VK_TIMEOUT == err) {
+            SkDebugf("Fence failed to signal: %d\n", err);
+            SkFAIL("failing");
+        }
+        SkASSERT(!err);
+
+        // Destroy the fence
+        GR_VK_CALL(gpu->vkInterface(), DestroyFence(gpu->device(), fSubmitFence, nullptr));
+        fSubmitFence = VK_NULL_HANDLE;
+    }
+}
+
+bool GrVkPrimaryCommandBuffer::finished(const GrVkGpu* gpu) const {
+    if (VK_NULL_HANDLE == fSubmitFence) {
+        return true;
+    }
+
+    VkResult err = GR_VK_CALL(gpu->vkInterface(), GetFenceStatus(gpu->device(), fSubmitFence));
+    switch (err) {
+        case VK_SUCCESS:
+            return true;
+
+        case VK_NOT_READY:
+            return false;
+
+        default:
+            SkDebugf("Error getting fence status: %d\n", err);
+            SkFAIL("failing");
+            break;
+    }
+
+    return false;
+}
+
+void GrVkPrimaryCommandBuffer::copyImage(const GrVkGpu* gpu,
+                                         GrVkImage* srcImage,
+                                         VkImageLayout srcLayout,
+                                         GrVkImage* dstImage,
+                                         VkImageLayout dstLayout,
+                                         uint32_t copyRegionCount,
+                                         const VkImageCopy* copyRegions) {
+    SkASSERT(fIsActive);
+    SkASSERT(!fActiveRenderPass);
+    this->addResource(srcImage->resource());
+    this->addResource(dstImage->resource());
+    GR_VK_CALL(gpu->vkInterface(), CmdCopyImage(fCmdBuffer,
+                                                srcImage->image(),
+                                                srcLayout,
+                                                dstImage->image(),
+                                                dstLayout,
+                                                copyRegionCount,
+                                                copyRegions));
+}
+
+void GrVkPrimaryCommandBuffer::blitImage(const GrVkGpu* gpu,
+                                         const GrVkResource* srcResource,
+                                         VkImage srcImage,
+                                         VkImageLayout srcLayout,
+                                         const GrVkResource* dstResource,
+                                         VkImage dstImage,
+                                         VkImageLayout dstLayout,
+                                         uint32_t blitRegionCount,
+                                         const VkImageBlit* blitRegions,
+                                         VkFilter filter) {
+    SkASSERT(fIsActive);
+    SkASSERT(!fActiveRenderPass);
+    this->addResource(srcResource);
+    this->addResource(dstResource);
+    GR_VK_CALL(gpu->vkInterface(), CmdBlitImage(fCmdBuffer,
+                                                srcImage,
+                                                srcLayout,
+                                                dstImage,
+                                                dstLayout,
+                                                blitRegionCount,
+                                                blitRegions,
+                                                filter));
+}
+
+void GrVkPrimaryCommandBuffer::copyImageToBuffer(const GrVkGpu* gpu,
+                                                 GrVkImage* srcImage,
+                                                 VkImageLayout srcLayout,
+                                                 GrVkTransferBuffer* dstBuffer,
+                                                 uint32_t copyRegionCount,
+                                                 const VkBufferImageCopy* copyRegions) {
+    SkASSERT(fIsActive);
+    SkASSERT(!fActiveRenderPass);
+    this->addResource(srcImage->resource());
+    this->addResource(dstBuffer->resource());
+    GR_VK_CALL(gpu->vkInterface(), CmdCopyImageToBuffer(fCmdBuffer,
+                                                        srcImage->image(),
+                                                        srcLayout,
+                                                        dstBuffer->buffer(),
+                                                        copyRegionCount,
+                                                        copyRegions));
+}
+
+void GrVkPrimaryCommandBuffer::copyBufferToImage(const GrVkGpu* gpu,
+                                                 GrVkTransferBuffer* srcBuffer,
+                                                 GrVkImage* dstImage,
+                                                 VkImageLayout dstLayout,
+                                                 uint32_t copyRegionCount,
+                                                 const VkBufferImageCopy* copyRegions) {
+    SkASSERT(fIsActive);
+    SkASSERT(!fActiveRenderPass);
+    this->addResource(srcBuffer->resource());
+    this->addResource(dstImage->resource());
+    GR_VK_CALL(gpu->vkInterface(), CmdCopyBufferToImage(fCmdBuffer,
+                                                        srcBuffer->buffer(),
+                                                        dstImage->image(),
+                                                        dstLayout,
+                                                        copyRegionCount,
+                                                        copyRegions));
+}
+
+void GrVkPrimaryCommandBuffer::clearColorImage(const GrVkGpu* gpu,
+                                               GrVkImage* image,
+                                               const VkClearColorValue* color,
+                                               uint32_t subRangeCount,
+                                               const VkImageSubresourceRange* subRanges) {
+    SkASSERT(fIsActive);
+    SkASSERT(!fActiveRenderPass);
+    this->addResource(image->resource());
+    GR_VK_CALL(gpu->vkInterface(), CmdClearColorImage(fCmdBuffer,
+                                                      image->image(),
+                                                      image->currentLayout(),
+                                                      color,
+                                                      subRangeCount,
+                                                      subRanges));
+}
+
+void GrVkPrimaryCommandBuffer::clearDepthStencilImage(const GrVkGpu* gpu,
+                                                      GrVkImage* image,
+                                                      const VkClearDepthStencilValue* color,
+                                                      uint32_t subRangeCount,
+                                                      const VkImageSubresourceRange* subRanges) {
+    SkASSERT(fIsActive);
+    SkASSERT(!fActiveRenderPass);
+    this->addResource(image->resource());
+    GR_VK_CALL(gpu->vkInterface(), CmdClearDepthStencilImage(fCmdBuffer,
+                                                             image->image(),
+                                                             image->currentLayout(),
+                                                             color,
+                                                             subRangeCount,
+                                                             subRanges));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// SecondaryCommandBuffer
+////////////////////////////////////////////////////////////////////////////////
+
+GrVkSecondaryCommandBuffer* GrVkSecondaryCommandBuffer::Create(
+                                                       const GrVkGpu* gpu,
+                                                       VkCommandPool cmdPool,
+                                                       const GrVkRenderPass* compatibleRenderPass) {
+    const VkCommandBufferAllocateInfo cmdInfo = {
+        VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,   // sType
+        NULL,                                             // pNext
+        cmdPool,                                          // commandPool
+        VK_COMMAND_BUFFER_LEVEL_SECONDARY,                // level
+        1                                                 // bufferCount
+    };
+
+    VkCommandBuffer cmdBuffer;
+    VkResult err = GR_VK_CALL(gpu->vkInterface(), AllocateCommandBuffers(gpu->device(),
+                                                                         &cmdInfo,
+                                                                         &cmdBuffer));
+    if (err) {
+        return nullptr;
+    }
+    return new GrVkSecondaryCommandBuffer(cmdBuffer, compatibleRenderPass);
+}
+
+
+void GrVkSecondaryCommandBuffer::begin(const GrVkGpu* gpu, const GrVkFramebuffer* framebuffer) {
+    SkASSERT(!fIsActive);
+    SkASSERT(fActiveRenderPass);
+
+    VkCommandBufferInheritanceInfo inheritanceInfo;
+    memset(&inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
+    inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
+    inheritanceInfo.pNext = nullptr;
+    inheritanceInfo.renderPass = fActiveRenderPass->vkRenderPass();
+    inheritanceInfo.subpass = 0; // Currently only using 1 subpass for each render pass
+    inheritanceInfo.framebuffer = framebuffer ? framebuffer->framebuffer() : VK_NULL_HANDLE;
+    inheritanceInfo.occlusionQueryEnable = false;
+    inheritanceInfo.queryFlags = 0;
+    inheritanceInfo.pipelineStatistics = 0;
+
+    VkCommandBufferBeginInfo cmdBufferBeginInfo;
+    memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
+    cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    cmdBufferBeginInfo.pNext = nullptr;
+    cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT |
+                               VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+    cmdBufferBeginInfo.pInheritanceInfo = &inheritanceInfo;
+
+    GR_VK_CALL_ERRCHECK(gpu->vkInterface(), BeginCommandBuffer(fCmdBuffer,
+                                                               &cmdBufferBeginInfo));
+    fIsActive = true;
+}
+
+void GrVkSecondaryCommandBuffer::end(const GrVkGpu* gpu) {
+    SkASSERT(fIsActive);
+    GR_VK_CALL_ERRCHECK(gpu->vkInterface(), EndCommandBuffer(fCmdBuffer));
+    this->invalidateState();
+    fIsActive = false;
+}
+
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index b513a47..709e4c6 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -13,6 +13,7 @@
 #include "GrVkUtil.h"
 #include "vk/GrVkDefines.h"
 
+class GrVkFramebuffer;
 class GrVkPipeline;
 class GrVkRenderPass;
 class GrVkRenderTarget;
@@ -20,24 +21,10 @@
 
 class GrVkCommandBuffer : public GrVkResource {
 public:
-    static GrVkCommandBuffer* Create(const GrVkGpu* gpu, VkCommandPool cmdPool);
     ~GrVkCommandBuffer() override;
 
-    void begin(const GrVkGpu* gpu);
-    void end(const GrVkGpu* gpu);
-
     void invalidateState();
 
-    // Begins render pass on this command buffer. The framebuffer from GrVkRenderTarget will be used
-    // in the render pass.
-    void beginRenderPass(const GrVkGpu* gpu,
-                         const GrVkRenderPass* renderPass,
-                         const GrVkRenderTarget& target);
-    void endRenderPass(const GrVkGpu* gpu);
-
-    void submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync);
-    bool finished(const GrVkGpu* gpu) const;
-
     ////////////////////////////////////////////////////////////////////////////
     // CommandBuffer commands
     ////////////////////////////////////////////////////////////////////////////
@@ -105,6 +92,98 @@
 
     void setBlendConstants(const GrVkGpu* gpu, const float blendConstants[4]);
 
+    // Commands that only work inside of a render pass
+    void clearAttachments(const GrVkGpu* gpu,
+                          int numAttachments,
+                          const VkClearAttachment* attachments,
+                          int numRects,
+                          const VkClearRect* clearRects) const;
+
+    void drawIndexed(const GrVkGpu* gpu,
+                     uint32_t indexCount,
+                     uint32_t instanceCount,
+                     uint32_t firstIndex,
+                     int32_t vertexOffset,
+                     uint32_t firstInstance) const;
+
+    void draw(const GrVkGpu* gpu,
+              uint32_t vertexCount,
+              uint32_t instanceCount,
+              uint32_t firstVertex,
+              uint32_t firstInstance) const;
+
+    // Add ref-counted resource that will be tracked and released when this
+    // command buffer finishes execution
+    void addResource(const GrVkResource* resource) {
+        resource->ref();
+        fTrackedResources.push_back(resource);
+    }
+
+protected:
+        GrVkCommandBuffer(VkCommandBuffer cmdBuffer, const GrVkRenderPass* rp = VK_NULL_HANDLE)
+            : fTrackedResources(kInitialTrackedResourcesCount)
+            , fIsActive(false)
+            , fActiveRenderPass(rp)
+            , fCmdBuffer(cmdBuffer)
+            , fSubmitFence(VK_NULL_HANDLE)
+            , fBoundVertexBufferIsValid(false)
+            , fBoundIndexBufferIsValid(false) {
+            this->invalidateState();
+        }
+        SkTArray<const GrVkResource*, true>     fTrackedResources;
+
+        // Tracks whether we are in the middle of a command buffer begin/end calls and thus can add
+        // new commands to the buffer;
+        bool fIsActive;
+
+        // Stores a pointer to the current active render pass (i.e. begin has been called but not
+        // end). A nullptr means there is no active render pass. The GrVKCommandBuffer does not own
+        // the render pass.
+        const GrVkRenderPass*     fActiveRenderPass;
+
+        VkCommandBuffer           fCmdBuffer;
+        VkFence                   fSubmitFence;
+
+private:
+    static const int kInitialTrackedResourcesCount = 32;
+
+    void freeGPUData(const GrVkGpu* gpu) const override;
+    void abandonSubResources() const override;
+
+    VkBuffer                                fBoundVertexBuffer;
+    bool                                    fBoundVertexBufferIsValid;
+
+    VkBuffer                                fBoundIndexBuffer;
+    bool                                    fBoundIndexBufferIsValid;
+
+    // Cached values used for dynamic state updates
+    VkViewport fCachedViewport;
+    VkRect2D   fCachedScissor;
+    float      fCachedBlendConstant[4];
+};
+
+class GrVkSecondaryCommandBuffer;
+
+class GrVkPrimaryCommandBuffer : public GrVkCommandBuffer {
+public:
+    static GrVkPrimaryCommandBuffer* Create(const GrVkGpu* gpu, VkCommandPool cmdPool);
+
+    void begin(const GrVkGpu* gpu);
+    void end(const GrVkGpu* gpu);
+
+    // Begins render pass on this command buffer. The framebuffer from GrVkRenderTarget will be used
+    // in the render pass.
+    void beginRenderPass(const GrVkGpu* gpu,
+                         const GrVkRenderPass* renderPass,
+                         const GrVkRenderTarget& target);
+    void endRenderPass(const GrVkGpu* gpu);
+
+    // Submits the SecondaryCommandBuffer into this command buffer. It is required that we are
+    // currently inside a render pass that is compatible with the one used to create the
+    // SecondaryCommandBuffer.
+    void executeCommands(const GrVkGpu* gpu,
+                         const GrVkSecondaryCommandBuffer* secondaryBuffer);
+
     // Commands that only work outside of a render pass
     void clearColorImage(const GrVkGpu* gpu,
                          GrVkImage* image,
@@ -169,75 +248,32 @@
                            uint32_t copyRegionCount,
                            const VkBufferImageCopy* copyRegions);
 
-    // Commands that only work inside of a render pass
-    void clearAttachments(const GrVkGpu* gpu,
-                          int numAttachments,
-                          const VkClearAttachment* attachments,
-                          int numRects,
-                          const VkClearRect* clearRects) const;
-
-    void drawIndexed(const GrVkGpu* gpu,
-                     uint32_t indexCount,
-                     uint32_t instanceCount,
-                     uint32_t firstIndex,
-                     int32_t vertexOffset,
-                     uint32_t firstInstance) const;
-
-    void draw(const GrVkGpu* gpu,
-              uint32_t vertexCount,
-              uint32_t instanceCount,
-              uint32_t firstVertex,
-              uint32_t firstInstance) const;
-
-    // Add ref-counted resource that will be tracked and released when this
-    // command buffer finishes execution
-    void addResource(const GrVkResource* resource) {
-        resource->ref();
-        fTrackedResources.push_back(resource);
-    }
+    void submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync);
+    bool finished(const GrVkGpu* gpu) const;
 
 private:
-    static const int kInitialTrackedResourcesCount = 32;
+    explicit GrVkPrimaryCommandBuffer(VkCommandBuffer cmdBuffer) : INHERITED(cmdBuffer) {}
 
-    explicit GrVkCommandBuffer(VkCommandBuffer cmdBuffer)
-        : fTrackedResources(kInitialTrackedResourcesCount)
-        , fCmdBuffer(cmdBuffer)
-        , fSubmitFence(VK_NULL_HANDLE)
-        , fBoundVertexBufferIsValid(false)
-        , fBoundIndexBufferIsValid(false)
-        , fIsActive(false)
-        , fActiveRenderPass(nullptr) {
-        this->invalidateState();
-    }
-
-    void freeGPUData(const GrVkGpu* gpu) const override;
-    void abandonSubResources() const override;
-
-    SkTArray<const GrVkResource*, true>     fTrackedResources;
-
-    VkCommandBuffer                         fCmdBuffer;
-    VkFence                                 fSubmitFence;
-
-    VkBuffer                                fBoundVertexBuffer;
-    bool                                    fBoundVertexBufferIsValid;
-
-    VkBuffer                                fBoundIndexBuffer;
-    bool                                    fBoundIndexBufferIsValid;
-
-    // Tracks whether we are in the middle of a command buffer begin/end calls and thus can add new
-    // commands to the buffer;
-    bool fIsActive;
-
-    // Stores a pointer to the current active render pass (i.e. begin has been called but not end).
-    // A nullptr means there is no active render pass. The GrVKCommandBuffer does not own the render
-    // pass.
-    const GrVkRenderPass*     fActiveRenderPass;
-
-    // Cached values used for dynamic state updates
-    VkViewport fCachedViewport;
-    VkRect2D   fCachedScissor;
-    float      fCachedBlendConstant[4];
+    typedef GrVkCommandBuffer INHERITED;
 };
 
+class GrVkSecondaryCommandBuffer : public GrVkCommandBuffer {
+public:
+    static GrVkSecondaryCommandBuffer* Create(const GrVkGpu* gpu, VkCommandPool cmdPool, 
+                                              const GrVkRenderPass* compatibleRenderPass);
+
+    void begin(const GrVkGpu* gpu, const GrVkFramebuffer* framebuffer);
+    void end(const GrVkGpu* gpu);
+
+private:
+    explicit GrVkSecondaryCommandBuffer(VkCommandBuffer cmdBuffer,
+                                        const GrVkRenderPass* compatibleRenderPass)
+        : INHERITED(cmdBuffer, compatibleRenderPass) {
+    }
+
+    friend class GrVkPrimaryCommandBuffer;
+
+    typedef GrVkCommandBuffer INHERITED;
+};
 
 #endif
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index fb533e3..d18481c 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -128,7 +128,7 @@
 
     // must call this after creating the CommandPool
     fResourceProvider.init();
-    fCurrentCmdBuffer = fResourceProvider.createCommandBuffer();
+    fCurrentCmdBuffer = fResourceProvider.createPrimaryCommandBuffer();
     SkASSERT(fCurrentCmdBuffer);
     fCurrentCmdBuffer->begin(this);
 }
@@ -169,7 +169,7 @@
 
     // Release old command buffer and create a new one
     fCurrentCmdBuffer->unref(this);
-    fCurrentCmdBuffer = fResourceProvider.createCommandBuffer();
+    fCurrentCmdBuffer = fResourceProvider.createPrimaryCommandBuffer();
     SkASSERT(fCurrentCmdBuffer);
 
     fCurrentCmdBuffer->begin(this);
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 506b237..00055ad 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -214,7 +214,7 @@
     // Created by GrVkGpu
     GrVkResourceProvider                   fResourceProvider;
     VkCommandPool                          fCmdPool;
-    GrVkCommandBuffer*                     fCurrentCmdBuffer;
+    GrVkPrimaryCommandBuffer*              fCurrentCmdBuffer;
     VkPhysicalDeviceMemoryProperties       fPhysDevMemProps;
 
 #ifdef ENABLE_VK_LAYERS
diff --git a/src/gpu/vk/GrVkRenderPass.cpp b/src/gpu/vk/GrVkRenderPass.cpp
index 6a0f953..a493938 100644
--- a/src/gpu/vk/GrVkRenderPass.cpp
+++ b/src/gpu/vk/GrVkRenderPass.cpp
@@ -233,11 +233,8 @@
     *contents = VK_SUBPASS_CONTENTS_INLINE;
 }
 
-bool GrVkRenderPass::isCompatible(const GrVkRenderTarget& target) const {
-    AttachmentsDescriptor desc;
-    AttachmentFlags flags;
-    target.getAttachmentsDescriptor(&desc, &flags);
-
+bool GrVkRenderPass::isCompatible(const AttachmentsDescriptor& desc,
+                                  const AttachmentFlags& flags) const {
     if (flags != fAttachmentFlags) {
         return false;
     }
@@ -261,6 +258,18 @@
     return true;
 }
 
+bool GrVkRenderPass::isCompatible(const GrVkRenderTarget& target) const {
+    AttachmentsDescriptor desc;
+    AttachmentFlags flags;
+    target.getAttachmentsDescriptor(&desc, &flags);
+
+    return this->isCompatible(desc, flags);
+}
+
+bool GrVkRenderPass::isCompatible(const GrVkRenderPass& renderPass) const {
+    return this->isCompatible(renderPass.fAttachmentsDescriptor, renderPass.fAttachmentFlags);
+}
+
 bool GrVkRenderPass::equalLoadStoreOps(const LoadStoreOps& colorOps,
                                        const LoadStoreOps& resolveOps,
                                        const LoadStoreOps& stencilOps) const {
diff --git a/src/gpu/vk/GrVkRenderPass.h b/src/gpu/vk/GrVkRenderPass.h
index b4f4b2b..997989d 100644
--- a/src/gpu/vk/GrVkRenderPass.h
+++ b/src/gpu/vk/GrVkRenderPass.h
@@ -110,6 +110,8 @@
     // basic RenderPasses that can be used when creating a VkFrameBuffer object.
     bool isCompatible(const GrVkRenderTarget& target) const;
 
+    bool isCompatible(const GrVkRenderPass& renderPass) const;
+
     bool equalLoadStoreOps(const LoadStoreOps& colorOps,
                            const LoadStoreOps& resolveOps,
                            const LoadStoreOps& stencilOps) const;
@@ -126,6 +128,8 @@
               const LoadStoreOps& resolveOps,
               const LoadStoreOps& stencilOps);
 
+    bool isCompatible(const AttachmentsDescriptor&, const AttachmentFlags&) const;
+
     void freeGPUData(const GrVkGpu* gpu) const override;
 
     VkRenderPass          fRenderPass;
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index cd3ba47..ae333bc 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -215,8 +215,8 @@
     *outPool = fUniformDescPool;
 }
 
-GrVkCommandBuffer* GrVkResourceProvider::createCommandBuffer() {
-    GrVkCommandBuffer* cmdBuffer = GrVkCommandBuffer::Create(fGpu, fGpu->cmdPool());
+GrVkPrimaryCommandBuffer* GrVkResourceProvider::createPrimaryCommandBuffer() {
+    GrVkPrimaryCommandBuffer* cmdBuffer = GrVkPrimaryCommandBuffer::Create(fGpu, fGpu->cmdPool());
     fActiveCommandBuffers.push_back(cmdBuffer);
     cmdBuffer->ref();
     return cmdBuffer;
diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h
index e754501..d4383af 100644
--- a/src/gpu/vk/GrVkResourceProvider.h
+++ b/src/gpu/vk/GrVkResourceProvider.h
@@ -25,7 +25,7 @@
 class GrPipeline;
 class GrPrimitiveProcessor;
 class GrTextureParams;
-class GrVkCommandBuffer;
+class GrVkPrimaryCommandBuffer;
 class GrVkGpu;
 class GrVkPipeline;
 class GrVkRenderTarget;
@@ -77,7 +77,7 @@
                                          const GrVkRenderPass::LoadStoreOps& stencilOps);
 
 
-    GrVkCommandBuffer* createCommandBuffer();
+    GrVkPrimaryCommandBuffer* createPrimaryCommandBuffer();
     void checkCommandBuffers();
 
     // Finds or creates a compatible GrVkDescriptorPool for the requested type and count.
@@ -201,7 +201,7 @@
     SkSTArray<4, CompatibleRenderPassSet> fRenderPassArray;
 
     // Array of CommandBuffers that are currently in flight
-    SkSTArray<4, GrVkCommandBuffer*> fActiveCommandBuffers;
+    SkSTArray<4, GrVkPrimaryCommandBuffer*> fActiveCommandBuffers;
 
     // Stores GrVkSampler objects that we've already created so we can reuse them across multiple
     // GrVkPipelineStates