HWUI: calculate used memory in FontCache for gfxinfo

bug:30427106
Change-Id: I653571d6a4e974e975fb0dc03fc2364eecbf2f84
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 949ad45..6d28c52 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -195,12 +195,7 @@
     log.appendFormat("  PatchCache           %8d / %8d\n",
             patchCache.getSize(), patchCache.getMaxSize());
 
-    const uint32_t sizeA8 = fontRenderer.getFontRendererSize(GL_ALPHA);
-    const uint32_t sizeRGBA = fontRenderer.getFontRendererSize(GL_RGBA);
-    log.appendFormat("  FontRenderer A8    %8d / %8d\n", sizeA8, sizeA8);
-    log.appendFormat("  FontRenderer RGBA  %8d / %8d\n", sizeRGBA, sizeRGBA);
-    log.appendFormat("  FontRenderer total %8d / %8d\n", sizeA8 + sizeRGBA,
-            sizeA8 + sizeRGBA);
+    fontRenderer.dumpMemoryUsage(log);
 
     log.appendFormat("Other:\n");
     log.appendFormat("  FboCache             %8d / %8d\n",
@@ -213,8 +208,7 @@
     total += tessellationCache.getSize();
     total += dropShadowCache.getSize();
     total += patchCache.getSize();
-    total += fontRenderer.getFontRendererSize(GL_ALPHA);
-    total += fontRenderer.getFontRendererSize(GL_RGBA);
+    total += fontRenderer.getSize();
 
     log.appendFormat("Total memory usage:\n");
     log.appendFormat("  %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 276c18d..1cd708f 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -747,18 +747,67 @@
     return size;
 }
 
-uint32_t FontRenderer::getCacheSize(GLenum format) const {
-    switch (format) {
-        case GL_ALPHA: {
-            return calculateCacheSize(mACacheTextures);
-        }
-        case GL_RGBA: {
-            return calculateCacheSize(mRGBACacheTextures);
-        }
-        default: {
-            return 0;
+static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
+    uint32_t size = 0;
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = cacheTextures[i];
+        if (cacheTexture && cacheTexture->getPixelBuffer()) {
+            size += cacheTexture->calculateFreeMemory();
         }
     }
+    return size;
+}
+
+const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const {
+    switch (format) {
+        case GL_ALPHA: {
+            return mACacheTextures;
+        }
+        case GL_RGBA: {
+            return mRGBACacheTextures;
+        }
+        default: {
+            LOG_ALWAYS_FATAL("Unsupported format: %d", format);
+            // Impossible to hit this, but the compiler doesn't know that
+            return *(new std::vector<CacheTexture*>());
+        }
+    }
+}
+
+static void dumpTextures(String8& log, const char* tag,
+        const std::vector<CacheTexture*>& cacheTextures) {
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = cacheTextures[i];
+        if (cacheTexture && cacheTexture->getPixelBuffer()) {
+            uint32_t free = cacheTexture->calculateFreeMemory();
+            uint32_t total = cacheTexture->getPixelBuffer()->getSize();
+            log.appendFormat("    %-4s texture %d     %8d / %8d\n", tag, i, total - free, total);
+        }
+    }
+}
+
+void FontRenderer::dumpMemoryUsage(String8& log) const {
+    const uint32_t sizeA8 = getCacheSize(GL_ALPHA);
+    const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA);
+    const uint32_t sizeRGBA = getCacheSize(GL_RGBA);
+    const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA);
+    log.appendFormat("  FontRenderer A8      %8d / %8d\n", usedA8, sizeA8);
+    dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA));
+    log.appendFormat("  FontRenderer RGBA    %8d / %8d\n", usedRGBA, sizeRGBA);
+    dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA));
+    log.appendFormat("  FontRenderer total   %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA);
+}
+
+uint32_t FontRenderer::getCacheSize(GLenum format) const {
+    return calculateCacheSize(cacheTexturesForFormat(format));
+}
+
+uint32_t FontRenderer::getFreeCacheSize(GLenum format) const {
+    return calculateFreeCacheSize(cacheTexturesForFormat(format));
+}
+
+uint32_t FontRenderer::getSize() const {
+    return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index e10a81b..e102a2f 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -23,6 +23,7 @@
 #include "font/Font.h"
 
 #include <utils/LruCache.h>
+#include <utils/String8.h>
 #include <utils/StrongPointer.h>
 
 #include <SkPaint.h>
@@ -132,7 +133,8 @@
         mLinearFiltering = linearFiltering;
     }
 
-    uint32_t getCacheSize(GLenum format) const;
+    uint32_t getSize() const;
+    void dumpMemoryUsage(String8& log) const;
 
 private:
     friend class Font;
@@ -175,6 +177,10 @@
         mUploadTexture = true;
     }
 
+    const std::vector<CacheTexture*>& cacheTexturesForFormat(GLenum format) const;
+    uint32_t getCacheSize(GLenum format) const;
+    uint32_t getFreeCacheSize(GLenum format) const;
+
     uint32_t mSmallCacheWidth;
     uint32_t mSmallCacheHeight;
     uint32_t mLargeCacheWidth;
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index 5813e7f..bd27a1a 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -22,6 +22,8 @@
 
 #include <SkPaint.h>
 
+#include <utils/String8.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -46,8 +48,16 @@
         return *mRenderer;
     }
 
-    uint32_t getFontRendererSize(GLenum format) const {
-        return mRenderer ? mRenderer->getCacheSize(format) : 0;
+    void dumpMemoryUsage(String8& log) const {
+        if (mRenderer) {
+            mRenderer->dumpMemoryUsage(log);
+        } else {
+            log.appendFormat("FontRenderer doesn't exist.\n");
+        }
+    }
+
+    uint32_t getSize() const {
+        return mRenderer ? mRenderer->getSize() : 0;
     }
 
     void endPrecaching();
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 8ba4761..4b13814 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -324,5 +324,17 @@
     return false;
 }
 
+uint32_t CacheTexture::calculateFreeMemory() const {
+    CacheBlock* cacheBlock = mCacheBlocks;
+    uint32_t free = 0;
+    // currently only two formats are supported: GL_ALPHA or GL_RGBA;
+    uint32_t bpp = mFormat == GL_RGBA ? 4 : 1;
+    while (cacheBlock) {
+        free += bpp * cacheBlock->mWidth * cacheBlock->mHeight;
+        cacheBlock = cacheBlock->mNext;
+    }
+    return free;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index 4dfb41d..6750a8a 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -178,6 +178,8 @@
         return mCurrentQuad == mMaxQuadCount;
     }
 
+    uint32_t calculateFreeMemory() const;
+
 private:
     void setDirty(bool dirty);