Add idle texture callback mechanism.

A proc can be registered with a GrTexture. The proc will be called when
it is safe to delete the texture is "idle." Idle means it referred to
outside of GrResourceCache and that the I/O operations on the GPU are
completed (this latter part applieas to Vulkan only).

The intended use case for this is to call promise image texture release
procs once we start caching GrTextures for deinstantiated promise
images.

Bug= skia:8613

Change-Id: Idce9a4292fef7b15370a053060d8878a9d6828fa
Reviewed-on: https://skia-review.googlesource.com/c/178937
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/vk/GrVkTexture.cpp b/src/gpu/vk/GrVkTexture.cpp
index a295c04..fe9723d 100644
--- a/src/gpu/vk/GrVkTexture.cpp
+++ b/src/gpu/vk/GrVkTexture.cpp
@@ -126,6 +126,11 @@
 }
 
 void GrVkTexture::onRelease() {
+    // When there is an idle proc, the Resource will call the proc in releaseImage() so
+    // we clear it here.
+    fIdleProc = nullptr;
+    fIdleProcContext = nullptr;
+
     // we create this and don't hand it off, so we should always destroy it
     if (fTextureView) {
         fTextureView->unref(this->getVkGpu());
@@ -138,6 +143,11 @@
 }
 
 void GrVkTexture::onAbandon() {
+    // When there is an idle proc, the Resource will call the proc in abandonImage() so
+    // we clear it here.
+    fIdleProc = nullptr;
+    fIdleProcContext = nullptr;
+    // we create this and don't hand it off, so we should always destroy it
     if (fTextureView) {
         fTextureView->unrefAndAbandon();
         fTextureView = nullptr;
@@ -160,3 +170,27 @@
     return fTextureView;
 }
 
+void GrVkTexture::setIdleProc(IdleProc proc, void* context) {
+    fIdleProc = proc;
+    fIdleProcContext = context;
+    if (auto* resource = this->resource()) {
+        resource->setIdleProc(proc ? this : nullptr, proc, context);
+    }
+}
+
+void GrVkTexture::becamePurgeable() {
+    if (!fIdleProc) {
+        return;
+    }
+    // This is called when the GrTexture is purgeable. However, we need to check whether the
+    // Resource is still owned by any command buffers. If it is then it will call the proc.
+    auto* resource = this->resource();
+    SkASSERT(resource);
+    if (resource->isOwnedByCommandBuffer()) {
+        return;
+    }
+    fIdleProc(fIdleProcContext);
+    fIdleProc = nullptr;
+    fIdleProcContext = nullptr;
+    resource->setIdleProc(nullptr, nullptr, nullptr);
+}