Modify fontcache GM to actually spill atlas.

Adds an option to GrDrawOpAtlas to disable multitexturing.

Adds option to GrContextOptions to disable multitexturing for glyph atlases.


Change-Id: If413ab7061538fa0e75628d252be4fd14215b6ba
Reviewed-on: https://skia-review.googlesource.com/67802
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 2146858..d3194be 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -204,7 +204,14 @@
     }
     fDrawingManager.reset(new GrDrawingManager(this, prcOptions, &fSingleOwner));
 
-    fAtlasGlyphCache = new GrAtlasGlyphCache(this, options.fGlyphCacheTextureMaximumBytes);
+    GrDrawOpAtlas::AllowMultitexturing allowMultitexturing;
+    if (options.fAllowMultipleGlyphCacheTextures == GrContextOptions::Enable::kNo) {
+        allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kNo;
+    } else {
+        allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes;
+    }
+    fAtlasGlyphCache = new GrAtlasGlyphCache(this, options.fGlyphCacheTextureMaximumBytes,
+                                             allowMultitexturing);
     this->contextPriv().addOnFlushCallbackObject(fAtlasGlyphCache);
 
     fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this));
diff --git a/src/gpu/GrDrawOpAtlas.cpp b/src/gpu/GrDrawOpAtlas.cpp
index 8d81285..c0358b7 100644
--- a/src/gpu/GrDrawOpAtlas.cpp
+++ b/src/gpu/GrDrawOpAtlas.cpp
@@ -14,13 +14,12 @@
 #include "GrTexture.h"
 #include "GrTracing.h"
 
-std::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig config,
-                                                   int width, int height,
-                                                   int numPlotsX, int numPlotsY,
-                                                   GrDrawOpAtlas::EvictionFunc func,
-                                                   void* data) {
-    std::unique_ptr<GrDrawOpAtlas> atlas(
-            new GrDrawOpAtlas(ctx, config, width, height, numPlotsX, numPlotsY));
+std::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig config, int width,
+                                                   int height, int numPlotsX, int numPlotsY,
+                                                   AllowMultitexturing allowMultitexturing,
+                                                   GrDrawOpAtlas::EvictionFunc func, void* data) {
+    std::unique_ptr<GrDrawOpAtlas> atlas(new GrDrawOpAtlas(ctx, config, width, height, numPlotsX,
+                                                           numPlotsY, allowMultitexturing));
     if (!atlas->getProxies()[0]) {
         return nullptr;
     }
@@ -147,13 +146,14 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, GrPixelConfig config, int width, int height,
-                             int numPlotsX, int numPlotsY)
+                             int numPlotsX, int numPlotsY, AllowMultitexturing allowMultitexturing)
         : fContext(context)
         , fPixelConfig(config)
         , fTextureWidth(width)
         , fTextureHeight(height)
         , fAtlasGeneration(kInvalidAtlasGeneration + 1)
         , fPrevFlushToken(GrDeferredUploadToken::AlreadyFlushedToken())
