Handle failure to create VkRenderPasses in vulkan backend.

Bug: skia:9603
Change-Id: I8c56f399d58b109d163ff69b654d07edbc44dde0
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/253497
Reviewed-by: Chris Dalton <csmartdalton@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/vk/GrVkOpsRenderPass.cpp b/src/gpu/vk/GrVkOpsRenderPass.cpp
index 01ff901..c880ace 100644
--- a/src/gpu/vk/GrVkOpsRenderPass.cpp
+++ b/src/gpu/vk/GrVkOpsRenderPass.cpp
@@ -112,7 +112,9 @@
                                                                      vkColorOps,
                                                                      vkStencilOps);
     }
-    SkASSERT(fCurrentRenderPass);
+    if (!fCurrentRenderPass) {
+        return false;
+    }
 
     VkClearValue vkClearColor;
     vkClearColor.color.float32[0] = clearColor[0];
@@ -380,7 +382,9 @@
                                                                      vkColorOps,
                                                                      vkStencilOps);
     }
-    SkASSERT(fCurrentRenderPass);
+    if (!fCurrentRenderPass) {
+        return;
+    }
 
     VkClearValue vkClearColor;
     memset(&vkClearColor, 0, sizeof(VkClearValue));
diff --git a/src/gpu/vk/GrVkRenderPass.cpp b/src/gpu/vk/GrVkRenderPass.cpp
index a022af6..818b3b8 100644
--- a/src/gpu/vk/GrVkRenderPass.cpp
+++ b/src/gpu/vk/GrVkRenderPass.cpp
@@ -42,17 +42,34 @@
     attachment->finalLayout = layout;
 }
 
