Add GrVkRecycledResource subclass

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

Review-Url: https://codereview.chromium.org/2167453003
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index 7fb143e..c9037c2 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -40,6 +40,10 @@
         fTrackedResources[i]->unref(gpu);
     }
 
+    for (int i = 0; i < fTrackedRecycledResources.count(); ++i) {
+        fTrackedRecycledResources[i]->recycle(const_cast<GrVkGpu*>(gpu));
+    }
+
     GR_VK_CALL(gpu->vkInterface(), FreeCommandBuffers(gpu->device(), gpu->cmdPool(),
                                                       1, &fCmdBuffer));
 
@@ -50,6 +54,11 @@
     for (int i = 0; i < fTrackedResources.count(); ++i) {
         fTrackedResources[i]->unrefAndAbandon();
     }
+
+    for (int i = 0; i < fTrackedRecycledResources.count(); ++i) {
+        // We don't recycle resources when abandoning them.
+        fTrackedRecycledResources[i]->unrefAndAbandon();
+    }
 }
 
 void GrVkCommandBuffer::reset(GrVkGpu* gpu) {
@@ -59,6 +68,12 @@
     }
     fTrackedResources.reset();
 
+    for (int i = 0; i < fTrackedRecycledResources.count(); ++i) {
+        fTrackedRecycledResources[i]->recycle(const_cast<GrVkGpu*>(gpu));
+    }
+    fTrackedRecycledResources.reset();
+
+
     this->invalidateState();
 
     // we will retain resources for later use
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index c8bac33..f439b27 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -117,11 +117,19 @@
         fTrackedResources.push_back(resource);
     }
 
+    // Add ref-counted resource that will be tracked and released when this command buffer finishes
+    // execution. When it is released, it will signal that the resource can be recycled for reuse.
+    void addRecycledResource(const GrVkRecycledResource* resource) {
+        resource->ref();
+        fTrackedRecycledResources.push_back(resource);
+    }
+
     void reset(GrVkGpu* gpu);
 
 protected:
         GrVkCommandBuffer(VkCommandBuffer cmdBuffer, const GrVkRenderPass* rp = VK_NULL_HANDLE)
             : fTrackedResources(kInitialTrackedResourcesCount)
+            , fTrackedRecycledResources(kInitialTrackedResourcesCount)
             , fIsActive(false)
             , fActiveRenderPass(rp)
             , fCmdBuffer(cmdBuffer)
@@ -129,7 +137,8 @@
             , fBoundIndexBufferIsValid(false) {
             this->invalidateState();
         }
-        SkTArray<const GrVkResource*, true>     fTrackedResources;
+        SkTArray<const GrVkResource*, true>          fTrackedResources;
+        SkTArray<const GrVkRecycledResource*, true>  fTrackedRecycledResources;
 
         // 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/GrVkResource.h b/src/gpu/vk/GrVkResource.h
index 83e82fb..190ee36 100644
--- a/src/gpu/vk/GrVkResource.h
+++ b/src/gpu/vk/GrVkResource.h
@@ -191,5 +191,21 @@
     typedef SkNoncopyable INHERITED;
 };
 
+// This subclass allows for recycling
+class GrVkRecycledResource : public GrVkResource {
+public:
+    // When recycle is called and there is only one ref left on the resource, we will signal that
+    // the resource can be recycled for reuse. This function will always unref the object. Thus
+    // if the object is recycled it should be ref'd inside the onRecycle call.
+    void recycle(GrVkGpu* gpu) const {
+        if (this->unique()) {
+            this->onRecycle(gpu);
+        }
+        this->unref(gpu);
+    }
+
+private:
+    virtual void onRecycle(GrVkGpu* gpu) const = 0;
+};
 
 #endif