Alter approximate scratch texture binning after 1024

As the powers-of-2 get larger the coarse binning can burn a lot of VRAM.

Granted it isn't the best metric but, with this CL, the number of textures created and scratch textures reused remains unchanged when running the GMs.

Change-Id: I84abbbae0ed01aabb387671b5ee0e4fcdb82b671
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/226226
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 0e171a8..db9ead2 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -209,6 +209,32 @@
     return fGpu->createTexture(desc, budgeted);
 }
 
+// Map 'value' to a larger multiple of 2. Values <= 'kMagicTol' will pop up to
+// the next power of 2. Those above 'kMagicTol' will only go up half the floor power of 2.
+uint32_t GrResourceProvider::MakeApprox(uint32_t value) {
+    static const int kMagicTol = 1024;
+
+    value = SkTMax(kMinScratchTextureSize, value);
+
+    if (SkIsPow2(value)) {
+        return value;
+    }
+
+    uint32_t ceilPow2 = GrNextPow2(value);
+    if (value <= kMagicTol) {
+        return ceilPow2;
+    }
+
+    uint32_t floorPow2 = ceilPow2 >> 1;
+    uint32_t mid = floorPow2 + (floorPow2 >> 1);
+
+    if (value <= mid) {
+        return mid;
+    }
+
+    return ceilPow2;
+}
+
 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc,
                                                          Flags flags) {
     ASSERT_SINGLE_OWNER
@@ -233,12 +259,12 @@
 
     SkTCopyOnFirstWrite<GrSurfaceDesc> copyDesc(desc);
 
-    // bin by pow2 with a reasonable min
+    // bin by some multiple or power of 2 with a reasonable min
     if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) &&
         (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) {
         GrSurfaceDesc* wdesc = copyDesc.writable();
-        wdesc->fWidth  = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fWidth));
-        wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fHeight));
+        wdesc->fWidth = MakeApprox(wdesc->fWidth);
+        wdesc->fHeight = MakeApprox(wdesc->fHeight);
     }
 
     if (auto tex = this->refScratchTexture(*copyDesc, flags)) {
@@ -273,6 +299,7 @@
                                                                     GrSurface::WorstCaseSize(desc),
                                                                     scratchFlags);
         if (resource) {
+            fGpu->stats()->incNumScratchTexturesReused();
             GrSurface* surface = static_cast<GrSurface*>(resource);
             return sk_sp<GrTexture>(surface->asTexture());
         }