Add handling of failed framebuffer creation in vulkan.

Bug: skia:9603
Change-Id: I264d1387f319cbe3bb27982ccc6e01fb530abbd5
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/253238
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/GrOpsTask.cpp b/src/gpu/GrOpsTask.cpp
index ed4aba5..62a94cd 100644
--- a/src/gpu/GrOpsTask.cpp
+++ b/src/gpu/GrOpsTask.cpp
@@ -543,6 +543,9 @@
             flushState->gpu(), proxy->peekRenderTarget(), fTargetView.origin(),
             fClippedContentBounds, fColorLoadOp, fLoadClearColor, stencilLoadOp, stencilStoreOp,
             fSampledProxies);
+    if (!renderPass) {
+        return false;
+    }
     flushState->setOpsRenderPass(renderPass);
     renderPass->begin();
 
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index 4177102..2aed1b5 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -421,15 +421,20 @@
     fHasWork = false;
 }
 
-void GrVkPrimaryCommandBuffer::beginRenderPass(const GrVkGpu* gpu,
+bool GrVkPrimaryCommandBuffer::beginRenderPass(GrVkGpu* gpu,
                                                const GrVkRenderPass* renderPass,
                                                const VkClearValue clearValues[],
-                                               const GrVkRenderTarget& target,
+                                               GrVkRenderTarget* target,
                                                const SkIRect& bounds,
                                                bool forSecondaryCB) {
     SkASSERT(fIsActive);
     SkASSERT(!fActiveRenderPass);
-    SkASSERT(renderPass->isCompatible(target));
+    SkASSERT(renderPass->isCompatible(*target));
+
+    const GrVkFramebuffer* framebuffer = target->getFramebuffer();
+    if (!framebuffer) {
+        return false;
+    }
 
     this->addingWork(gpu);
 
@@ -442,7 +447,7 @@
     beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
     beginInfo.pNext = nullptr;
     beginInfo.renderPass = renderPass->vkRenderPass();
-    beginInfo.framebuffer = target.framebuffer()->framebuffer();
+    beginInfo.framebuffer = framebuffer->framebuffer();
     beginInfo.renderArea = renderArea;
     beginInfo.clearValueCount = renderPass->clearValueCount();
     beginInfo.pClearValues = clearValues;
@@ -453,7 +458,8 @@
     GR_VK_CALL(gpu->vkInterface(), CmdBeginRenderPass(fCmdBuffer, &beginInfo, contents));
     fActiveRenderPass = renderPass;
     this->addResource(renderPass);
-    target.addResources(*this);
+    target->addResources(*this);
+    return true;
 }
 
 void GrVkPrimaryCommandBuffer::endRenderPass(const GrVkGpu* gpu) {
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index 7b34e2b..cb603f6 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -99,6 +99,7 @@
     // Add ref-counted resource that will be tracked and released when this command buffer finishes
     // execution
     void addResource(const GrVkResource* resource) {
+        SkASSERT(resource);
         resource->ref();
         resource->notifyAddedToCommandBuffer();
         fTrackedResources.append(1, &resource);
@@ -205,10 +206,10 @@
 
     // Begins render pass on this command buffer. The framebuffer from GrVkRenderTarget will be used
     // in the render pass.
-    void beginRenderPass(const GrVkGpu* gpu,
+    bool beginRenderPass(GrVkGpu* gpu,
                          const GrVkRenderPass* renderPass,
                          const VkClearValue clearValues[],
-                         const GrVkRenderTarget& target,
+                         GrVkRenderTarget* target,
                          const SkIRect& bounds,
                          bool forSecondaryCB);
     void endRenderPass(const GrVkGpu* gpu);
diff --git a/src/gpu/vk/GrVkFramebuffer.cpp b/src/gpu/vk/GrVkFramebuffer.cpp
index a06d792..f256999 100644
--- a/src/gpu/vk/GrVkFramebuffer.cpp
+++ b/src/gpu/vk/GrVkFramebuffer.cpp
@@ -40,10 +40,9 @@
     createInfo.layers = 1;
 
     VkFramebuffer framebuffer;
-    VkResult err = GR_VK_CALL(gpu->vkInterface(), CreateFramebuffer(gpu->device(),
-                                                                    &createInfo,
-                                                                    nullptr,
-                                                                    &framebuffer));
+    VkResult err;
+    GR_VK_CALL_RESULT(gpu, err, CreateFramebuffer(gpu->device(), &createInfo, nullptr,
+                                                  &framebuffer));
     if (err) {
         return nullptr;
     }
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 99e6afd..cb48930 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -328,7 +328,9 @@
         fCachedOpsRenderPass.reset(new GrVkOpsRenderPass(this));
     }
 
-    fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies);
+    if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
+        return nullptr;
+    }
     return fCachedOpsRenderPass.get();
 }
 
