Disable texture strip atlasing for DDL

Ultimately we will want to perform inline and ASAP uploads for the
texture strip atlas. Unfortunately, that functionality relies on the
existance of the flushState (which we don't have for the opList-based
DDL implementation). For now we will punt and try storing the individual
texture strips in their own image-based texture proxy for DDLs.

Change-Id: Ic2ee0deb230172bda4a5d4b69cc802dbe84ad7ac
Reviewed-on: https://skia-review.googlesource.com/102464
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp
index 56ec66a..f6e4224 100644
--- a/src/core/SkSpecialImage.cpp
+++ b/src/core/SkSpecialImage.cpp
@@ -87,6 +87,7 @@
         return curContext == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
     }
 
+    auto proxyProvider = context->contextPriv().proxyProvider();
     SkBitmap bmp;
     // At this point, we are definitely not texture-backed, so we must be raster or generator
     // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that
@@ -102,8 +103,7 @@
 
     // TODO: this is a tight copy of 'bmp' but it doesn't have to be (given SkSpecialImage's
     // semantics). Since this is cached though we would have to bake the fit into the cache key.
-    sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(context->contextPriv().proxyProvider(),
-                                                          bmp);
+    sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(proxyProvider, bmp);
     if (!proxy) {
         return nullptr;
     }
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index d808c6f..45c70d6 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -444,17 +444,24 @@
     desc.fWidth  = bitmap.width();
     desc.fHeight = 128;
     desc.fRowHeight = bitmap.height();
-
     // TODO: this seems a bit heavy handed (passing a GrContext as part of the desc)
     desc.fContext = context;
     desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *context->caps());
+
     GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
     int row = atlas->lockRow(bitmap);
     sk_sp<GrTextureProxy> proxy;
     if (-1 == row) {
         atlas = nullptr;
 
-        proxy = GrMakeCachedBitmapProxy(context->contextPriv().proxyProvider(), bitmap);
+        SkASSERT(bitmap.isImmutable());
+
+        sk_sp<SkImage> srcImage = SkImage::MakeFromBitmap(bitmap);
+        if (!srcImage) {
+            return nullptr;
+        }
+
+        proxy = GrMakeCachedImageProxy(context->contextPriv().proxyProvider(), std::move(srcImage));
     } else {
         proxy = atlas->asTextureProxyRef();
     }
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 90fe4f6..ad996f8 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -23,6 +23,7 @@
 #include "SkColorFilter.h"
 #include "SkConvertPixels.h"
 #include "SkData.h"
+#include "SkImage_Base.h"
 #include "SkImageInfoPriv.h"
 #include "SkMaskFilterBase.h"
 #include "SkMessageBus.h"
@@ -239,6 +240,43 @@
     return proxy;
 }
 
