Begin renderpasses immediately in GrVkOpsRenderPass.

This change will allow us to easily switch between rendering to a
primary vs secondary command buffer.

Change-Id: Iaa066f24b64a686db41a1554b0d75c185714ef8c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/239100
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/vk/GrVkOpsRenderPass.cpp b/src/gpu/vk/GrVkOpsRenderPass.cpp
index a42bef4..e884710 100644
--- a/src/gpu/vk/GrVkOpsRenderPass.cpp
+++ b/src/gpu/vk/GrVkOpsRenderPass.cpp
@@ -26,25 +26,6 @@
 #include "src/gpu/vk/GrVkSemaphore.h"
 #include "src/gpu/vk/GrVkTexture.h"
 
-GrVkPrimaryCommandBufferTask::~GrVkPrimaryCommandBufferTask() = default;
-GrVkPrimaryCommandBufferTask::GrVkPrimaryCommandBufferTask() = default;
-
-namespace {
-
-class InlineUpload : public GrVkPrimaryCommandBufferTask {
-public:
-    InlineUpload(GrOpFlushState* state, const GrDeferredTextureUploadFn& upload)
-            : fFlushState(state), fUpload(upload) {}
-
-    void execute(const Args& args) override { fFlushState->doUpload(fUpload, true); }
-
-private:
-    GrOpFlushState* fFlushState;
-    GrDeferredTextureUploadFn fUpload;
-};
-
-}  // anonymous namespace
-
 /////////////////////////////////////////////////////////////////////////////
 
 void get_vk_load_store_ops(GrLoadOp loadOpIn, GrStoreOp storeOpIn,
@@ -79,64 +60,81 @@
 
 GrVkOpsRenderPass::GrVkOpsRenderPass(GrVkGpu* gpu) : fGpu(gpu) {}
 
-void GrVkOpsRenderPass::init() {
-    GrVkRenderPass::LoadStoreOps vkColorOps(fVkColorLoadOp, fVkColorStoreOp);
-    GrVkRenderPass::LoadStoreOps vkStencilOps(fVkStencilLoadOp, fVkStencilStoreOp);
+void GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
+                             const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
+                             const SkPMColor4f& clearColor) {
 
-    CommandBufferInfo& cbInfo = fCommandBufferInfos.push_back();
-    SkASSERT(fCommandBufferInfos.count() == 1);
-    fCurrentCmdInfo = 0;
+    VkAttachmentLoadOp loadOp;
+    VkAttachmentStoreOp storeOp;
+    get_vk_load_store_ops(colorInfo.fLoadOp, colorInfo.fStoreOp,
+                          &loadOp, &storeOp);
+    GrVkRenderPass::LoadStoreOps vkColorOps(loadOp, storeOp);
+
+    get_vk_load_store_ops(stencilInfo.fLoadOp, stencilInfo.fStoreOp,
+                          &loadOp, &storeOp);
+    GrVkRenderPass::LoadStoreOps vkStencilOps(loadOp, storeOp);
 
     GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
+    GrVkImage* targetImage = vkRT->msaaImage() ? vkRT->msaaImage() : vkRT;
+
+    // Change layout of our render target so it can be used as the color attachment.
+    // TODO: If we know that we will never be blending or loading the attachment we could drop the
+    // VK_ACCESS_COLOR_ATTACHMENT_READ_BIT.
+    targetImage->setImageLayout(fGpu,
+                                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                                VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+                                VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+                                VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+                                false);
+
+    // If we are using a stencil attachment we also need to update its layout
+    if (GrStencilAttachment* stencil = fRenderTarget->renderTargetPriv().getStencilAttachment()) {
+        GrVkStencilAttachment* vkStencil = (GrVkStencilAttachment*)stencil;
+        // We need the write and read access bits since we may load and store the stencil.
+        // The initial load happens in the VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT so we
+        // wait there.
+        vkStencil->setImageLayout(fGpu,
+                                  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+                                  VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+                                  VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
+                                  VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
+                                  false);
+    }
+
     const GrVkResourceProvider::CompatibleRPHandle& rpHandle = vkRT->compatibleRenderPassHandle();
     if (rpHandle.isValid()) {
-        cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
+        fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
                                                                      vkColorOps,
                                                                      vkStencilOps);
     } else {
-        cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(*vkRT,
+        fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(*vkRT,
                                                                      vkColorOps,
                                                                      vkStencilOps);
     }
+    SkASSERT(fCurrentRenderPass);
 
-    cbInfo.fColorClearValue.color.float32[0] = fClearColor[0];
-    cbInfo.fColorClearValue.color.float32[1] = fClearColor[1];
-    cbInfo.fColorClearValue.color.float32[2] = fClearColor[2];
-    cbInfo.fColorClearValue.color.float32[3] = fClearColor[3];
+    VkClearValue vkClearColor;
+    vkClearColor.color.float32[0] = clearColor[0];
+    vkClearColor.color.float32[1] = clearColor[1];
+    vkClearColor.color.float32[2] = clearColor[2];
+    vkClearColor.color.float32[3] = clearColor[3];
 
-    if (VK_ATTACHMENT_LOAD_OP_CLEAR == fVkColorLoadOp) {
-        cbInfo.fBounds = SkRect::MakeWH(vkRT->width(), vkRT->height());
-    } else {
-        cbInfo.fBounds.setEmpty();
-    }
+    fGpu->beginRenderPass(fCurrentRenderPass, &vkClearColor, vkRT, fOrigin, fBounds);
 
-    if (VK_ATTACHMENT_LOAD_OP_CLEAR == fVkColorLoadOp) {
-        cbInfo.fLoadStoreState = LoadStoreState::kStartsWithClear;
-    } else if (VK_ATTACHMENT_LOAD_OP_LOAD == fVkColorLoadOp &&
-               VK_ATTACHMENT_STORE_OP_STORE == fVkColorStoreOp) {
-        cbInfo.fLoadStoreState = LoadStoreState::kLoadAndStore;
-    } else if (VK_ATTACHMENT_LOAD_OP_DONT_CARE == fVkColorLoadOp) {
-        cbInfo.fLoadStoreState = LoadStoreState::kStartsWithDiscard;
-    }
-
-    cbInfo.fCommandBuffer = fGpu->cmdPool()->findOrCreateSecondaryCommandBuffer(fGpu);
-    cbInfo.currentCmdBuf()->begin(fGpu, vkRT->framebuffer(), cbInfo.fRenderPass);
+    fCurrentSecondaryCommandBuffer = fGpu->cmdPool()->findOrCreateSecondaryCommandBuffer(fGpu);
+    fCurrentSecondaryCommandBuffer->begin(fGpu, vkRT->framebuffer(), fCurrentRenderPass);
 }
 
 void GrVkOpsRenderPass::initWrapped() {
-    CommandBufferInfo& cbInfo = fCommandBufferInfos.push_back();
-    SkASSERT(fCommandBufferInfos.count() == 1);
-    fCurrentCmdInfo = 0;
-
     GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
     SkASSERT(vkRT->wrapsSecondaryCommandBuffer());
-    cbInfo.fRenderPass = vkRT->externalRenderPass();
-    cbInfo.fRenderPass->ref();
+    fCurrentRenderPass = vkRT->externalRenderPass();
+    SkASSERT(fCurrentRenderPass);
+    fCurrentRenderPass->ref();
 
-    cbInfo.fBounds.setEmpty();
-    cbInfo.fCommandBuffer.reset(
+    fCurrentSecondaryCommandBuffer.reset(
             GrVkSecondaryCommandBuffer::Create(vkRT->getExternalSecondaryCommandBuffer()));
-    cbInfo.currentCmdBuf()->begin(fGpu, nullptr, cbInfo.fRenderPass);
+    fCurrentSecondaryCommandBuffer->begin(fGpu, nullptr, fCurrentRenderPass);
 }
 
 GrVkOpsRenderPass::~GrVkOpsRenderPass() {
@@ -145,9 +143,15 @@
 
 GrGpu* GrVkOpsRenderPass::gpu() { return fGpu; }
 
+GrVkCommandBuffer* GrVkOpsRenderPass::currentCommandBuffer() {
+    // TODO: In the future this function may return the GrVkGpu's primary command buffer.
+    SkASSERT(fCurrentSecondaryCommandBuffer);
+    return fCurrentSecondaryCommandBuffer.get();
+}
+
 void GrVkOpsRenderPass::end() {
-    if (fCurrentCmdInfo >= 0) {
-        fCommandBufferInfos[fCurrentCmdInfo].currentCmdBuf()->end(fGpu);
+    if (fCurrentSecondaryCommandBuffer) {
+        fCurrentSecondaryCommandBuffer->end(fGpu);
     }
 }
 
@@ -156,85 +160,15 @@
         return;
     }
 
-    GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
-    GrVkImage* targetImage = vkRT->msaaImage() ? vkRT->msaaImage() : vkRT;
-    GrStencilAttachment* stencil = fRenderTarget->renderTargetPriv().getStencilAttachment();
-    auto currPreCmd = fPreCommandBufferTasks.begin();
-
-    GrVkPrimaryCommandBufferTask::Args taskArgs{fGpu, fRenderTarget};
-    for (int i = 0; i < fCommandBufferInfos.count(); ++i) {
-        CommandBufferInfo& cbInfo = fCommandBufferInfos[i];
-
-        for (int c = 0; c < cbInfo.fNumPreCmds; ++c, ++currPreCmd) {
-            currPreCmd->execute(taskArgs);
-        }
-
-        // TODO: Many things create a scratch texture which adds the discard immediately, but then
-        // don't draw to it right away. This causes the discard to be ignored and we get yelled at
-        // for loading uninitialized data. However, once MDB lands with reordering, the discard will
-        // get reordered with the rest of the draw commands and we can remove the discard check.
-        if (cbInfo.fIsEmpty &&
-            cbInfo.fLoadStoreState != LoadStoreState::kStartsWithClear &&
-            cbInfo.fLoadStoreState != LoadStoreState::kStartsWithDiscard) {
-            // We have sumbitted no actual draw commands to the command buffer and we are not using
-            // the render pass to do a clear so there is no need to submit anything.
-            continue;
-        }
-
-        // We don't want to actually submit the secondary command buffer if it is wrapped.
-        if (this->wrapsSecondaryCommandBuffer()) {
-            // There should have only been one secondary command buffer in the wrapped case so it is
-            // safe to just return here.
-            SkASSERT(fCommandBufferInfos.count() == 1);
-            return;
-        }
-
-        // Make sure if we only have a discard load that we execute the discard on the whole image.
-        // TODO: Once we improve our tracking of discards so that we never end up flushing a discard
-        // call with no actually ops, remove this.
-        if (cbInfo.fIsEmpty && cbInfo.fLoadStoreState == LoadStoreState::kStartsWithDiscard) {
-            cbInfo.fBounds = SkRect::MakeWH(vkRT->width(), vkRT->height());
-        }
-
-        if (cbInfo.fBounds.intersect(SkRect::MakeIWH(fRenderTarget->width(),
-                                                     fRenderTarget->height()))) {
-            // Make sure we do the following layout changes after all copies, uploads, or any other
-            // pre-work is done since we may change the layouts in the pre-work. Also since the
-            // draws will be submitted in different render passes, we need to guard againts write
-            // and write issues.
-
-            // Change layout of our render target so it can be used as the color attachment.
-            // TODO: If we know that we will never be blending or loading the attachment we could
-            // drop the VK_ACCESS_COLOR_ATTACHMENT_READ_BIT.
-            targetImage->setImageLayout(fGpu,
-                                        VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
-                                        VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
-                                        VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
-                                        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
-                                        false);
-
-            // If we are using a stencil attachment we also need to update its layout
-            if (stencil) {
-                GrVkStencilAttachment* vkStencil = (GrVkStencilAttachment*)stencil;
-                // We need the write and read access bits since we may load and store the stencil.
-                // The initial load happens in the VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT so we
-                // wait there.
-                vkStencil->setImageLayout(fGpu,
-                                          VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
-                                          VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
-                                          VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
-                                          VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
-                                          false);
-            }
-
-            SkIRect iBounds;
-            cbInfo.fBounds.roundOut(&iBounds);
-
-            fGpu->submitSecondaryCommandBuffer(std::move(cbInfo.fCommandBuffer), cbInfo.fRenderPass,
-                                               &cbInfo.fColorClearValue, vkRT, fOrigin, iBounds);
-        }
+    // We don't want to actually submit the secondary command buffer if it is wrapped.
+    if (this->wrapsSecondaryCommandBuffer()) {
+        return;
     }
-    SkASSERT(currPreCmd == fPreCommandBufferTasks.end());
+
+    if (fCurrentSecondaryCommandBuffer) {
+        fGpu->submitSecondaryCommandBuffer(std::move(fCurrentSecondaryCommandBuffer));
+    }
+    fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
 }
 
 void GrVkOpsRenderPass::set(GrRenderTarget* rt, GrSurfaceOrigin origin,
@@ -242,10 +176,7 @@
                             const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
                             const SkTArray<GrTextureProxy*, true>& sampledProxies) {
     SkASSERT(!fRenderTarget);
-    SkASSERT(fCommandBufferInfos.empty());
-    SkASSERT(-1 == fCurrentCmdInfo);
     SkASSERT(fGpu == rt->getContext()->priv().getGpu());
-    SkASSERT(!fLastPipelineState);
 
 #ifdef SK_DEBUG
     fIsActive = true;
@@ -268,31 +199,23 @@
         return;
     }
 
-    fClearColor = colorInfo.fClearColor;
+    // TODO: This should be passed in via the GrOpsTask instead of always setting it to the full
+    // render target bounds.
+    fBounds = SkIRect::MakeWH(fRenderTarget->width(), fRenderTarget->height());
 
-    get_vk_load_store_ops(colorInfo.fLoadOp, colorInfo.fStoreOp,
-                          &fVkColorLoadOp, &fVkColorStoreOp);
-
-    get_vk_load_store_ops(stencilInfo.fLoadOp, stencilInfo.fStoreOp,
-                          &fVkStencilLoadOp, &fVkStencilStoreOp);
-
-    this->init();
+    this->init(colorInfo, stencilInfo, colorInfo.fClearColor);
 }
 
 void GrVkOpsRenderPass::reset() {
-    for (int i = 0; i < fCommandBufferInfos.count(); ++i) {
-        CommandBufferInfo& cbInfo = fCommandBufferInfos[i];
-        if (cbInfo.fCommandBuffer) {
-            cbInfo.fCommandBuffer.release()->recycle(fGpu);
-        }
-        cbInfo.fRenderPass->unref(fGpu);
+    if (fCurrentSecondaryCommandBuffer) {
+        fCurrentSecondaryCommandBuffer.release()->recycle(fGpu);
     }
-    fCommandBufferInfos.reset();
-    fPreCommandBufferTasks.reset();
+    if (fCurrentRenderPass) {
+        fCurrentRenderPass->unref(fGpu);
+        fCurrentRenderPass = nullptr;
+    }
+    fCurrentCBIsEmpty = true;
 
-    fCurrentCmdInfo = -1;
-
-    fLastPipelineState = nullptr;
     fRenderTarget = nullptr;
 
 #ifdef SK_DEBUG
@@ -314,8 +237,6 @@
 void GrVkOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
     SkASSERT(!clip.hasWindowRectangles());
 
-    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
-
     GrStencilAttachment* sb = fRenderTarget->renderTargetPriv().getStencilAttachment();
     // this should only be called internally when we know we have a
     // stencil buffer.
@@ -353,30 +274,21 @@
     clearRect.layerCount = 1;
 
     uint32_t stencilIndex;
-    SkAssertResult(cbInfo.fRenderPass->stencilAttachmentIndex(&stencilIndex));
+    SkAssertResult(fCurrentRenderPass->stencilAttachmentIndex(&stencilIndex));
 
     VkClearAttachment attachment;
     attachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
     attachment.colorAttachment = 0; // this value shouldn't matter
     attachment.clearValue.depthStencil = vkStencilColor;
 
-    cbInfo.currentCmdBuf()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
-    cbInfo.fIsEmpty = false;
-
-    // Update command buffer bounds
-    if (!clip.scissorEnabled()) {
-        cbInfo.fBounds.join(fRenderTarget->getBoundsRect());
-    } else {
-        cbInfo.fBounds.join(SkRect::Make(clip.scissorRect()));
-    }
+    this->currentCommandBuffer()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
+    fCurrentCBIsEmpty = false;
 }
 
 void GrVkOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) {
     // parent class should never let us get here with no RT
     SkASSERT(!clip.hasWindowRectangles());
 
-    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
-
     VkClearColorValue vkColor = {{color.fR, color.fG, color.fB, color.fA}};
 
     // If we end up in a situation where we are calling clear without a scissior then in general it
@@ -385,7 +297,7 @@
     // load op (e.g. if we needed to execute a wait op). Thus we also have the empty check here.
     // TODO: Make the waitOp a RenderTask instead so we can clear out the GrOpsTask for a clear. We
     // can then reenable this assert assuming we can't get messed up by a waitOp.
-    //SkASSERT(!cbInfo.fIsEmpty || clip.scissorEnabled());
+    //SkASSERT(!fCurrentCBIsEmpty || clip.scissorEnabled());
 
     // We always do a sub rect clear with clearAttachments since we are inside a render pass
     VkClearRect clearRect;
@@ -406,35 +318,24 @@
     clearRect.layerCount = 1;
 
     uint32_t colorIndex;
-    SkAssertResult(cbInfo.fRenderPass->colorAttachmentIndex(&colorIndex));
+    SkAssertResult(fCurrentRenderPass->colorAttachmentIndex(&colorIndex));
 
     VkClearAttachment attachment;
     attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     attachment.colorAttachment = colorIndex;
     attachment.clearValue.color = vkColor;
 
-    cbInfo.currentCmdBuf()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
-    cbInfo.fIsEmpty = false;
-
-    // Update command buffer bounds
-    if (!clip.scissorEnabled()) {
-        cbInfo.fBounds.join(fRenderTarget->getBoundsRect());
-    } else {
-        cbInfo.fBounds.join(SkRect::Make(clip.scissorRect()));
-    }
+    this->currentCommandBuffer()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
+    fCurrentCBIsEmpty = false;
     return;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrVkOpsRenderPass::addAdditionalRenderPass() {
+    SkASSERT(!this->wrapsSecondaryCommandBuffer());
     GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
 
-    fCommandBufferInfos[fCurrentCmdInfo].currentCmdBuf()->end(fGpu);
-
-    CommandBufferInfo& cbInfo = fCommandBufferInfos.push_back();
-    fCurrentCmdInfo++;
-
     GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_LOAD,
                                             VK_ATTACHMENT_STORE_OP_STORE);
     GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD,
@@ -442,34 +343,42 @@
 
     const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
             vkRT->compatibleRenderPassHandle();
+    SkASSERT(fCurrentRenderPass);
+    fCurrentRenderPass->unref(fGpu);
     if (rpHandle.isValid()) {
-        cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
+        fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
                                                                      vkColorOps,
                                                                      vkStencilOps);
     } else {
-        cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(*vkRT,
+        fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(*vkRT,
                                                                      vkColorOps,
                                                                      vkStencilOps);
     }
-    cbInfo.fLoadStoreState = LoadStoreState::kLoadAndStore;
+    SkASSERT(fCurrentRenderPass);
 
-    cbInfo.fCommandBuffer = fGpu->cmdPool()->findOrCreateSecondaryCommandBuffer(fGpu);
-    // It shouldn't matter what we set the clear color to here since we will assume loading of the
-    // attachment.
-    memset(&cbInfo.fColorClearValue, 0, sizeof(VkClearValue));
-    cbInfo.fBounds.setEmpty();
+    VkClearValue vkClearColor;
+    memset(&vkClearColor, 0, sizeof(VkClearValue));
+    // We use the same fBounds as the whole GrVkOpsRenderPass since we have no way of tracking the
+    // bounds in GrOpsTask for parts before and after inline uploads separately.
+    fGpu->beginRenderPass(fCurrentRenderPass, &vkClearColor, vkRT, fOrigin, fBounds);
 
-    cbInfo.currentCmdBuf()->begin(fGpu, vkRT->framebuffer(), cbInfo.fRenderPass);
+    fCurrentSecondaryCommandBuffer = fGpu->cmdPool()->findOrCreateSecondaryCommandBuffer(fGpu);
+    fCurrentSecondaryCommandBuffer->begin(fGpu, vkRT->framebuffer(), fCurrentRenderPass);
 }
 
 void GrVkOpsRenderPass::inlineUpload(GrOpFlushState* state,
                                           GrDeferredTextureUploadFn& upload) {
-    if (!fCommandBufferInfos[fCurrentCmdInfo].fIsEmpty) {
-        this->addAdditionalRenderPass();
+    if (fCurrentSecondaryCommandBuffer) {
+        fCurrentSecondaryCommandBuffer->end(fGpu);
+        fGpu->submitSecondaryCommandBuffer(std::move(fCurrentSecondaryCommandBuffer));
     }
+    fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
 
-    fPreCommandBufferTasks.emplace<InlineUpload>(state, upload);
-    ++fCommandBufferInfos[fCurrentCmdInfo].fNumPreCmds;
+    // We pass in true here to signal that after the upload we need to set the upload textures
+    // layout back to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.
+    state->doUpload(upload, true);
+
+    this->addAdditionalRenderPass();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -477,7 +386,7 @@
 void GrVkOpsRenderPass::bindGeometry(const GrGpuBuffer* indexBuffer,
                                           const GrGpuBuffer* vertexBuffer,
                                           const GrGpuBuffer* instanceBuffer) {
-    GrVkSecondaryCommandBuffer* currCmdBuf = fCommandBufferInfos[fCurrentCmdInfo].currentCmdBuf();
+    GrVkCommandBuffer* currCmdBuf = this->currentCommandBuffer();
     // There is no need to put any memory barriers to make sure host writes have finished here.
     // When a command buffer is submitted to a queue, there is an implicit memory barrier that
     // occurs for all host writes. Additionally, BufferMemoryBarriers are not allowed inside of
@@ -516,10 +425,10 @@
         const GrPipeline::FixedDynamicState* fixedDynamicState,
         const GrPipeline::DynamicStateArrays* dynamicStateArrays,
         GrPrimitiveType primitiveType) {
-    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
-    SkASSERT(cbInfo.fRenderPass);
+    GrVkCommandBuffer* currentCB = this->currentCommandBuffer();
+    SkASSERT(fCurrentRenderPass);
 
-    VkRenderPass compatibleRenderPass = cbInfo.fRenderPass->vkRenderPass();
+    VkRenderPass compatibleRenderPass = fCurrentRenderPass->vkRenderPass();
 
     const GrTextureProxy* const* primProcProxies = nullptr;
     if (dynamicStateArrays && dynamicStateArrays->fPrimitiveProcessorTextures) {
@@ -541,34 +450,27 @@
         return pipelineState;
     }
 
-    fLastPipelineState = pipelineState;
+    pipelineState->bindPipeline(fGpu, currentCB);
 
-    pipelineState->bindPipeline(fGpu, cbInfo.currentCmdBuf());
-
-    pipelineState->setAndBindUniforms(fGpu, fRenderTarget, fOrigin,
-                                      primProc, pipeline, cbInfo.currentCmdBuf());
+    pipelineState->setAndBindUniforms(fGpu, fRenderTarget, fOrigin, primProc, pipeline, currentCB);
 
     // Check whether we need to bind textures between each GrMesh. If not we can bind them all now.
     bool setTextures = !(dynamicStateArrays && dynamicStateArrays->fPrimitiveProcessorTextures);
     if (setTextures) {
-        pipelineState->setAndBindTextures(fGpu, primProc, pipeline, primProcProxies,
-                                          cbInfo.currentCmdBuf());
+        pipelineState->setAndBindTextures(fGpu, primProc, pipeline, primProcProxies, currentCB);
     }
 
     if (!pipeline.isScissorEnabled()) {
-        GrVkPipeline::SetDynamicScissorRectState(fGpu, cbInfo.currentCmdBuf(),
-                                                 fRenderTarget, fOrigin,
+        GrVkPipeline::SetDynamicScissorRectState(fGpu, currentCB, fRenderTarget, fOrigin,
                                                  SkIRect::MakeWH(fRenderTarget->width(),
                                                                  fRenderTarget->height()));
     } else if (!dynamicStateArrays || !dynamicStateArrays->fScissorRects) {
         SkASSERT(fixedDynamicState);
-        GrVkPipeline::SetDynamicScissorRectState(fGpu, cbInfo.currentCmdBuf(), fRenderTarget,
-                                                 fOrigin,
+        GrVkPipeline::SetDynamicScissorRectState(fGpu, currentCB, fRenderTarget, fOrigin,
                                                  fixedDynamicState->fScissorRect);
     }
-    GrVkPipeline::SetDynamicViewportState(fGpu, cbInfo.currentCmdBuf(), fRenderTarget);
-    GrVkPipeline::SetDynamicBlendConstantState(fGpu, cbInfo.currentCmdBuf(),
-                                               pipeline.outputSwizzle(),
+    GrVkPipeline::SetDynamicViewportState(fGpu, currentCB, fRenderTarget);
+    GrVkPipeline::SetDynamicBlendConstantState(fGpu, currentCB, pipeline.outputSwizzle(),
                                                pipeline.getXferProcessor());
 
     return pipelineState;
@@ -594,8 +496,6 @@
         return;
     }
 
-    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
-
 #ifdef SK_DEBUG
     if (dynamicStateArrays && dynamicStateArrays->fPrimitiveProcessorTextures) {
         for (int m = 0, i = 0; m < meshCount; ++m) {
@@ -646,22 +546,21 @@
         }
 
         if (dynamicScissor) {
-            GrVkPipeline::SetDynamicScissorRectState(fGpu, cbInfo.currentCmdBuf(), fRenderTarget,
-                                                     fOrigin,
+            GrVkPipeline::SetDynamicScissorRectState(fGpu, this->currentCommandBuffer(),
+                                                     fRenderTarget, fOrigin,
                                                      dynamicStateArrays->fScissorRects[i]);
         }
         if (dynamicTextures) {
             GrTextureProxy* const* meshProxies = dynamicStateArrays->fPrimitiveProcessorTextures +
                                                  primProc.numTextureSamplers() * i;
             pipelineState->setAndBindTextures(fGpu, primProc, pipeline, meshProxies,
-                                              cbInfo.currentCmdBuf());
+                                              this->currentCommandBuffer());
         }
         SkASSERT(pipelineState);
         mesh.sendToGpu(this);
     }
 
-    cbInfo.fBounds.join(bounds);
-    cbInfo.fIsEmpty = false;
+    fCurrentCBIsEmpty = false;
 }
 
 void GrVkOpsRenderPass::sendInstancedMeshToGpu(GrPrimitiveType,
@@ -671,13 +570,12 @@
                                                const GrBuffer* instanceBuffer,
                                                int instanceCount,
                                                int baseInstance) {
-    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
     SkASSERT(!vertexBuffer || !vertexBuffer->isCpuBuffer());
     SkASSERT(!instanceBuffer || !instanceBuffer->isCpuBuffer());
     auto gpuVertexBuffer = static_cast<const GrGpuBuffer*>(vertexBuffer);
     auto gpuInstanceBuffer = static_cast<const GrGpuBuffer*>(instanceBuffer);
     this->bindGeometry(nullptr, gpuVertexBuffer, gpuInstanceBuffer);
-    cbInfo.currentCmdBuf()->draw(fGpu, vertexCount, instanceCount, baseVertex, baseInstance);
+    this->currentCommandBuffer()->draw(fGpu, vertexCount, instanceCount, baseVertex, baseInstance);
     fGpu->stats()->incNumDraws();
 }
 
@@ -692,7 +590,6 @@
                                                       int baseInstance,
                                                       GrPrimitiveRestart restart) {
     SkASSERT(restart == GrPrimitiveRestart::kNo);
-    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
     SkASSERT(!vertexBuffer || !vertexBuffer->isCpuBuffer());
     SkASSERT(!instanceBuffer || !instanceBuffer->isCpuBuffer());
     SkASSERT(!indexBuffer->isCpuBuffer());
@@ -700,8 +597,8 @@
     auto gpuVertexBuffer = static_cast<const GrGpuBuffer*>(vertexBuffer);
     auto gpuInstanceBuffer = static_cast<const GrGpuBuffer*>(instanceBuffer);
     this->bindGeometry(gpuIndexxBuffer, gpuVertexBuffer, gpuInstanceBuffer);
-    cbInfo.currentCmdBuf()->drawIndexed(fGpu, indexCount, instanceCount,
-                                        baseIndex, baseVertex, baseInstance);
+    this->currentCommandBuffer()->drawIndexed(fGpu, indexCount, instanceCount,
+                                              baseIndex, baseVertex, baseInstance);
     fGpu->stats()->incNumDraws();
 }
 
@@ -712,15 +609,16 @@
 
     GrVkImage* targetImage = target->msaaImage() ? target->msaaImage() : target;
 
-    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
     VkRect2D bounds;
     bounds.offset = { 0, 0 };
     bounds.extent = { 0, 0 };
 
+    SkASSERT(fCurrentSecondaryCommandBuffer);
+
     GrVkDrawableInfo vkInfo;
-    vkInfo.fSecondaryCommandBuffer = cbInfo.currentCmdBuf()->vkCommandBuffer();
-    vkInfo.fCompatibleRenderPass = cbInfo.fRenderPass->vkRenderPass();
-    SkAssertResult(cbInfo.fRenderPass->colorAttachmentIndex(&vkInfo.fColorAttachmentIndex));
+    vkInfo.fSecondaryCommandBuffer = fCurrentSecondaryCommandBuffer->vkCommandBuffer();
+    vkInfo.fCompatibleRenderPass = fCurrentRenderPass->vkRenderPass();
+    SkAssertResult(fCurrentRenderPass->colorAttachmentIndex(&vkInfo.fColorAttachmentIndex));
     vkInfo.fFormat = targetImage->imageFormat();
     vkInfo.fDrawBounds = &bounds;
 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
@@ -732,18 +630,11 @@
     GrBackendDrawableInfo info(vkInfo);
 
     // After we draw into the command buffer via the drawable, cached state we have may be invalid.
-    cbInfo.currentCmdBuf()->invalidateState();
+    this->currentCommandBuffer()->invalidateState();
     // Also assume that the drawable produced output.
-    cbInfo.fIsEmpty = false;
+    fCurrentCBIsEmpty = false;
 
     drawable->draw(info);
     fGpu->addDrawable(std::move(drawable));
-
-    if (bounds.extent.width == 0 || bounds.extent.height == 0) {
-        cbInfo.fBounds.join(target->getBoundsRect());
-    } else {
-        cbInfo.fBounds.join(SkRect::MakeXYWH(bounds.offset.x, bounds.offset.y,
-                                             bounds.extent.width, bounds.extent.height));
-    }
 }