Release YUVA planes in SkImage_GpuYUVA after flattenning to RGBA.

Also removed unused virtual function from SkImage_GpuBase and override
on SkImage_GpuYUVA.

Change-Id: Ib47b46b529b16976181cb9453976133d66e0f952
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/212734
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrImageTextureMaker.cpp b/src/gpu/GrImageTextureMaker.cpp
index 80b39d0..0fb1cbe 100644
--- a/src/gpu/GrImageTextureMaker.cpp
+++ b/src/gpu/GrImageTextureMaker.cpp
@@ -91,8 +91,9 @@
     bool coordsLimitedToConstraintRect,
     const GrSamplerState::Filter* filterOrNullForBicubic) {
 
-    // Check simple cases to see if we need to fall back to flattening the image
-    if (!filterOrNullForBicubic || this->domainNeedsDecal()) {
+    // Check simple cases to see if we need to fall back to flattening the image (or whether it's
+    // already been flattened.)
+    if (!filterOrNullForBicubic || this->domainNeedsDecal() || fImage->fRGBProxy) {
         return this->INHERITED::createFragmentProcessor(textureMatrix, constraintRect,
                                                         filterConstraint,
                                                         coordsLimitedToConstraintRect,
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index b06d7fc..a3b86c5 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -64,8 +64,6 @@
         return nullptr;
     }
     virtual bool isYUVA() const { return false; }
-    virtual bool asYUVATextureProxiesRef(sk_sp<GrTextureProxy>[4], SkYUVAIndex[4],
-                                         SkYUVColorSpace*) const { return false; }
     virtual GrTexture* onGetTexture() const { return nullptr; }
 #endif
     virtual GrBackendTexture onGetBackendTexture(bool flushPendingGrContextIO,
diff --git a/src/image/SkImage_GpuYUVA.cpp b/src/image/SkImage_GpuYUVA.cpp
index 915d0de..146e9f5 100644
--- a/src/image/SkImage_GpuYUVA.cpp
+++ b/src/image/SkImage_GpuYUVA.cpp
@@ -71,8 +71,12 @@
         SkASSERT(SkYUVAIndex::AreValidIndices(image->fYUVAIndices, &textureCount));
     SkASSERT(textureCount == fNumProxies);
 
-    for (int i = 0; i < fNumProxies; ++i) {
-        fProxies[i] = image->fProxies[i];  // we ref in this case, not move
+    if (image->fRGBProxy) {
+        fRGBProxy = image->fRGBProxy;  // we ref in this case, not move
+    } else {
+        for (int i = 0; i < fNumProxies; ++i) {
+            fProxies[i] = image->fProxies[i];  // we ref in this case, not move
+        }
     }
     memcpy(fYUVAIndices, image->fYUVAIndices, 4 * sizeof(SkYUVAIndex));
 }
@@ -80,6 +84,8 @@
 SkImage_GpuYUVA::~SkImage_GpuYUVA() {}
 
 bool SkImage_GpuYUVA::setupMipmapsForPlanes(GrRecordingContext* context) const {
+    // We shouldn't get here if the planes were already flattened to RGBA.
+    SkASSERT(fProxies[0] && !fRGBProxy);
     if (!context || !fContext->priv().matches(context)) {
         return false;
     }
@@ -108,12 +114,15 @@
         return GrSemaphoresSubmitted::kNo;
     }
 
-    GrSurfaceProxy* proxies[5] = {fProxies[0].get(), fProxies[1].get(),
-                                  fProxies[2].get(), fProxies[3].get(), nullptr};
+    GrSurfaceProxy* proxies[4] = {fProxies[0].get(), fProxies[1].get(),
+                                  fProxies[2].get(), fProxies[3].get()};
     int numProxies = fNumProxies;
     if (fRGBProxy) {
-        proxies[fNumProxies] = fRGBProxy.get();
-        ++numProxies;
+        // Either we've already flushed the flattening draw or the flattening is unflushed. In the
+        // latter case it should still be ok to just pass fRGBProxy because it in turn depends on
+        // the planar proxies and will cause all of their work to flush as well.
+        proxies[0] = fRGBProxy.get();
+        numProxies = 1;
     }
     return context->priv().flushSurfaces(proxies, numProxies, info);
 }
@@ -155,6 +164,9 @@
     }
 
     fRGBProxy = renderTargetContext->asTextureProxyRef();
+    for (auto& p : fProxies) {
+        p.reset();
+    }
     return fRGBProxy;
 }
 
diff --git a/src/image/SkImage_GpuYUVA.h b/src/image/SkImage_GpuYUVA.h
index daa9ee1..bcad20b 100644
--- a/src/image/SkImage_GpuYUVA.h
+++ b/src/image/SkImage_GpuYUVA.h
@@ -42,23 +42,19 @@
                                                 SkColorType, sk_sp<SkColorSpace>) const final;
 
     virtual bool isYUVA() const override { return true; }
