Loading libs/hwui/FontRenderer.cpp +142 −87 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include "Caches.h" #include "Debug.h" #include "FontRenderer.h" #include "Caches.h" namespace android { namespace uirenderer { Loading @@ -35,10 +36,28 @@ namespace uirenderer { #define DEFAULT_TEXT_CACHE_WIDTH 1024 #define DEFAULT_TEXT_CACHE_HEIGHT 256 // We should query these values from the GL context #define MAX_TEXT_CACHE_WIDTH 2048 #define MAX_TEXT_CACHE_HEIGHT 2048 #define TEXTURE_BORDER_SIZE 2 /////////////////////////////////////////////////////////////////////////////// // CacheTextureLine /////////////////////////////////////////////////////////////////////////////// bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) { if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) { return false; } if (mCurrentCol + glyph.fWidth + TEXTURE_BORDER_SIZE < mMaxWidth) { *retOriginX = mCurrentCol + 1; *retOriginY = mCurrentRow + 1; mCurrentCol += glyph.fWidth + TEXTURE_BORDER_SIZE; mDirty = true; return true; } return false; } /////////////////////////////////////////////////////////////////////////////// // Font Loading Loading @@ -108,7 +127,7 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) { mState->appendMeshQuad(nPenX, nPenY, u1, v2, nPenX + width, nPenY, u2, v2, nPenX + width, nPenY - height, u2, v1, nPenX, nPenY - height, u1, v1); nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture); } void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, Loading @@ -119,8 +138,9 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint32_t endX = glyph->mStartX + glyph->mBitmapWidth; uint32_t endY = glyph->mStartY + glyph->mBitmapHeight; uint32_t cacheWidth = mState->getCacheWidth(); const uint8_t* cacheBuffer = mState->getTextTextureData(); CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture; uint32_t cacheWidth = cacheTexture->mWidth; const uint8_t* cacheBuffer = cacheTexture->mTexture; uint32_t cacheX = 0, cacheY = 0; int32_t bX = 0, bY = 0; Loading @@ -134,10 +154,9 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, bitmap[bY * bitmapW + bX] = tempCol; } } } Font::CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) { CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) { CachedGlyphInfo* cachedGlyph = NULL; ssize_t index = mCachedGlyphs.indexOfKey(textUnit); if (index >= 0) { Loading Loading @@ -246,7 +265,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp // Get the bitmap for the glyph paint->findImage(skiaGlyph); glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY); mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY); if (!glyph->mIsValid) { return; Loading @@ -260,8 +279,8 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp glyph->mBitmapWidth = skiaGlyph.fWidth; glyph->mBitmapHeight = skiaGlyph.fHeight; uint32_t cacheWidth = mState->getCacheWidth(); uint32_t cacheHeight = mState->getCacheHeight(); uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth; uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight; glyph->mBitmapMinU = (float) startX / (float) cacheWidth; glyph->mBitmapMinV = (float) startY / (float) cacheHeight; Loading @@ -271,7 +290,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp mState->mUploadTexture = true; } Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) { CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) { CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); mCachedGlyphs.add(glyph, newGlyph); Loading Loading @@ -320,25 +339,29 @@ FontRenderer::FontRenderer() { mInitialized = false; mMaxNumberOfQuads = 1024; mCurrentQuadIndex = 0; mTextureId = 0; mTextMeshPtr = NULL; mTextTexture = NULL; mCurrentCacheTexture = NULL; mLastCacheTexture = NULL; mCacheTextureSmall = NULL; mCacheTexture128 = NULL; mCacheTexture256 = NULL; mCacheTexture512 = NULL; mIndexBufferID = 0; mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; mSmallCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { if (sLogFontRendererCreate) { INIT_LOGD(" Setting text cache width to %s pixels", property); } mCacheWidth = atoi(property); mSmallCacheWidth = atoi(property); } else { if (sLogFontRendererCreate) { INIT_LOGD(" Using default text cache width of %i pixels", mCacheWidth); INIT_LOGD(" Using default text cache width of %i pixels", mSmallCacheWidth); } } Loading @@ -346,10 +369,10 @@ FontRenderer::FontRenderer() { if (sLogFontRendererCreate) { INIT_LOGD(" Setting text cache width to %s pixels", property); } mCacheHeight = atoi(property); mSmallCacheHeight = atoi(property); } else { if (sLogFontRendererCreate) { INIT_LOGD(" Using default text cache height of %i pixels", mCacheHeight); INIT_LOGD(" Using default text cache height of %i pixels", mSmallCacheHeight); } } Loading @@ -364,11 +387,10 @@ FontRenderer::~FontRenderer() { if (mInitialized) { delete[] mTextMeshPtr; delete[] mTextTexture; } if (mTextureId) { glDeleteTextures(1, &mTextureId); delete mCacheTextureSmall; delete mCacheTexture128; delete mCacheTexture256; delete mCacheTexture512; } Vector<Font*> fontsToDereference = mActiveFonts; Loading @@ -390,20 +412,21 @@ void FontRenderer::flushAllAndInvalidate() { } } bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) { // If the glyph is too tall, don't cache it if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { if (mCacheHeight < MAX_TEXT_CACHE_HEIGHT) { // Default cache not large enough for large glyphs - resize cache to // max size and try again flushAllAndInvalidate(); initTextTexture(true); uint8_t* FontRenderer::allocateTextureMemory(int width, int height) { uint8_t* textureMemory = new uint8_t[width * height]; memset(textureMemory, 0, width * height * sizeof(uint8_t)); return textureMemory; } if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, uint32_t* retOriginX, uint32_t* retOriginY) { cachedGlyph->mIsValid = false; // If the glyph is too tall, don't cache it if (glyph.fHeight + TEXTURE_BORDER_SIZE > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { LOGE("Font size to large to fit in cache. width, height = %i, %i", (int) glyph.fWidth, (int) glyph.fHeight); return false; } return; } // Now copy the bitmap into the cache texture Loading @@ -411,9 +434,11 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3 uint32_t startY = 0; bool bitmapFit = false; CacheTextureLine *cacheLine; for (uint32_t i = 0; i < mCacheLines.size(); i++) { bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); if (bitmapFit) { cacheLine = mCacheLines[i]; break; } } Loading @@ -426,27 +451,33 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3 for (uint32_t i = 0; i < mCacheLines.size(); i++) { bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); if (bitmapFit) { cacheLine = mCacheLines[i]; break; } } // if we still don't fit, something is wrong and we shouldn't draw if (!bitmapFit) { LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int) glyph.fWidth, (int) glyph.fHeight); return false; return; } } cachedGlyph->mCachedTextureLine = cacheLine; *retOriginX = startX; *retOriginY = startY; uint32_t endX = startX + glyph.fWidth; uint32_t endY = startY + glyph.fHeight; uint32_t cacheWidth = mCacheWidth; uint32_t cacheWidth = cacheLine->mMaxWidth; uint8_t* cacheBuffer = mTextTexture; CacheTexture *cacheTexture = cacheLine->mCacheTexture; if (cacheTexture->mTexture == NULL) { // Large-glyph texture memory is allocated only as needed cacheTexture->mTexture = allocateTextureMemory(cacheTexture->mWidth, cacheTexture->mHeight); } uint8_t* cacheBuffer = cacheTexture->mTexture; uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; unsigned int stride = glyph.rowBytes(); Loading @@ -457,30 +488,17 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3 cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; } } return true; } void FontRenderer::initTextTexture(bool largeFonts) { mCacheLines.clear(); if (largeFonts) { mCacheWidth = MAX_TEXT_CACHE_WIDTH; mCacheHeight = MAX_TEXT_CACHE_HEIGHT; cachedGlyph->mIsValid = true; } mTextTexture = new uint8_t[mCacheWidth * mCacheHeight]; memset(mTextTexture, 0, mCacheWidth * mCacheHeight * sizeof(uint8_t)); mUploadTexture = false; if (mTextureId != 0) { glDeleteTextures(1, &mTextureId); } glGenTextures(1, &mTextureId); glBindTexture(GL_TEXTURE_2D, mTextureId); CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) { uint8_t* textureMemory = allocate ? allocateTextureMemory(width, height) : NULL; GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Initialize texture dimensions glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0, glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0); mLinearFiltering = false; Loading @@ -490,30 +508,55 @@ void FontRenderer::initTextTexture(bool largeFonts) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Split up our cache texture into lines of certain widths return new CacheTexture(textureMemory, textureId, width, height); } void FontRenderer::initTextTexture() { mCacheLines.clear(); // Next, use other, separate caches for large glyphs. uint16_t maxWidth = 0; if (Caches::hasInstance()) { maxWidth = Caches::getInstance().maxTextureSize; } if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) { maxWidth = MAX_TEXT_CACHE_WIDTH; } if (mCacheTextureSmall != NULL) { delete mCacheTextureSmall; delete mCacheTexture128; delete mCacheTexture256; delete mCacheTexture512; } mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true); mCacheTexture128 = createCacheTexture(maxWidth, 256, false); mCacheTexture256 = createCacheTexture(maxWidth, 256, false); mCacheTexture512 = createCacheTexture(maxWidth, 512, false); mCurrentCacheTexture = mCacheTextureSmall; mUploadTexture = false; // Split up our default cache texture into lines of certain widths int nextLine = 0; mCacheLines.push(new CacheTextureLine(mCacheWidth, 18, nextLine, 0)); nextLine += mCacheLines.top()->mMaxHeight; mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; mCacheLines.push(new CacheTextureLine(mCacheWidth, 42, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; if (largeFonts) { int nextSize = 76; // Make several new lines with increasing font sizes while (nextSize < (int)(mCacheHeight - nextLine - (2 * nextSize))) { mCacheLines.push(new CacheTextureLine(mCacheWidth, nextSize, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; nextSize += 50; } } mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine, nextLine, 0, mCacheTextureSmall)); // The first cache is split into 2 lines of height 128, the rest have just one cache line. mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, 0, mCacheTexture128)); mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, 0, mCacheTexture128)); mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, 0, mCacheTexture256)); mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, 0, mCacheTexture512)); } // Avoid having to reallocate memory and render quad by quad Loading Loading @@ -568,22 +611,22 @@ void FontRenderer::checkInit() { } void FontRenderer::checkTextureUpdate() { if (!mUploadTexture) { if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) { return; } glBindTexture(GL_TEXTURE_2D, mTextureId); // Iterate over all the cache lines and see which ones need to be updated for (uint32_t i = 0; i < mCacheLines.size(); i++) { CacheTextureLine* cl = mCacheLines[i]; if (cl->mDirty) { if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) { CacheTexture* cacheTexture = cl->mCacheTexture; uint32_t xOffset = 0; uint32_t yOffset = cl->mCurrentRow; uint32_t width = mCacheWidth; uint32_t width = cl->mMaxWidth; uint32_t height = cl->mMaxHeight; void* textureData = mTextTexture + yOffset * width; void* textureData = cacheTexture->mTexture + (yOffset * width); glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId); glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, textureData); Loading @@ -591,6 +634,9 @@ void FontRenderer::checkTextureUpdate() { } } glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId); mLastCacheTexture = mCurrentCacheTexture; mUploadTexture = false; } Loading @@ -617,12 +663,21 @@ void FontRenderer::issueDrawCommand() { void FontRenderer::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) { if (mClip && (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) { return; } if (texture != mCurrentCacheTexture) { if (mCurrentQuadIndex != 0) { // First, draw everything stored already which uses the previous texture issueDrawCommand(); mCurrentQuadIndex = 0; } // Now use the new texture id mCurrentCacheTexture = texture; } const uint32_t vertsPerQuad = 4; const uint32_t floatsPerVert = 4; Loading libs/hwui/FontRenderer.h +104 −79 Original line number Diff line number Diff line Loading @@ -55,6 +55,77 @@ namespace uirenderer { 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 /////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -101,33 +172,6 @@ protected: 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); Loading Loading @@ -209,19 +253,28 @@ public: 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 getCacheSize() const { uint32_t size = 0; if (mCacheTextureSmall != NULL && mCacheTextureSmall->mTexture != NULL) { size += mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight; } uint32_t getCacheHeight() const { return mCacheHeight; 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: Loading @@ -229,41 +282,11 @@ protected: 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(); Loading @@ -277,10 +300,10 @@ protected: 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(); Loading @@ -288,12 +311,14 @@ protected: 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; Loading libs/hwui/GammaFontRenderer.h +1 −1 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ struct GammaFontRenderer { FontRenderer* renderer = mRenderers[fontRenderer]; if (!renderer) return 0; return renderer->getCacheHeight() * renderer->getCacheWidth(); return renderer->getCacheSize(); } private: Loading Loading
libs/hwui/FontRenderer.cpp +142 −87 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include "Caches.h" #include "Debug.h" #include "FontRenderer.h" #include "Caches.h" namespace android { namespace uirenderer { Loading @@ -35,10 +36,28 @@ namespace uirenderer { #define DEFAULT_TEXT_CACHE_WIDTH 1024 #define DEFAULT_TEXT_CACHE_HEIGHT 256 // We should query these values from the GL context #define MAX_TEXT_CACHE_WIDTH 2048 #define MAX_TEXT_CACHE_HEIGHT 2048 #define TEXTURE_BORDER_SIZE 2 /////////////////////////////////////////////////////////////////////////////// // CacheTextureLine /////////////////////////////////////////////////////////////////////////////// bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) { if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) { return false; } if (mCurrentCol + glyph.fWidth + TEXTURE_BORDER_SIZE < mMaxWidth) { *retOriginX = mCurrentCol + 1; *retOriginY = mCurrentRow + 1; mCurrentCol += glyph.fWidth + TEXTURE_BORDER_SIZE; mDirty = true; return true; } return false; } /////////////////////////////////////////////////////////////////////////////// // Font Loading Loading @@ -108,7 +127,7 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) { mState->appendMeshQuad(nPenX, nPenY, u1, v2, nPenX + width, nPenY, u2, v2, nPenX + width, nPenY - height, u2, v1, nPenX, nPenY - height, u1, v1); nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture); } void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, Loading @@ -119,8 +138,9 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint32_t endX = glyph->mStartX + glyph->mBitmapWidth; uint32_t endY = glyph->mStartY + glyph->mBitmapHeight; uint32_t cacheWidth = mState->getCacheWidth(); const uint8_t* cacheBuffer = mState->getTextTextureData(); CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture; uint32_t cacheWidth = cacheTexture->mWidth; const uint8_t* cacheBuffer = cacheTexture->mTexture; uint32_t cacheX = 0, cacheY = 0; int32_t bX = 0, bY = 0; Loading @@ -134,10 +154,9 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, bitmap[bY * bitmapW + bX] = tempCol; } } } Font::CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) { CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) { CachedGlyphInfo* cachedGlyph = NULL; ssize_t index = mCachedGlyphs.indexOfKey(textUnit); if (index >= 0) { Loading Loading @@ -246,7 +265,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp // Get the bitmap for the glyph paint->findImage(skiaGlyph); glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY); mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY); if (!glyph->mIsValid) { return; Loading @@ -260,8 +279,8 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp glyph->mBitmapWidth = skiaGlyph.fWidth; glyph->mBitmapHeight = skiaGlyph.fHeight; uint32_t cacheWidth = mState->getCacheWidth(); uint32_t cacheHeight = mState->getCacheHeight(); uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth; uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight; glyph->mBitmapMinU = (float) startX / (float) cacheWidth; glyph->mBitmapMinV = (float) startY / (float) cacheHeight; Loading @@ -271,7 +290,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp mState->mUploadTexture = true; } Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) { CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) { CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); mCachedGlyphs.add(glyph, newGlyph); Loading Loading @@ -320,25 +339,29 @@ FontRenderer::FontRenderer() { mInitialized = false; mMaxNumberOfQuads = 1024; mCurrentQuadIndex = 0; mTextureId = 0; mTextMeshPtr = NULL; mTextTexture = NULL; mCurrentCacheTexture = NULL; mLastCacheTexture = NULL; mCacheTextureSmall = NULL; mCacheTexture128 = NULL; mCacheTexture256 = NULL; mCacheTexture512 = NULL; mIndexBufferID = 0; mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; mSmallCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { if (sLogFontRendererCreate) { INIT_LOGD(" Setting text cache width to %s pixels", property); } mCacheWidth = atoi(property); mSmallCacheWidth = atoi(property); } else { if (sLogFontRendererCreate) { INIT_LOGD(" Using default text cache width of %i pixels", mCacheWidth); INIT_LOGD(" Using default text cache width of %i pixels", mSmallCacheWidth); } } Loading @@ -346,10 +369,10 @@ FontRenderer::FontRenderer() { if (sLogFontRendererCreate) { INIT_LOGD(" Setting text cache width to %s pixels", property); } mCacheHeight = atoi(property); mSmallCacheHeight = atoi(property); } else { if (sLogFontRendererCreate) { INIT_LOGD(" Using default text cache height of %i pixels", mCacheHeight); INIT_LOGD(" Using default text cache height of %i pixels", mSmallCacheHeight); } } Loading @@ -364,11 +387,10 @@ FontRenderer::~FontRenderer() { if (mInitialized) { delete[] mTextMeshPtr; delete[] mTextTexture; } if (mTextureId) { glDeleteTextures(1, &mTextureId); delete mCacheTextureSmall; delete mCacheTexture128; delete mCacheTexture256; delete mCacheTexture512; } Vector<Font*> fontsToDereference = mActiveFonts; Loading @@ -390,20 +412,21 @@ void FontRenderer::flushAllAndInvalidate() { } } bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) { // If the glyph is too tall, don't cache it if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { if (mCacheHeight < MAX_TEXT_CACHE_HEIGHT) { // Default cache not large enough for large glyphs - resize cache to // max size and try again flushAllAndInvalidate(); initTextTexture(true); uint8_t* FontRenderer::allocateTextureMemory(int width, int height) { uint8_t* textureMemory = new uint8_t[width * height]; memset(textureMemory, 0, width * height * sizeof(uint8_t)); return textureMemory; } if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, uint32_t* retOriginX, uint32_t* retOriginY) { cachedGlyph->mIsValid = false; // If the glyph is too tall, don't cache it if (glyph.fHeight + TEXTURE_BORDER_SIZE > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { LOGE("Font size to large to fit in cache. width, height = %i, %i", (int) glyph.fWidth, (int) glyph.fHeight); return false; } return; } // Now copy the bitmap into the cache texture Loading @@ -411,9 +434,11 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3 uint32_t startY = 0; bool bitmapFit = false; CacheTextureLine *cacheLine; for (uint32_t i = 0; i < mCacheLines.size(); i++) { bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); if (bitmapFit) { cacheLine = mCacheLines[i]; break; } } Loading @@ -426,27 +451,33 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3 for (uint32_t i = 0; i < mCacheLines.size(); i++) { bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); if (bitmapFit) { cacheLine = mCacheLines[i]; break; } } // if we still don't fit, something is wrong and we shouldn't draw if (!bitmapFit) { LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int) glyph.fWidth, (int) glyph.fHeight); return false; return; } } cachedGlyph->mCachedTextureLine = cacheLine; *retOriginX = startX; *retOriginY = startY; uint32_t endX = startX + glyph.fWidth; uint32_t endY = startY + glyph.fHeight; uint32_t cacheWidth = mCacheWidth; uint32_t cacheWidth = cacheLine->mMaxWidth; uint8_t* cacheBuffer = mTextTexture; CacheTexture *cacheTexture = cacheLine->mCacheTexture; if (cacheTexture->mTexture == NULL) { // Large-glyph texture memory is allocated only as needed cacheTexture->mTexture = allocateTextureMemory(cacheTexture->mWidth, cacheTexture->mHeight); } uint8_t* cacheBuffer = cacheTexture->mTexture; uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; unsigned int stride = glyph.rowBytes(); Loading @@ -457,30 +488,17 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3 cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; } } return true; } void FontRenderer::initTextTexture(bool largeFonts) { mCacheLines.clear(); if (largeFonts) { mCacheWidth = MAX_TEXT_CACHE_WIDTH; mCacheHeight = MAX_TEXT_CACHE_HEIGHT; cachedGlyph->mIsValid = true; } mTextTexture = new uint8_t[mCacheWidth * mCacheHeight]; memset(mTextTexture, 0, mCacheWidth * mCacheHeight * sizeof(uint8_t)); mUploadTexture = false; if (mTextureId != 0) { glDeleteTextures(1, &mTextureId); } glGenTextures(1, &mTextureId); glBindTexture(GL_TEXTURE_2D, mTextureId); CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) { uint8_t* textureMemory = allocate ? allocateTextureMemory(width, height) : NULL; GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Initialize texture dimensions glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0, glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0); mLinearFiltering = false; Loading @@ -490,30 +508,55 @@ void FontRenderer::initTextTexture(bool largeFonts) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Split up our cache texture into lines of certain widths return new CacheTexture(textureMemory, textureId, width, height); } void FontRenderer::initTextTexture() { mCacheLines.clear(); // Next, use other, separate caches for large glyphs. uint16_t maxWidth = 0; if (Caches::hasInstance()) { maxWidth = Caches::getInstance().maxTextureSize; } if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) { maxWidth = MAX_TEXT_CACHE_WIDTH; } if (mCacheTextureSmall != NULL) { delete mCacheTextureSmall; delete mCacheTexture128; delete mCacheTexture256; delete mCacheTexture512; } mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true); mCacheTexture128 = createCacheTexture(maxWidth, 256, false); mCacheTexture256 = createCacheTexture(maxWidth, 256, false); mCacheTexture512 = createCacheTexture(maxWidth, 512, false); mCurrentCacheTexture = mCacheTextureSmall; mUploadTexture = false; // Split up our default cache texture into lines of certain widths int nextLine = 0; mCacheLines.push(new CacheTextureLine(mCacheWidth, 18, nextLine, 0)); nextLine += mCacheLines.top()->mMaxHeight; mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; mCacheLines.push(new CacheTextureLine(mCacheWidth, 42, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; if (largeFonts) { int nextSize = 76; // Make several new lines with increasing font sizes while (nextSize < (int)(mCacheHeight - nextLine - (2 * nextSize))) { mCacheLines.push(new CacheTextureLine(mCacheWidth, nextSize, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, 0, mCacheTextureSmall)); nextLine += mCacheLines.top()->mMaxHeight; nextSize += 50; } } mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0)); mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine, nextLine, 0, mCacheTextureSmall)); // The first cache is split into 2 lines of height 128, the rest have just one cache line. mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, 0, mCacheTexture128)); mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, 0, mCacheTexture128)); mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, 0, mCacheTexture256)); mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, 0, mCacheTexture512)); } // Avoid having to reallocate memory and render quad by quad Loading Loading @@ -568,22 +611,22 @@ void FontRenderer::checkInit() { } void FontRenderer::checkTextureUpdate() { if (!mUploadTexture) { if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) { return; } glBindTexture(GL_TEXTURE_2D, mTextureId); // Iterate over all the cache lines and see which ones need to be updated for (uint32_t i = 0; i < mCacheLines.size(); i++) { CacheTextureLine* cl = mCacheLines[i]; if (cl->mDirty) { if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) { CacheTexture* cacheTexture = cl->mCacheTexture; uint32_t xOffset = 0; uint32_t yOffset = cl->mCurrentRow; uint32_t width = mCacheWidth; uint32_t width = cl->mMaxWidth; uint32_t height = cl->mMaxHeight; void* textureData = mTextTexture + yOffset * width; void* textureData = cacheTexture->mTexture + (yOffset * width); glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId); glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, textureData); Loading @@ -591,6 +634,9 @@ void FontRenderer::checkTextureUpdate() { } } glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId); mLastCacheTexture = mCurrentCacheTexture; mUploadTexture = false; } Loading @@ -617,12 +663,21 @@ void FontRenderer::issueDrawCommand() { void FontRenderer::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) { if (mClip && (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) { return; } if (texture != mCurrentCacheTexture) { if (mCurrentQuadIndex != 0) { // First, draw everything stored already which uses the previous texture issueDrawCommand(); mCurrentQuadIndex = 0; } // Now use the new texture id mCurrentCacheTexture = texture; } const uint32_t vertsPerQuad = 4; const uint32_t floatsPerVert = 4; Loading
libs/hwui/FontRenderer.h +104 −79 Original line number Diff line number Diff line Loading @@ -55,6 +55,77 @@ namespace uirenderer { 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 /////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -101,33 +172,6 @@ protected: 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); Loading Loading @@ -209,19 +253,28 @@ public: 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 getCacheSize() const { uint32_t size = 0; if (mCacheTextureSmall != NULL && mCacheTextureSmall->mTexture != NULL) { size += mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight; } uint32_t getCacheHeight() const { return mCacheHeight; 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: Loading @@ -229,41 +282,11 @@ protected: 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(); Loading @@ -277,10 +300,10 @@ protected: 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(); Loading @@ -288,12 +311,14 @@ protected: 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; Loading
libs/hwui/GammaFontRenderer.h +1 −1 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ struct GammaFontRenderer { FontRenderer* renderer = mRenderers[fontRenderer]; if (!renderer) return 0; return renderer->getCacheHeight() * renderer->getCacheWidth(); return renderer->getCacheSize(); } private: Loading