Simplify plots to always be 512x512 and simplify GrDrawOpAtlasConfig

Change-Id: I1353d3facf191e3323027fc288715672240d1f87
Reviewed-on: https://skia-review.googlesource.com/152591
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h
index f68cc83..afb3949 100644
--- a/src/gpu/GrContextPriv.h
+++ b/src/gpu/GrContextPriv.h
@@ -263,10 +263,6 @@
         this is for testing only */
     void setTextBlobCacheLimit_ForTesting(size_t bytes);
 
-    /** Specify the sizes of the GrAtlasTextContext atlases.  The configs pointer below should be
-        to an array of 3 entries */
-    void setTextContextAtlasSizes_ForTesting(const GrDrawOpAtlasConfig* configs);
-
     /** Get pointer to atlas texture for given mask format. Note that this wraps an
         actively mutating texture in an SkImage. This could yield unexpected results
         if it gets cached or used more generally. */
diff --git a/src/gpu/GrDrawOpAtlas.h b/src/gpu/GrDrawOpAtlas.h
index e1253f0..41807b3 100644
--- a/src/gpu/GrDrawOpAtlas.h
+++ b/src/gpu/GrDrawOpAtlas.h
@@ -8,7 +8,11 @@
 #ifndef GrDrawOpAtlas_DEFINED
 #define GrDrawOpAtlas_DEFINED
 
+#include <cmath>
+
+#include "SkGlyphRun.h"
 #include "SkIPoint16.h"
+#include "SkSize.h"
 #include "SkTDArray.h"
 #include "SkTInternalLList.h"
 
@@ -17,13 +21,68 @@
 class GrOnFlushResourceProvider;
 class GrRectanizer;
 
