Revert "Update GrTextureStripAtlas for DDLs"

This reverts commit c042d41f2a09d2bb08d9c686a44b3e1e5f664732.

Reason for revert: Leaking

Original change's description:
> Update GrTextureStripAtlas for DDLs
> 
> Change-Id: I9d1344103b338f7e9dcd12739a9f192390f4cb94
> Reviewed-on: https://skia-review.googlesource.com/144305
> Commit-Queue: Robert Phillips <robertphillips@google.com>
> Reviewed-by: Greg Daniel <egdaniel@google.com>

TBR=egdaniel@google.com,robertphillips@google.com

Change-Id: I1c4b10ef5a66585c9d85ddfcab8bffcabdee2c19
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/145180
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 3fc89e0..1c25078 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -358,8 +358,6 @@
   "$_src/gpu/effects/GrBicubicEffect.h",
   "$_src/gpu/effects/GrBitmapTextGeoProc.cpp",
   "$_src/gpu/effects/GrBitmapTextGeoProc.h",
-  "$_src/gpu/effects/GrDDLTextureStripAtlas.cpp",
-  "$_src/gpu/effects/GrDDLTextureStripAtlas.h",
   "$_src/gpu/effects/GrDisableColorXP.cpp",
   "$_src/gpu/effects/GrDisableColorXP.h",
   "$_src/gpu/effects/GrDistanceFieldGeoProc.cpp",
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index 9eb626b..25cfa6b 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -287,7 +287,6 @@
 #include "GrContext.h"
 #include "GrContextPriv.h"
 #include "GrFragmentProcessor.h"
-#include "GrTexture.h"
 #include "GrTextureStripAtlas.h"
 #include "SkGr.h"
 #include "glsl/GrGLSLFragmentProcessor.h"
@@ -308,10 +307,6 @@
 
     std::unique_ptr<GrFragmentProcessor> clone() const override;
 