+static void create_unique_key_for_image(const SkImage* image, GrUniqueKey* result) {
+    if (!image) {
+        result->reset(); // will be invalid
+        return;
+    }
+
+    if (const SkBitmap* bm = as_IB(image)->onPeekBitmap()) {
+        SkIPoint origin = bm->pixelRefOrigin();
+        SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bm->width(), bm->height());
+        GrMakeKeyFromImageID(result, bm->getGenerationID(), subset);
+        return;
+    }
+
+    GrMakeKeyFromImageID(result, image->uniqueID(), image->bounds());
+}
+
+sk_sp<GrTextureProxy> GrMakeCachedImageProxy(GrProxyProvider* proxyProvider,
+                                             sk_sp<SkImage> srcImage) {
+    sk_sp<GrTextureProxy> proxy;
+    GrUniqueKey originalKey;
+
+    create_unique_key_for_image(srcImage.get(), &originalKey);
+
+    if (originalKey.isValid()) {
+        proxy = proxyProvider->findOrCreateProxyByUniqueKey(originalKey, kTopLeft_GrSurfaceOrigin);
+    }
+    if (!proxy) {
+        proxy = proxyProvider->createTextureProxy(std::move(srcImage), kNone_GrSurfaceFlags,
+                                                  kTopLeft_GrSurfaceOrigin, 0, SkBudgeted::kYes);
+        if (proxy && originalKey.isValid()) {
+            proxyProvider->assignUniqueKeyToProxy(originalKey, proxy.get());
+        }
+    }
+
+    return proxy;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 GrColor4f SkColorToPremulGrColor4f(SkColor c, const GrColorSpaceInfo& colorSpaceInfo) {
diff --git a/src/gpu/SkGr.h b/src/gpu/SkGr.h
index 3bf3ba9..8cd6e61 100644
--- a/src/gpu/SkGr.h
+++ b/src/gpu/SkGr.h
@@ -244,6 +244,11 @@
 //    }
 sk_sp<GrTextureProxy> GrMakeCachedBitmapProxy(GrProxyProvider*, const SkBitmap& bitmap);
 
+/*
+ * Create a texture proxy from the provided 'srcImage' and add it to the texture cache
+ * using the key also extracted from 'srcImage'.
+ */
+sk_sp<GrTextureProxy> GrMakeCachedImageProxy(GrProxyProvider*, sk_sp<SkImage> srcImage);
 
 /**
  *  Our key includes the offset, width, and height so that bitmaps created by extractSubset()
diff --git a/src/gpu/effects/GrTextureStripAtlas.cpp b/src/gpu/effects/GrTextureStripAtlas.cpp
index f5697c9..a3d4fc0 100644
--- a/src/gpu/effects/GrTextureStripAtlas.cpp
+++ b/src/gpu/effects/GrTextureStripAtlas.cpp
@@ -95,6 +95,15 @@
 
 int GrTextureStripAtlas::lockRow(const SkBitmap& bitmap) {
     VALIDATE;
+
+    if (!this->getContext()->contextPriv().resourceProvider()) {
+        // DDL TODO: For DDL we need to schedule inline & ASAP uploads. However these systems
+        // currently use the flushState which we can't use for the opList-based DDL phase.
+        // For the opList-based solution every texture strip will get its own texture proxy.
+        // We will revisit this for the flushState-based solution.
+        return -1;
+    }
+
     if (0 == fLockedRows) {
         this->lockTexture();
         if (!fTexContext) {
diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp
index 3367d9e..871c7ba 100644
--- a/src/shaders/gradients/SkGradientShader.cpp
+++ b/src/shaders/gradients/SkGradientShader.cpp
@@ -591,6 +591,7 @@
 
         bitmap->allocPixels(info);
         this->initLinearBitmap(bitmap, bitmapType);
+        bitmap->setImmutable();
         gCache->add(storage.get(), size, *bitmap);
     }
 }
@@ -1275,7 +1276,7 @@
         GrTextureStripAtlas::Desc desc;
         desc.fWidth  = bitmap.width();
         desc.fHeight = 32;
-        desc.fRowHeight = bitmap.height();
+        desc.fRowHeight = bitmap.height(); // always 1 here
         desc.fContext = args.fContext;
         desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *args.fContext->caps());
         fAtlas = GrTextureStripAtlas::GetAtlas(desc);
@@ -1297,11 +1298,18 @@
             // and the proxy is:
             //   exact fit, power of two in both dimensions
             // Only the x-tileMode is unknown. However, given all the other knowns we know
-            // that GrMakeCachedBitmapProxy is sufficient (i.e., it won't need to be
+            // that GrMakeCachedImageProxy is sufficient (i.e., it won't need to be
             // extracted to a subset or mipmapped).
-            sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(
+
+            SkASSERT(bitmap.isImmutable());
+            sk_sp<SkImage> srcImage = SkImage::MakeFromBitmap(bitmap);
+            if (!srcImage) {
+                return;
+            }
+
+            sk_sp<GrTextureProxy> proxy = GrMakeCachedImageProxy(
                                                      args.fContext->contextPriv().proxyProvider(),
-                                                     bitmap);
+                                                     std::move(srcImage));
             if (!proxy) {
                 SkDebugf("Gradient won't draw. Could not create texture.");
                 return;