Rewrite GrTextureMaker to disentangle bitmap case from base class and give GPU object a say in what copying needs to be done.

Committed: https://skia.googlesource.com/skia/+/fcffaf22d697f06f903c3193308f9dc54a959f79

Committed: https://skia.googlesource.com/skia/+/1a197ea31e0aac7ea312e9a6c0d9f5df626b0350

Review URL: https://codereview.chromium.org/1409163002
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index d844496..3c3f3e8 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -5,13 +5,13 @@
  * found in the LICENSE file.
  */
 
-#include "GrTextureMaker.h"
 
 #include "SkGr.h"
 
 #include "GrCaps.h"
 #include "GrContext.h"
-#include "GrDrawContext.h"
+#include "GrTextureParamsAdjuster.h"
+#include "GrGpuResourcePriv.h"
 #include "GrXferProcessor.h"
 #include "GrYUVProvider.h"
 
@@ -48,64 +48,17 @@
     return desc;
 }
 
-static void get_stretch(const GrCaps& caps, int width, int height,
-                        const GrTextureParams& params, SkGrStretch* stretch) {
-    stretch->fType = SkGrStretch::kNone_Type;
-    bool doStretch = false;
-    if (params.isTiled() && !caps.npotTextureTileSupport() &&
-        (!SkIsPow2(width) || !SkIsPow2(height))) {
-        doStretch = true;
-        stretch->fWidth = GrNextPow2(SkTMax(width, caps.minTextureSize()));
-        stretch->fHeight = GrNextPow2(SkTMax(height, caps.minTextureSize()));
-    } else if (width < caps.minTextureSize() || height < caps.minTextureSize()) {
-        // The small texture issues appear to be with tiling. Hence it seems ok to scale them
-        // up using the GPU. If issues persist we may need to CPU-stretch.
-        doStretch = true;
-        stretch->fWidth = SkTMax(width, caps.minTextureSize());
-        stretch->fHeight = SkTMax(height, caps.minTextureSize());
-    }
-    if (doStretch) {
-        switch (params.filterMode()) {
-            case GrTextureParams::kNone_FilterMode:
-                stretch->fType = SkGrStretch::kNearest_Type;
-                break;
-            case GrTextureParams::kBilerp_FilterMode:
-            case GrTextureParams::kMipMap_FilterMode:
-                stretch->fType = SkGrStretch::kBilerp_Type;
-                break;
-        }
-    } else {
-        stretch->fWidth = -1;
-        stretch->fHeight = -1;
-        stretch->fType = SkGrStretch::kNone_Type;
-    }
-}
-
-static void make_unstretched_key(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset) {
-    SkASSERT(SkIsU16(subset.width()));
-    SkASSERT(SkIsU16(subset.height()));
-
-    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
-    GrUniqueKey::Builder builder(key, kDomain, 4);
+void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds) {
+    SkASSERT(key);
+    SkASSERT(imageID);
+    SkASSERT(!imageBounds.isEmpty());
+    static const GrUniqueKey::Domain kImageIDDomain = GrUniqueKey::GenerateDomain();
+    GrUniqueKey::Builder builder(key, kImageIDDomain, 5);
     builder[0] = imageID;
-    builder[1] = subset.x();
-    builder[2] = subset.y();
-    builder[3] = subset.width() | (subset.height() << 16);
-}
-
-void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset,
-                          const GrCaps& caps, const GrTextureParams& params) {
-    SkGrStretch stretch;
-    get_stretch(caps, subset.width(), subset.height(), params, &stretch);
-    if (SkGrStretch::kNone_Type != stretch.fType) {
-        GrUniqueKey tmpKey;
-        make_unstretched_key(&tmpKey, imageID, subset);
-        if (!GrMakeStretchedKey(tmpKey, stretch, key)) {
-            *key = tmpKey;
-        }
-    } else {
-        make_unstretched_key(key, imageID, subset);
-    }
+    builder[1] = imageBounds.fLeft;
+    builder[2] = imageBounds.fTop;
+    builder[3] = imageBounds.fRight;
+    builder[4] = imageBounds.fBottom;
 }
 
 GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
@@ -150,16 +103,19 @@
     return kUnknown_GrPixelConfig;
 }
 