-struct GrDrawOpAtlasConfig {
-    int numPlotsX() const { return fWidth / fPlotWidth; }
-    int numPlotsY() const { return fHeight / fPlotHeight; }
-    int fWidth;
-    int fHeight;
-    int fPlotWidth;
-    int fPlotHeight;
+// There are three atlases (A8, 565, ARGB) that are kept in relation with one another. In
+// general, the A8 dimensions are NxN and 565 and ARGB are N/2xN with the constraint that an atlas
+// size will always contain at least one plot. Since the ARGB atlas takes the most space, its
+// dimensions are used to size the other two atlases.
+class GrDrawOpAtlasConfig {
+public:
+    GrDrawOpAtlasConfig(int maxDimension, size_t maxBytes)
+            : fPlotsPerLongDimension{PlotsPerLongDimensionForARGB(maxDimension, maxBytes)} {
+        SkASSERT(kPlotSize >= SkGlyphCacheCommon::kSkSideTooBigForAtlas);
+    }
+
+    // For testing only - make minimum sized atlases -- 1x1 plots wide.
+    GrDrawOpAtlasConfig() : fPlotsPerLongDimension{1} {
+        SkASSERT(kPlotSize >= SkGlyphCacheCommon::kSkSideTooBigForAtlas);
+    }
+
+    SkISize numPlots(GrMaskFormat type) const {
+        switch(type) {
+            case kA8_GrMaskFormat:
+                return {fPlotsPerLongDimension, fPlotsPerLongDimension};
+            case kA565_GrMaskFormat:
+            case kARGB_GrMaskFormat: {
+                int plotsPerWidth = std::max(1, fPlotsPerLongDimension / 2);
+                return {plotsPerWidth, fPlotsPerLongDimension};
+            }
+        }
+
+        // This make some compilers happy.
+        return {1,1};
+    }
+
+    SkISize atlasDimensions(GrMaskFormat type) const {
+        SkISize plots = this->numPlots(type);
+        return {plots.width() * kPlotSize, plots.height() * kPlotSize};
+    }
+
+private:
+    static int PlotsPerLongDimensionForARGB(size_t maxDimension, size_t maxBytes) {
+        // Find the largest area of pixels in a width:height with a proportion of 1:2 that fits in
+        // maxTextureBytes. In the following P is pixel size, H is height, and W is width.
+        // P*H*W = maxTextureSize => P*H*(H/2) = maxTextureSize => H = sqrt(2*maxTextureSize/P)
+        double fitsHeight =
+                std::sqrt(2.0 * maxBytes /  GrMaskFormatBytesPerPixel(kARGB_GrMaskFormat));
+
+        // Because of limitations of the distance field text, the largest an atlas can be is 2048.
+        maxDimension = std::min(maxDimension, SkTo<size_t>(2048));
+
+        // Limit height to the maximum texture dimension and the minimum atlas size.
+        double height = std::max(std::min(fitsHeight, (double)maxDimension), (double)kPlotSize);
+
+        // Find the greatest power of 2 that is less than height.
+        double alignedHeight = std::exp2(std::floor(std::log2(height)));
+
+        // Calculate the atlas dimensions.
+        return (int)alignedHeight / kPlotSize;
+    }
+
+    // The width and height of a plot.
+    static constexpr int kPlotSize = 512;
+
+    // This is the height (longest dimension) of the ARGB atlas divided by the plot size.
+    const int fPlotsPerLongDimension;
 };
 
 /**
@@ -55,6 +114,7 @@
 private:
     static constexpr auto kMaxMultitexturePages = 4;
 
+
 public:
     /** Is the atlas allowed to use more than one texture? */
     enum class AllowMultitexturing : bool { kNo, kYes };
diff --git a/src/gpu/text/GrAtlasManager.cpp b/src/gpu/text/GrAtlasManager.cpp
index ddd0b03..c1b3d7b 100644
--- a/src/gpu/text/GrAtlasManager.cpp
+++ b/src/gpu/text/GrAtlasManager.cpp
@@ -10,66 +10,17 @@
 #include "GrGlyph.h"
 #include "GrGlyphCache.h"
 
-void GrAtlasManager::ComputeAtlasLimits(int maxTextureSize, size_t maxTextureBytes, int* maxDim,
-                                        int* minDim, int* maxPlot, int* minPlot) {
-    SkASSERT(maxDim && minDim && maxPlot && minPlot);
-    // Calculate RGBA size. Must be between 512 x 256 and MaxTextureSize x MaxTextureSize / 2
-    int log2MaxTextureSize = SkPrevLog2(maxTextureSize);
-    int log2MaxDim = 9;
-    static const size_t kOne = 1u;
-    for (; log2MaxDim <= log2MaxTextureSize; ++log2MaxDim) {
-        size_t maxDimTmp = kOne << log2MaxDim;
-        size_t minDimTmp = kOne << (log2MaxDim - 1);
-
-        if (maxDimTmp * minDimTmp * 4 >= maxTextureBytes) {
-            break;
-        }
-    }
-
-
-    int log2MinDim = log2MaxDim - 1;
-    *maxDim = 1 << log2MaxDim;
-    *minDim = 1 << log2MinDim;
-    // Plots are either 256 or 512.
-    *maxPlot = SkTMin(512, SkTMax(256, 1 << (log2MaxDim - 2)));
-    *minPlot = SkTMin(512, SkTMax(256, 1 << (log2MaxDim - 3)));
-}
-
 GrAtlasManager::GrAtlasManager(GrProxyProvider* proxyProvider, GrGlyphCache* glyphCache,
-                               float maxTextureBytes,
+                               size_t maxTextureBytes,
                                GrDrawOpAtlas::AllowMultitexturing allowMultitexturing)
-            : fAllowMultitexturing(allowMultitexturing)
-            , fProxyProvider(proxyProvider)
-            , fGlyphCache(glyphCache) {
-    fCaps = fProxyProvider->refCaps();
+            : fAllowMultitexturing{allowMultitexturing}
+            , fGlyphSizeLimit{SkGlyphCacheCommon::kSkSideTooBigForAtlas}
+            , fProxyProvider{proxyProvider}
+            , fCaps{fProxyProvider->refCaps()}
+            , fGlyphCache{glyphCache}
+            , fAtlasConfigs{fCaps->maxTextureSize(), maxTextureBytes} { }
 
-    int maxDim, minDim, maxPlot, minPlot;
-    ComputeAtlasLimits(fCaps->maxTextureSize(), maxTextureBytes, &maxDim, &minDim, &maxPlot,
-                       &minPlot);
-
-    // Setup default atlas configs. The A8 atlas uses maxDim for both width and height, as the A8
-    // format is already very compact.
-    fAtlasConfigs[kA8_GrMaskFormat].fWidth = maxDim;
-    fAtlasConfigs[kA8_GrMaskFormat].fHeight = maxDim;
-    fAtlasConfigs[kA8_GrMaskFormat].fPlotWidth = maxPlot;
-    fAtlasConfigs[kA8_GrMaskFormat].fPlotHeight = maxPlot;
-
-    // A565 and ARGB use maxDim x minDim.
-    fAtlasConfigs[kA565_GrMaskFormat].fWidth = minDim;
-    fAtlasConfigs[kA565_GrMaskFormat].fHeight = maxDim;
-    fAtlasConfigs[kA565_GrMaskFormat].fPlotWidth = minPlot;
-    fAtlasConfigs[kA565_GrMaskFormat].fPlotHeight = minPlot;
-
-    fAtlasConfigs[kARGB_GrMaskFormat].fWidth = minDim;
-    fAtlasConfigs[kARGB_GrMaskFormat].fHeight = maxDim;
-    fAtlasConfigs[kARGB_GrMaskFormat].fPlotWidth = minPlot;
-    fAtlasConfigs[kARGB_GrMaskFormat].fPlotHeight = minPlot;
-
-    fGlyphSizeLimit = minPlot;
-}
-
-GrAtlasManager::~GrAtlasManager() {
-}
+GrAtlasManager::~GrAtlasManager() = default;
 
 static GrPixelConfig mask_format_to_pixel_config(GrMaskFormat format) {
     switch (format) {
@@ -196,28 +147,28 @@
 }
 #endif
 
-void GrAtlasManager::setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3]) {
+void GrAtlasManager::setAtlasSizesToMinimum_ForTesting() {
     // Delete any old atlases.
     // This should be safe to do as long as we are not in the middle of a flush.
     for (int i = 0; i < kMaskFormatCount; i++) {
         fAtlases[i] = nullptr;
     }
-    memcpy(fAtlasConfigs, configs, sizeof(fAtlasConfigs));
+
+    // Set all the atlas sizes to 1x1 plot each.
+    new (&fAtlasConfigs) GrDrawOpAtlasConfig{};
 }
 
 bool GrAtlasManager::initAtlas(GrMaskFormat format) {
     int index = MaskFormatToAtlasIndex(format);
-    if (!fAtlases[index]) {
+    if (fAtlases[index] == nullptr) {
         GrPixelConfig config = mask_format_to_pixel_config(format);
-        int width = fAtlasConfigs[index].fWidth;
-        int height = fAtlasConfigs[index].fHeight;
-        int numPlotsX = fAtlasConfigs[index].numPlotsX();
-        int numPlotsY = fAtlasConfigs[index].numPlotsY();
+        SkISize atlasDimensions = fAtlasConfigs.atlasDimensions(format);
+        SkISize numPlots = fAtlasConfigs.numPlots(format);
 
-        fAtlases[index] = GrDrawOpAtlas::Make(fProxyProvider, config, width, height,
-                                              numPlotsX, numPlotsY, fAllowMultitexturing,
-                                              &GrGlyphCache::HandleEviction,
-                                              fGlyphCache);
+        fAtlases[index] = GrDrawOpAtlas::Make(
+                fProxyProvider, config, atlasDimensions.width(), atlasDimensions.height(),
+                numPlots.width(), numPlots.height(), fAllowMultitexturing,
+                &GrGlyphCache::HandleEviction, fGlyphCache);
         if (!fAtlases[index]) {
             return false;
         }
diff --git a/src/gpu/text/GrAtlasManager.h b/src/gpu/text/GrAtlasManager.h
index 6c16853..e857ae8 100644
--- a/src/gpu/text/GrAtlasManager.h
+++ b/src/gpu/text/GrAtlasManager.h
@@ -27,7 +27,7 @@
 class GrAtlasManager : public GrOnFlushCallbackObject {
 public:
     GrAtlasManager(GrProxyProvider*, GrGlyphCache*,
-                   float maxTextureBytes, GrDrawOpAtlas::AllowMultitexturing);
+                   size_t maxTextureBytes, GrDrawOpAtlas::AllowMultitexturing);
     ~GrAtlasManager() override;
 
     // Change an expected 565 mask format to 8888 if 565 is not supported (will happen when using
@@ -57,9 +57,6 @@
 
     SkScalar getGlyphSizeLimit() const { return fGlyphSizeLimit; }
 
-    static void ComputeAtlasLimits(int maxTextureSize, size_t maxTextureBytes, int* maxDim,
-                                   int* minDim, int* maxPlot, int* minPlot);
-
     void freeAll();
 
     bool hasGlyph(GrGlyph* glyph);
@@ -121,7 +118,7 @@
     void dump(GrContext* context) const;
 #endif
 
-    void setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3]);
+    void setAtlasSizesToMinimum_ForTesting();
     void setMaxPages_TestingOnly(uint32_t maxPages);
 
 private:
@@ -147,13 +144,13 @@
         return fAtlases[atlasIndex].get();
     }
 
-    sk_sp<const GrCaps> fCaps;
     GrDrawOpAtlas::AllowMultitexturing fAllowMultitexturing;
     std::unique_ptr<GrDrawOpAtlas> fAtlases[kMaskFormatCount];
-    GrDrawOpAtlasConfig fAtlasConfigs[kMaskFormatCount];
     SkScalar fGlyphSizeLimit;
     GrProxyProvider* fProxyProvider;
+    sk_sp<const GrCaps> fCaps;
     GrGlyphCache* fGlyphCache;
+    GrDrawOpAtlasConfig fAtlasConfigs;
 
     typedef GrOnFlushCallbackObject INHERITED;
 };
diff --git a/src/gpu/text/GrGlyphCache.cpp b/src/gpu/text/GrGlyphCache.cpp
index 4890804..933a1c0 100644
--- a/src/gpu/text/GrGlyphCache.cpp
+++ b/src/gpu/text/GrGlyphCache.cpp
@@ -42,10 +42,7 @@
 }
 
 SkScalar GrGlyphCache::ComputeGlyphSizeLimit(int maxTextureSize, size_t maxTextureBytes) {
-    int maxDim, minDim, maxPlot, minPlot;
-    GrAtlasManager::ComputeAtlasLimits(maxTextureSize, maxTextureBytes, &maxDim, &minDim, &maxPlot,
-                                       &minPlot);
-    return minPlot;
+    return SkGlyphCacheCommon::kSkSideTooBigForAtlas;
 }
 
 void GrGlyphCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) {