Less aggressive glyphs precaching

The renderer used to pre-cache glyphs at record time. This then changed
to pre-caching at the beginning of every frame. This unfortunately entails
a lot of duplicate work on every frame, which amounts to 0.5 to 1ms in
some stock applications.

This change is somewhere in the middle: pre-caching happens the first
time a DrawTextOp is deferred or every time the screen-space transform
is different from the last pre-caching operation.

Change-Id: Id6d9e2599d90a5b75010b0f0a28746befbf3c205
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 105f45f..4e6b552 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1169,6 +1169,7 @@
             break;
         }
         mLocalBounds.set(x, mY + metrics.fTop, x + length, mY + metrics.fBottom);
+        memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
     }
 
     /*
@@ -1179,9 +1180,11 @@
     virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
         SkPaint* paint = getPaint(renderer);
         FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
-        const bool pureTranslate = state.mMatrix.isPureTranslate();
-        const mat4 transform = renderer.findBestFontTransform(state.mMatrix);
-        fontRenderer.precache(paint, mText, mCount, transform);
+        const mat4& transform = renderer.findBestFontTransform(state.mMatrix);
+        if (mPrecacheTransform != transform) {
+            fontRenderer.precache(paint, mText, mCount, transform);
+            mPrecacheTransform = transform;
+        }
     }
 
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
@@ -1210,6 +1213,7 @@
     float mY;
     const float* mPositions;
     float mLength;
+    mat4 mPrecacheTransform;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 7b7357e..75e280c 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -93,6 +93,14 @@
         return *this;
     }
 
+    friend bool operator==(const Matrix4& a, const Matrix4& b) {
+        return !memcmp(&a.data[0], &b.data[0], 16 * sizeof(float));
+    }
+
+    friend bool operator!=(const Matrix4& a, const Matrix4& b) {
+        return !(a == b);
+    }
+
     void loadIdentity();
 
     void load(const float* v);
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index c932087..02c1aa1 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -15,10 +15,12 @@
  */
 
 #define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
 
 #include <cutils/compiler.h>
 
 #include <utils/JenkinsHash.h>
+#include <utils/Trace.h>
 
 #include <SkGlyph.h>
 #include <SkUtils.h>
@@ -261,11 +263,8 @@
 }
 
 CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching) {
-    CachedGlyphInfo* cachedGlyph = NULL;
-    ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
-    if (index >= 0) {
-        cachedGlyph = mCachedGlyphs.valueAt(index);
-
+    CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueFor(textUnit);
+    if (cachedGlyph) {
         // Is the glyph still in texture cache?
         if (!cachedGlyph->mIsValid) {
             const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit,
@@ -346,11 +345,13 @@
 }
 
 void Font::precache(SkPaint* paint, const char* text, int numGlyphs) {
+    ATRACE_NAME("precacheText");
+
     if (numGlyphs == 0 || text == NULL) {
         return;
     }
-    int glyphsCount = 0;
 
+    int glyphsCount = 0;
     while (glyphsCount < numGlyphs) {
         glyph_t glyph = GET_GLYPH(text);
 
@@ -360,7 +361,6 @@
         }
 
         CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph, true);
-
         glyphsCount++;
     }
 }