-/*  Fill out buffer with the compressed format Ganesh expects from a colortable
- based bitmap. [palette (colortable) + indices].
+//////////////////////////////////////////////////////////////////////////////
 
- At the moment Ganesh only supports 8bit version. If Ganesh allowed we others
- we could detect that the colortable.count is <= 16, and then repack the
- indices as nibbles to save RAM, but it would take more time (i.e. a lot
- slower than memcpy), so skipping that for now.
-
- Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big
- as the colortable.count says it is.
+/**
+ * Fill out buffer with the compressed format Ganesh expects from a colortable
+ * based bitmap. [palette (colortable) + indices].
+ *
+ * At the moment Ganesh only supports 8bit version. If Ganesh allowed we others
+ * we could detect that the colortable.count is <= 16, and then repack the
+ * indices as nibbles to save RAM, but it would take more time (i.e. a lot
+ * slower than memcpy), so skipping that for now.
+ *
+ * Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big
+ * as the colortable.count says it is.
  */
 static void build_index8_data(void* buffer, const SkBitmap& bitmap) {
     SkASSERT(kIndex_8_SkColorType == bitmap.colorType());
@@ -207,130 +163,7 @@
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-
-
-bool GrMakeStretchedKey(const GrUniqueKey& origKey, const SkGrStretch& stretch,
-                        GrUniqueKey* stretchedKey) {
-    if (origKey.isValid() && SkGrStretch::kNone_Type != stretch.fType) {
-        uint32_t width = SkToU16(stretch.fWidth);
-        uint32_t height = SkToU16(stretch.fHeight);
-        static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
-        GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 2);
-        builder[0] = stretch.fType;
-        builder[1] = width | (height << 16);
-        builder.finish();
-        return true;
-    }
-    SkASSERT(!stretchedKey->isValid());
-    return false;
-}
-
-namespace {
-
-// When the SkPixelRef genID changes, invalidate a corresponding GrResource described by key.
-class BitmapInvalidator : public SkPixelRef::GenIDChangeListener {
-public:
-    explicit BitmapInvalidator(const GrUniqueKey& key) : fMsg(key) {}
-private:
-    GrUniqueKeyInvalidatedMessage fMsg;
-
-    void onChange() override {
-        SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
-    }
-};
-
-}  // namespace
-
-
-GrTexture* GrCreateTextureForPixels(GrContext* ctx,
-                                    const GrUniqueKey& optionalKey,
-                                    GrSurfaceDesc desc,
-                                    SkPixelRef* pixelRefForInvalidationNotification,
-                                    const void* pixels,
-                                    size_t rowBytes) {
-    GrTexture* result = ctx->textureProvider()->createTexture(desc, true, pixels, rowBytes);
-    if (result && optionalKey.isValid()) {
-        if (pixelRefForInvalidationNotification) {
-            BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
-            pixelRefForInvalidationNotification->addGenIDChangeListener(listener);
-        }
-        ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, result);
-    }
-    return result;
-}
-
-// creates a new texture that is the input texture scaled up. If optionalKey is valid it will be
-// set on the new texture. stretch controls whether the scaling is done using nearest or bilerp
-// filtering and the size to stretch the texture to.
-GrTexture* stretch_texture(GrTexture* inputTexture, const SkGrStretch& stretch,
-                           SkPixelRef* pixelRef,
-                           const GrUniqueKey& optionalKey) {
-    SkASSERT(SkGrStretch::kNone_Type != stretch.fType);
-
-    GrContext* context = inputTexture->getContext();
-    SkASSERT(context);
-    const GrCaps* caps = context->caps();
-
-    // Either it's a cache miss or the original wasn't cached to begin with.
-    GrSurfaceDesc rtDesc = inputTexture->desc();
-    rtDesc.fFlags =  rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
-    rtDesc.fWidth  = stretch.fWidth;
-    rtDesc.fHeight = stretch.fHeight;
-    rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig);
-
-    // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise,
-    // fail.
-    if (!caps->isConfigRenderable(rtDesc.fConfig, false)) {
-        if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) {
-            if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
-                rtDesc.fConfig = kAlpha_8_GrPixelConfig;
-            } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
-                rtDesc.fConfig = kSkia8888_GrPixelConfig;
-            } else {
-                return nullptr;
-            }
-        } else if (kRGB_GrColorComponentFlags ==
-                   (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) {
-            if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
-                rtDesc.fConfig = kSkia8888_GrPixelConfig;
-            } else {
-                return nullptr;
-            }
-        } else {
-            return nullptr;
-        }
-    }
-
-    SkAutoTUnref<GrTexture> stretched(GrCreateTextureForPixels(context, optionalKey, rtDesc,
-                                                               pixelRef, nullptr,0));
-    if (!stretched) {
-        return nullptr;
-    }
-    GrPaint paint;
-
-    // If filtering is not desired then we want to ensure all texels in the resampled image are
-    // copies of texels from the original.
-    GrTextureParams params(SkShader::kClamp_TileMode,
-                           SkGrStretch::kBilerp_Type == stretch.fType ?
-                              GrTextureParams::kBilerp_FilterMode :
-                              GrTextureParams::kNone_FilterMode);
-    paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
-
-    SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
-    SkRect localRect = SkRect::MakeWH(1.f, 1.f);
-
-    SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(stretched->asRenderTarget()));
-    if (!drawContext) {
-        return nullptr;
-    }
-
-    drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, localRect);
-
-    return stretched.detach();
-}
-
-/*
+/**
  *  Once we have made SkImages handle all lazy/deferred/generated content, the YUV apis will
  *  be gone from SkPixelRef, and we can remove this subclass entirely.
  */