@@ -2390,7 +2392,7 @@
     }
 }
 
-void GrVkGpu::beginRenderPass(const GrVkRenderPass* renderPass,
+bool GrVkGpu::beginRenderPass(const GrVkRenderPass* renderPass,
                               const VkClearValue* colorClear,
                               GrVkRenderTarget* target, GrSurfaceOrigin origin,
                               const SkIRect& bounds, bool forSecondaryCB) {
@@ -2423,8 +2425,8 @@
     clears[1].depthStencil.depth = 0.0f;
     clears[1].depthStencil.stencil = 0;
 
-    fCurrentCmdBuffer->beginRenderPass(this, renderPass, clears, *target, adjustedBounds,
-                                       forSecondaryCB);
+   return fCurrentCmdBuffer->beginRenderPass(this, renderPass, clears, target, adjustedBounds,
+                                             forSecondaryCB);
 }
 
 void GrVkGpu::endRenderPass(GrRenderTarget* target, GrSurfaceOrigin origin,
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index ebccc19..d835521 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -166,7 +166,7 @@
 
     void storeVkPipelineCacheData() override;
 
-    void beginRenderPass(const GrVkRenderPass*,
+    bool beginRenderPass(const GrVkRenderPass*,
                          const VkClearValue* colorClear,
                          GrVkRenderTarget*, GrSurfaceOrigin,
                          const SkIRect& bounds, bool forSecondaryCB);
diff --git a/src/gpu/vk/GrVkOpsRenderPass.cpp b/src/gpu/vk/GrVkOpsRenderPass.cpp
index 6b61980..fe811c3 100644
--- a/src/gpu/vk/GrVkOpsRenderPass.cpp
+++ b/src/gpu/vk/GrVkOpsRenderPass.cpp
@@ -60,7 +60,7 @@
 
 GrVkOpsRenderPass::GrVkOpsRenderPass(GrVkGpu* gpu) : fGpu(gpu) {}
 
-void GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
+bool GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
                              const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
                              const SkPMColor4f& clearColor) {
 
@@ -101,13 +101,14 @@
                                   false);
     }
 
-    const GrVkResourceProvider::CompatibleRPHandle& rpHandle = vkRT->compatibleRenderPassHandle();
+    const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
+            vkRT->compatibleRenderPassHandle();
     if (rpHandle.isValid()) {
         fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
                                                                      vkColorOps,
                                                                      vkStencilOps);
     } else {
-        fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(*vkRT,
+        fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(vkRT,
                                                                      vkColorOps,
                                                                      vkStencilOps);
     }
@@ -121,11 +122,19 @@
 
     if (!fGpu->vkCaps().preferPrimaryOverSecondaryCommandBuffers()) {
         fCurrentSecondaryCommandBuffer = fGpu->cmdPool()->findOrCreateSecondaryCommandBuffer(fGpu);
-        fCurrentSecondaryCommandBuffer->begin(fGpu, vkRT->framebuffer(), fCurrentRenderPass);
+        fCurrentSecondaryCommandBuffer->begin(fGpu, vkRT->getFramebuffer(), fCurrentRenderPass);
     }
 
-    fGpu->beginRenderPass(fCurrentRenderPass, &vkClearColor, vkRT, fOrigin, fBounds,
-                          SkToBool(fCurrentSecondaryCommandBuffer));
+    if (!fGpu->beginRenderPass(fCurrentRenderPass, &vkClearColor, vkRT, fOrigin, fBounds,
+                               SkToBool(fCurrentSecondaryCommandBuffer))) {
+        if (fCurrentSecondaryCommandBuffer) {
+            fCurrentSecondaryCommandBuffer->end(fGpu);
+        }
+        fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
+        fCurrentRenderPass = nullptr;
+        return false;
+    }
+    return true;
 }
 
 void GrVkOpsRenderPass::initWrapped() {
@@ -163,6 +172,10 @@
     if (!fRenderTarget) {
         return;
     }
+    if (!fCurrentRenderPass) {
+        SkASSERT(fGpu->isDeviceLost());
+        return;
+    }
 
     // We don't want to actually submit the secondary command buffer if it is wrapped.
     if (this->wrapsSecondaryCommandBuffer()) {
@@ -175,7 +188,7 @@
     fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
 }
 
-void GrVkOpsRenderPass::set(GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds,
+bool GrVkOpsRenderPass::set(GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds,
                             const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
                             const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
                             const SkTArray<GrTextureProxy*, true>& sampledProxies) {
@@ -203,10 +216,10 @@
 
     if (this->wrapsSecondaryCommandBuffer()) {
         this->initWrapped();
-        return;
+        return true;
     }
 
-    this->init(colorInfo, stencilInfo, colorInfo.fClearColor);
+    return this->init(colorInfo, stencilInfo, colorInfo.fClearColor);
 }
 
 void GrVkOpsRenderPass::reset() {
@@ -238,6 +251,11 @@
 }
 
 void GrVkOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
+    if (!fCurrentRenderPass) {
+        SkASSERT(fGpu->isDeviceLost());
+        return;
+    }
+
     SkASSERT(!clip.hasWindowRectangles());
 
     GrStencilAttachment* sb = fRenderTarget->renderTargetPriv().getStencilAttachment();
@@ -289,6 +307,11 @@
 }
 
 void GrVkOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) {
+    if (!fCurrentRenderPass) {
+        SkASSERT(fGpu->isDeviceLost());
+        return;
+    }
+
     // parent class should never let us get here with no RT
     SkASSERT(!clip.hasWindowRectangles());
 
@@ -353,7 +376,7 @@
                                                                      vkColorOps,
                                                                      vkStencilOps);
     } else {
-        fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(*vkRT,
+        fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(vkRT,
                                                                      vkColorOps,
                                                                      vkStencilOps);
     }
@@ -365,16 +388,26 @@
     if (!fGpu->vkCaps().preferPrimaryOverSecondaryCommandBuffers() ||
         mustUseSecondaryCommandBuffer) {
         fCurrentSecondaryCommandBuffer = fGpu->cmdPool()->findOrCreateSecondaryCommandBuffer(fGpu);
-        fCurrentSecondaryCommandBuffer->begin(fGpu, vkRT->framebuffer(), fCurrentRenderPass);
+        fCurrentSecondaryCommandBuffer->begin(fGpu, vkRT->getFramebuffer(), fCurrentRenderPass);
     }
 
     // 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,
-                          SkToBool(fCurrentSecondaryCommandBuffer));
+    if (!fGpu->beginRenderPass(fCurrentRenderPass, &vkClearColor, vkRT, fOrigin, fBounds,
+                               SkToBool(fCurrentSecondaryCommandBuffer))) {
+        if (fCurrentSecondaryCommandBuffer) {
+            fCurrentSecondaryCommandBuffer->end(fGpu);
+        }
+        fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
+        fCurrentRenderPass = nullptr;
+    }
 }
 
 void GrVkOpsRenderPass::inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) {
+    if (!fCurrentRenderPass) {
+        SkASSERT(fGpu->isDeviceLost());
+        return;
+    }
     if (fCurrentSecondaryCommandBuffer) {
         fCurrentSecondaryCommandBuffer->end(fGpu);
         fGpu->submitSecondaryCommandBuffer(std::move(fCurrentSecondaryCommandBuffer));
@@ -493,6 +526,10 @@
 void GrVkOpsRenderPass::onDraw(const GrProgramInfo& programInfo,
                                const GrMesh meshes[], int meshCount,
                                const SkRect& bounds) {
+    if (!fCurrentRenderPass) {
+        SkASSERT(fGpu->isDeviceLost());
+        return;
+    }
 
     SkASSERT(meshCount); // guaranteed by GrOpsRenderPass::draw
 
@@ -616,6 +653,10 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrVkOpsRenderPass::executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
+    if (!fCurrentRenderPass) {
+        SkASSERT(fGpu->isDeviceLost());
+        return;
+    }
     GrVkRenderTarget* target = static_cast<GrVkRenderTarget*>(fRenderTarget);
 
     GrVkImage* targetImage = target->msaaImage() ? target->msaaImage() : target;
@@ -627,6 +668,11 @@
     if (!fCurrentSecondaryCommandBuffer) {
         fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
         this->addAdditionalRenderPass(true);
+        // We may have failed to start a new render pass
+        if (!fCurrentRenderPass) {
+            SkASSERT(fGpu->isDeviceLost());
+            return;
+        }
     }
     SkASSERT(fCurrentSecondaryCommandBuffer);
 
diff --git a/src/gpu/vk/GrVkOpsRenderPass.h b/src/gpu/vk/GrVkOpsRenderPass.h
index 65d6b5b..784bc04 100644
--- a/src/gpu/vk/GrVkOpsRenderPass.h
+++ b/src/gpu/vk/GrVkOpsRenderPass.h
@@ -38,7 +38,7 @@
 
     void executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>) override;
 
-    void set(GrRenderTarget*, GrSurfaceOrigin, const SkIRect& bounds,
+    bool set(GrRenderTarget*, GrSurfaceOrigin, const SkIRect& bounds,
              const GrOpsRenderPass::LoadAndStoreInfo&,
              const GrOpsRenderPass::StencilLoadAndStoreInfo&,
              const SkTArray<GrTextureProxy*, true>& sampledProxies);
@@ -51,7 +51,7 @@
 #endif
 
 private:
-    void init(const GrOpsRenderPass::LoadAndStoreInfo&,
+    bool init(const GrOpsRenderPass::LoadAndStoreInfo&,
               const GrOpsRenderPass::StencilLoadAndStoreInfo&,
               const SkPMColor4f& clearColor);
 
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
index 52c7c52..bb3647d 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
@@ -343,7 +343,9 @@
     desc->fShaderKeyLength = SkToU32(keyLength);
 
     GrVkRenderTarget* vkRT = (GrVkRenderTarget*)renderTarget;
-    vkRT->simpleRenderPass()->genKey(&b);
+    // TODO: support failure in getSimpleRenderPass
+    SkASSERT(vkRT->getSimpleRenderPass());
+    vkRT->getSimpleRenderPass()->genKey(&b);
 
     stencil.genKey(&b);
 
diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp
index d7d53fb..ff42b58 100644
--- a/src/gpu/vk/GrVkRenderTarget.cpp
+++ b/src/gpu/vk/GrVkRenderTarget.cpp
@@ -39,11 +39,10 @@
         , fMSAAImage(new GrVkImage(msaaInfo, std::move(msaaLayout),
                                    GrBackendObjectOwnership::kOwned))
         , fResolveAttachmentView(resolveAttachmentView)
-        , fFramebuffer(nullptr)
+        , fCachedFramebuffer(nullptr)
         , fCachedSimpleRenderPass(nullptr) {
     SkASSERT(info.fProtected == msaaInfo.fProtected);
     SkASSERT(sampleCnt > 1);
-    this->createFramebuffer(gpu);
     this->registerWithCacheWrapped(GrWrapCacheable::kNo);
 }
 
@@ -67,11 +66,10 @@
         , fMSAAImage(
                   new GrVkImage(msaaInfo, std::move(msaaLayout), GrBackendObjectOwnership::kOwned))
         , fResolveAttachmentView(resolveAttachmentView)
-        , fFramebuffer(nullptr)
+        , fCachedFramebuffer(nullptr)
         , fCachedSimpleRenderPass(nullptr) {
     SkASSERT(info.fProtected == msaaInfo.fProtected);
     SkASSERT(sampleCnt > 1);
-    this->createFramebuffer(gpu);
 }
 
 // We're virtually derived from GrSurface (via GrRenderTarget) so its
@@ -87,9 +85,8 @@
         , fColorAttachmentView(colorAttachmentView)
         , fMSAAImage(nullptr)
         , fResolveAttachmentView(nullptr)
-        , fFramebuffer(nullptr)
+        , fCachedFramebuffer(nullptr)
         , fCachedSimpleRenderPass(nullptr) {
-    this->createFramebuffer(gpu);
     this->registerWithCacheWrapped(GrWrapCacheable::kNo);
 }
 
@@ -107,9 +104,8 @@
         , fColorAttachmentView(colorAttachmentView)
         , fMSAAImage(nullptr)
         , fResolveAttachmentView(nullptr)
-        , fFramebuffer(nullptr)
+        , fCachedFramebuffer(nullptr)
         , fCachedSimpleRenderPass(nullptr) {
-    this->createFramebuffer(gpu);
 }
 
 GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
@@ -124,7 +120,7 @@
         , fColorAttachmentView(nullptr)
         , fMSAAImage(nullptr)
         , fResolveAttachmentView(nullptr)
-        , fFramebuffer(nullptr)
+        , fCachedFramebuffer(nullptr)
         , fCachedSimpleRenderPass(renderPass)
         , fSecondaryCommandBuffer(secondaryCommandBuffer) {
     SkASSERT(fSecondaryCommandBuffer != VK_NULL_HANDLE);
@@ -236,30 +232,56 @@
 
 bool GrVkRenderTarget::completeStencilAttachment() {
     SkASSERT(!this->wrapsSecondaryCommandBuffer());
-    this->createFramebuffer(this->getVkGpu());
+    // If we have a previous renderpass or framebuffer it will have been made without stencil, so
+    // we set it to null to trigger creating a new one the next time we need it.
+    if (fCachedSimpleRenderPass) {
+        fCachedSimpleRenderPass->unref(this->getVkGpu());
+        fCachedSimpleRenderPass = nullptr;
+    }
+    if (fCachedFramebuffer) {
+        fCachedFramebuffer->unref(this->getVkGpu());
+        fCachedFramebuffer = nullptr;
+    }
+    fCompatibleRPHandle = GrVkResourceProvider::CompatibleRPHandle();
     return true;
 }
 
-void GrVkRenderTarget::createFramebuffer(GrVkGpu* gpu) {
-    SkASSERT(!this->wrapsSecondaryCommandBuffer());
-    if (fFramebuffer) {
-        fFramebuffer->unref(gpu);
-    }
+const GrVkRenderPass* GrVkRenderTarget::getSimpleRenderPass() {
     if (fCachedSimpleRenderPass) {
-        fCachedSimpleRenderPass->unref(gpu);
+        return fCachedSimpleRenderPass;
     }
+    return this->createSimpleRenderPass();
+}
 
-    // Vulkan requires us to create a compatible renderpass before we can create our framebuffer,
-    // so we use this to get a (cached) basic renderpass, only for creation.
+const GrVkRenderPass* GrVkRenderTarget::createSimpleRenderPass() {
+    SkASSERT(!this->wrapsSecondaryCommandBuffer());
+    SkASSERT(!fCachedSimpleRenderPass);
+
     fCachedSimpleRenderPass =
-        gpu->resourceProvider().findCompatibleRenderPass(*this, &fCompatibleRPHandle);
+        this->getVkGpu()->resourceProvider().findCompatibleRenderPass(*this, &fCompatibleRPHandle);
+    // TODO: allow for the above call to fail and handle returning null from getSimpleRenderPass
+    SkASSERT(fCachedSimpleRenderPass);
+    return fCachedSimpleRenderPass;
+}
 
+const GrVkFramebuffer* GrVkRenderTarget::getFramebuffer() {
+    if (fCachedFramebuffer) {
+        return fCachedFramebuffer;
+    }
+    return this->createFramebuffer();
+}
+
+const GrVkFramebuffer* GrVkRenderTarget::createFramebuffer() {
+    SkASSERT(!this->wrapsSecondaryCommandBuffer());
+    SkASSERT(!fCachedFramebuffer);
+
+    GrVkGpu* gpu = this->getVkGpu();
     // Stencil attachment view is stored in the base RT stencil attachment
     const GrVkImageView* stencilView = this->stencilAttachmentView();
-    fFramebuffer = GrVkFramebuffer::Create(gpu, this->width(), this->height(),
-                                           fCachedSimpleRenderPass, fColorAttachmentView,
-                                           stencilView);
-    SkASSERT(fFramebuffer);
+    fCachedFramebuffer = GrVkFramebuffer::Create(gpu, this->width(), this->height(),
+                                                 this->getSimpleRenderPass(),
+                                                 fColorAttachmentView, stencilView);
+    return fCachedFramebuffer;
 }
 
 void GrVkRenderTarget::getAttachmentsDescriptor(
@@ -289,12 +311,12 @@
     SkASSERT(!fMSAAImage);
     SkASSERT(!fResolveAttachmentView);
     SkASSERT(!fColorAttachmentView);
-    SkASSERT(!fFramebuffer);
+    SkASSERT(!fCachedFramebuffer);
     SkASSERT(!fCachedSimpleRenderPass);
 }
 
-void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer) const {
-    commandBuffer.addResource(this->framebuffer());
+void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer) {
+    commandBuffer.addResource(this->getFramebuffer());
     commandBuffer.addResource(this->colorAttachmentView());
     commandBuffer.addResource(this->msaaImageResource() ? this->msaaImageResource()
                                                         : this->resource());
@@ -320,9 +342,9 @@
         fColorAttachmentView->unref(gpu);
         fColorAttachmentView = nullptr;
     }
-    if (fFramebuffer) {
-        fFramebuffer->unref(gpu);
-        fFramebuffer = nullptr;
+    if (fCachedFramebuffer) {
+        fCachedFramebuffer->unref(gpu);
+        fCachedFramebuffer = nullptr;
     }
     if (fCachedSimpleRenderPass) {
         fCachedSimpleRenderPass->unref(gpu);
@@ -344,9 +366,9 @@
         fColorAttachmentView->unrefAndAbandon();
         fColorAttachmentView = nullptr;
     }
-    if (fFramebuffer) {
-        fFramebuffer->unrefAndAbandon();
-        fFramebuffer = nullptr;
+    if (fCachedFramebuffer) {
+        fCachedFramebuffer->unrefAndAbandon();
+        fCachedFramebuffer = nullptr;
     }
     if (fCachedSimpleRenderPass) {
         fCachedSimpleRenderPass->unrefAndAbandon();
diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h
index 9372aa1..2f7ec83 100644
--- a/src/gpu/vk/GrVkRenderTarget.h
+++ b/src/gpu/vk/GrVkRenderTarget.h
@@ -44,7 +44,7 @@
 
     GrBackendFormat backendFormat() const override { return this->getBackendFormat(); }
 
-    const GrVkFramebuffer* framebuffer() const { return fFramebuffer; }
+    const GrVkFramebuffer* getFramebuffer();
     const GrVkImageView* colorAttachmentView() const { return fColorAttachmentView; }
     const GrVkResource* msaaImageResource() const {
         if (fMSAAImage) {
@@ -57,9 +57,13 @@
     const GrVkResource* stencilImageResource() const;
     const GrVkImageView* stencilAttachmentView() const;
 
-    const GrVkRenderPass* simpleRenderPass() const { return fCachedSimpleRenderPass; }
-    GrVkResourceProvider::CompatibleRPHandle compatibleRenderPassHandle() const {
+    const GrVkRenderPass* getSimpleRenderPass();
+    GrVkResourceProvider::CompatibleRPHandle compatibleRenderPassHandle() {
         SkASSERT(!this->wrapsSecondaryCommandBuffer());
+        if (!fCompatibleRPHandle.isValid()) {
+            SkASSERT(!fCachedSimpleRenderPass);
+            this->createSimpleRenderPass();
+        }
         return fCompatibleRPHandle;
     }
     const GrVkRenderPass* externalRenderPass() const {
@@ -84,7 +88,7 @@
     void getAttachmentsDescriptor(GrVkRenderPass::AttachmentsDescriptor* desc,
                                   GrVkRenderPass::AttachmentFlags* flags) const;
 
-    void addResources(GrVkCommandBuffer& commandBuffer) const;
+    void addResources(GrVkCommandBuffer& commandBuffer);
 
 protected:
     GrVkRenderTarget(GrVkGpu* gpu,
@@ -105,8 +109,6 @@
                      const GrVkImageView* colorAttachmentView,
                      GrBackendObjectOwnership);
 
-    GrVkGpu* getVkGpu() const;
-
     void onAbandon() override;
     void onRelease() override;
 
@@ -122,12 +124,6 @@
                                       numColorSamples, GrMipMapped::kNo);
     }
 
-    void createFramebuffer(GrVkGpu* gpu);
-
-    const GrVkImageView*       fColorAttachmentView;
-    std::unique_ptr<GrVkImage> fMSAAImage;
-    const GrVkImageView*       fResolveAttachmentView;
-
 private:
     GrVkRenderTarget(GrVkGpu* gpu,
                      const GrSurfaceDesc& desc,
@@ -153,6 +149,11 @@
                      const GrVkRenderPass* renderPass,
                      VkCommandBuffer secondaryCommandBuffer);
 
+    GrVkGpu* getVkGpu() const;
+
+    const GrVkRenderPass* createSimpleRenderPass();
+    const GrVkFramebuffer* createFramebuffer();
+
     bool completeStencilAttachment() override;
 
     // In Vulkan we call the release proc after we are finished with the underlying
@@ -165,7 +166,11 @@
     void releaseInternalObjects();
     void abandonInternalObjects();
 
-    const GrVkFramebuffer*     fFramebuffer;
+    const GrVkImageView*       fColorAttachmentView;
+    std::unique_ptr<GrVkImage> fMSAAImage;
+    const GrVkImageView*       fResolveAttachmentView;
+
+    const GrVkFramebuffer*     fCachedFramebuffer;
 
     // This is a cached pointer to a simple render pass. The render target should unref it
     // once it is done with it.
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index 6fb8788..c869029 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -160,18 +160,18 @@
 }
 
 const GrVkRenderPass* GrVkResourceProvider::findRenderPass(
-                                                     const GrVkRenderTarget& target,
+                                                     GrVkRenderTarget* target,
                                                      const GrVkRenderPass::LoadStoreOps& colorOps,
                                                      const GrVkRenderPass::LoadStoreOps& stencilOps,
                                                      CompatibleRPHandle* compatibleHandle) {
     GrVkResourceProvider::CompatibleRPHandle tempRPHandle;
     GrVkResourceProvider::CompatibleRPHandle* pRPHandle = compatibleHandle ? compatibleHandle
                                                                            : &tempRPHandle;
-    *pRPHandle = target.compatibleRenderPassHandle();
+    *pRPHandle = target->compatibleRenderPassHandle();
 
     // This will get us the handle to (and possible create) the compatible set for the specific
     // GrVkRenderPass we are looking for.
-    this->findCompatibleRenderPass(target, compatibleHandle);
+    this->findCompatibleRenderPass(*target, compatibleHandle);
     return this->findRenderPass(*pRPHandle, colorOps, stencilOps);
 }
 
diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h
index e07de2b..9cafcb4 100644
--- a/src/gpu/vk/GrVkResourceProvider.h
+++ b/src/gpu/vk/GrVkResourceProvider.h
@@ -70,7 +70,7 @@
     // refcount, and returns. The caller can optionally pass in a pointer to a CompatibleRPHandle.
     // If this is non null it will be set to a handle that can be used in the furutre to quickly
     // return a GrVkRenderPasses without the need inspecting a GrVkRenderTarget.
-    const GrVkRenderPass* findRenderPass(const GrVkRenderTarget& target,
+    const GrVkRenderPass* findRenderPass(GrVkRenderTarget* target,
                                          const GrVkRenderPass::LoadStoreOps& colorOps,
                                          const GrVkRenderPass::LoadStoreOps& stencilOps,
                                          CompatibleRPHandle* compatibleHandle = nullptr);