When font cache still has empty space,
precache some commonly used characters to reduce studder.
Change-Id: I1f66f57482c4a025672dfd1d8ecaf2b9736cd9a0
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 14ad7d7..5595ab0 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -80,6 +80,21 @@
nPenX, nPenY - height, 0, u1, v1);
}
+Font::CachedGlyphInfo* Font::getCachedUTFChar(SkPaint* paint, int32_t utfChar) {
+ CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueFor(utfChar);
+ if (cachedGlyph == NULL) {
+ cachedGlyph = cacheGlyph(paint, utfChar);
+ }
+
+ // Is the glyph still in texture cache?
+ if (!cachedGlyph->mIsValid) {
+ const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar);
+ updateGlyphCache(paint, skiaGlyph, cachedGlyph);
+ }
+
+ return cachedGlyph;
+}
+
void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, int x, int y) {
if (numGlyphs == 0 || text == NULL || len == 0) {
@@ -102,16 +117,7 @@
break;
}
- CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueFor(utfChar);
- if (cachedGlyph == NULL) {
- cachedGlyph = cacheGlyph(paint, utfChar);
- }
-
- // Is the glyph still in texture cache?
- if (!cachedGlyph->mIsValid) {
- const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar);
- updateGlyphCache(paint, skiaGlyph, cachedGlyph);
- }
+ CachedGlyphInfo* cachedGlyph = getCachedUTFChar(paint, utfChar);
// If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
if (cachedGlyph->mIsValid) {
@@ -340,6 +346,8 @@
nextLine += mCacheLines.top()->mMaxHeight;
mCacheLines.push(new CacheTextureLine(mCacheWidth, 24, nextLine, 0));
nextLine += mCacheLines.top()->mMaxHeight;
+ mCacheLines.push(new CacheTextureLine(mCacheWidth, 24, nextLine, 0));
+ nextLine += mCacheLines.top()->mMaxHeight;
mCacheLines.push(new CacheTextureLine(mCacheWidth, 32, nextLine, 0));
nextLine += mCacheLines.top()->mMaxHeight;
mCacheLines.push(new CacheTextureLine(mCacheWidth, 32, nextLine, 0));
@@ -392,6 +400,12 @@
initTextTexture();
initVertexArrayBuffers();
+ // We store a string with letters in a rough frequency of occurrence
+ mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq ");
+ mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ");
+ mLatinPrecache += String16(",.?!()-+@;:`'");
+ mLatinPrecache += String16("0123456789");
+
mInitialized = true;
}
@@ -484,8 +498,38 @@
}
}
-void FontRenderer::setFont(uint32_t fontId, float fontSize) {
+uint32_t FontRenderer::getRemainingCacheCapacity() {
+ uint32_t remainingCapacity = 0;
+ float totalPixels = 0;
+ for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
+ remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
+ totalPixels += mCacheLines[i]->mMaxWidth;
+ }
+ remainingCapacity = (remainingCapacity * 100) / totalPixels;
+ return remainingCapacity;
+}
+
+void FontRenderer::precacheLatin(SkPaint* paint) {
+ // Remaining capacity is measured in %
+ uint32_t remainingCapacity = getRemainingCacheCapacity();
+ uint32_t precacheIdx = 0;
+ while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
+ mCurrentFont->getCachedUTFChar(paint, (int32_t)mLatinPrecache[precacheIdx]);
+ remainingCapacity = getRemainingCacheCapacity();
+ precacheIdx ++;
+ }
+}
+
+void FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) {
+ uint32_t currentNumFonts = mActiveFonts.size();
mCurrentFont = Font::create(this, fontId, fontSize);
+
+ const float maxPrecacheFontSize = 40.0f;
+ bool isNewFont = currentNumFonts != mActiveFonts.size();
+
+ if(isNewFont && fontSize <= maxPrecacheFontSize ){
+ precacheLatin(paint);
+ }
}
void FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index bacd3aa..2f7a8ba 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -18,6 +18,7 @@
#define ANDROID_UI_FONT_RENDERER_H
#include <utils/String8.h>
+#include <utils/String16.h>
#include <utils/Vector.h>
#include <utils/KeyedVector.h>
@@ -82,10 +83,12 @@
void invalidateTextureCache();
- CachedGlyphInfo *cacheGlyph(SkPaint* paint, int32_t glyph);
+ CachedGlyphInfo* cacheGlyph(SkPaint* paint, int32_t glyph);
void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo *glyph);
void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y);
+ CachedGlyphInfo* getCachedUTFChar(SkPaint* paint, int32_t utfChar);
+
FontRenderer* mState;
uint32_t mFontId;
float mFontSize;
@@ -99,7 +102,7 @@
void init();
void deinit();
- void setFont(uint32_t fontId, float fontSize);
+ void setFont(SkPaint* paint, uint32_t fontId, float fontSize);
void renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
uint32_t len, int numGlyphs, int x, int y);
@@ -160,6 +163,9 @@
void checkInit();
+ String16 mLatinPrecache;
+ void precacheLatin(SkPaint* paint);
+
void issueDrawCommand();
void appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2, float y2,
float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3,
@@ -169,6 +175,7 @@
uint32_t mCacheHeight;
Vector<CacheTextureLine*> mCacheLines;
+ uint32_t getRemainingCacheCapacity();
Font* mCurrentFont;
Vector<Font*> mActiveFonts;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index d30d718..2e44e122 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -569,7 +569,7 @@
// TODO: Implement scale properly
const Rect& clip = mSnapshot->getLocalClip();
- mFontRenderer.setFont(SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize());
+ mFontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize());
mFontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);