@@ -350,33 +183,22 @@
     }
 };
 
-static GrTexture* load_yuv_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
-                                   const SkBitmap& bm, const GrSurfaceDesc& desc) {
+static GrTexture* create_texture_from_yuv(GrContext* ctx, const SkBitmap& bm,
+                                          const GrSurfaceDesc& desc) {
     // Subsets are not supported, the whole pixelRef is loaded when using YUV decoding
     SkPixelRef* pixelRef = bm.pixelRef();
     if ((nullptr == pixelRef) ||
-        (pixelRef->info().width()  != bm.info().width()) ||
+        (pixelRef->info().width() != bm.info().width()) ||
         (pixelRef->info().height() != bm.info().height())) {
         return nullptr;
     }
 
-    const bool useCache = optionalKey.isValid();
     PixelRef_GrYUVProvider provider(pixelRef);
-    GrTexture* texture = provider.refAsTexture(ctx, desc, useCache);
-    if (!texture) {
-        return nullptr;
-    }
 
-    if (useCache) {
-        BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
-        pixelRef->addGenIDChangeListener(listener);
-        ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, texture);
-    }
-    return texture;
+    return provider.refAsTexture(ctx, desc, !bm.isVolatile());
 }
 
-static GrTexture* load_etc1_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
-                                    const SkBitmap &bm, GrSurfaceDesc desc) {
+static GrTexture* load_etc1_texture(GrContext* ctx, const SkBitmap &bm, GrSurfaceDesc desc) {
     SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
     if (!data) {
         return nullptr;
@@ -389,19 +211,19 @@
         return nullptr;
     }
 
-    return GrCreateTextureForPixels(ctx, optionalKey, desc, bm.pixelRef(), startOfTexData, 0);
+    return ctx->textureProvider()->createTexture(desc, true, startOfTexData, 0);
 }
 
-static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
-                                                    const SkBitmap& origBitmap,
-                                                    const GrUniqueKey& optionalKey) {
-    if (origBitmap.width() < ctx->caps()->minTextureSize() ||
-        origBitmap.height() < ctx->caps()->minTextureSize()) {
+GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bmp) {
+    SkASSERT(!bmp.getTexture());
+
+    if (bmp.width() < ctx->caps()->minTextureSize() ||
+        bmp.height() < ctx->caps()->minTextureSize()) {
         return nullptr;
     }
-    SkBitmap tmpBitmap;
 
-    const SkBitmap* bitmap = &origBitmap;
+    SkBitmap tmpBitmap;
+    const SkBitmap* bitmap = &bmp;
 
     GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap->info());
     const GrCaps* caps = ctx->caps();
@@ -411,14 +233,14 @@
             size_t imageSize = GrCompressedFormatDataSize(kIndex_8_GrPixelConfig,
                                                           bitmap->width(), bitmap->height());
             SkAutoMalloc storage(imageSize);
-            build_index8_data(storage.get(), origBitmap);
+            build_index8_data(storage.get(), bmp);
 
             // our compressed data will be trimmed, so pass width() for its
             // "rowBytes", since they are the same now.
-            return GrCreateTextureForPixels(ctx, optionalKey, desc, origBitmap.pixelRef(),
-                                            storage.get(), bitmap->width());
+            return ctx->textureProvider()->createTexture(desc, true, storage.get(),
+                                                         bitmap->width());
         } else {
-            origBitmap.copyTo(&tmpBitmap, kN32_SkColorType);
+            bmp.copyTo(&tmpBitmap, kN32_SkColorType);
             // now bitmap points to our temp, which has been promoted to 32bits
             bitmap = &tmpBitmap;
             desc.fConfig = SkImageInfo2GrPixelConfig(bitmap->info());
@@ -428,13 +250,16 @@
         // compressed data on 'refEncodedData' and upload it. Probably not good, since if
         // the bitmap has available pixels, then they might not be what the decompressed
         // data is.
-        GrTexture *texture = load_etc1_texture(ctx, optionalKey, *bitmap, desc);
+
+        // Really?? We aren't doing this with YUV.
+
+        GrTexture *texture = load_etc1_texture(ctx, *bitmap, desc);
         if (texture) {
             return texture;
         }
     }
 