-void GrVkRenderPass::initSimple(GrVkGpu* gpu, const GrVkRenderTarget& target) {
+GrVkRenderPass* GrVkRenderPass::CreateSimple(GrVkGpu* gpu, const GrVkRenderTarget& target) {
     static const GrVkRenderPass::LoadStoreOps kBasicLoadStoreOps(VK_ATTACHMENT_LOAD_OP_LOAD,
                                                                  VK_ATTACHMENT_STORE_OP_STORE);
 
-    this->init(gpu, target, kBasicLoadStoreOps, kBasicLoadStoreOps);
+    AttachmentFlags attachmentFlags;
+    AttachmentsDescriptor attachmentsDescriptor;
+    // Get attachment information from render target. This includes which attachments the render
+    // target has (color, stencil) and the attachments format and sample count.
+    target.getAttachmentsDescriptor(&attachmentsDescriptor, &attachmentFlags);
+    return Create(gpu, attachmentFlags, attachmentsDescriptor, kBasicLoadStoreOps,
+                  kBasicLoadStoreOps);
 }
 
-void GrVkRenderPass::init(GrVkGpu* gpu,
-                          const LoadStoreOps& colorOp,
-                          const LoadStoreOps& stencilOp) {
-    uint32_t numAttachments = fAttachmentsDescriptor.fAttachmentCount;
+GrVkRenderPass* GrVkRenderPass::Create(GrVkGpu* gpu,
+                            const GrVkRenderPass& compatibleRenderPass,
+                            const LoadStoreOps& colorOp,
+                            const LoadStoreOps& stencilOp) {
+    AttachmentFlags attachmentFlags = compatibleRenderPass.fAttachmentFlags;
+    AttachmentsDescriptor attachmentsDescriptor = compatibleRenderPass.fAttachmentsDescriptor;
+    return Create(gpu, attachmentFlags, attachmentsDescriptor, colorOp, stencilOp);
+}
+
+GrVkRenderPass* GrVkRenderPass::Create(GrVkGpu* gpu,
+                                       AttachmentFlags attachmentFlags,
+                                       AttachmentsDescriptor& attachmentsDescriptor,
+                                       const LoadStoreOps& colorOp,
+                                       const LoadStoreOps& stencilOp) {
+    uint32_t numAttachments = attachmentsDescriptor.fAttachmentCount;
     // Attachment descriptions to be set on the render pass
     SkTArray<VkAttachmentDescription> attachments(numAttachments);
     attachments.reset(numAttachments);
@@ -74,11 +91,13 @@
     subpassDesc.pInputAttachments = nullptr;
     subpassDesc.pResolveAttachments = nullptr;
 
-    if (fAttachmentFlags & kColor_AttachmentFlag) {
+    uint32_t clearValueCount = 0;
+
+    if (attachmentFlags & kColor_AttachmentFlag) {
         // set up color attachment
-        fAttachmentsDescriptor.fColor.fLoadStoreOps = colorOp;
+        attachmentsDescriptor.fColor.fLoadStoreOps = colorOp;
         setup_vk_attachment_description(&attachments[currentAttachment],
-                                        fAttachmentsDescriptor.fColor,
+                                        attachmentsDescriptor.fColor,
                                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
         // setup subpass use of attachment
         colorRef.attachment = currentAttachment++;
@@ -86,7 +105,7 @@
         subpassDesc.colorAttachmentCount = 1;
 
         if (VK_ATTACHMENT_LOAD_OP_CLEAR == colorOp.fLoadOp) {
-            fClearValueCount = colorRef.attachment + 1;
+            clearValueCount = colorRef.attachment + 1;
         }
     } else {
         // I don't think there should ever be a time where we don't have a color attachment
@@ -97,17 +116,17 @@
     }
     subpassDesc.pColorAttachments = &colorRef;
 
-    if (fAttachmentFlags & kStencil_AttachmentFlag) {
+    if (attachmentFlags & kStencil_AttachmentFlag) {
         // set up stencil attachment
-        fAttachmentsDescriptor.fStencil.fLoadStoreOps = stencilOp;
+        attachmentsDescriptor.fStencil.fLoadStoreOps = stencilOp;
         setup_vk_attachment_description(&attachments[currentAttachment],
-                                        fAttachmentsDescriptor.fStencil,
+                                        attachmentsDescriptor.fStencil,
                                         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
         // setup subpass use of attachment
         stencilRef.attachment = currentAttachment++;
         stencilRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
         if (VK_ATTACHMENT_LOAD_OP_CLEAR == stencilOp.fLoadOp) {
-            fClearValueCount = SkTMax(fClearValueCount, stencilRef.attachment + 1);
+            clearValueCount = SkTMax(clearValueCount, stencilRef.attachment + 1);
         }
     } else {
         stencilRef.attachment = VK_ATTACHMENT_UNUSED;
@@ -133,31 +152,34 @@
     createInfo.dependencyCount = 0;
     createInfo.pDependencies = nullptr;
 
-    GR_VK_CALL_ERRCHECK(gpu, CreateRenderPass(gpu->device(), &createInfo, nullptr, &fRenderPass));
+    VkResult result;
+    VkRenderPass renderPass;
+    GR_VK_CALL_RESULT(gpu, result, CreateRenderPass(gpu->device(),
+                                                    &createInfo,
+                                                    nullptr,
+                                                    &renderPass));
+    if (result != VK_SUCCESS) {
+        return nullptr;
+    }
 
+    VkExtent2D granularity;
     // Get granularity for this render pass
     GR_VK_CALL(gpu->vkInterface(), GetRenderAreaGranularity(gpu->device(),
-                                                            fRenderPass,
-                                                            &fGranularity));
+                                                            renderPass,
+                                                            &granularity));
+
+    return new GrVkRenderPass(renderPass, attachmentFlags, attachmentsDescriptor, granularity,
+                              clearValueCount);
 }
 
-void GrVkRenderPass::init(GrVkGpu* gpu,
-                          const GrVkRenderPass& compatibleRenderPass,
-                          const LoadStoreOps& colorOp,
-                          const LoadStoreOps& stencilOp) {
-    fAttachmentFlags = compatibleRenderPass.fAttachmentFlags;
-    fAttachmentsDescriptor = compatibleRenderPass.fAttachmentsDescriptor;
-    this->init(gpu, colorOp, stencilOp);
-}
-
-void GrVkRenderPass::init(GrVkGpu* gpu,
-                          const GrVkRenderTarget& target,
-                          const LoadStoreOps& colorOp,
-                          const LoadStoreOps& stencilOp) {
-    // Get attachment information from render target. This includes which attachments the render
-    // target has (color, stencil) and the attachments format and sample count.
-    target.getAttachmentsDescriptor(&fAttachmentsDescriptor, &fAttachmentFlags);
-    this->init(gpu, colorOp, stencilOp);
+GrVkRenderPass::GrVkRenderPass(VkRenderPass renderPass, AttachmentFlags flags,
+                               const AttachmentsDescriptor& descriptor,
+                               const VkExtent2D& granularity, uint32_t clearValueCount)
+        : fRenderPass(renderPass)
+        , fAttachmentFlags(flags)
+        , fAttachmentsDescriptor(descriptor)
+        , fGranularity(granularity)
+        , fClearValueCount(clearValueCount) {
 }
 
 void GrVkRenderPass::freeGPUData(GrVkGpu* gpu) const {
diff --git a/src/gpu/vk/GrVkRenderPass.h b/src/gpu/vk/GrVkRenderPass.h
index 6ec1a85..1474c7b 100644
--- a/src/gpu/vk/GrVkRenderPass.h
+++ b/src/gpu/vk/GrVkRenderPass.h
@@ -18,17 +18,6 @@
 
 class GrVkRenderPass : public GrVkResource {
 public:
-    GrVkRenderPass() : INHERITED(), fRenderPass(VK_NULL_HANDLE), fClearValueCount(0) {}
-
-    // Used when importing an external render pass. In this case we have to explicitly be told the
-    // color attachment index
-    explicit GrVkRenderPass(VkRenderPass renderPass, uint32_t colorAttachmentIndex)
-            : INHERITED()
-            , fRenderPass(renderPass)
-            , fAttachmentFlags(kExternal_AttachmentFlag)
-            , fClearValueCount(0)
-            , fColorAttachmentIndex(colorAttachmentIndex) {}
-
     struct LoadStoreOps {
         VkAttachmentLoadOp  fLoadOp;
         VkAttachmentStoreOp fStoreOp;
@@ -46,16 +35,20 @@
         }
     };
 
-    void initSimple(GrVkGpu* gpu, const GrVkRenderTarget& target);
-    void init(GrVkGpu* gpu,
-              const GrVkRenderTarget& target,
-              const LoadStoreOps& colorOp,
-              const LoadStoreOps& stencilOp);
+    static GrVkRenderPass* CreateSimple(GrVkGpu* gpu, const GrVkRenderTarget& target);
+    static GrVkRenderPass* Create(GrVkGpu* gpu,
+                                  const GrVkRenderPass& compatibleRenderPass,
+                                  const LoadStoreOps& colorOp,
+                                  const LoadStoreOps& stencilOp);
 
-    void init(GrVkGpu* gpu,
-              const GrVkRenderPass& compatibleRenderPass,
-              const LoadStoreOps& colorOp,
-              const LoadStoreOps& stencilOp);
+    // Used when importing an external render pass. In this case we have to explicitly be told the
+    // color attachment index
+    explicit GrVkRenderPass(VkRenderPass renderPass, uint32_t colorAttachmentIndex)
+            : INHERITED()
+            , fRenderPass(renderPass)
+            , fAttachmentFlags(kExternal_AttachmentFlag)
+            , fClearValueCount(0)
+            , fColorAttachmentIndex(colorAttachmentIndex) {}
 
     struct AttachmentsDescriptor {
         struct AttachmentDesc {
@@ -132,11 +125,14 @@
 #endif
 
 private:
-    GrVkRenderPass(const GrVkRenderPass&);
+    GrVkRenderPass(VkRenderPass, AttachmentFlags, const AttachmentsDescriptor&,
+                   const VkExtent2D& granularity, uint32_t clearValueCount);
 
-    void init(GrVkGpu* gpu,
-              const LoadStoreOps& colorOps,
-              const LoadStoreOps& stencilOps);
+    static GrVkRenderPass* Create(GrVkGpu* gpu,
+                                  AttachmentFlags,
+                                  AttachmentsDescriptor&,
+                                  const LoadStoreOps& colorOps,
+                                  const LoadStoreOps& stencilOps);
 
     bool isCompatible(const AttachmentsDescriptor&, const AttachmentFlags&) const;
 
diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp
index ff42b58..af7b97d 100644
--- a/src/gpu/vk/GrVkRenderTarget.cpp
+++ b/src/gpu/vk/GrVkRenderTarget.cpp
@@ -259,8 +259,6 @@
 
     fCachedSimpleRenderPass =
         this->getVkGpu()->resourceProvider().findCompatibleRenderPass(*this, &fCompatibleRPHandle);
-    // TODO: allow for the above call to fail and handle returning null from getSimpleRenderPass
-    SkASSERT(fCachedSimpleRenderPass);
     return fCachedSimpleRenderPass;
 }
 
@@ -278,8 +276,11 @@
     GrVkGpu* gpu = this->getVkGpu();
     // Stencil attachment view is stored in the base RT stencil attachment
     const GrVkImageView* stencilView = this->stencilAttachmentView();
-    fCachedFramebuffer = GrVkFramebuffer::Create(gpu, this->width(), this->height(),
-                                                 this->getSimpleRenderPass(),
+    const GrVkRenderPass* renderPass = this->getSimpleRenderPass();
+    if (!renderPass) {
+        return nullptr;
+    }
+    fCachedFramebuffer = GrVkFramebuffer::Create(gpu, this->width(), this->height(), renderPass,
                                                  fColorAttachmentView, stencilView);
     return fCachedFramebuffer;
 }
diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h
index 2f7ec83..99bac20 100644
--- a/src/gpu/vk/GrVkRenderTarget.h
+++ b/src/gpu/vk/GrVkRenderTarget.h
@@ -64,6 +64,7 @@
             SkASSERT(!fCachedSimpleRenderPass);
             this->createSimpleRenderPass();
         }
+        SkASSERT(fCompatibleRPHandle.isValid() == SkToBool(fCachedSimpleRenderPass));
         return fCompatibleRPHandle;
     }
     const GrVkRenderPass* externalRenderPass() const {
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index 96bdaa8..73204c5 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -119,9 +119,11 @@
         }
     }
 
-    const GrVkRenderPass* renderPass =
-        fRenderPassArray.emplace_back(fGpu, target).getCompatibleRenderPass();
-    renderPass->ref();
+    GrVkRenderPass* renderPass = GrVkRenderPass::CreateSimple(fGpu, target);
+    if (!renderPass) {
+        return nullptr;
+    }
+    fRenderPassArray.emplace_back(renderPass);
 
     if (compatibleHandle) {
         *compatibleHandle = CompatibleRPHandle(fRenderPassArray.count() - 1);
@@ -134,6 +136,7 @@
     SkASSERT(compatibleHandle.isValid() && compatibleHandle.toIndex() < fRenderPassArray.count());
     int index = compatibleHandle.toIndex();
     const GrVkRenderPass* renderPass = fRenderPassArray[index].getCompatibleRenderPass();
+    SkASSERT(renderPass);
     renderPass->ref();
     return renderPass;
 }
@@ -167,10 +170,10 @@
     GrVkResourceProvider::CompatibleRPHandle* pRPHandle = compatibleHandle ? compatibleHandle
                                                                            : &tempRPHandle;
     *pRPHandle = target->compatibleRenderPassHandle();
+    if (!pRPHandle->isValid()) {
+        return nullptr;
+    }
 
-    // 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);
     return this->findRenderPass(*pRPHandle, colorOps, stencilOps);
 }
 
@@ -183,6 +186,9 @@
     const GrVkRenderPass* renderPass = compatibleSet.getRenderPass(fGpu,
                                                                    colorOps,
                                                                    stencilOps);
+    if (!renderPass) {
+        return nullptr;
+    }
     renderPass->ref();
     return renderPass;
 }
@@ -533,10 +539,10 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-GrVkResourceProvider::CompatibleRenderPassSet::CompatibleRenderPassSet(
-        GrVkGpu* gpu, const GrVkRenderTarget& target) : fLastReturnedIndex(0) {
-    fRenderPasses.emplace_back(new GrVkRenderPass());
-    fRenderPasses[0]->initSimple(gpu, target);
+GrVkResourceProvider::CompatibleRenderPassSet::CompatibleRenderPassSet(GrVkRenderPass* renderPass)
+        : fLastReturnedIndex(0) {
+    renderPass->ref();
+    fRenderPasses.push_back(renderPass);
 }
 
 bool GrVkResourceProvider::CompatibleRenderPassSet::isCompatible(
@@ -558,8 +564,12 @@
             return fRenderPasses[idx];
         }
     }
-    GrVkRenderPass* renderPass = fRenderPasses.emplace_back(new GrVkRenderPass());
-    renderPass->init(gpu, *this->getCompatibleRenderPass(), colorOps, stencilOps);
+    GrVkRenderPass* renderPass = GrVkRenderPass::Create(gpu, *this->getCompatibleRenderPass(),
+                                                        colorOps, stencilOps);
+    if (!renderPass) {
+        return nullptr;
+    }
+    fRenderPasses.push_back(renderPass);
     fLastReturnedIndex = fRenderPasses.count() - 1;
     return renderPass;
 }
diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h
index 8449a88..32baa60 100644
--- a/src/gpu/vk/GrVkResourceProvider.h
+++ b/src/gpu/vk/GrVkResourceProvider.h
@@ -218,7 +218,7 @@
         // This will always construct the basic load store render pass (all attachments load and
         // store their data) so that there is at least one compatible VkRenderPass that can be used
         // with this set.
-        CompatibleRenderPassSet(GrVkGpu* gpu, const GrVkRenderTarget& target);
+        CompatibleRenderPassSet(GrVkRenderPass* renderPass);
 
         bool isCompatible(const GrVkRenderTarget& target) const;