-    int peekBackingHeight() const {
-        return fTextureSampler.peekTexture()->height();
-    }
-
 private:
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
@@ -352,8 +347,8 @@
     float rgbaYValues[4];
     const ColorTableEffect& cte = proc.cast<ColorTableEffect>();
     if (cte.atlas()) {
-        SkScalar yDelta = 1.0f / cte.peekBackingHeight();
-        rgbaYValues[3] = cte.atlas()->rowToTextureY(cte.atlasRow()) * yDelta;
+        SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight();
+        rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta;
         rgbaYValues[0] = rgbaYValues[3] + yDelta;
         rgbaYValues[1] = rgbaYValues[0] + yDelta;
         rgbaYValues[2] = rgbaYValues[1] + yDelta;
@@ -417,31 +412,26 @@
 ///////////////////////////////////////////////////////////////////////////////
 std::unique_ptr<GrFragmentProcessor> ColorTableEffect::Make(GrContext* context,
                                                             const SkBitmap& bitmap) {
-    SkASSERT(kPremul_SkAlphaType == bitmap.alphaType());
-    SkASSERT(bitmap.isImmutable());
-
-    if (kUnknown_GrPixelConfig == SkColorType2GrPixelConfig(bitmap.colorType())) {
-        return nullptr;
-    }
-
     GrTextureStripAtlas::Desc desc;
-    desc.fColorType = bitmap.colorType();
     desc.fWidth  = bitmap.width();
     desc.fHeight = 128;
     desc.fRowHeight = bitmap.height();
+    desc.fConfig = SkColorType2GrPixelConfig(bitmap.colorType());
+
+    if (kUnknown_GrPixelConfig == desc.fConfig) {
+        return nullptr;
+    }
 
     auto atlasManager = context->contextPriv().textureStripAtlasManager();
 
-    int row;
-    sk_sp<GrTextureStripAtlas> atlas = atlasManager->addStrip(context, desc, bitmap, &row);
-    if (!context->contextPriv().resourceProvider()) {
-        SkASSERT(atlas && row >= 0);  // In DDL mode we should always be able to atlas
-    }
-
+    sk_sp<GrTextureStripAtlas> atlas = atlasManager->refAtlas(desc);
+    int row = atlas->lockRow(context, bitmap);
     sk_sp<GrTextureProxy> proxy;
     if (-1 == row) {
         atlas = nullptr;
 
+        SkASSERT(bitmap.isImmutable());
+
         sk_sp<SkImage> srcImage = SkImage::MakeFromBitmap(bitmap);
         if (!srcImage) {
             return nullptr;
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index b849bea..d7c5129 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -25,7 +25,6 @@
 #include "GrTexturePriv.h"
 #include "GrTextureProxy.h"
 #include "GrTextureProxyPriv.h"
-#include "GrTextureStripAtlas.h"
 #include "GrTracing.h"
 #include "SkDeferredDisplayList.h"
 #include "SkSurface_Gpu.h"
@@ -395,9 +394,6 @@
 }
 
 void GrDrawingManager::moveOpListsToDDL(SkDeferredDisplayList* ddl) {
-    fContext->contextPriv().textureStripAtlasManager()->finish(
-                                                          fContext->contextPriv().proxyProvider());
-
     for (int i = 0; i < fOpLists.count(); ++i) {
         // no opList should receive a new command after this
         fOpLists[i]->makeClosed(*fContext->contextPriv().caps());
diff --git a/src/gpu/GrTextureStripAtlas.h b/src/gpu/GrTextureStripAtlas.h
index 3f4e897..af972b5 100644
--- a/src/gpu/GrTextureStripAtlas.h
+++ b/src/gpu/GrTextureStripAtlas.h
@@ -8,6 +8,8 @@
 #ifndef GrTextureStripAtlas_DEFINED
 #define GrTextureStripAtlas_DEFINED
 
+#include "effects/GrDynamicTextureStripAtlas.h"
+
 #include "SkNoncopyable.h"
 #include "SkOpts.h"
 #include "SkRefCnt.h"
@@ -18,100 +20,17 @@
 class GrTextureProxy;
 class SkBitmap;
 
-/**
- * Base class for the texture strip atlases.
- * It is ref counted because the GradientShader and TableColorFilter are given a pointer to it
- * so that they can lock and unlock rows.
- */
-class GrTextureStripAtlas : public SkRefCnt {
-public:
-    /**
-     * Descriptor struct which we'll use both to find and initialize an atlas and as a hash
-     * table key in the GrTextureStripAtlasManager.
-     */
-    struct Desc {
-        Desc() { sk_bzero(this, sizeof(*this)); }
-        SkColorType fColorType;
-        uint16_t    fWidth;
-        uint16_t    fHeight; // the max height for the DDL version, the size of the atlas for normal
-        uint16_t    fRowHeight;
-        uint16_t    fUnusedPadding;
-
-        bool operator==(const Desc& other) const {
-            return 0 == memcmp(this, &other, sizeof(Desc));
-        }
-    };
-
-    ~GrTextureStripAtlas() override {}
-
-    /**
-     * This is intended to be used when cloning a processor that already holds a lock. It is
-     * assumed that the row already has at least one lock.
-     */
-    virtual void lockRow(int row) = 0;
-
-    /**
-     * Some user of a given row is done. Release that row for reuse.
-     */
-    virtual void unlockRow(int row) = 0;
-
-    /**
-     * This returns the absolute Y location of the given row in the atlas. For atlases with
-     * 'fRowHeight' > 1, this is Y location of the topmost row of the atlas entry. It is always
-     * the middle of the row.
-     */
-    SkScalar rowToTextureY(int row) const {
-        return row * fDesc.fRowHeight + SK_ScalarHalf;
-    }
-
-    /**
-     * Get the texture proxy backing this atlas. Note that the texture proxy may be fully lazy
-     * (i.e., when recording DDLs) and, in particular, the final height may not be known.
-     */
-    virtual sk_sp<GrTextureProxy> asTextureProxyRef() const = 0;
-
-protected:
-    GrTextureStripAtlas(const Desc& desc) : fDesc(desc) {}
-
-    const Desc fDesc;
-
-private:
-    friend class GrTextureStripAtlasManager; // for addStrip, finish
-
-    /**
-     * Add a texture strip to the atlas
-     *  @param context Everyone's favorite class
-     *  @param bitmap  Bitmap data to copy into the row
-     *  @return The row index we inserted into, or -1 if we failed to find an open row. The caller
-     *      is responsible for calling unlockRow() with this row index when it's done with it.
-     */
-    virtual int addStrip(GrContext*, const SkBitmap& bitmap) = 0;
-
-    /**
-     * This method is called when an atlas needs to finish its work on the current texture.
-     * Currently it is only called in DDL mode and when either:
-     *        a given atlas has become full or,
-     *        a DDL is being snapped from a DDL recorder
-     */
-    virtual void finish(GrProxyProvider*) = 0;
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
 class GrTextureStripAtlasManager {
 public:
     GrTextureStripAtlasManager() {}
     ~GrTextureStripAtlasManager();
 
     void abandon();
-    void finish(GrProxyProvider*);
 
     /**
-     * Add a new texture strip to the atlas matching the descriptor. Upon failure, nullptr
-     * will be returned and 'row' will be set to -1.
+     * Try to find an atlas with the required parameters, creates a new one if necessary
      */
-    sk_sp<GrTextureStripAtlas> addStrip(GrContext*,
-                                        const GrTextureStripAtlas::Desc&,
-                                        const SkBitmap&, int* row);
+    sk_sp<GrTextureStripAtlas> refAtlas(const GrTextureStripAtlas::Desc&);
 
 private:
     void deleteAllAtlases();
@@ -119,17 +38,21 @@
     // Hash table entry for atlases
     class AtlasEntry : public ::SkNoncopyable {
     public:
-        AtlasEntry(sk_sp<GrTextureStripAtlas> atlas) : fAtlas(std::move(atlas)) {}
+        AtlasEntry(const GrTextureStripAtlas::Desc& desc, sk_sp<GrTextureStripAtlas> atlas)
+            : fDesc(desc)
+            , fAtlas(std::move(atlas)) {
+        }
         ~AtlasEntry() { }
 
         // for SkTDynamicHash
         static const GrTextureStripAtlas::Desc& GetKey(const AtlasEntry& entry) {
-            return entry.fAtlas->fDesc;
+            return entry.fDesc;
         }
         static uint32_t Hash(const GrTextureStripAtlas::Desc& desc) {
             return SkOpts::hash(&desc, sizeof(GrTextureStripAtlas::Desc));
         }
 
+        const GrTextureStripAtlas::Desc fDesc;
         sk_sp<GrTextureStripAtlas> fAtlas;
     };
 
diff --git a/src/gpu/effects/GrDDLTextureStripAtlas.cpp b/src/gpu/effects/GrDDLTextureStripAtlas.cpp
deleted file mode 100644
index ac22df5..0000000
--- a/src/gpu/effects/GrDDLTextureStripAtlas.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrDDLTextureStripAtlas.h"
-
-#include "GrContextPriv.h"
-#include "GrTexture.h"
-#include "SkGr.h"
-#include "SkTSearch.h"
-
-GrDDLTextureStripAtlas::GrDDLTextureStripAtlas(const Desc& desc)
-        : INHERITED(desc)
-        , fAtlasBitmap(nullptr)
-        , fMaxNumRows(desc.fHeight / desc.fRowHeight)
-        , fCurRow(0)
-        , fRows(new AtlasRow[fMaxNumRows]) {
-    SkASSERT(fMaxNumRows * fDesc.fRowHeight == fDesc.fHeight);
-    SkDEBUGCODE(this->validate();)
-}
-
-GrDDLTextureStripAtlas::~GrDDLTextureStripAtlas() { delete[] fRows; }
-
-// Flush the current state of the atlas.
-void GrDDLTextureStripAtlas::finish(GrProxyProvider* proxyProvider) {
-    SkDEBUGCODE(this->validate();)
-
-    if (!fCurRow) {
-        SkASSERT(!fCurProxy && !fAtlasBitmap);
-        return;
-    }
-
-    int height = fCurRow * fDesc.fRowHeight;
-    SkASSERT(height <= fDesc.fHeight);
-
-    SkImageInfo ii = SkImageInfo::Make(fDesc.fWidth, height,
-                                       fDesc.fColorType, kPremul_SkAlphaType);
-    fAtlasBitmap->allocPixels(ii);
-
-    for (int i = 0; i < fCurRow; ++i) {
-        SkASSERT(fRows[i].fBitmap.height() == fDesc.fRowHeight);
-
-        int yPos = i * fDesc.fRowHeight;
-        fAtlasBitmap->writePixels(fRows[i].fBitmap.pixmap(), 0, yPos);
-    }
-
-    GrUniqueKey key;
-    {
-        static const GrUniqueKey::Domain kTextureStripAtlasDomain = GrUniqueKey::GenerateDomain();
-        GrUniqueKey::Builder builder(&key, kTextureStripAtlasDomain, fCurRow,
-                                     "DDL Texture Strip Atlas");
-        for (int i = 0; i < fCurRow; ++i) {
-            builder[i] = fRows[i].fBitmap.getGenerationID();
-        }
-        builder.finish();
-    }
-
-    sk_sp<GrTextureProxy> interloper = proxyProvider->findProxyByUniqueKey(key,
-                                                                           fCurProxy->origin());
-    if (!interloper) {
-        // In the unlikely event that there is already a proxy with this key (i.e., it has exactly
-        // the same strips in exactly the same order) we'll just let it keep the key.
-        proxyProvider->assignUniqueKeyToProxy(key, fCurProxy.get());
-    }
-
-    // reset the state for the next aggregate texture
-    for (int i = 0; i < fCurRow; ++i) {
-        fRows[i].fBitmap.reset();
-    }
-    fCurRow = 0;
-    fCurProxy = nullptr;
-    fAtlasBitmap = nullptr;
-    fKeyTable.rewind();
-    SkDEBUGCODE(this->validate();)
-}
-
-int GrDDLTextureStripAtlas::addStrip(GrContext* context, const SkBitmap& bitmap) {
-    SkDEBUGCODE(this->validate();)
-
-    const int key = bitmap.getGenerationID();
-    int index = this->searchByKey(key);
-
-    if (fCurRow >= fMaxNumRows && index < 0) {
-        // The current atlas is full and adding another strip would make it overflow. Calve it off
-        // and allow the next block to start a new one.
-        this->finish(context->contextPriv().proxyProvider());
-        index = this->searchByKey(key); // 'finish' cleared the table
-    }
-
-    if (!fCurProxy) {
-        SkASSERT(!fAtlasBitmap);
-
-        const GrCaps* caps = context->contextPriv().caps();
-        GrPixelConfig pixelConfig = SkColorType2GrPixelConfig(fDesc.fColorType);
-        SkASSERT(kUnknown_GrPixelConfig != pixelConfig);
-
-        SkBitmap* atlasBitmap = new SkBitmap();
-
-        fCurProxy = GrProxyProvider::MakeFullyLazyProxy(
-                [atlasBitmap, pixelConfig](GrResourceProvider* provider) -> sk_sp<GrSurface> {
-                        if (!provider) {
-                            delete atlasBitmap;
-                            return sk_sp<GrSurface>();
-                        }
-                        // When this is called 'atlasBitmap' should've been filled in and be
-                        // non-empty
-                        SkASSERT(atlasBitmap->width() && atlasBitmap->height());
-                        GrSurfaceDesc desc;
-                        desc.fFlags = kNone_GrSurfaceFlags;
-                        desc.fWidth = atlasBitmap->width();
-                        desc.fHeight = atlasBitmap->height();
-                        desc.fConfig = pixelConfig;
-
-                        GrMipLevel mipLevel = { atlasBitmap->getPixels(), atlasBitmap->rowBytes() };
-
-                        return provider->createTexture(desc, SkBudgeted::kYes,
-                                                       SkBackingFit::kExact, mipLevel);
-                },
-                GrProxyProvider::Renderable::kNo, kTopLeft_GrSurfaceOrigin, pixelConfig, *caps);
-
-        fAtlasBitmap = atlasBitmap;
-    }
-
-    SkASSERT(bitmap.width() == fDesc.fWidth);
-    SkASSERT(bitmap.height() == fDesc.fRowHeight);
-    SkASSERT(!context->contextPriv().resourceProvider());  // This atlas class is DDL specific
-    SkASSERT(fCurRow < fMaxNumRows);
-
-    int rowNumber = -1;
-
-    if (index >= 0) {
-        // We already have the data in a row, so we can just return that row
-        AtlasRow* row = fKeyTable[index];
-
-        // Since all the rows are always stored in a contiguous array, we can save the memory
-        // required for storing row numbers and just compute it with some pointer arithmetic
-        rowNumber = static_cast<int>(row - fRows);
-    } else {
-        // ~index is the index where we will insert the new key to keep things sorted
-        index = ~index;
-
-        rowNumber = fCurRow;
-        fRows[fCurRow].fBitmap = bitmap;
-
-        AtlasRow* row = &fRows[rowNumber];
-        fKeyTable.insert(index, 1, &row);
-
-        ++fCurRow;
-        SkASSERT(fCurRow <= fMaxNumRows);
-    }
-
-    SkASSERT(rowNumber >= 0);
-    SkDEBUGCODE(this->validate();)
-    return rowNumber;
-}
-
-int GrDDLTextureStripAtlas::searchByKey(uint32_t generationID) {
-    static struct AtlasRowLessFunctor {
-        bool operator()(const AtlasRow* row, const uint32_t& id) const {
-            return row->fBitmap.getGenerationID() < id;
-        }
-        bool operator()(const uint32_t& id, const AtlasRow* row) const {
-            return id < row->fBitmap.getGenerationID();
-        }
-    } functor;
-
-    return SkTSearch(fKeyTable.begin(), fKeyTable.count(), generationID, sizeof(AtlasRow*),
-                     functor);
-}
-
-#ifdef SK_DEBUG
-void GrDDLTextureStripAtlas::validate() {
-    static const int kBitmapInvalidGenID = 0;
-
-    // Our key table should be sorted
-    uint32_t prev = fKeyTable.count() >= 1 ? fKeyTable[0]->fBitmap.getGenerationID() : 0;
-    for (int i = 1; i < fKeyTable.count(); ++i) {
-        AtlasRow* row = fKeyTable[i];
-        SkASSERT(prev < row->fBitmap.getGenerationID());
-        SkASSERT(row->fBitmap.getGenerationID() != kBitmapInvalidGenID);
-        prev = row->fBitmap.getGenerationID();
-    }
-
-    for (int i = 0; i < fCurRow; ++i) {
-        // These should all have a valid bitmap and be in the search table
-        SkASSERT(fRows[i].fBitmap.getGenerationID() != kBitmapInvalidGenID);
-        SkASSERT(this->searchByKey(fRows[i].fBitmap.getGenerationID()) >= 0);
-    }
-    for (int i = fCurRow; i < fMaxNumRows; ++i) {
-        // These should all be empty
-        SkASSERT(fRows[i].fBitmap.getGenerationID() == kBitmapInvalidGenID);
-    }
-}
-#endif
diff --git a/src/gpu/effects/GrDDLTextureStripAtlas.h b/src/gpu/effects/GrDDLTextureStripAtlas.h
deleted file mode 100644
index 5fb5804..0000000
--- a/src/gpu/effects/GrDDLTextureStripAtlas.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrDDLTextureStripAtlas_DEFINED
-#define GrDDLTextureStripAtlas_DEFINED
-
-#include "GrTextureStripAtlas.h"
-
-#include "SkBitmap.h"
-#include "SkTDArray.h"
-
-/**
- * The DDL version of the texture strip atlas consolidates individual strips into a larger texture
- * until some limit is reached, at which point a new large texture is started.
- * This can lead to the same strip being duplicated in VRAM. This can happen if a strip appears once
- * early in a rendering (that has, say, a lot of gradients) and then again later in the rendering
- * when one of the large textures has been filled. The second, probably more common, case is
- * if the same strip is used in different DDL recordings. Since the texture strip atlases aren't
- * dedupped across threads, if the same strip is used in two different DDL recordings it will
- * be duplicated in both of the DDL recorders' atlases.
- * Note, one additional feature of the DDL texture strip atlases is that, if DDL recording is ended
- * before one of the large textures is full, the large texture will be "shrunk" to fit its
- * contents.
- */
-class GrDDLTextureStripAtlas final : public GrTextureStripAtlas {
-public:
-    ~GrDDLTextureStripAtlas() final;
-
-    // Overrides from GrTextureStripAtlas
-    void lockRow(int row) final { /* The DDL version doesn't lock & unlock individual rows */}
-    void unlockRow(int row) final { /* The DDL version doesn't lock & unlock individual rows */}
-
-    // Caution: this method will only return the appropriate proxy after a successful 'addStrip'
-    // call has been made. Additionally, the proxy return will be fully lazy (i.e., its final
-    // height will be unknown).
-    sk_sp<GrTextureProxy> asTextureProxyRef() const final {
-        SkASSERT(fCurProxy);
-        return fCurProxy;
-    }
-
-private:
-    friend class GrTextureStripAtlasManager; // for ctor
-
-    // Overrides from GrTextureStripAtlas
-    int addStrip(GrContext*, const SkBitmap&) final;
-    void finish(GrProxyProvider*) final;
-
-    /**
-     * The state of a single row in our cache. For the DDL texture strip atlas we hold onto all
-     * the individual strip bitmaps and, upon finish, combine them all into a single bitmap.
-     */
-    struct AtlasRow : ::SkNoncopyable {
-        AtlasRow() {}
-
-        SkBitmap fBitmap;
-    };
-
-    /**
-     * Only the GrTextureStripAtlasManager is allowed to create GrDDLTextureStripAtlas
-     */
-    GrDDLTextureStripAtlas(const Desc& desc);
-
-    /**
-     * Searches the key table for a key and returns the index if found; if not found, it returns
-     * the bitwise not of the index at which we could insert the key to maintain a sorted list.
-     **/
-    int searchByKey(uint32_t key);
-
-    SkDEBUGCODE(void validate();)
-
-    sk_sp<GrTextureProxy> fCurProxy;    // the lazy proxy that will be split off in the finish call
-    SkBitmap*             fAtlasBitmap; // the bitmap backing 'fCurProxy'
-
-    const uint16_t        fMaxNumRows;
-    uint16_t              fCurRow;
-
-    AtlasRow*             fRows;        // We just store the source bitmap for each row.
-
-    // A list of pointers to AtlasRows that currently contain cached images, sorted by key
-    SkTDArray<AtlasRow*> fKeyTable;
-
-    typedef GrTextureStripAtlas INHERITED;
-};
-
-#endif
diff --git a/src/gpu/effects/GrDynamicTextureStripAtlas.cpp b/src/gpu/effects/GrDynamicTextureStripAtlas.cpp
index 04683e1..ede6809 100644
--- a/src/gpu/effects/GrDynamicTextureStripAtlas.cpp
+++ b/src/gpu/effects/GrDynamicTextureStripAtlas.cpp
@@ -18,7 +18,7 @@
     #define VALIDATE
 #endif
 
-uint32_t GrDynamicTextureStripAtlas::CreateUniqueID() {
+uint32_t GrTextureStripAtlas::CreateUniqueID() {
     static int32_t gUniqueID = SK_InvalidUniqueID;
     uint32_t id;
     // Loop in case our global wraps around, as we never want to return a 0.
@@ -28,30 +28,30 @@
     return id;
 }
 
-GrDynamicTextureStripAtlas::GrDynamicTextureStripAtlas(const Desc& desc)
-        : INHERITED(desc)
-        , fCacheKey(CreateUniqueID())
-        , fLockedRows(0)
-        , fNumRows(desc.fHeight / desc.fRowHeight)
-        , fRows(new AtlasRow[fNumRows])
-        , fLRUFront(nullptr)
-        , fLRUBack(nullptr) {
+GrTextureStripAtlas::GrTextureStripAtlas(const Desc& desc)
+    : fCacheKey(CreateUniqueID())
+    , fLockedRows(0)
+    , fDesc(desc)
+    , fNumRows(desc.fHeight / desc.fRowHeight)
+    , fRows(new AtlasRow[fNumRows])
+    , fLRUFront(nullptr)
+    , fLRUBack(nullptr) {
     SkASSERT(fNumRows * fDesc.fRowHeight == fDesc.fHeight);
     this->initLRU();
     fNormalizedYHeight = SK_Scalar1 / fDesc.fHeight;
     VALIDATE;
 }
 
-GrDynamicTextureStripAtlas::~GrDynamicTextureStripAtlas() { delete[] fRows; }
+GrTextureStripAtlas::~GrTextureStripAtlas() { delete[] fRows; }
 
-void GrDynamicTextureStripAtlas::lockRow(int row) {
+void GrTextureStripAtlas::lockRow(int row) {
     // This should only be called on a row that is already locked.
     SkASSERT(fRows[row].fLocks);
     fRows[row].fLocks++;
     ++fLockedRows;
 }
 
-int GrDynamicTextureStripAtlas::addStrip(GrContext* context, const SkBitmap& bitmap) {
+int GrTextureStripAtlas::lockRow(GrContext* context, const SkBitmap& bitmap) {
     VALIDATE;
 
     if (!context->contextPriv().resourceProvider()) {
@@ -142,11 +142,11 @@
     return rowNumber;
 }
 
-sk_sp<GrTextureProxy> GrDynamicTextureStripAtlas::asTextureProxyRef() const {
+sk_sp<GrTextureProxy> GrTextureStripAtlas::asTextureProxyRef() const {
     return fTexContext->asTextureProxyRef();
 }
 
-void GrDynamicTextureStripAtlas::unlockRow(int row) {
+void GrTextureStripAtlas::unlockRow(int row) {
     VALIDATE;
     --fRows[row].fLocks;
     --fLockedRows;
@@ -160,13 +160,13 @@
     VALIDATE;
 }
 
-GrDynamicTextureStripAtlas::AtlasRow* GrDynamicTextureStripAtlas::getLRU() {
+GrTextureStripAtlas::AtlasRow* GrTextureStripAtlas::getLRU() {
     // Front is least-recently-used
     AtlasRow* row = fLRUFront;
     return row;
 }
 
-void GrDynamicTextureStripAtlas::lockTexture(GrContext* context) {
+void GrTextureStripAtlas::lockTexture(GrContext* context) {
 
     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
     GrUniqueKey key;
@@ -179,12 +179,10 @@
     sk_sp<GrTextureProxy> proxy = proxyProvider->findOrCreateProxyByUniqueKey(
                                                                 key, kTopLeft_GrSurfaceOrigin);
     if (!proxy) {
-        GrPixelConfig pixelConfig = SkColorType2GrPixelConfig(fDesc.fColorType);
-
         GrSurfaceDesc texDesc;
         texDesc.fWidth  = fDesc.fWidth;
         texDesc.fHeight = fDesc.fHeight;
-        texDesc.fConfig = pixelConfig;
+        texDesc.fConfig = fDesc.fConfig;
 
         proxy = proxyProvider->createProxy(texDesc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kExact,
                                            SkBudgeted::kYes, GrInternalSurfaceFlags::kNoPendingIO);
@@ -202,12 +200,12 @@
     fTexContext = context->contextPriv().makeWrappedSurfaceContext(std::move(proxy));
 }
 
-void GrDynamicTextureStripAtlas::unlockTexture() {
+void GrTextureStripAtlas::unlockTexture() {
     SkASSERT(fTexContext && 0 == fLockedRows);
     fTexContext.reset();
 }
 
-void GrDynamicTextureStripAtlas::initLRU() {
+void GrTextureStripAtlas::initLRU() {
     fLRUFront = nullptr;
     fLRUBack = nullptr;
     // Initially all the rows are in the LRU list
@@ -221,7 +219,7 @@
     SkASSERT(nullptr == fLRUBack || nullptr == fLRUBack->fNext);
 }
 
-void GrDynamicTextureStripAtlas::appendLRU(AtlasRow* row) {
+void GrTextureStripAtlas::appendLRU(AtlasRow* row) {
     SkASSERT(nullptr == row->fPrev && nullptr == row->fNext);
     if (nullptr == fLRUFront && nullptr == fLRUBack) {
         fLRUFront = row;
@@ -233,7 +231,7 @@
     }
 }
 
-void GrDynamicTextureStripAtlas::removeFromLRU(AtlasRow* row) {
+void GrTextureStripAtlas::removeFromLRU(AtlasRow* row) {
     SkASSERT(row);
     if (row->fNext && row->fPrev) {
         row->fPrev->fNext = row->fNext;
@@ -258,17 +256,19 @@
     row->fPrev = nullptr;
 }
 
-int GrDynamicTextureStripAtlas::searchByKey(uint32_t key) {
+int GrTextureStripAtlas::searchByKey(uint32_t key) {
     AtlasRow target;
     target.fKey = key;
-    return SkTSearch<const AtlasRow, KeyLess>((const AtlasRow**)fKeyTable.begin(),
-                                              fKeyTable.count(),
-                                              &target,
-                                              sizeof(AtlasRow*));
+    return SkTSearch<const AtlasRow,
+                     GrTextureStripAtlas::KeyLess>((const AtlasRow**)fKeyTable.begin(),
+                                                   fKeyTable.count(),
+                                                   &target,
+                                                   sizeof(AtlasRow*));
 }
 
 #ifdef SK_DEBUG
-void GrDynamicTextureStripAtlas::validate() {
+void GrTextureStripAtlas::validate() {
+
     // Our key table should be sorted
     uint32_t prev = 1 > fKeyTable.count() ? 0 : fKeyTable[0]->fKey;
     for (int i = 1; i < fKeyTable.count(); ++i) {
diff --git a/src/gpu/effects/GrDynamicTextureStripAtlas.h b/src/gpu/effects/GrDynamicTextureStripAtlas.h
index 301617b..b404f57 100644
--- a/src/gpu/effects/GrDynamicTextureStripAtlas.h
+++ b/src/gpu/effects/GrDynamicTextureStripAtlas.h
@@ -8,35 +8,39 @@
 #ifndef GrDynamicTextureStripAtlas_DEFINED
 #define GrDynamicTextureStripAtlas_DEFINED
 
-#include "GrTextureStripAtlas.h"
+#include "GrTypesPriv.h"
+
+#include "SkNoncopyable.h"
+#include "SkRefCnt.h"
+#include "SkScalar.h"
 #include "SkTDArray.h"
 
+class GrContext;
 class GrSurfaceContext;
+class GrTextureProxy;
+
+class SkBitmap;
 
 /**
  * Maintains a single large texture whose rows store many textures of a small fixed height,
  * stored in rows across the x-axis such that we can safely wrap/repeat them horizontally.
  */
-class GrDynamicTextureStripAtlas final : public GrTextureStripAtlas {
+class GrTextureStripAtlas : public SkRefCnt {
 public:
-    ~GrDynamicTextureStripAtlas() final;
-
     /**
-     * This is intended to be used when cloning a processor that already holds a lock. It is
-     * assumed that the row already has at least one lock.
+     * Descriptor struct which we'll use as a hash table key
      */
-    void lockRow(int row) final;
-    void unlockRow(int row) final;
+    struct Desc {
+        Desc() { sk_bzero(this, sizeof(*this)); }
+        GrPixelConfig fConfig;
+        uint16_t fWidth, fHeight, fRowHeight;
+        uint16_t fUnusedPadding;
+        bool operator==(const Desc& other) const {
+            return 0 == memcmp(this, &other, sizeof(Desc));
+        }
+    };
 
-    sk_sp<GrTextureProxy> asTextureProxyRef() const final;
-
-private:
-    friend class GrTextureStripAtlasManager; // for ctor
-
-    /**
-     * Only the GrTextureStripAtlasManager is allowed to create GrTextureStripAtlases
-     */
-    GrDynamicTextureStripAtlas(const Desc& desc);
+    ~GrTextureStripAtlas();
 
     /**
      * Add a texture to the atlas
@@ -44,9 +48,38 @@
      *  @return The row index we inserted into, or -1 if we failed to find an open row. The caller
      *      is responsible for calling unlockRow() with this row index when it's done with it.
      */
-    int addStrip(GrContext*, const SkBitmap&) final;
+    int lockRow(GrContext*, const SkBitmap&);
 
-    void finish(GrProxyProvider*) final { SkASSERT(0); }  // this is only called in DDL mode
+    /**
+     * This is intended to be used when cloning a processor that already holds a lock. It is
+     * assumed that the row already has at least one lock.
+     */
+    void lockRow(int row);
+    void unlockRow(int row);
+
+    /**
+     * These functions help turn an integer row index in [0, 1, 2, ... numRows] into a scalar y
+     * texture coordinate in [0, 1] that we can use in a shader.
+     *
+     * If a regular texture access without using the atlas looks like:
+     *
+     *      texture2D(sampler, float2(x, y))
+     *
+     * Then when using the atlas we'd replace it with:
+     *
+     *       texture2D(sampler, float2(x, yOffset + y * scaleFactor))
+     *
+     * Where yOffset, returned by getYOffset(), is the offset to the start of the row within the
+     * atlas and scaleFactor, returned by getNormalizedTexelHeight, is the normalized height of
+     * one texel row.
+     */
+    SkScalar getYOffset(int row) const { return SkIntToScalar(row) / fNumRows; }
+    SkScalar getNormalizedTexelHeight() const { return fNormalizedYHeight; }
+
+    sk_sp<GrTextureProxy> asTextureProxyRef() const;
+
+private:
+    friend class GrTextureStripAtlasManager; // for ctor
 
     static uint32_t CreateUniqueID();
 
@@ -68,6 +101,11 @@
         AtlasRow* fPrev;
     };
 
+    /**
+     * Only the GrTextureStripAtlasManager is allowed to create GrTextureStripAtlases
+     */
+    GrTextureStripAtlas(const Desc& desc);
+
     void lockTexture(GrContext*);
     void unlockTexture();
 
@@ -109,6 +147,7 @@
     // Total locks on all rows (when this reaches zero, we can unlock our texture)
     int32_t fLockedRows;
 
+    const Desc fDesc;
     const uint16_t fNumRows;
     sk_sp<GrSurfaceContext> fTexContext;
 
@@ -126,8 +165,6 @@
 
     // A list of pointers to AtlasRows that currently contain cached images, sorted by key
     SkTDArray<AtlasRow*> fKeyTable;
-
-    typedef GrTextureStripAtlas INHERITED;
 };
 
 #endif
diff --git a/src/gpu/effects/GrTextureStripAtlas.cpp b/src/gpu/effects/GrTextureStripAtlas.cpp
index 9144184..eecaadf 100644
--- a/src/gpu/effects/GrTextureStripAtlas.cpp
+++ b/src/gpu/effects/GrTextureStripAtlas.cpp
@@ -8,10 +8,10 @@
 #include "GrTextureStripAtlas.h"
 #include "GrContext.h"
 #include "GrContextPriv.h"
-#include "GrDDLTextureStripAtlas.h"
 #include "GrDynamicTextureStripAtlas.h"
 #include "SkBitmap.h"
 
+////////////////////////////////////////////////////////////////////////////////
 GrTextureStripAtlasManager::~GrTextureStripAtlasManager() {
     this->deleteAllAtlases();
 }
@@ -30,41 +30,15 @@
     this->deleteAllAtlases();
 }
 
-void GrTextureStripAtlasManager::finish(GrProxyProvider* proxyProvider) {
-    for (AtlasHash::Iter iter(&fAtlasCache); !iter.done(); ++iter) {
-        AtlasEntry* tmp = &(*iter);
-        tmp->fAtlas->finish(proxyProvider);
-    }
-    fAtlasCache.reset();
-}
-
-
-sk_sp<GrTextureStripAtlas> GrTextureStripAtlasManager::addStrip(
-                                                          GrContext* context,
-                                                          const GrTextureStripAtlas::Desc& desc,
-                                                          const SkBitmap& bitmap,
-                                                          int* row) {
-    SkASSERT(kPremul_SkAlphaType == bitmap.alphaType());
-
+sk_sp<GrTextureStripAtlas> GrTextureStripAtlasManager::refAtlas(
+                                                          const GrTextureStripAtlas::Desc& desc) {
     AtlasEntry* entry = fAtlasCache.find(desc);
     if (!entry) {
-        sk_sp<GrTextureStripAtlas> atlas;
+        // TODO: Does the AtlasEntry need a copy of the Desc if the GrTextureStripAtlas has one?
+        entry = new AtlasEntry(desc, sk_sp<GrTextureStripAtlas>(new GrTextureStripAtlas(desc)));
 
-        if (!context->contextPriv().resourceProvider()) {
-            atlas.reset(new GrDDLTextureStripAtlas(desc));
-        } else {
-            atlas.reset(new GrDynamicTextureStripAtlas(desc));
-        }
-
-        entry = new AtlasEntry(sk_sp<GrTextureStripAtlas>(std::move(atlas)));
         fAtlasCache.add(entry);
     }
 
-    *row = entry->fAtlas->addStrip(context, bitmap);
-    if (*row < 0) {
-        return nullptr;
-    }
-
     return entry->fAtlas;
 }
-
diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp
index 536a7a8..aa44ae6 100644
--- a/src/shaders/gradients/SkGradientShader.cpp
+++ b/src/shaders/gradients/SkGradientShader.cpp
@@ -919,7 +919,6 @@
 #include "GrContext.h"
 #include "GrContextPriv.h"
 #include "GrShaderCaps.h"
-#include "GrTexture.h"
 #include "GrTextureStripAtlas.h"
 #include "gl/GrGLContext.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
@@ -967,8 +966,7 @@
             break;
         case GrGradientEffect::InterpolationStrategy::kTexture:
             if (e.fYCoord != fCachedYCoord) {
-                SkScalar yDelta = 1.0f / e.fTextureSampler.peekTexture()->height();
-                pdman.set1f(fFSYUni, e.fYCoord * yDelta);
+                pdman.set1f(fFSYUni, e.fYCoord);
                 fCachedYCoord = e.fYCoord;
             }
             break;
@@ -1248,8 +1246,6 @@
         SkBitmap bitmap;
         shader.getGradientTableBitmap(xformedColors.fColors, &bitmap, colorType);
         SkASSERT(1 == bitmap.height() && SkIsPow2(bitmap.width()));
-        SkASSERT(kPremul_SkAlphaType == bitmap.alphaType());
-        SkASSERT(bitmap.isImmutable());
 
         auto atlasManager = args.fContext->contextPriv().textureStripAtlasManager();
 
@@ -1257,24 +1253,18 @@
         desc.fWidth  = bitmap.width();
         desc.fHeight = 32;
         desc.fRowHeight = bitmap.height(); // always 1 here
-        desc.fColorType = bitmap.colorType();
-
-        int row;
-        fAtlas = atlasManager->addStrip(args.fContext, desc, bitmap, &row);
-        if (!args.fContext->contextPriv().resourceProvider()) {
-            // In DDL mode we should always be able to atlas
-            SkASSERT(fAtlas && row >= 0);
-        }
+        desc.fConfig = SkColorType2GrPixelConfig(bitmap.colorType());
+        fAtlas = atlasManager->refAtlas(desc);
+        SkASSERT(fAtlas);
 
         // We always filter the gradient table. Each table is one row of a texture, always
         // y-clamp.
         GrSamplerState samplerState(args.fWrapMode, GrSamplerState::Filter::kBilerp);
 
+        fRow = fAtlas->lockRow(args.fContext, bitmap);
         if (-1 != fRow) {
-            SkASSERT(fAtlas);
-
-            fYCoord = fAtlas->rowToTextureY(fRow);
-            // This is 1/2 places where auto-normalization is disabled bc the gradient T is 0..1
+            fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight();
+            // This is 1/2 places where auto-normalization is disabled
             fCoordTransform.reset(*args.fMatrix, fAtlas->asTextureProxyRef().get(), false);
             fTextureSampler.reset(fAtlas->asTextureProxyRef(), samplerState);
         } else {
@@ -1286,6 +1276,7 @@
             // that GrMakeCachedImageProxy is sufficient (i.e., it won't need to be
             // extracted to a subset or mipmapped).
 
+            SkASSERT(bitmap.isImmutable());
             sk_sp<SkImage> srcImage = SkImage::MakeFromBitmap(bitmap);
             if (!srcImage) {
                 return;
@@ -1298,13 +1289,11 @@
                 SkDebugf("Gradient won't draw. Could not create texture.");
                 return;
             }
-            // This is 2/2 places where auto-normalization is disabled because the graient T is 0..1
+            // This is 2/2 places where auto-normalization is disabled
             fCoordTransform.reset(*args.fMatrix, proxy.get(), false);
             fTextureSampler.reset(std::move(proxy), samplerState);
-            SkASSERT(1 == bitmap.height());
             fYCoord = SK_ScalarHalf;
         }
-
         this->setTextureSamplerCnt(1);
     }
 
diff --git a/src/shaders/gradients/SkGradientShaderPriv.h b/src/shaders/gradients/SkGradientShaderPriv.h
index f3e10d0..6aa5da2 100644
--- a/src/shaders/gradients/SkGradientShaderPriv.h
+++ b/src/shaders/gradients/SkGradientShaderPriv.h
@@ -156,7 +156,6 @@
 #include "glsl/GrGLSLProgramDataManager.h"
 
 class GrInvariantOutput;
-class GrTextureStripAtlas;
 
 /*
  * The interpretation of the texture matrix depends on the sample mode. The
@@ -181,6 +180,8 @@
  *  determines the gradient value.
  */
 
+ class GrTextureStripAtlas;
+
 // Base class for Gr gradient effects
 class GrGradientEffect : public GrFragmentProcessor {
 public: