Skip to content

Commit 378e919

Browse files
committed
Remove CacheTextureLine structure from FontRenderer
CacheTextureLine was useful before we were packing the glyph textures; it allowed simple packing of any particular texture according to how many lines there were in a texture, and how tall those lines were. Now that we are packing more efficiently (both horizontally and vertically in any given texture line), it is more efficient to have open space in every texture, removing the need for CacheTextureLine (which now gets in the way since it limits how much can be stored in each line). This change removes CacheTextureLine and just uses CacheTexture directly, allowing caching of glyphs anywhere in the open space of each texture. As before, the packing of these glyphs is determined by the CacheBlock structure, which is a linked list of open spaces in each CacheTexture. Change-Id: Id6f628170df0f676f8743ac7de76f2377fc6a012
1 parent 6b7d46b commit 378e919

File tree

2 files changed

+103
-205
lines changed

2 files changed

+103
-205
lines changed

libs/hwui/FontRenderer.cpp

Lines changed: 73 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock *blockToRemove)
109109
}
110110

111111
///////////////////////////////////////////////////////////////////////////////
112-
// CacheTextureLine
112+
// CacheTexture
113113
///////////////////////////////////////////////////////////////////////////////
114114

115-
bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
116-
if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) {
115+
bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
116+
if (glyph.fHeight + TEXTURE_BORDER_SIZE > mHeight) {
117117
return false;
118118
}
119119

@@ -138,18 +138,18 @@ bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uin
138138
roundedUpW = glyphW;
139139
}
140140
*retOriginX = cacheBlock->mX;
141-
*retOriginY = mCurrentRow + cacheBlock->mY;
141+
*retOriginY = cacheBlock->mY;
142142
// If this is the remainder space, create a new cache block for this column. Otherwise,
143143
// adjust the info about this column.
144144
if (cacheBlock->mY == TEXTURE_BORDER_SIZE) {
145145
uint16_t oldX = cacheBlock->mX;
146146
// Adjust remainder space dimensions
147147
cacheBlock->mWidth -= roundedUpW;
148148
cacheBlock->mX += roundedUpW;
149-
if (mMaxHeight - glyphH >= glyphH) {
149+
if (mHeight - glyphH >= glyphH) {
150150
// There's enough height left over to create a new CacheBlock
151151
CacheBlock *newBlock = new CacheBlock(oldX, glyphH, roundedUpW,
152-
mMaxHeight - glyphH);
152+
mHeight - glyphH);
153153
#if DEBUG_FONT_RENDERER
154154
ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
155155
newBlock, newBlock->mX, newBlock->mY,
@@ -213,10 +213,10 @@ Font::~Font() {
213213
}
214214
}
215215

216-
void Font::invalidateTextureCache(CacheTextureLine *cacheLine) {
216+
void Font::invalidateTextureCache(CacheTexture *cacheTexture) {
217217
for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
218218
CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i);
219-
if (cacheLine == NULL || cachedGlyph->mCachedTextureLine == cacheLine) {
219+
if (cacheTexture == NULL || cachedGlyph->mCacheTexture == cacheTexture) {
220220
cachedGlyph->mIsValid = false;
221221
}
222222
}
@@ -260,7 +260,7 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
260260
mState->appendMeshQuad(nPenX, nPenY, u1, v2,
261261
nPenX + width, nPenY, u2, v2,
262262
nPenX + width, nPenY - height, u2, v1,
263-
nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture);
263+
nPenX, nPenY - height, u1, v1, glyph->mCacheTexture);
264264
}
265265

266266
void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
@@ -271,7 +271,7 @@ void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
271271
uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
272272
uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
273273

274-
CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture;
274+
CacheTexture *cacheTexture = glyph->mCacheTexture;
275275
uint32_t cacheWidth = cacheTexture->mWidth;
276276
const uint8_t* cacheBuffer = cacheTexture->mTexture;
277277

@@ -325,7 +325,7 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float
325325
position->fY + destination[2].fY, u2, v1,
326326
position->fX + destination[3].fX,
327327
position->fY + destination[3].fY, u1, v1,
328-
glyph->mCachedTextureLine->mCacheTexture);
328+
glyph->mCacheTexture);
329329
}
330330

331331
CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
@@ -556,8 +556,8 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
556556
glyph->mBitmapWidth = skiaGlyph.fWidth;
557557
glyph->mBitmapHeight = skiaGlyph.fHeight;
558558

559-
uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth;
560-
uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight;
559+
uint32_t cacheWidth = glyph->mCacheTexture->mWidth;
560+
uint32_t cacheHeight = glyph->mCacheTexture->mHeight;
561561

562562
glyph->mBitmapMinU = startX / (float) cacheWidth;
563563
glyph->mBitmapMinV = startY / (float) cacheHeight;
@@ -620,10 +620,6 @@ FontRenderer::FontRenderer() {
620620
mTextMeshPtr = NULL;
621621
mCurrentCacheTexture = NULL;
622622
mLastCacheTexture = NULL;
623-
mCacheTextureSmall = NULL;
624-
mCacheTexture128 = NULL;
625-
mCacheTexture256 = NULL;
626-
mCacheTexture512 = NULL;
627623

628624
mLinearFiltering = false;
629625

@@ -659,21 +655,17 @@ FontRenderer::FontRenderer() {
659655
}
660656

661657
FontRenderer::~FontRenderer() {
662-
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
663-
delete mCacheLines[i];
658+
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
659+
delete mCacheTextures[i];
664660
}
665-
mCacheLines.clear();
661+
mCacheTextures.clear();
666662

667663
if (mInitialized) {
668664
// Unbinding the buffer shouldn't be necessary but it crashes with some drivers
669665
Caches::getInstance().unbindIndicesBuffer();
670666
glDeleteBuffers(1, &mIndexBufferID);
671667

672668
delete[] mTextMeshPtr;
673-
delete mCacheTextureSmall;
674-
delete mCacheTexture128;
675-
delete mCacheTexture256;
676-
delete mCacheTexture512;
677669
}
678670

679671
Vector<Font*> fontsToDereference = mActiveFonts;
@@ -692,29 +684,19 @@ void FontRenderer::flushAllAndInvalidate() {
692684
mActiveFonts[i]->invalidateTextureCache();
693685
}
694686

695-
uint16_t totalGlyphs = 0;
696-
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
697-
totalGlyphs += mCacheLines[i]->mNumGlyphs;
698-
mCacheLines[i]->init();
687+
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
688+
mCacheTextures[i]->init();
699689
}
700690

701-
#if DEBUG_FONT_RENDERER
702-
// Erase caches, just as a debugging facility
703-
if (mCacheTextureSmall && mCacheTextureSmall->mTexture) {
704-
memset(mCacheTextureSmall->mTexture, 0,
705-
mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight);
706-
}
707-
if (mCacheTexture128 && mCacheTexture128->mTexture) {
708-
memset(mCacheTexture128->mTexture, 0,
709-
mCacheTexture128->mWidth * mCacheTexture128->mHeight);
710-
}
711-
if (mCacheTexture256 && mCacheTexture256->mTexture) {
712-
memset(mCacheTexture256->mTexture, 0,
713-
mCacheTexture256->mWidth * mCacheTexture256->mHeight);
714-
}
715-
if (mCacheTexture512 && mCacheTexture512->mTexture) {
716-
memset(mCacheTexture512->mTexture, 0,
717-
mCacheTexture512->mWidth * mCacheTexture512->mHeight);
691+
#if DEBUG_FONT_RENDERER
692+
uint16_t totalGlyphs = 0;
693+
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
694+
totalGlyphs += mCacheTextures[i]->mNumGlyphs;
695+
// Erase caches, just as a debugging facility
696+
if (mCacheTextures[i]->mTexture) {
697+
memset(mCacheTextures[i]->mTexture, 0,
698+
mCacheTextures[i]->mWidth * mCacheTextures[i]->mHeight);
699+
}
718700
}
719701
ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs);
720702
#endif
@@ -730,38 +712,17 @@ void FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) {
730712
}
731713

732714
void FontRenderer::flushLargeCaches() {
733-
if ((!mCacheTexture128 || !mCacheTexture128->mTexture) &&
734-
(!mCacheTexture256 || !mCacheTexture256->mTexture) &&
735-
(!mCacheTexture512 || !mCacheTexture512->mTexture)) {
736-
// Typical case; no large glyph caches allocated
737-
return;
738-
}
739-
740-
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
741-
CacheTextureLine* cacheLine = mCacheLines[i];
742-
if ((cacheLine->mCacheTexture == mCacheTexture128 ||
743-
cacheLine->mCacheTexture == mCacheTexture256 ||
744-
cacheLine->mCacheTexture == mCacheTexture512) &&
745-
cacheLine->mCacheTexture->mTexture != NULL) {
746-
#if DEBUG_FONT_RENDERER
747-
if (cacheLine->mCacheTexture == mCacheTexture128) {
748-
ALOGD("flushing cacheTexture128");
749-
} else if (cacheLine->mCacheTexture == mCacheTexture256) {
750-
ALOGD("flushing cacheTexture256");
751-
} else {
752-
ALOGD("flushing cacheTexture512");
753-
}
754-
#endif
755-
cacheLine->init();
756-
for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
757-
mActiveFonts[i]->invalidateTextureCache(cacheLine);
715+
// Start from 1; don't deallocate smallest/default texture
716+
for (uint32_t i = 1; i < mCacheTextures.size(); i++) {
717+
CacheTexture* cacheTexture = mCacheTextures[i];
718+
if (cacheTexture->mTexture != NULL) {
719+
cacheTexture->init();
720+
for (uint32_t j = 0; j < mActiveFonts.size(); j++) {
721+
mActiveFonts[j]->invalidateTextureCache(cacheTexture);
758722
}
723+
deallocateTextureMemory(cacheTexture);
759724
}
760725
}
761-
762-
deallocateTextureMemory(mCacheTexture128);
763-
deallocateTextureMemory(mCacheTexture256);
764-
deallocateTextureMemory(mCacheTexture512);
765726
}
766727

767728
void FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) {
@@ -789,12 +750,24 @@ void FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) {
789750
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
790751
}
791752

753+
CacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph,
754+
uint32_t* startX, uint32_t* startY) {
755+
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
756+
if (mCacheTextures[i]->fitBitmap(glyph, startX, startY)) {
757+
return mCacheTextures[i];
758+
}
759+
}
760+
// Could not fit glyph into current cache textures
761+
return NULL;
762+
}
763+
792764
void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
793765
uint32_t* retOriginX, uint32_t* retOriginY) {
794766
checkInit();
795767
cachedGlyph->mIsValid = false;
796768
// If the glyph is too tall, don't cache it
797-
if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
769+
if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
770+
mCacheTextures[mCacheTextures.size() - 1]->mHeight) {
798771
ALOGE("Font size too large to fit in cache. width, height = %i, %i",
799772
(int) glyph.fWidth, (int) glyph.fHeight);
800773
return;
@@ -804,46 +777,31 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
804777
uint32_t startX = 0;
805778
uint32_t startY = 0;
806779

807-
bool bitmapFit = false;
808-
CacheTextureLine *cacheLine;
809-
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
810-
bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
811-
if (bitmapFit) {
812-
cacheLine = mCacheLines[i];
813-
break;
814-
}
815-
}
780+
CacheTexture* cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
816781

