Upgrade SkSpecialImage to have getTextureRef & getROPixels entry points

This more closely aligns the SkSpecialImage API with the SkImage API. In doing so it allows the image filters to handle SkImages that can sneak through while remaining encoded (e.g., if an input filter just returns a wrapped version of the source SkImage)

GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1861643003

Review URL: https://codereview.chromium.org/1861643003
diff --git a/include/core/SkPixelRef.h b/include/core/SkPixelRef.h
index 651176e..90e0de5 100644
--- a/include/core/SkPixelRef.h
+++ b/include/core/SkPixelRef.h
@@ -404,6 +404,7 @@
     void setImmutableWithID(uint32_t genID);
     friend class SkImage_Gpu;
     friend class SkImageCacherator;
+    friend class SkSpecialImage_Gpu;
 
     typedef SkRefCnt INHERITED;
 };
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 743dc2a..fb5c915 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -601,10 +601,10 @@
     sk_sp<SkSpecialImage> result(input->filterImage(src, this->mapContext(ctx), offset));
 
 #if SK_SUPPORT_GPU
-    if (src->peekTexture() && result && !result->peekTexture()) {
+    if (src->isTextureBacked() && result && !result->isTextureBacked()) {
         // Keep the result on the GPU - this is still required for some
         // image filters that don't support GPU in all cases
-        GrContext* context = src->peekTexture()->getContext();
+        GrContext* context = src->getContext();
         return result->makeTextureImage(src->internal_getProxy(), context);
     }
 #endif
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp
index abac947..f7bbf9e 100644
--- a/src/core/SkSpecialImage.cpp
+++ b/src/core/SkSpecialImage.cpp
@@ -12,6 +12,7 @@
 #include "SkGr.h"
 #endif
 
+#include "SkBitmapCache.h"
 #include "SkCanvas.h"
 #include "SkImage_Base.h"
 #include "SkSpecialSurface.h"
@@ -28,11 +29,11 @@
 
     virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
 
-    virtual bool onPeekPixels(SkPixmap*) const { return false; }
+    virtual bool onGetROPixels(SkBitmap*) const = 0;
 
     virtual GrTexture* onPeekTexture() const { return nullptr; }
 
-    virtual bool testingOnlyOnGetROPixels(SkBitmap*) const = 0;
+    virtual GrTexture* onAsTextureRef(GrContext* context) const = 0;
 
     // Delete this entry point ASAP (see skbug.com/4965)
     virtual bool getBitmapDeprecated(SkBitmap* result) const = 0;
@@ -70,7 +71,7 @@
     if (!context) {
         return nullptr;
     }
-    if (GrTexture* peek = as_SIB(this)->peekTexture()) {
+    if (GrTexture* peek = as_SIB(this)->onPeekTexture()) {
         return peek->getContext() == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
     }
 
@@ -104,16 +105,32 @@
     return as_SIB(this)->onDraw(canvas, x, y, paint);
 }
 
-bool SkSpecialImage::peekPixels(SkPixmap* pixmap) const {
-    return as_SIB(this)->onPeekPixels(pixmap);
+bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
+    return as_SIB(this)->onGetROPixels(bm);
 }
 
-GrTexture* SkSpecialImage::peekTexture() const {
-    return as_SIB(this)->onPeekTexture();
+bool SkSpecialImage::isTextureBacked() const {
+#if SK_SUPPORT_GPU
+    return as_SIB(this)->onPeekTexture() && as_SIB(this)->onPeekTexture()->getContext();
+#else
+    return false;
+#endif
 }
 
-bool SkSpecialImage::testingOnlyGetROPixels(SkBitmap* result) const {
-    return as_SIB(this)->testingOnlyOnGetROPixels(result);
+GrContext* SkSpecialImage::getContext() const {
+#if SK_SUPPORT_GPU
+    GrTexture* texture = as_SIB(this)->onPeekTexture();
+    
+    if (texture) {
+        return texture->getContext();
+    }
+#endif
+    return nullptr;
+}
+
+
+GrTexture* SkSpecialImage::asTextureRef(GrContext* context) const {
+    return as_SIB(this)->onAsTextureRef(context);
 }
 
 sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageInfo& info) const {
@@ -206,11 +223,19 @@
                               dst, paint, SkCanvas::kStrict_SrcRectConstraint);
     }
 
-    bool onPeekPixels(SkPixmap* pixmap) const override {
-        return fImage->peekPixels(pixmap);
+    bool onGetROPixels(SkBitmap* bm) const override {
+        return as_IB(fImage)->getROPixels(bm);
     }
 
-    GrTexture* onPeekTexture() const override { return as_IB(fImage.get())->peekTexture(); }
+    GrTexture* onPeekTexture() const override { return as_IB(fImage)->peekTexture(); }
+
+    GrTexture* onAsTextureRef(GrContext* context) const override {
+#if SK_SUPPORT_GPU
+        return as_IB(fImage)->asTextureRef(context, GrTextureParams::ClampNoFilter());
+#else
+        return nullptr;
+#endif
+    }
 
     bool getBitmapDeprecated(SkBitmap* result) const override {
 #if SK_SUPPORT_GPU
@@ -230,10 +255,6 @@
         return as_IB(fImage.get())->asBitmapForImageFilters(result);
     }
 
-    bool testingOnlyOnGetROPixels(SkBitmap* result) const override {
-        return fImage->asLegacyBitmap(result, SkImage::kRO_LegacyBitmapMode);
-    }
-
     sk_sp<SkSpecialSurface> onMakeSurface(const SkImageInfo& info) const override {
 #if SK_SUPPORT_GPU
         GrTexture* texture = as_IB(fImage.get())->peekTexture();
@@ -346,26 +367,22 @@
                                dst, paint, SkCanvas::kStrict_SrcRectConstraint);
     }
 
-    bool onPeekPixels(SkPixmap* pixmap) const override {
-        const SkImageInfo info = fBitmap.info();
-
-        if (kUnknown_SkColorType == info.colorType()) {
-            return false;
-        }
-
-        if (!fBitmap.peekPixels(pixmap)) {
-            fBitmap.lockPixels();
-        }
-
-        return fBitmap.peekPixels(pixmap);
-    }
-
-    bool getBitmapDeprecated(SkBitmap* result) const override {
-        *result = fBitmap;
+    bool onGetROPixels(SkBitmap* bm) const override {
+        *bm = fBitmap;
         return true;
     }
 
-    bool testingOnlyOnGetROPixels(SkBitmap* result) const override {
+    GrTexture* onAsTextureRef(GrContext* context) const override {
+#if SK_SUPPORT_GPU
+        if (context) {
+            return GrRefCachedBitmapTexture(context, fBitmap, GrTextureParams::ClampNoFilter());
+        }
+#endif
+
+        return nullptr;
+    }
+
+    bool getBitmapDeprecated(SkBitmap* result) const override {
         *result = fBitmap;
         return true;
     }
@@ -443,10 +460,15 @@
                        const SkSurfaceProps* props)
         : INHERITED(proxy, subset, uniqueID, props)
         , fTexture(SkRef(tex))
-        , fAlphaType(at) {
+        , fAlphaType(at)
+        , fAddedRasterVersionToCache(false) {
     }
 
-    ~SkSpecialImage_Gpu() override { }
+    ~SkSpecialImage_Gpu() override {
+        if (fAddedRasterVersionToCache.load()) {
+            SkNotifyBitmapGenIDIsStale(this->uniqueID());
+        }
+    }
 
     bool isOpaque() const override {
         return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType;
@@ -469,6 +491,35 @@
 
     GrTexture* onPeekTexture() const override { return fTexture; }
 
+    GrTexture* onAsTextureRef(GrContext*) const override { return SkRef(fTexture.get()); }
+
+    bool onGetROPixels(SkBitmap* dst) const override {
+        if (SkBitmapCache::Find(this->uniqueID(), dst)) {
+            SkASSERT(dst->getGenerationID() == this->uniqueID());
+            SkASSERT(dst->isImmutable());
+            SkASSERT(dst->getPixels());
+            return true;
+        }
+
+        SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
+                                                this->isOpaque() ? kOpaque_SkAlphaType
+                                                                 : kPremul_SkAlphaType);
+
+        if (!dst->tryAllocPixels(info)) {
+            return false;
+        }
+
+        if (!fTexture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
+                                  dst->getPixels(), dst->rowBytes())) {
+            return false;
+        }
+
+        dst->pixelRef()->setImmutableWithID(this->uniqueID());
+        SkBitmapCache::Add(this->uniqueID(), *dst);
+        fAddedRasterVersionToCache.store(true);
+        return true;
+    }
+
     bool getBitmapDeprecated(SkBitmap* result) const override {
         const SkImageInfo info = GrMakeInfoFromTexture(fTexture,
                                                        this->width(), this->height(),
@@ -484,25 +535,6 @@
         return true;
     }
 
-    bool testingOnlyOnGetROPixels(SkBitmap* result) const override {
-
-        const SkImageInfo info = SkImageInfo::MakeN32(this->width(),
-                                                      this->height(),
-                                                      this->isOpaque() ? kOpaque_SkAlphaType
-                                                                       : kPremul_SkAlphaType);
-        if (!result->tryAllocPixels(info)) {
-            return false;
-        }
-
-        if (!fTexture->readPixels(0, 0, result->width(), result->height(), kSkia8888_GrPixelConfig,
-                                  result->getPixels(), result->rowBytes())) {
-            return false;
-        }
-
-        result->pixelRef()->setImmutable();
-        return true;
-    }
-
     sk_sp<SkSpecialSurface> onMakeSurface(const SkImageInfo& info) const override {
         if (!fTexture->getContext()) {
             return nullptr;
@@ -555,6 +587,7 @@
 private:
     SkAutoTUnref<GrTexture> fTexture;
     const SkAlphaType       fAlphaType;
+    mutable SkAtomic<bool>  fAddedRasterVersionToCache;
 
     typedef SkSpecialImage_Base INHERITED;
 };
diff --git a/src/core/SkSpecialImage.h b/src/core/SkSpecialImage.h
index 57785fa..2aa5bc6 100644
--- a/src/core/SkSpecialImage.h
+++ b/src/core/SkSpecialImage.h
@@ -123,24 +123,29 @@
 
     // TODO: hide this when GrLayerHoister uses SkSpecialImages more fully (see skbug.com/5063)
     /**
-     *  If the SpecialImage is backed by a gpu texture, return that texture.
+     *  If the SpecialImage is backed by a gpu texture, return true.
+     */
+    bool isTextureBacked() const;
+
+    /**
+     * Return the GrContext if the SkSpecialImage is GrTexture-backed
+     */
+    GrContext* getContext() const;
+
+    /**
+     *  Regardless of the underlying backing store, return the contents as a GrTexture.
      *  The active portion of the texture can be retrieved via 'subset'.
      */
-    GrTexture* peekTexture() const;
+    GrTexture* asTextureRef(GrContext*) const;
 
     // TODO: hide this whe the imagefilter all have a consistent draw path (see skbug.com/5063)
     /**
-     *  If the SpecialImage is backed by cpu pixels, return the const address
-     *  of those pixels and, if not null, the ImageInfo, rowBytes, and, if present,
-     *  the color table. The returned address(es) is/are only valid while the image object
-     *  is in scope.
+     *  Regardless of the underlying backing store, return the contents as an SkBitmap
      *
      *  The returned ImageInfo represents the backing memory. Use 'subset'
      *  to get the active portion's dimensions.
-     *
-     *  On failure, return false and ignore the pixmap parameter.
      */
-    bool peekPixels(SkPixmap*) const;
+    bool getROPixels(SkBitmap*) const;
 
 protected:
     SkSpecialImage(SkImageFilter::Proxy*, const SkIRect& subset, uint32_t uniqueID,
@@ -150,10 +155,6 @@
     friend class TestingSpecialImageAccess;
     friend class TestingSpecialSurfaceAccess;
 
-    // This entry point is for testing only. It does a readback from VRAM for
-    // GPU-backed special images.
-    bool testingOnlyGetROPixels(SkBitmap*) const;
-
     // TODO: remove this ASAP (see skbug.com/4965)
     SkImageFilter::Proxy* proxy() const { return fProxy; }
 
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
index 10c8a0b..4442b7e 100644
--- a/src/effects/SkBlurImageFilter.cpp
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -95,7 +95,11 @@
     const SkVector sigma = map_sigma(fSigma, ctx.ctm());
 
 #if SK_SUPPORT_GPU
-    if (input->peekTexture() && input->peekTexture()->getContext()) {
+    if (source->isTextureBacked()) {
+        GrContext* context = source->getContext();
+        GrTexture* inputTexture = input->asTextureRef(context);
+        SkASSERT(inputTexture);
+
         if (0 == sigma.x() && 0 == sigma.y()) {
             offset->fX = inputBounds.x();
             offset->fY = inputBounds.y();
@@ -103,14 +107,12 @@
                                                             -inputOffset.y()));
         }
 
-        GrTexture* inputTexture = input->peekTexture();
-
         offset->fX = dstBounds.fLeft;
         offset->fY = dstBounds.fTop;
         inputBounds.offset(-inputOffset);
         dstBounds.offset(-inputOffset);
         SkRect inputBoundsF(SkRect::Make(inputBounds));
-        SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(inputTexture->getContext(),
+        SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(context,
                                                                  inputTexture,
                                                                  false,
                                                                  source->props().allowSRGBInputs(),
@@ -145,39 +147,39 @@
                                                         -inputOffset.y()));
     }
 
-    SkPixmap inputPixmap;
+    SkBitmap inputBM;
 
-    if (!input->peekPixels(&inputPixmap)) {
+    if (!input->getROPixels(&inputBM)) {
         return nullptr;
     }
 
-    if (inputPixmap.colorType() != kN32_SkColorType) {
+    if (inputBM.colorType() != kN32_SkColorType) {
         return nullptr;
     }
 
     SkImageInfo info = SkImageInfo::Make(dstBounds.width(), dstBounds.height(),
-                                         inputPixmap.colorType(), inputPixmap.alphaType());
+                                         inputBM.colorType(), inputBM.alphaType());
 
     SkBitmap tmp, dst;
     if (!tmp.tryAllocPixels(info) || !dst.tryAllocPixels(info)) {
         return nullptr;
     }
 
-    SkAutoLockPixels tmpLock(tmp), dstLock(dst);
+    SkAutoLockPixels inputLock(inputBM), tmpLock(tmp), dstLock(dst);
 
     offset->fX = dstBounds.fLeft;
     offset->fY = dstBounds.fTop;
     SkPMColor* t = tmp.getAddr32(0, 0);
     SkPMColor* d = dst.getAddr32(0, 0);
     int w = dstBounds.width(), h = dstBounds.height();
-    const SkPMColor* s = inputPixmap.addr32(inputBounds.x() - inputOffset.x(),
-                                            inputBounds.y() - inputOffset.y());
+    const SkPMColor* s = inputBM.getAddr32(inputBounds.x() - inputOffset.x(),
+                                           inputBounds.y() - inputOffset.y());
     inputBounds.offset(-dstBounds.x(), -dstBounds.y());
     dstBounds.offset(-dstBounds.x(), -dstBounds.y());
     SkIRect inputBoundsT = SkIRect::MakeLTRB(inputBounds.top(), inputBounds.left(),
                                              inputBounds.bottom(), inputBounds.right());
     SkIRect dstBoundsT = SkIRect::MakeWH(dstBounds.height(), dstBounds.width());
-    int sw = int(inputPixmap.rowBytes() >> 2);
+    int sw = int(inputBM.rowBytes() >> 2);
 
     /**
      *
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index 616c0d2..d6e7dfa 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -43,9 +43,9 @@
 }
 
 static void call_proc_X(SkMorphologyImageFilter::Proc procX,
-                        const SkPixmap& src, SkBitmap* dst,
+                        const SkBitmap& src, SkBitmap* dst,
                         int radiusX, const SkIRect& bounds) {
-    procX(src.addr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0),
+    procX(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0),
           radiusX, bounds.width(), bounds.height(),
           src.rowBytesAsPixels(), dst->rowBytesAsPixels());
 }
@@ -446,13 +446,13 @@
     }
 }
 
-static sk_sp<SkSpecialImage> apply_morphology(SkSpecialImage* input,
+static sk_sp<SkSpecialImage> apply_morphology(GrContext* context,
+                                              SkSpecialImage* input,
                                               const SkIRect& rect,
                                               GrMorphologyEffect::MorphologyType morphType,
                                               SkISize radius) {
-    SkAutoTUnref<GrTexture> srcTexture(SkRef(input->peekTexture()));
+    SkAutoTUnref<GrTexture> srcTexture(input->asTextureRef(context));
     SkASSERT(srcTexture);
-    GrContext* context = srcTexture->getContext();
 
     // setup new clip
     GrClip clip(SkRect::MakeWH(SkIntToScalar(srcTexture->width()),
@@ -552,10 +552,12 @@
     }
 
 #if SK_SUPPORT_GPU
-    if (input->peekTexture() && input->peekTexture()->getContext()) {
+    if (source->isTextureBacked()) {
+        GrContext* context = source->getContext();
+
         auto type = (kDilate_Op == this->op()) ? GrMorphologyEffect::kDilate_MorphologyType
                                                : GrMorphologyEffect::kErode_MorphologyType;
-        sk_sp<SkSpecialImage> result(apply_morphology(input.get(), srcBounds, type,
+        sk_sp<SkSpecialImage> result(apply_morphology(context, input.get(), srcBounds, type,
                                                       SkISize::Make(width, height)));
         if (result) {
             offset->fX = bounds.left();
@@ -565,25 +567,25 @@
     }
 #endif
 
-    SkPixmap inputPixmap;
+    SkBitmap inputBM;
 
-    if (!input->peekPixels(&inputPixmap)) {
+    if (!input->getROPixels(&inputBM)) {
         return nullptr;
     }
 
-    if (inputPixmap.colorType() != kN32_SkColorType) {
+    if (inputBM.colorType() != kN32_SkColorType) {
         return nullptr;
     }
 
     SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(),
-                                         inputPixmap.colorType(), inputPixmap.alphaType());
+                                         inputBM.colorType(), inputBM.alphaType());
 
     SkBitmap dst;
     if (!dst.tryAllocPixels(info)) {
         return nullptr;
     }
 
-    SkAutoLockPixels dstLock(dst);
+    SkAutoLockPixels inputLock(inputBM), dstLock(dst);
 
     SkMorphologyImageFilter::Proc procX, procY;
 
@@ -603,17 +605,17 @@
 
         SkAutoLockPixels tmpLock(tmp);
 
-        call_proc_X(procX, inputPixmap, &tmp, width, srcBounds);
+        call_proc_X(procX, inputBM, &tmp, width, srcBounds);
         SkIRect tmpBounds = SkIRect::MakeWH(srcBounds.width(), srcBounds.height());
         call_proc_Y(procY,
                     tmp.getAddr32(tmpBounds.left(), tmpBounds.top()), tmp.rowBytesAsPixels(),
                     &dst, height, tmpBounds);
     } else if (width > 0) {
-        call_proc_X(procX, inputPixmap, &dst, width, srcBounds);
+        call_proc_X(procX, inputBM, &dst, width, srcBounds);
     } else if (height > 0) {
         call_proc_Y(procY,
-                    inputPixmap.addr32(srcBounds.left(), srcBounds.top()),
-                    inputPixmap.rowBytesAsPixels(),
+                    inputBM.getAddr32(srcBounds.left(), srcBounds.top()),
+                    inputBM.rowBytesAsPixels(),
                     &dst, height, srcBounds);
     }
     offset->fX = bounds.left();
diff --git a/src/gpu/GrLayerHoister.cpp b/src/gpu/GrLayerHoister.cpp
index dd8a485..9a2be0b 100644
--- a/src/gpu/GrLayerHoister.cpp
+++ b/src/gpu/GrLayerHoister.cpp
@@ -318,8 +318,9 @@
         return;
     }
 
-    SkASSERT(result->peekTexture());
-    layer->setTexture(result->peekTexture(), result->subset(), false);
+    SkASSERT(result->isTextureBacked());
+    SkAutoTUnref<GrTexture> texture(result->asTextureRef(context));
+    layer->setTexture(texture, result->subset(), false);
     layer->setOffset(offset);
 }
 
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index f1df84e..b37f958 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -580,10 +580,10 @@
     SkBitmap positiveResultBM1, positiveResultBM2;
     SkBitmap negativeResultBM1, negativeResultBM2;
 
-    TestingSpecialImageAccess::GetROPixels(positiveResult1.get(), &positiveResultBM1);
-    TestingSpecialImageAccess::GetROPixels(positiveResult2.get(), &positiveResultBM2);
-    TestingSpecialImageAccess::GetROPixels(negativeResult1.get(), &negativeResultBM1);
-    TestingSpecialImageAccess::GetROPixels(negativeResult2.get(), &negativeResultBM2);
+    REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
+    REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
+    REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
+    REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
 
     SkAutoLockPixels lockP1(positiveResultBM1);
     SkAutoLockPixels lockP2(positiveResultBM2);
@@ -683,7 +683,7 @@
 
     SkBitmap resultBM;
 
-    TestingSpecialImageAccess::GetROPixels(result.get(), &resultBM);
+    REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
 
     SkAutoLockPixels lock(resultBM);
     for (int y = 0; y < resultBM.height(); y++) {
@@ -725,7 +725,7 @@
     REPORTER_ASSERT(reporter, nullptr != result.get());
     if (result.get()) {
         SkBitmap resultBM;
-        TestingSpecialImageAccess::GetROPixels(result.get(), &resultBM);
+        REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
         SkAutoLockPixels lock(resultBM);
         REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
     }
@@ -1504,7 +1504,7 @@
     REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
 
     SkBitmap resultBM;
-    TestingSpecialImageAccess::GetROPixels(result.get(), &resultBM);
+    REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
     SkAutoLockPixels lock(resultBM);
     REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
 }
diff --git a/tests/SpecialImageTest.cpp b/tests/SpecialImageTest.cpp
index 1c71f75..2818ce9 100644
--- a/tests/SpecialImageTest.cpp
+++ b/tests/SpecialImageTest.cpp
@@ -51,7 +51,7 @@
 
 // Basic test of the SkSpecialImage public API (e.g., peekTexture, peekPixels & draw)
 static void test_image(const sk_sp<SkSpecialImage>& img, skiatest::Reporter* reporter,
-                       bool peekPixelsSucceeds, bool peekTextureSucceeds,
+                       GrContext* context, bool peekTextureSucceeds,
                        int offset, int size) {
     const SkIRect subset = TestingSpecialImageAccess::Subset(img.get());
     REPORTER_ASSERT(reporter, offset == subset.left());
@@ -61,17 +61,27 @@
 
     //--------------
     // Test that peekTexture reports the correct backing type
-    REPORTER_ASSERT(reporter, peekTextureSucceeds ==
-                                        !!TestingSpecialImageAccess::PeekTexture(img.get()));
+    REPORTER_ASSERT(reporter, peekTextureSucceeds == img->isTextureBacked());
+
+#if SK_SUPPORT_GPU
+    //--------------
+    // Test getTextureAsRef - as long as there is a context this should succeed
+    if (context) {
+        sk_sp<GrTexture> texture(img->asTextureRef(context));
+        REPORTER_ASSERT(reporter, texture);
+    }
+#endif
 
     //--------------
-    // Test that peekPixels reports the correct backing type
-    SkPixmap pixmap;
-    REPORTER_ASSERT(reporter, peekPixelsSucceeds ==
-                              !!TestingSpecialImageAccess::PeekPixels(img.get(), &pixmap));
-    if (peekPixelsSucceeds) {
-        REPORTER_ASSERT(reporter, size == pixmap.width());
-        REPORTER_ASSERT(reporter, size == pixmap.height());
+    // Test getROPixels - this should always succeed regardless of backing store
+    SkBitmap bitmap;
+    REPORTER_ASSERT(reporter, img->getROPixels(&bitmap));
+    if (context) {
+        REPORTER_ASSERT(reporter, kSmallerSize == bitmap.width());
+        REPORTER_ASSERT(reporter, kSmallerSize == bitmap.height());
+    } else {
+        REPORTER_ASSERT(reporter, size == bitmap.width());
+        REPORTER_ASSERT(reporter, size == bitmap.height());
     }
 
     //--------------
@@ -110,7 +120,7 @@
         REPORTER_ASSERT(reporter, tightImg->height() == subset.height());
         REPORTER_ASSERT(reporter, peekTextureSucceeds == !!tightImg->getTexture());
         SkPixmap tmpPixmap;
-        REPORTER_ASSERT(reporter, peekPixelsSucceeds == !!tightImg->peekPixels(&tmpPixmap));
+        REPORTER_ASSERT(reporter, peekTextureSucceeds != !!tightImg->peekPixels(&tmpPixmap));
     }
     {
         SkImageInfo info = SkImageInfo::MakeN32(subset.width(), subset.height(),
@@ -122,7 +132,7 @@
         REPORTER_ASSERT(reporter, peekTextureSucceeds ==
                      !!tightSurf->getTextureHandle(SkSurface::kDiscardWrite_BackendHandleAccess));
         SkPixmap tmpPixmap;
-        REPORTER_ASSERT(reporter, peekPixelsSucceeds == !!tightSurf->peekPixels(&tmpPixmap));
+        REPORTER_ASSERT(reporter, peekTextureSucceeds != !!tightSurf->peekPixels(&tmpPixmap));
     }
 }
 
@@ -138,12 +148,12 @@
 
     {
         sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromRaster(nullptr, subset, bm));
-        test_image(subSImg1, reporter, true, false, kPad, kFullSize);
+        test_image(subSImg1, reporter, nullptr, false, kPad, kFullSize);
     }
 
     {
         sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
-        test_image(subSImg2, reporter, true, false, 0, kSmallerSize);
+        test_image(subSImg2, reporter, nullptr, false, 0, kSmallerSize);
     }
 }
 
@@ -162,12 +172,12 @@
     {
         sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromImage(nullptr, subset,
                                                                      fullImage));
-        test_image(subSImg1, reporter, true, false, kPad, kFullSize);
+        test_image(subSImg1, reporter, nullptr, false, kPad, kFullSize);
     }
 
     {
         sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
-        test_image(subSImg2, reporter, true, false, 0, kSmallerSize);
+        test_image(subSImg2, reporter, nullptr, false, 0, kSmallerSize);
     }
 }
 
@@ -185,7 +195,7 @@
     {
         sk_sp<SkSpecialImage> img(SkSpecialImage::MakeFromPixmap(nullptr, subset, pixmap,
                                                                  nullptr, nullptr));
-        test_image(img, reporter, true, false, kPad, kFullSize);
+        test_image(img, reporter, nullptr, false, kPad, kFullSize);
     }
 }
 
@@ -196,7 +206,7 @@
                                 const sk_sp<SkSpecialImage>& orig,
                                 const sk_sp<SkSpecialImage>& gpuBacked) {
     REPORTER_ASSERT(reporter, gpuBacked);
-    REPORTER_ASSERT(reporter, gpuBacked->peekTexture());
+    REPORTER_ASSERT(reporter, gpuBacked->isTextureBacked());
     REPORTER_ASSERT(reporter, gpuBacked->uniqueID() == orig->uniqueID());
     REPORTER_ASSERT(reporter, gpuBacked->subset().width() == orig->subset().width() &&
                               gpuBacked->subset().height() == orig->subset().height());
@@ -297,12 +307,12 @@
                                                                nullptr, subset,
                                                                kNeedNewImageUniqueID_SpecialImage,
                                                                texture));
-        test_image(subSImg1, reporter, false, true, kPad, kFullSize);
+        test_image(subSImg1, reporter, context, true, kPad, kFullSize);
     }
 
     {
         sk_sp<SkSpecialImage> subSImg2(fullSImg->makeSubset(subset));
-        test_image(subSImg2, reporter, false, true, kPad, kFullSize);
+        test_image(subSImg2, reporter, context, true, kPad, kFullSize);
     }
 }
 
diff --git a/tests/TestingSpecialImageAccess.h b/tests/TestingSpecialImageAccess.h
index 8dd4e9b..64a6d29 100644
--- a/tests/TestingSpecialImageAccess.h
+++ b/tests/TestingSpecialImageAccess.h
@@ -13,18 +13,6 @@
     static const SkIRect& Subset(const SkSpecialImage* img) {
         return img->subset();
     }
-
-    static bool PeekPixels(const SkSpecialImage* img, SkPixmap* pixmap) {
-        return img->peekPixels(pixmap);
-    }
-
-    static GrTexture* PeekTexture(const SkSpecialImage* img) {
-        return img->peekTexture();
-    }
-
-    static bool GetROPixels(const SkSpecialImage* img, SkBitmap* result) {
-        return img->testingOnlyGetROPixels(result);
-    }
 };
 
 #endif