-    GrTexture *texture = load_yuv_texture(ctx, optionalKey, *bitmap, desc);
+    GrTexture *texture = create_texture_from_yuv(ctx, *bitmap, desc);
     if (texture) {
         return texture;
     }
@@ -444,83 +269,92 @@
         return nullptr;
     }
 
-    return GrCreateTextureForPixels(ctx, optionalKey, desc, origBitmap.pixelRef(),
-                                    bitmap->getPixels(), bitmap->rowBytes());
+    return ctx->textureProvider()->createTexture(desc, true, bitmap->getPixels(),
+                                                 bitmap->rowBytes());
 }
 
-static SkBitmap stretch_on_cpu(const SkBitmap& bmp, const SkGrStretch& stretch) {
-    SkBitmap stretched;
-    stretched.allocN32Pixels(stretch.fWidth, stretch.fHeight);
-    SkCanvas canvas(stretched);
-    SkPaint paint;
-    switch (stretch.fType) {
-        case SkGrStretch::kNearest_Type:
-            paint.setFilterQuality(kNone_SkFilterQuality);
-            break;
-        case SkGrStretch::kBilerp_Type:
-            paint.setFilterQuality(kLow_SkFilterQuality);
-            break;
-        case SkGrStretch::kNone_Type:
-            SkDEBUGFAIL("Shouldn't get here.");
-            break;
-    }
-    SkRect dstRect = SkRect::MakeWH(SkIntToScalar(stretch.fWidth), SkIntToScalar(stretch.fHeight));
-    canvas.drawBitmapRect(bmp, dstRect, &paint);
-    return stretched;
-}
 
-class Bitmap_GrTextureMaker : public GrTextureMaker {
+////////////////////////////////////////////////////////////////////////////////
+
+class Bitmap_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
 public:
-    Bitmap_GrTextureMaker(const SkBitmap& bitmap)
+    Bitmap_GrTextureParamsAdjuster(const SkBitmap& bitmap)
         : INHERITED(bitmap.width(), bitmap.height())
         , fBitmap(bitmap)
-    {}
+    {
+        if (!bitmap.isVolatile()) {
+            SkIPoint origin = bitmap.pixelRefOrigin();
+            SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bitmap.width(),
+                                               bitmap.height());
+            GrMakeKeyFromImageID(&fOriginalKey, bitmap.pixelRef()->getGenerationID(), subset);
+        }
+    }
 
 protected:
-    GrTexture* onRefUnstretchedTexture(GrContext* ctx) override {
+    GrTexture* peekOriginalTexture() override { return fBitmap.getTexture();  }
+
+    GrTexture* refOriginalTexture(GrContext* ctx) override {
         GrTexture* tex = fBitmap.getTexture();
         if (tex) {
             return SkRef(tex);
         }
 
-        GrUniqueKey unstretchedKey;
-        make_unstretched_key(&unstretchedKey, fBitmap.getGenerationID(), fBitmap.getSubset());
-
-        GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(unstretchedKey);
-        if (result) {
-            return result;
-        }
-        return create_unstretched_bitmap_texture(ctx, fBitmap, unstretchedKey);
-    }
-
-    bool onMakeStretchedKey(const SkGrStretch& stretch, GrUniqueKey* stretchedKey) override {
-        if (fBitmap.isVolatile()) {
-            return false;
+        if (fOriginalKey.isValid()) {
+            tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(fOriginalKey);
+            if (tex) {
+                return tex;
+            }
         }
 
-        GrUniqueKey unstretchedKey;
-        make_unstretched_key(&unstretchedKey, fBitmap.getGenerationID(), fBitmap.getSubset());
-        return GrMakeStretchedKey(unstretchedKey, stretch, stretchedKey);
+        tex = GrUploadBitmapToTexture(ctx, fBitmap);
+        if (tex && fOriginalKey.isValid()) {
+            tex->resourcePriv().setUniqueKey(fOriginalKey);
+            InstallInvalidator(fOriginalKey, fBitmap.pixelRef());
+        }
+        return tex;
     }
 
-    void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override {
-        fBitmap.pixelRef()->addGenIDChangeListener(new BitmapInvalidator(stretchedKey));
+    void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) override {
+        if (fOriginalKey.isValid()) {
+            MakeCopyKeyFromOrigKey(fOriginalKey, copyParams, copyKey);
+        }
     }
 
-    bool onGetROBitmap(SkBitmap* bitmap) override {
+    void didCacheCopy(const GrUniqueKey& copyKey) override {
+        InstallInvalidator(copyKey, fBitmap.pixelRef());
+    }
+
+    bool getROBitmap(SkBitmap* bitmap) override {
+        SkASSERT(!fBitmap.getTexture());
         *bitmap = fBitmap;
         return true;
     }
 
 private:
-    const SkBitmap fBitmap;
+    static void InstallInvalidator(const GrUniqueKey& key, SkPixelRef* pixelRef) {
+        class Invalidator : public SkPixelRef::GenIDChangeListener {
+        public:
+            explicit Invalidator(const GrUniqueKey& key) : fMsg(key) {}
+        private:
+            GrUniqueKeyInvalidatedMessage fMsg;
 
-    typedef GrTextureMaker INHERITED;
+            void onChange() override {
+                SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
+            }
+        };
+        Invalidator* listener = new Invalidator(key);
+        pixelRef->addGenIDChangeListener(listener);
+    }
+
+    const SkBitmap  fBitmap;
+    GrUniqueKey     fOriginalKey;
+
+    typedef GrTextureParamsAdjuster INHERITED;
 };
 
 GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
                                     const GrTextureParams& params) {
-    return Bitmap_GrTextureMaker(bitmap).refCachedTexture(ctx, params);
+    return Bitmap_GrTextureParamsAdjuster(bitmap).refTextureForParams(ctx, params);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -592,7 +426,6 @@
     return true;
 }
 
-
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 static inline bool blend_requires_shader(const SkXfermode::Mode mode, bool primitiveIsSrc) {
@@ -842,54 +675,3 @@
     }
     return textureFilterMode;
 }
-
-////////////////////////////////////////////////////////////////////////////////////////////////
-
-GrTexture* GrTextureMaker::refCachedTexture(GrContext* ctx, const GrTextureParams& params) {
-    SkGrStretch stretch;
-    get_stretch(*ctx->caps(), this->width(), this->height(), params, &stretch);
-
-    if (SkGrStretch::kNone_Type == stretch.fType) {
-        return this->onRefUnstretchedTexture(ctx);
-    }
-
-    GrUniqueKey stretchedKey;
-    if (this->onMakeStretchedKey(stretch, &stretchedKey)) {
-        GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(stretchedKey);
-        if (result) {
-            return result;
-        }
-    }
-
-    GrTexture* result = this->onGenerateStretchedTexture(ctx, stretch);
-    if (!result) {
-        return nullptr;
-    }
-
-    if (stretchedKey.isValid()) {
-        ctx->textureProvider()->assignUniqueKeyToTexture(stretchedKey, result);
-        this->onNotifyStretchCached(stretchedKey);
-    }
-    return result;
-}
-
-GrTexture* GrTextureMaker::onGenerateStretchedTexture(GrContext* ctx, const SkGrStretch& stretch) {
-    if (this->width() < ctx->caps()->minTextureSize() ||
-        this->height() < ctx->caps()->minTextureSize())
-    {
-        // we can't trust our ability to use HW to perform the stretch, so we request
-        // a raster instead, and perform the stretch on the CPU.
-        SkBitmap bitmap;
-        if (!this->onGetROBitmap(&bitmap)) {
-            return nullptr;
-        }
-        SkBitmap stretchedBmp = stretch_on_cpu(bitmap, stretch);
-        return create_unstretched_bitmap_texture(ctx, stretchedBmp, GrUniqueKey());
-    } else {
-        SkAutoTUnref<GrTexture> unstretched(this->onRefUnstretchedTexture(ctx));
-        if (!unstretched) {
-            return nullptr;
-        }
-        return stretch_texture(unstretched, stretch, nullptr, GrUniqueKey());
-    }
-}