Memory optimizations for libhwui
Bug #5566149

Lazily initialize font renderers
Keep 60% of the texture cache when an app goes to the background
Delete least used font renderer when going to the background
Delete all font renderers on full memory trim

Change-Id: I3c2454d46dc1107ec0f0f72a9ce69cbbcc8825e7
diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
index e8362dc..eb863e9 100644
--- a/libs/hwui/GammaFontRenderer.cpp
+++ b/libs/hwui/GammaFontRenderer.cpp
@@ -67,20 +67,63 @@
     const float whiteGamma = 1.0f / gamma;
 
     for (uint32_t i = 0; i <= 255; i++) {
-        mDefault[i] = i;
+        mGammaTable[i] = i;
 
         const float v = i / 255.0f;
         const float black = pow(v, blackGamma);
         const float white = pow(v, whiteGamma);
 
-        mBlackGamma[i] = uint8_t((float)::floor(black * 255.0f + 0.5f));
-        mWhiteGamma[i] = uint8_t((float)::floor(white * 255.0f + 0.5f));
+        mGammaTable[256 + i] = uint8_t((float)::floor(black * 255.0f + 0.5f));
+        mGammaTable[512 + i] = uint8_t((float)::floor(white * 255.0f + 0.5f));
     }
 
-    // Configure the font renderers
-    mDefaultRenderer.setGammaTable(&mDefault[0]);
-    mBlackGammaRenderer.setGammaTable(&mBlackGamma[0]);
-    mWhiteGammaRenderer.setGammaTable(&mWhiteGamma[0]);
+    memset(mRenderers, 0, sizeof(FontRenderer*) * kGammaCount);
+    memset(mRenderersUsageCount, 0, sizeof(uint32_t) * kGammaCount);
+}
+
+GammaFontRenderer::~GammaFontRenderer() {
+    for (int i = 0; i < kGammaCount; i++) {
+        delete mRenderers[i];
+    }
+}
+
+void GammaFontRenderer::clear() {
+    for (int i = 0; i < kGammaCount; i++) {
+        delete mRenderers[i];
+        mRenderers[i] = NULL;
+    }
+}
+
+void GammaFontRenderer::flush() {
+    int count = 0;
+    int min = -1;
+    uint32_t minCount = UINT_MAX;
+
+    for (int i = 0; i < kGammaCount; i++) {
+        if (mRenderers[i]) {
+            count++;
+            if (mRenderersUsageCount[i] < minCount) {
+                minCount = mRenderersUsageCount[i];
+                min = i;
+            }
+        }
+    }
+
+    if (count <= 1 || min < 0) return;
+
+    delete mRenderers[min];
+    mRenderers[min] = NULL;
+}
+
+FontRenderer* GammaFontRenderer::getRenderer(Gamma gamma) {
+    FontRenderer* renderer = mRenderers[gamma];
+    if (!renderer) {
+        renderer = new FontRenderer();
+        mRenderers[gamma] = renderer;
+        renderer->setGammaTable(&mGammaTable[gamma * 256]);
+    }
+    mRenderersUsageCount[gamma]++;
+    return renderer;
 }
 
 FontRenderer& GammaFontRenderer::getFontRenderer(const SkPaint* paint) {
@@ -92,12 +135,12 @@
         const int luminance = (r * 2 + g * 5 + b) >> 3;
 
         if (luminance <= mBlackThreshold) {
-            return mBlackGammaRenderer;
+            return *getRenderer(kGammaBlack);
         } else if (luminance >= mWhiteThreshold) {
-            return mWhiteGammaRenderer;
+            return *getRenderer(kGammaWhite);
         }
     }
-    return mDefaultRenderer;
+    return *getRenderer(kGammaDefault);
 }
 
 }; // namespace uirenderer