-    virtual bool asYUVATextureProxiesRef(sk_sp<GrTextureProxy> proxies[4],
-                                         SkYUVAIndex yuvaIndices[4],
-                                         SkYUVColorSpace* yuvColorSpace) const override {
-        for (int i = 0; i < 4; ++i) {
-            proxies[i] = fProxies[i];
-            yuvaIndices[i] = fYUVAIndices[i];
-        }
-        *yuvColorSpace = fYUVColorSpace;
-        return true;
-    }
 
     bool setupMipmapsForPlanes(GrRecordingContext*) const;
 
     // Returns a ref-ed texture proxy with miplevels
     sk_sp<GrTextureProxy> asMippedTextureProxyRef(GrRecordingContext*) const;
 
-    bool testingOnly_IsFlattened() const { return SkToBool(fRGBProxy); }
+#if GR_TEST_UTILS
+    bool testingOnly_IsFlattened() const {
+        // We should only have the flattened proxy or the planar proxies at one point in time.
+        SkASSERT(SkToBool(fRGBProxy) != SkToBool(fProxies[0]));
+        return SkToBool(fRGBProxy);
+    }
+#endif
 
     /**
      * This is the implementation of SkDeferredDisplayListRecorder::makeYUVAPromiseTexture.
diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp
index bd4bad0..87b0bc5 100644
--- a/tests/ImageTest.cpp
+++ b/tests/ImageTest.cpp
@@ -1376,6 +1376,19 @@
     }
 }
 
+static sk_sp<SkImage> make_yuva_image(GrContext* c) {
+    SkAutoPixmapStorage pm;
+    pm.alloc(SkImageInfo::Make(1, 1, kAlpha_8_SkColorType, kPremul_SkAlphaType));
+    const SkPixmap pmaps[] = {pm, pm, pm, pm};
+    SkYUVAIndex indices[] = {{0, SkColorChannel::kA},
+                             {1, SkColorChannel::kA},
+                             {2, SkColorChannel::kA},
+                             {3, SkColorChannel::kA}};
+
+    return SkImage::MakeFromYUVAPixmaps(c, kJPEG_SkYUVColorSpace, pmaps, indices,
+                                        SkISize::Make(1, 1), kTopLeft_GrSurfaceOrigin, false);
+}
+
 DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFlush, reporter, ctxInfo) {
     auto c = ctxInfo.grContext();
     auto ii = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
@@ -1386,15 +1399,8 @@
     s->getCanvas()->clear(SK_ColorBLUE);
     auto i1 = s->makeImageSnapshot();
     s->getCanvas()->clear(SK_ColorGREEN);
-
     // Make a YUVA image.
-    SkAutoPixmapStorage pm;
-    pm.alloc(SkImageInfo::Make(1, 1, kAlpha_8_SkColorType, kPremul_SkAlphaType));
-    const SkPixmap pmaps[] = {pm, pm, pm, pm};
-    SkYUVAIndex indices[] = {{0, SkColorChannel::kA}, {1, SkColorChannel::kA},
-                             {2, SkColorChannel::kA}, {3, SkColorChannel::kA}};
-    auto i2 = SkImage::MakeFromYUVAPixmaps(c, kJPEG_SkYUVColorSpace, pmaps, indices,
-                                           SkISize::Make(1, 1), kTopLeft_GrSurfaceOrigin, false);
+    auto i2 = make_yuva_image(c);
 
     // Flush all the setup work we did above and then make little lambda that reports the flush
     // count delta since the last time it was called.
@@ -1448,4 +1454,35 @@
     // Since we just did a simple image draw it should not have been flattened.
     REPORTER_ASSERT(reporter,
                     !static_cast<SkImage_GpuYUVA*>(as_IB(i2.get()))->testingOnly_IsFlattened());
+
+    // Flatten it and repeat.
+    as_IB(i2.get())->asTextureProxyRef(c);
+    REPORTER_ASSERT(reporter,
+                    static_cast<SkImage_GpuYUVA*>(as_IB(i2.get()))->testingOnly_IsFlattened());
+    s->getCanvas()->drawImage(i2, 0, 0);
+    // Flushing image 0 should do nothing.
+    i0->flush(c);
+    REPORTER_ASSERT(reporter, numFlushes() == 0);
+    // Flushing image 1 do nothing.
+    i1->flush(c);
+    REPORTER_ASSERT(reporter, numFlushes() == 0);
+    // Flushing image 2 should flush.
+    i2->flush(c);
+    REPORTER_ASSERT(reporter, numFlushes() == 1);
+
+    // Test case where flatten happens before the first flush.
+    i2 = make_yuva_image(c);
+    as_IB(i2.get())->asTextureProxyRef(c);
+    REPORTER_ASSERT(reporter,
+                    static_cast<SkImage_GpuYUVA*>(as_IB(i2.get()))->testingOnly_IsFlattened());
+    s->getCanvas()->drawImage(i2, 0, 0);
+    // Flushing image 0 should do nothing.
+    i0->flush(c);
+    REPORTER_ASSERT(reporter, numFlushes() == 0);
+    // Flushing image 1 do nothing.
+    i1->flush(c);
+    REPORTER_ASSERT(reporter, numFlushes() == 0);
+    // Flushing image 2 should flush.
+    i2->flush(c);
+    REPORTER_ASSERT(reporter, numFlushes() == 1);
 }