Make glyph cache more flexible
Some GPU architectures could not handle the previous implementation
of our glyph cache. Frequent uploads would cause memory problems in the GPU
and eventually a crash due to these memory issues. The solution is to move to
a system of several, smaller caches instead of one monolythic cache for all
glyphs.
Change-Id: I0fc7a323360940d16d5a33eeb33abfab194c5920
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index f945873..cac915d 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -55,6 +55,77 @@
class FontRenderer;
+class CacheTexture {
+public:
+ CacheTexture(){}
+ CacheTexture(uint8_t* texture, GLuint textureId, uint16_t width, uint16_t height) :
+ mTexture(texture), mTextureId(textureId), mWidth(width), mHeight(height) {}
+ ~CacheTexture() {
+ if (mTexture != NULL) {
+ delete[] mTexture;
+ }
+ if (mTextureId != 0) {
+ glDeleteTextures(1, &mTextureId);
+ }
+ }
+
+ uint8_t* mTexture;
+ GLuint mTextureId;
+ uint16_t mWidth;
+ uint16_t mHeight;
+};
+
+class CacheTextureLine {
+public:
+ CacheTextureLine(uint16_t maxWidth, uint16_t maxHeight, uint32_t currentRow,
+ uint32_t currentCol, CacheTexture* cacheTexture):
+ mMaxHeight(maxHeight),
+ mMaxWidth(maxWidth),
+ mCurrentRow(currentRow),
+ mCurrentCol(currentCol),
+ mDirty(false),
+ mCacheTexture(cacheTexture){
+ }
+
+ bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);
+
+ uint16_t mMaxHeight;
+ uint16_t mMaxWidth;
+ uint32_t mCurrentRow;
+ uint32_t mCurrentCol;
+ bool mDirty;
+ CacheTexture *mCacheTexture;
+};
+
+struct CachedGlyphInfo {
+ // Has the cache been invalidated?
+ bool mIsValid;
+ // Location of the cached glyph in the bitmap
+ // in case we need to resize the texture or
+ // render to bitmap
+ uint32_t mStartX;
+ uint32_t mStartY;
+ uint32_t mBitmapWidth;
+ uint32_t mBitmapHeight;
+ // Also cache texture coords for the quad
+ float mBitmapMinU;
+ float mBitmapMinV;
+ float mBitmapMaxU;
+ float mBitmapMaxV;
+ // Minimize how much we call freetype
+ uint32_t mGlyphIndex;
+ uint32_t mAdvanceX;
+ uint32_t mAdvanceY;
+ // Values below contain a glyph's origin in the bitmap
+ int32_t mBitmapLeft;
+ int32_t mBitmapTop;
+ // Auto-kerning
+ SkFixed mLsbDelta;
+ SkFixed mRsbDelta;
+ CacheTextureLine* mCachedTextureLine;
+};
+
+
///////////////////////////////////////////////////////////////////////////////
// Font
///////////////////////////////////////////////////////////////////////////////
@@ -101,33 +172,6 @@
void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, Rect *bounds);
- struct CachedGlyphInfo {
- // Has the cache been invalidated?
- bool mIsValid;
- // Location of the cached glyph in the bitmap
- // in case we need to resize the texture or
- // render to bitmap
- uint32_t mStartX;
- uint32_t mStartY;
- uint32_t mBitmapWidth;
- uint32_t mBitmapHeight;
- // Also cache texture coords for the quad
- float mBitmapMinU;
- float mBitmapMinV;
- float mBitmapMaxU;
- float mBitmapMaxV;
- // Minimize how much we call freetype
- uint32_t mGlyphIndex;
- uint32_t mAdvanceX;
- uint32_t mAdvanceY;
- // Values below contain a glyph's origin in the bitmap
- int32_t mBitmapLeft;
- int32_t mBitmapTop;
- // Auto-kerning
- SkFixed mLsbDelta;
- SkFixed mRsbDelta;
- };
-
Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle,
uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth);
@@ -218,19 +262,28 @@
mLinearFiltering = linearFiltering;
const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
- glBindTexture(GL_TEXTURE_2D, mTextureId);
+ glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
}
- return mTextureId;
+ return mCurrentCacheTexture->mTextureId;
}
- uint32_t getCacheWidth() const {
- return mCacheWidth;
- }
-
- uint32_t getCacheHeight() const {
- return mCacheHeight;
+ uint32_t getCacheSize() const {
+ uint32_t size = 0;
+ if (mCacheTextureSmall != NULL && mCacheTextureSmall->mTexture != NULL) {
+ size += mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight;
+ }
+ if (mCacheTexture128 != NULL && mCacheTexture128->mTexture != NULL) {
+ size += mCacheTexture128->mWidth * mCacheTexture128->mHeight;
+ }
+ if (mCacheTexture256 != NULL && mCacheTexture256->mTexture != NULL) {
+ size += mCacheTexture256->mWidth * mCacheTexture256->mHeight;
+ }
+ if (mCacheTexture512 != NULL && mCacheTexture512->mTexture != NULL) {
+ size += mCacheTexture512->mWidth * mCacheTexture512->mHeight;
+ }
+ return size;
}
protected:
@@ -238,41 +291,11 @@
const uint8_t* mGammaTable;
- struct CacheTextureLine {
- uint16_t mMaxHeight;
- uint16_t mMaxWidth;
- uint32_t mCurrentRow;
- uint32_t mCurrentCol;
- bool mDirty;
-
- CacheTextureLine(uint16_t maxWidth, uint16_t maxHeight, uint32_t currentRow,
- uint32_t currentCol):
- mMaxHeight(maxHeight),
- mMaxWidth(maxWidth),
- mCurrentRow(currentRow),
- mCurrentCol(currentCol),
- mDirty(false) {
- }
-
- bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
- if (glyph.fHeight + 2 > mMaxHeight) {
- return false;
- }
-
- if (mCurrentCol + glyph.fWidth + 2 < mMaxWidth) {
- *retOriginX = mCurrentCol + 1;
- *retOriginY = mCurrentRow + 1;
- mCurrentCol += glyph.fWidth + 2;
- mDirty = true;
- return true;
- }
-
- return false;
- }
- };
-
- void initTextTexture(bool largeFonts = false);
- bool cacheBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);
+ uint8_t* allocateTextureMemory(int width, int height);
+ void initTextTexture();
+ CacheTexture *createCacheTexture(int width, int height, bool allocate);
+ void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
+ uint32_t *retOriginX, uint32_t *retOriginY);
void flushAllAndInvalidate();
void initVertexArrayBuffers();
@@ -286,10 +309,10 @@
void appendMeshQuad(float x1, float y1, float u1, float v1,
float x2, float y2, float u2, float v2,
float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4);
+ float x4, float y4, float u4, float v4, CacheTexture* texture);
- uint32_t mCacheWidth;
- uint32_t mCacheHeight;
+ uint32_t mSmallCacheWidth;
+ uint32_t mSmallCacheHeight;
Vector<CacheTextureLine*> mCacheLines;
uint32_t getRemainingCacheCapacity();
@@ -297,12 +320,14 @@
Font* mCurrentFont;
Vector<Font*> mActiveFonts;
- // Texture to cache glyph bitmaps
- uint8_t* mTextTexture;
- const uint8_t* getTextTextureData() const {
- return mTextTexture;
- }
- GLuint mTextureId;
+ CacheTexture* mCurrentCacheTexture;
+ CacheTexture* mLastCacheTexture;
+ CacheTexture* mCacheTextureSmall;
+ CacheTexture* mCacheTexture128;
+ CacheTexture* mCacheTexture256;
+ CacheTexture* mCacheTexture512;
+
+
void checkTextureUpdate();
bool mUploadTexture;