Fix computation of texture size for approximately-fit deferred proxies

For approximate-fit deferred proxies asserts were firing when the instantiated size was larger than the pre-computed exact-fit size.

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4972

Change-Id: I879e16b86ab4d9ef9834163c24ccd6507fe4b94a
Reviewed-on: https://skia-review.googlesource.com/4972
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/include/gpu/GrSurface.h b/include/gpu/GrSurface.h
index 3f91a2f..46b9986 100644
--- a/include/gpu/GrSurface.h
+++ b/include/gpu/GrSurface.h
@@ -129,8 +129,9 @@
     void setLastOpList(GrOpList* opList);
     GrOpList* getLastOpList() { return fLastOpList; }
 
-    static size_t WorstCaseSize(const GrSurfaceDesc& desc);
-    static size_t ComputeSize(const GrSurfaceDesc& desc, int colorSamplesPerPixel, bool hasMIPMaps);
+    static size_t WorstCaseSize(const GrSurfaceDesc& desc, bool useNextPow2 = false);
+    static size_t ComputeSize(const GrSurfaceDesc& desc, int colorSamplesPerPixel,
+                              bool hasMIPMaps, bool useNextPow2 = false);
 
 protected:
     // Methods made available via GrSurfacePriv
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp
index 8eb335d..cb9b97a 100644
--- a/src/gpu/GrRenderTargetProxy.cpp
+++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -71,6 +71,6 @@
     }
 
     // TODO: do we have enough information to improve this worst case estimate?
-    return GrSurface::ComputeSize(fDesc, fDesc.fSampleCnt+1, false);
+    return GrSurface::ComputeSize(fDesc, fDesc.fSampleCnt+1, false, SkBackingFit::kApprox == fFit);
 }
 
diff --git a/src/gpu/GrSurface.cpp b/src/gpu/GrSurface.cpp
index 7f571b8..f67bfd4 100644
--- a/src/gpu/GrSurface.cpp
+++ b/src/gpu/GrSurface.cpp
@@ -13,6 +13,7 @@
 #include "SkBitmap.h"
 #include "SkGrPriv.h"
 #include "SkImageEncoder.h"
+#include "SkMathPriv.h"
 #include <stdio.h>
 
 GrSurface::~GrSurface() {
@@ -25,9 +26,12 @@
     SkASSERT(NULL == fReleaseProc);
 }
 
-size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc) {
+size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc, bool useNextPow2) {
     size_t size;
 
+    int width = useNextPow2 ? GrNextPow2(desc.fWidth) : desc.fWidth;
+    int height = useNextPow2 ? GrNextPow2(desc.fHeight) : desc.fHeight;
+
     bool isRenderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
     if (isRenderTarget) {
         // We own one color value for each MSAA sample.
@@ -38,7 +42,7 @@
         }
         SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
         SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
-        size_t colorBytes = (size_t) desc.fWidth * desc.fHeight * GrBytesPerPixel(desc.fConfig);
+        size_t colorBytes = (size_t) width * height * GrBytesPerPixel(desc.fConfig);
 
         // This would be a nice assert to have (i.e., we aren't creating 0 width/height surfaces).
         // Unfortunately Chromium seems to want to do this.
@@ -48,9 +52,9 @@
         size += colorBytes/3; // in case we have to mipmap
     } else {
         if (GrPixelConfigIsCompressed(desc.fConfig)) {
-            size = GrCompressedFormatDataSize(desc.fConfig, desc.fWidth, desc.fHeight);
+            size = GrCompressedFormatDataSize(desc.fConfig, width, height);
         } else {
-            size = (size_t) desc.fWidth * desc.fHeight * GrBytesPerPixel(desc.fConfig);
+            size = (size_t) width * height * GrBytesPerPixel(desc.fConfig);
         }
 
         size += size/3;  // in case we have to mipmap
@@ -61,14 +65,18 @@
 
 size_t GrSurface::ComputeSize(const GrSurfaceDesc& desc,
                               int colorSamplesPerPixel,
-                              bool hasMIPMaps) {
+                              bool hasMIPMaps,
+                              bool useNextPow2) {
     size_t colorSize;
 
+    int width = useNextPow2 ? GrNextPow2(desc.fWidth) : desc.fWidth;
+    int height = useNextPow2 ? GrNextPow2(desc.fHeight) : desc.fHeight;
+
     SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
     if (GrPixelConfigIsCompressed(desc.fConfig)) {
-        colorSize = GrCompressedFormatDataSize(desc.fConfig, desc.fWidth, desc.fHeight);
+        colorSize = GrCompressedFormatDataSize(desc.fConfig, width, height);
     } else {
-        colorSize = (size_t) desc.fWidth * desc.fHeight * GrBytesPerPixel(desc.fConfig);
+        colorSize = (size_t) width * height * GrBytesPerPixel(desc.fConfig);
     }
     SkASSERT(colorSize > 0);
 
@@ -80,7 +88,7 @@
         finalSize += colorSize/3;
     }
 
-    SkASSERT(finalSize <= WorstCaseSize(desc));
+    SkASSERT(finalSize <= WorstCaseSize(desc, useNextPow2));
     return finalSize;
 }
 
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index 9798747..77a8402 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -35,5 +35,5 @@
 
     static const bool kHasMipMaps = true;
     // TODO: add tracking of mipmap state to improve the estimate
-    return GrSurface::ComputeSize(fDesc, 1, kHasMipMaps);
+    return GrSurface::ComputeSize(fDesc, 1, kHasMipMaps, SkBackingFit::kApprox == fFit);
 }
diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp
index 95451e9..212ea0a 100644
--- a/src/gpu/GrTextureRenderTargetProxy.cpp
+++ b/src/gpu/GrTextureRenderTargetProxy.cpp
@@ -36,6 +36,6 @@
     }
 
     // TODO: do we have enough information to improve this worst case estimate?
-    return GrSurface::ComputeSize(fDesc, fDesc.fSampleCnt+1, true);
+    return GrSurface::ComputeSize(fDesc, fDesc.fSampleCnt+1, true, SkBackingFit::kApprox == fFit);
 }
 
diff --git a/tests/ProxyTest.cpp b/tests/ProxyTest.cpp
index 8d59cae..a228e16 100644
--- a/tests/ProxyTest.cpp
+++ b/tests/ProxyTest.cpp
@@ -136,6 +136,13 @@
                                 sk_sp<GrSurfaceProxy> sProxy(GrSurfaceProxy::MakeDeferred(
                                                                                 caps, desc, 
                                                                                 fit, budgeted));
+                                // This forces the proxy to compute and cache its pre-instantiation

+                                // size guess. Later, when it is actually instantiated, it checks

+                                // that the instantiated size is <= to the pre-computation. 

+                                // If the proxy never computed its pre-instantiation size then the

+                                // check is skipped.

+                                sProxy->gpuMemorySize();
+
                                 check_surface(reporter, sProxy.get(), origin,
                                               widthHeight, widthHeight, config,
                                               kInvalidResourceID, budgeted);
@@ -151,6 +158,13 @@
                                                                                       desc,
                                                                                       fit,
                                                                                       budgeted));
+                            // This forces the proxy to compute and cache its pre-instantiation

+                            // size guess. Later, when it is actually instantiated, it checks

+                            // that the instantiated size is <= to the pre-computation. 

+                            // If the proxy never computed its pre-instantiation size then the

+                            // check is skipped.
+                            sProxy->gpuMemorySize();
+
                             check_surface(reporter, sProxy.get(), origin,
                                           widthHeight, widthHeight, config,
                                           kInvalidResourceID, budgeted);