817782
// If the new glyph didn't fit, flush the state so far and invalidate everything
818-
if (!bitmapFit) {
783+
if (!cacheTexture) {
819784
flushAllAndInvalidate();
820785

821786
// Try to fit it again
822-
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
823-
bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
824-
if (bitmapFit) {
825-
cacheLine = mCacheLines[i];
826-
break;
827-
}
828-
}
787+
cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
829788

830789
// if we still don't fit, something is wrong and we shouldn't draw
831-
if (!bitmapFit) {
790+
if (!cacheTexture) {
832791
return;
833792
}
834793
}
835794

836-
cachedGlyph->mCachedTextureLine = cacheLine;
795+
cachedGlyph->mCacheTexture = cacheTexture;
837796

838797
*retOriginX = startX;
839798
*retOriginY = startY;
840799

841800
uint32_t endX = startX + glyph.fWidth;
842801
uint32_t endY = startY + glyph.fHeight;
843802

844-
uint32_t cacheWidth = cacheLine->mMaxWidth;
803+
uint32_t cacheWidth = cacheTexture->mWidth;
845804

846-
CacheTexture* cacheTexture = cacheLine->mCacheTexture;
847805
if (!cacheTexture->mTexture) {
848806
// Large-glyph texture memory is allocated only as needed
849807
allocateTextureMemory(cacheTexture);
@@ -896,17 +854,10 @@ CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool alloc
896854
}
897855

898856
void FontRenderer::initTextTexture() {
899-
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
900-
delete mCacheLines[i];
901-
}
902-
mCacheLines.clear();
903-
904-
if (mCacheTextureSmall) {
905-
delete mCacheTextureSmall;
906-
delete mCacheTexture128;
907-
delete mCacheTexture256;
908-
delete mCacheTexture512;
857+
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
858+
delete mCacheTextures[i];
909859
}
860+
mCacheTextures.clear();
910861

911862
// Next, use other, separate caches for large glyphs.
912863
uint16_t maxWidth = 0;
@@ -918,35 +869,12 @@ void FontRenderer::initTextTexture() {
918869
maxWidth = MAX_TEXT_CACHE_WIDTH;
919870
}
920871

921-
mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true);
922-
mCacheTexture128 = createCacheTexture(maxWidth, 256, false);
923-
mCacheTexture256 = createCacheTexture(maxWidth, 256, false);
924-
mCacheTexture512 = createCacheTexture(maxWidth, 512, false);
925-
mCurrentCacheTexture = mCacheTextureSmall;
926-
927872
mUploadTexture = false;
928-
// Split up our default cache texture into lines of certain widths
929-
int nextLine = 0;
930-
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, mCacheTextureSmall));
931-
nextLine += mCacheLines.top()->mMaxHeight;
932-
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, mCacheTextureSmall));
933-
nextLine += mCacheLines.top()->mMaxHeight;
934-
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, mCacheTextureSmall));
935-
nextLine += mCacheLines.top()->mMaxHeight;
936-
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, mCacheTextureSmall));
937-
nextLine += mCacheLines.top()->mMaxHeight;
938-
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, mCacheTextureSmall));
939-
nextLine += mCacheLines.top()->mMaxHeight;
940-
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, mCacheTextureSmall));
941-
nextLine += mCacheLines.top()->mMaxHeight;
942-
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine,
943-
nextLine, mCacheTextureSmall));
944-
945-
// The first cache is split into 2 lines of height 128, the rest have just one cache line.
946-
mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, mCacheTexture128));
947-
mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, mCacheTexture128));
948-
mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, mCacheTexture256));
949-
mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, mCacheTexture512));
873+
mCacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true));
874+
mCacheTextures.push(createCacheTexture(maxWidth, 256, false));
875+
mCacheTextures.push(createCacheTexture(maxWidth, 256, false));
876+
mCacheTextures.push(createCacheTexture(maxWidth, 512, false));
877+
mCurrentCacheTexture = mCacheTextures[0];
950878
}
951879

952880
// Avoid having to reallocate memory and render quad by quad
@@ -1001,30 +929,28 @@ void FontRenderer::checkTextureUpdate() {
1001929

1002930
Caches& caches = Caches::getInstance();
1003931
GLuint lastTextureId = 0;
1004-
// Iterate over all the cache lines and see which ones need to be updated
1005-
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
1006-
CacheTextureLine* cl = mCacheLines[i];
1007-
if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) {
1008-
CacheTexture* cacheTexture = cl->mCacheTexture;
932+
// Iterate over all the cache textures and see which ones need to be updated
933+
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
934+
CacheTexture* cacheTexture = mCacheTextures[i];
935+
if (cacheTexture->mDirty && cacheTexture->mTexture != NULL) {
1009936
uint32_t xOffset = 0;
1010-
uint32_t yOffset = cl->mCurrentRow;
1011-
uint32_t width = cl->mMaxWidth;
1012-
uint32_t height = cl->mMaxHeight;
1013-
void* textureData = cacheTexture->mTexture + (yOffset * width);
937+
uint32_t width = cacheTexture->mWidth;
938+
uint32_t height = cacheTexture->mHeight;
939+
void* textureData = cacheTexture->mTexture;
1014940

1015941
if (cacheTexture->mTextureId != lastTextureId) {
1016942
caches.activeTexture(0);
1017943
glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
1018944
lastTextureId = cacheTexture->mTextureId;
1019945
}
1020946
#if DEBUG_FONT_RENDERER
1021-
ALOGD("glTextSubimage for cacheLine %d: xOff, yOff, width height = %d, %d, %d, %d", i,
1022-
xOffset, yOffset, width, height);
947+
ALOGD("glTextSubimage for cacheTexture %d: xOff, width height = %d, %d, %d",
948+
i, xOffset, width, height);
1023949
#endif
1024-
glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
950+
glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, 0, width, height,
1025951
GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
1026952

1027-
cl->mDirty = false;
953+
cacheTexture->mDirty = false;
1028954
}
1029955
}
1030956

0 commit comments

Comments
 (0)