+        , fAllowMultitexturing(allowMultitexturing)
         , fNumPages(0) {
     fPlotWidth = fTextureWidth / numPlotsX;
     fPlotHeight = fTextureHeight / numPlotsY;
@@ -242,7 +242,7 @@
     for (unsigned int pageIdx = 0; pageIdx < fNumPages; ++pageIdx) {
         Plot* plot = fPages[pageIdx].fPlotList.tail();
         SkASSERT(plot);
-        if ((fNumPages == kMaxPages && plot->lastUseToken() < target->nextTokenToFlush()) ||
+        if ((fNumPages == this->maxPages() && plot->lastUseToken() < target->nextTokenToFlush()) ||
             plot->flushesSinceLastUsed() >= kRecentlyUsedCount) {
             this->processEvictionAndResetRects(plot);
             SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
@@ -448,7 +448,7 @@
 }
 
 bool GrDrawOpAtlas::createNewPage() {
-    if (fNumPages == kMaxPages) {
+    if (fNumPages == this->maxPages()) {
         return false;
     }
 
diff --git a/src/gpu/GrDrawOpAtlas.h b/src/gpu/GrDrawOpAtlas.h
index 91a88ec..edab2cb 100644
--- a/src/gpu/GrDrawOpAtlas.h
+++ b/src/gpu/GrDrawOpAtlas.h
@@ -51,7 +51,13 @@
  * and passes in the given GrDrawUploadToken.
  */
 class GrDrawOpAtlas {
+private:
+    static constexpr auto kMaxMultitexturePages = 4;
+
 public:
+    /** Is the atlas allowed to use more than one texture? */
+    enum class AllowMultitexturing : bool { kNo, kYes };
+
     /**
      * An AtlasID is an opaque handle which callers can use to determine if the atlas contains
      * a specific piece of data.
@@ -77,15 +83,16 @@
      *                          direction
      *  @param numPlotsY        The number of plots the atlas should be broken up into in the Y
      *                          direction
+     *  @param allowMultitexturing Can the atlas use more than one texture.
      *  @param func             An eviction function which will be called whenever the atlas has to
      *                          evict data
-     *  @param data             User supplied data which will be passed into func whenver an
+     *  @param data             User supplied data which will be passed into func whenever an
      *                          eviction occurs
      *  @return                 An initialized GrDrawOpAtlas, or nullptr if creation fails
      */
-    static std::unique_ptr<GrDrawOpAtlas> Make(GrContext*, GrPixelConfig,
-                                               int width, int height,
+    static std::unique_ptr<GrDrawOpAtlas> Make(GrContext*, GrPixelConfig, int width, int height,
                                                int numPlotsX, int numPlotsY,
+                                               AllowMultitexturing allowMultitexturing,
                                                GrDrawOpAtlas::EvictionFunc func, void* data);
 
     /**
@@ -134,7 +141,6 @@
         data->fData = userData;
     }
 
-    static constexpr auto kMaxPages = 4;
     uint32_t pageCount() { return fNumPages; }
 
     /**
@@ -186,7 +192,7 @@
         static constexpr int kMinItems = 4;
         static constexpr int kMaxPlots = 32;
         SkSTArray<kMinItems, PlotData, true> fPlotsToUpdate;
-        uint32_t fPlotAlreadyUpdated[kMaxPages];
+        uint32_t fPlotAlreadyUpdated[kMaxMultitexturePages];
 
         friend class GrDrawOpAtlas;
     };
@@ -217,8 +223,12 @@
     }
 
 private:
-    GrDrawOpAtlas(GrContext*, GrPixelConfig config, int width, int height,
-                  int numPlotsX, int numPlotsY);
+    uint32_t maxPages() const {
+        return AllowMultitexturing::kYes == fAllowMultitexturing ? kMaxMultitexturePages : 1;
+    }
+
+    GrDrawOpAtlas(GrContext*, GrPixelConfig config, int width, int height, int numPlotsX,
+                  int numPlotsY, AllowMultitexturing allowMultitexturing);
 
     /**
      * The backing GrTexture for a GrDrawOpAtlas is broken into a spatial grid of Plots. The Plots
@@ -282,7 +292,7 @@
         static GrDrawOpAtlas::AtlasID CreateId(uint32_t pageIdx, uint32_t plotIdx,
                                                uint64_t generation) {
             SkASSERT(pageIdx < (1 << 8));
-            SkASSERT(pageIdx < kMaxPages);
+            SkASSERT(pageIdx < kMaxMultitexturePages);
             SkASSERT(plotIdx < (1 << 8));
             SkASSERT(generation < ((uint64_t)1 << 48));
             return generation << 16 | plotIdx << 8 | pageIdx;
@@ -376,8 +386,9 @@
         PlotList fPlotList;
     };
     // proxies kept separate to make it easier to pass them up to client
-    sk_sp<GrTextureProxy> fProxies[kMaxPages];
-    Page fPages[kMaxPages];
+    sk_sp<GrTextureProxy> fProxies[kMaxMultitexturePages];
+    Page fPages[kMaxMultitexturePages];
+    AllowMultitexturing fAllowMultitexturing;
     uint32_t fNumPages;
 };
 
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index d308498..4f4dcc1 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -181,10 +181,9 @@
         fHelper.visitProxies(func);
 
         const sk_sp<GrTextureProxy>* proxies = fAtlas->getProxies();
-        for (int i = 0; i < GrDrawOpAtlas::kMaxPages; ++i) {
-            if (proxies[i].get()) {
-                func(proxies[i].get());
-            }
+        for (uint32_t i = 0; i < fAtlas->pageCount(); ++i) {
+            SkASSERT(proxies[i]);
+            func(proxies[i].get());
         }
     }
 
@@ -793,6 +792,7 @@
                                      kAlpha_8_GrPixelConfig,
                                      ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
                                      NUM_PLOTS_X, NUM_PLOTS_Y,
+                                     GrDrawOpAtlas::AllowMultitexturing::kYes,
                                      &GrSmallPathRenderer::HandleEviction,
                                      (void*)this);
         if (!fAtlas) {
@@ -861,6 +861,7 @@
         gTestStruct.fAtlas = GrDrawOpAtlas::Make(context, kAlpha_8_GrPixelConfig,
                                                  ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
                                                  NUM_PLOTS_X, NUM_PLOTS_Y,
+                                                 GrDrawOpAtlas::AllowMultitexturing::kYes,
                                                  &PathTestStruct::HandleEviction,
                                                  (void*)&gTestStruct);
     }
diff --git a/src/gpu/text/GrAtlasGlyphCache.cpp b/src/gpu/text/GrAtlasGlyphCache.cpp
index 25575be..80f4314 100644
--- a/src/gpu/text/GrAtlasGlyphCache.cpp
+++ b/src/gpu/text/GrAtlasGlyphCache.cpp
@@ -25,9 +25,9 @@
         int numPlotsX = fAtlasConfigs[index].numPlotsX();
         int numPlotsY = fAtlasConfigs[index].numPlotsY();
 
-        fAtlases[index] = GrDrawOpAtlas::Make(
-                fContext, config, width, height, numPlotsX, numPlotsY,
-                &GrAtlasGlyphCache::HandleEviction, (void*)this);
+        fAtlases[index] = GrDrawOpAtlas::Make(fContext, config, width, height, numPlotsX, numPlotsY,
+                                              fAllowMultitexturing,
+                                              &GrAtlasGlyphCache::HandleEviction, (void*)this);
         if (!fAtlases[index]) {
             return false;
         }
@@ -35,11 +35,12 @@
     return true;
 }
 
-GrAtlasGlyphCache::GrAtlasGlyphCache(GrContext* context, float maxTextureBytes)
-        : fContext(context), fPreserveStrike(nullptr) {
-    // Calculate RGBA size. Must be between 1024 x 512 and MaxTextureSize x MaxTextureSize / 2
+GrAtlasGlyphCache::GrAtlasGlyphCache(GrContext* context, float maxTextureBytes,
+                                     GrDrawOpAtlas::AllowMultitexturing allowMultitexturing)
+        : fContext(context), fAllowMultitexturing(allowMultitexturing), fPreserveStrike(nullptr) {
+    // Calculate RGBA size. Must be between 512 x 256 and MaxTextureSize x MaxTextureSize / 2
     int log2MaxTextureSize = SkPrevLog2(context->caps()->maxTextureSize());
-    int log2MaxDim = 10;
+    int log2MaxDim = 9;
     for (; log2MaxDim <= log2MaxTextureSize; ++log2MaxDim) {
         int maxDim = 1 << log2MaxDim;
         int minDim = 1 << (log2MaxDim - 1);
@@ -177,17 +178,16 @@
     for (int i = 0; i < kMaskFormatCount; ++i) {
         if (fAtlases[i]) {
             const sk_sp<GrTextureProxy>* proxies = fAtlases[i]->getProxies();
-            for (int pageIdx = 0; pageIdx < GrDrawOpAtlas::kMaxPages; ++pageIdx) {
-                if (proxies[pageIdx]) {
-                    SkString filename;
+            for (uint32_t pageIdx = 0; pageIdx < fAtlases[i]->pageCount(); ++pageIdx) {
+                SkASSERT(proxies[pageIdx]);
+                SkString filename;
 #ifdef SK_BUILD_FOR_ANDROID
-                    filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
+                filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
 #else
-                    filename.printf("fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
+                filename.printf("fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
 #endif
 
-                    save_pixels(fContext, proxies[pageIdx].get(), filename.c_str());
-                }
+                save_pixels(fContext, proxies[pageIdx].get(), filename.c_str());
             }
         }
     }
diff --git a/src/gpu/text/GrAtlasGlyphCache.h b/src/gpu/text/GrAtlasGlyphCache.h
index 20bc32a..a75ef53 100644
--- a/src/gpu/text/GrAtlasGlyphCache.h
+++ b/src/gpu/text/GrAtlasGlyphCache.h
@@ -111,7 +111,7 @@
  */
 class GrAtlasGlyphCache : public GrOnFlushCallbackObject {
 public:
-    GrAtlasGlyphCache(GrContext*, float maxTextureBytes);
+    GrAtlasGlyphCache(GrContext*, float maxTextureBytes, GrDrawOpAtlas::AllowMultitexturing);
     ~GrAtlasGlyphCache() override;
     // The user of the cache may hold a long-lived ref to the returned strike. However, actions by
     // another client of the cache may cause the strike to be purged while it is still reffed.
@@ -256,6 +256,7 @@
     using StrikeHash = SkTDynamicHash<GrAtlasTextStrike, SkDescriptor>;
     GrContext* fContext;
     StrikeHash fCache;
+    GrDrawOpAtlas::AllowMultitexturing fAllowMultitexturing;
     std::unique_ptr<GrDrawOpAtlas> fAtlases[kMaskFormatCount];
     GrAtlasTextStrike* fPreserveStrike;
     GrDrawOpAtlasConfig fAtlasConfigs[kMaskFormatCount];