Don't destroy VkPipelineLayouts until after command buffer recording.

Bug: skia:
Change-Id: I70be1dc6b29db9a9152e008293a7d0a276384011
Reviewed-on: https://skia-review.googlesource.com/135867
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 40d7495..7e5dd62 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -582,6 +582,8 @@
   "$_src/gpu/vk/GrVkMemory.h",
   "$_src/gpu/vk/GrVkPipeline.cpp",
   "$_src/gpu/vk/GrVkPipeline.h",
+  "$_src/gpu/vk/GrVkPipelineLayout.cpp",
+  "$_src/gpu/vk/GrVkPipelineLayout.h",
   "$_src/gpu/vk/GrVkPipelineState.cpp",
   "$_src/gpu/vk/GrVkPipelineState.h",
   "$_src/gpu/vk/GrVkPipelineStateBuilder.cpp",
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index 2b6dde2..caff3ca 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -16,6 +16,7 @@
 #include "GrVkPipelineState.h"
 #include "GrVkRenderPass.h"
 #include "GrVkRenderTarget.h"
+#include "GrVkPipelineLayout.h"
 #include "GrVkPipelineState.h"
 #include "GrVkTransferBuffer.h"
 #include "GrVkUtil.h"
@@ -49,6 +50,10 @@
         fTrackedRecycledResources[i]->recycle(const_cast<GrVkGpu*>(gpu));
     }
 
+    for (int i = 0; i < fTrackedRecordingResources.count(); ++i) {
+        fTrackedRecordingResources[i]->unref(gpu);
+    }
+
     GR_VK_CALL(gpu->vkInterface(), FreeCommandBuffers(gpu->device(), gpu->cmdPool(),
                                                       1, &fCmdBuffer));
 
@@ -64,6 +69,10 @@
         // We don't recycle resources when abandoning them.
         fTrackedRecycledResources[i]->unrefAndAbandon();
     }
+
+    for (int i = 0; i < fTrackedRecordingResources.count(); ++i) {
+        fTrackedRecordingResources[i]->unrefAndAbandon();
+    }
 }
 
 void GrVkCommandBuffer::reset(GrVkGpu* gpu) {
@@ -75,15 +84,22 @@
         fTrackedRecycledResources[i]->recycle(const_cast<GrVkGpu*>(gpu));
     }
 
+    for (int i = 0; i < fTrackedRecordingResources.count(); ++i) {
+        fTrackedRecordingResources[i]->unref(gpu);
+    }
+
     if (++fNumResets > kNumRewindResetsBeforeFullReset) {
         fTrackedResources.reset();
         fTrackedRecycledResources.reset();
+        fTrackedRecordingResources.reset();
         fTrackedResources.setReserve(kInitialTrackedResourcesCount);
         fTrackedRecycledResources.setReserve(kInitialTrackedResourcesCount);
+        fTrackedRecordingResources.setReserve(kInitialTrackedResourcesCount);
         fNumResets = 0;
     } else {
         fTrackedResources.rewind();
         fTrackedRecycledResources.rewind();
+        fTrackedRecordingResources.rewind();
     }
 
 
@@ -211,7 +227,7 @@
 
 void GrVkCommandBuffer::bindDescriptorSets(const GrVkGpu* gpu,
                                            GrVkPipelineState* pipelineState,
-                                           VkPipelineLayout layout,
+                                           GrVkPipelineLayout* layout,
                                            uint32_t firstSet,
                                            uint32_t setCount,
                                            const VkDescriptorSet* descriptorSets,
@@ -220,19 +236,20 @@
     SkASSERT(fIsActive);
     GR_VK_CALL(gpu->vkInterface(), CmdBindDescriptorSets(fCmdBuffer,
                                                          VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                                         layout,
+                                                         layout->layout(),
                                                          firstSet,
                                                          setCount,
                                                          descriptorSets,
                                                          dynamicOffsetCount,
                                                          dynamicOffsets));
+    this->addRecordingResource(layout);
     pipelineState->addUniformResources(*this);
 }
 
 void GrVkCommandBuffer::bindDescriptorSets(const GrVkGpu* gpu,
                                            const SkTArray<const GrVkRecycledResource*>& recycled,
                                            const SkTArray<const GrVkResource*>& resources,
-                                           VkPipelineLayout layout,
+                                           GrVkPipelineLayout* layout,
                                            uint32_t firstSet,
                                            uint32_t setCount,
                                            const VkDescriptorSet* descriptorSets,
@@ -241,12 +258,13 @@
     SkASSERT(fIsActive);
     GR_VK_CALL(gpu->vkInterface(), CmdBindDescriptorSets(fCmdBuffer,
                                                          VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                                         layout,
+                                                         layout->layout(),
                                                          firstSet,
                                                          setCount,
                                                          descriptorSets,
                                                          dynamicOffsetCount,
                                                          dynamicOffsets));
+    this->addRecordingResource(layout);
     for (int i = 0; i < recycled.count(); ++i) {
         this->addRecycledResource(recycled[i]);
     }
@@ -378,6 +396,10 @@
     SkASSERT(fIsActive);
     SkASSERT(!fActiveRenderPass);
     GR_VK_CALL_ERRCHECK(gpu->vkInterface(), EndCommandBuffer(fCmdBuffer));
+    for (int i = 0; i < fTrackedRecordingResources.count(); ++i) {
+        fTrackedRecordingResources[i]->unref(gpu);
+    }
+    fTrackedRecordingResources.rewind();
     this->invalidateState();
     fIsActive = false;
 }
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index 362d457..cb2875d 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -53,7 +53,7 @@
 
     void bindDescriptorSets(const GrVkGpu* gpu,
                             GrVkPipelineState*,
-                            VkPipelineLayout layout,
+                            GrVkPipelineLayout* layout,
                             uint32_t firstSet,
                             uint32_t setCount,
                             const VkDescriptorSet* descriptorSets,
@@ -63,7 +63,7 @@
     void bindDescriptorSets(const GrVkGpu* gpu,
                             const SkTArray<const GrVkRecycledResource*>&,
                             const SkTArray<const GrVkResource*>&,
-                            VkPipelineLayout layout,
+                            GrVkPipelineLayout* layout,
                             uint32_t firstSet,
                             uint32_t setCount,
                             const VkDescriptorSet* descriptorSets,
@@ -102,8 +102,8 @@
               uint32_t firstVertex,
               uint32_t firstInstance) const;
 
-    // Add ref-counted resource that will be tracked and released when this
-    // command buffer finishes execution
+    // Add ref-counted resource that will be tracked and released when this command buffer finishes
+    // execution
     void addResource(const GrVkResource* resource) {
         resource->ref();
         fTrackedResources.append(1, &resource);
@@ -116,6 +116,13 @@
         fTrackedRecycledResources.append(1, &resource);
     }
 
+    // Add ref-counted resource that will be tracked and released when this command buffer finishes
+    // recording.
+    void addRecordingResource(const GrVkResource* resource) {
+        resource->ref();
+        fTrackedRecordingResources.append(1, &resource);
+    }
+
     void reset(GrVkGpu* gpu);
 
 protected:
@@ -126,11 +133,13 @@
             , fNumResets(0) {
             fTrackedResources.setReserve(kInitialTrackedResourcesCount);
             fTrackedRecycledResources.setReserve(kInitialTrackedResourcesCount);
+            fTrackedRecordingResources.setReserve(kInitialTrackedResourcesCount);
             this->invalidateState();
         }
 
         SkTDArray<const GrVkResource*>          fTrackedResources;
         SkTDArray<const GrVkRecycledResource*>  fTrackedRecycledResources;
+        SkTDArray<const GrVkResource*>          fTrackedRecordingResources;
 
         // Tracks whether we are in the middle of a command buffer begin/end calls and thus can add
         // new commands to the buffer;
diff --git a/src/gpu/vk/GrVkCopyManager.cpp b/src/gpu/vk/GrVkCopyManager.cpp
index 28ca8b4..9af85db 100644
--- a/src/gpu/vk/GrVkCopyManager.cpp
+++ b/src/gpu/vk/GrVkCopyManager.cpp
@@ -17,6 +17,7 @@
 #include "GrVkDescriptorSet.h"
 #include "GrVkGpu.h"
 #include "GrVkImageView.h"
+#include "GrVkPipelineLayout.h"
 #include "GrVkRenderTarget.h"
 #include "GrVkResourceProvider.h"
 #include "GrVkSampler.h"
@@ -30,7 +31,7 @@
 GrVkCopyManager::GrVkCopyManager()
     : fVertShaderModule(VK_NULL_HANDLE)
     , fFragShaderModule(VK_NULL_HANDLE)
-    , fPipelineLayout(VK_NULL_HANDLE) {}
+    , fPipelineLayout(nullptr) {}
 
 GrVkCopyManager::~GrVkCopyManager() {}
 
@@ -114,15 +115,18 @@
     layoutCreateInfo.pushConstantRangeCount = 0;
     layoutCreateInfo.pPushConstantRanges = nullptr;
 
+    VkPipelineLayout pipelineLayout;
     VkResult err = GR_VK_CALL(gpu->vkInterface(), CreatePipelineLayout(gpu->device(),
                                                                        &layoutCreateInfo,
                                                                        nullptr,
-                                                                       &fPipelineLayout));
+                                                                       &pipelineLayout));
     if (err) {
         this->destroyResources(gpu);
         return false;
     }
 
+    fPipelineLayout = new GrVkPipelineLayout(pipelineLayout);
+
     static const float vdata[] = {
         0, 0,
         0, 1,
@@ -169,7 +173,7 @@
 
     if (VK_NULL_HANDLE == fVertShaderModule) {
         SkASSERT(VK_NULL_HANDLE == fFragShaderModule &&
-                 VK_NULL_HANDLE == fPipelineLayout &&
+                 nullptr == fPipelineLayout &&
                  nullptr == fVertexBuffer.get() &&
                  nullptr == fUniformBuffer.get());
         if (!this->createCopyProgram(gpu)) {
@@ -177,12 +181,13 @@
             return false;
         }
     }
+    SkASSERT(fPipelineLayout);
 
     GrVkResourceProvider& resourceProv = gpu->resourceProvider();
 
     GrVkCopyPipeline* pipeline = resourceProv.findOrCreateCopyPipeline(rt,
                                                                        fShaderStageInfo,
-                                                                       fPipelineLayout);
+                                                                       fPipelineLayout->layout());
     if (!pipeline) {
         return false;
     }
@@ -412,10 +417,9 @@
         fFragShaderModule = VK_NULL_HANDLE;
     }
 
-    if (VK_NULL_HANDLE != fPipelineLayout) {
-        GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(), fPipelineLayout,
-                                                             nullptr));
-        fPipelineLayout = VK_NULL_HANDLE;
+    if (fPipelineLayout) {
+        fPipelineLayout->unref(gpu);
+        fPipelineLayout = nullptr;
     }
 
     if (fUniformBuffer) {
@@ -427,7 +431,10 @@
 void GrVkCopyManager::abandonResources() {
     fVertShaderModule = VK_NULL_HANDLE;
     fFragShaderModule = VK_NULL_HANDLE;
-    fPipelineLayout = VK_NULL_HANDLE;
+    if (fPipelineLayout) {
+        fPipelineLayout->unrefAndAbandon();
+        fPipelineLayout = nullptr;
+    }
 
     if (fUniformBuffer) {
         fUniformBuffer->abandon();
diff --git a/src/gpu/vk/GrVkCopyManager.h b/src/gpu/vk/GrVkCopyManager.h
index f36cc30..4b47895 100644
--- a/src/gpu/vk/GrVkCopyManager.h
+++ b/src/gpu/vk/GrVkCopyManager.h
@@ -16,6 +16,7 @@
 class GrSurface;
 class GrVkCopyPipeline;
 class GrVkGpu;
+class GrVkPipelineLayout;
 class GrVkUniformBuffer;
 class GrVkVertexBuffer;
 struct SkIPoint;
@@ -45,7 +46,7 @@
     VkPipelineShaderStageCreateInfo fShaderStageInfo[2];
 
     GrVkDescriptorSetManager::Handle fSamplerDSHandle;
-    VkPipelineLayout fPipelineLayout;
+    GrVkPipelineLayout* fPipelineLayout;
 
     sk_sp<GrVkVertexBuffer> fVertexBuffer;
     std::unique_ptr<GrVkUniformBuffer> fUniformBuffer;
diff --git a/src/gpu/vk/GrVkPipelineLayout.cpp b/src/gpu/vk/GrVkPipelineLayout.cpp
new file mode 100644
index 0000000..7deb5ac
--- /dev/null
+++ b/src/gpu/vk/GrVkPipelineLayout.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrVkPipelineLayout.h"
+#include "GrVkGpu.h"
+#include "GrVkUtil.h"
+
+void GrVkPipelineLayout::freeGPUData(const GrVkGpu* gpu) const {
+    GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(), fPipelineLayout, nullptr));
+}
diff --git a/src/gpu/vk/GrVkPipelineLayout.h b/src/gpu/vk/GrVkPipelineLayout.h
new file mode 100644
index 0000000..7ab3242
--- /dev/null
+++ b/src/gpu/vk/GrVkPipelineLayout.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrVkPipelineLayout_DEFINED
+#define GrVkPipelineLayout_DEFINED
+
+#include "GrTypes.h"
+#include "GrVkResource.h"
+#include "vk/GrVkDefines.h"
+
+class GrVkPipelineLayout : public GrVkResource {
+public:
+    GrVkPipelineLayout(VkPipelineLayout layout) : fPipelineLayout(layout) {}
+
+    VkPipelineLayout layout() const { return fPipelineLayout; }
+
+#ifdef SK_TRACE_VK_RESOURCES
+    void dumpInfo() const override {
+        SkDebugf("GrVkPipelineLayout: %d (%d refs)\n", fPipelineLayout, this->getRefCnt());
+    }
+#endif
+
+private:
+    GrVkPipelineLayout(const GrVkPipelineLayout&);
+    GrVkPipelineLayout& operator=(const GrVkPipelineLayout&);
+
+    void freeGPUData(const GrVkGpu* gpu) const override;
+
+    VkPipelineLayout  fPipelineLayout;
+
+    typedef GrVkResource INHERITED;
+};
+
+#endif
diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp
index 993f57d..84aa682 100644
--- a/src/gpu/vk/GrVkPipelineState.cpp
+++ b/src/gpu/vk/GrVkPipelineState.cpp
@@ -19,6 +19,7 @@
 #include "GrVkImageView.h"
 #include "GrVkMemory.h"
 #include "GrVkPipeline.h"
+#include "GrVkPipelineLayout.h"
 #include "GrVkSampler.h"
 #include "GrVkTexelBuffer.h"
 #include "GrVkTexture.h"
@@ -45,7 +46,7 @@
         std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
         int fragmentProcessorCnt)
         : fPipeline(pipeline)
-        , fPipelineLayout(layout)
+        , fPipelineLayout(new GrVkPipelineLayout(layout))
         , fUniformDescriptorSet(nullptr)
         , fSamplerDescriptorSet(nullptr)
         , fTexelBufferDescriptorSet(nullptr)
@@ -119,10 +120,8 @@
     }
 
     if (fPipelineLayout) {
-        GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(),
-                                                             fPipelineLayout,
-                                                             nullptr));
-        fPipelineLayout = VK_NULL_HANDLE;
+        fPipelineLayout->unref(gpu);
+        fPipelineLayout = nullptr;
     }
 
     if (fGeometryUniformBuffer) {
@@ -153,10 +152,15 @@
 }
 
 void GrVkPipelineState::abandonGPUResources() {
-    fPipeline->unrefAndAbandon();
-    fPipeline = nullptr;
+    if (fPipeline) {
+        fPipeline->unrefAndAbandon();
+        fPipeline = nullptr;
+    }
 
-    fPipelineLayout = VK_NULL_HANDLE;
+    if (fPipelineLayout) {
+        fPipelineLayout->unrefAndAbandon();
+        fPipelineLayout = nullptr;
+    }
 
     fGeometryUniformBuffer->abandon();
     fFragmentUniformBuffer->abandon();
diff --git a/src/gpu/vk/GrVkPipelineState.h b/src/gpu/vk/GrVkPipelineState.h
index 2ea01c1..ee948a8 100644
--- a/src/gpu/vk/GrVkPipelineState.h
+++ b/src/gpu/vk/GrVkPipelineState.h
@@ -23,6 +23,7 @@
 class GrVkGpu;
 class GrVkImageView;
 class GrVkPipeline;
+class GrVkPipelineLayout;
 class GrVkSampler;
 class GrVkUniformBuffer;
 
@@ -125,7 +126,7 @@
 
     // Used for binding DescriptorSets to the command buffer but does not need to survive during
     // command buffer execution. Thus this is not need to be a GrVkResource.
-    VkPipelineLayout fPipelineLayout;
+    GrVkPipelineLayout* fPipelineLayout;
 
     // The DescriptorSets need to survive until the gpu has finished all draws that use them.
     // However, they will only be freed by the descriptor pool. Thus by simply keeping the