am 24214390: Merge "Remove CacheTextureLine structure from FontRenderer" into jb-mr1-dev

* commit '242143904800e0fe145977cd8880974545a166a5':
  Remove CacheTextureLine structure from FontRenderer
This commit is contained in:
Chet Haase
2012-08-16 15:04:36 -07:00
committed by Android Git Automerger
2 changed files with 103 additions and 205 deletions

View File

@@ -109,11 +109,11 @@ CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock *blockToRemove)
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// CacheTextureLine // CacheTexture
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) { bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) { if (glyph.fHeight + TEXTURE_BORDER_SIZE > mHeight) {
return false; return false;
} }
@@ -138,7 +138,7 @@ bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uin
roundedUpW = glyphW; roundedUpW = glyphW;
} }
*retOriginX = cacheBlock->mX; *retOriginX = cacheBlock->mX;
*retOriginY = mCurrentRow + cacheBlock->mY; *retOriginY = cacheBlock->mY;
// If this is the remainder space, create a new cache block for this column. Otherwise, // If this is the remainder space, create a new cache block for this column. Otherwise,
// adjust the info about this column. // adjust the info about this column.
if (cacheBlock->mY == TEXTURE_BORDER_SIZE) { if (cacheBlock->mY == TEXTURE_BORDER_SIZE) {
@@ -146,10 +146,10 @@ bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uin
// Adjust remainder space dimensions // Adjust remainder space dimensions
cacheBlock->mWidth -= roundedUpW; cacheBlock->mWidth -= roundedUpW;
cacheBlock->mX += roundedUpW; cacheBlock->mX += roundedUpW;
if (mMaxHeight - glyphH >= glyphH) { if (mHeight - glyphH >= glyphH) {
// There's enough height left over to create a new CacheBlock // There's enough height left over to create a new CacheBlock
CacheBlock *newBlock = new CacheBlock(oldX, glyphH, roundedUpW, CacheBlock *newBlock = new CacheBlock(oldX, glyphH, roundedUpW,
mMaxHeight - glyphH); mHeight - glyphH);
#if DEBUG_FONT_RENDERER #if DEBUG_FONT_RENDERER
ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d", ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
newBlock, newBlock->mX, newBlock->mY, newBlock, newBlock->mX, newBlock->mY,
@@ -213,10 +213,10 @@ Font::~Font() {
} }
} }
void Font::invalidateTextureCache(CacheTextureLine *cacheLine) { void Font::invalidateTextureCache(CacheTexture *cacheTexture) {
for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i); CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i);
if (cacheLine == NULL || cachedGlyph->mCachedTextureLine == cacheLine) { if (cacheTexture == NULL || cachedGlyph->mCacheTexture == cacheTexture) {
cachedGlyph->mIsValid = false; cachedGlyph->mIsValid = false;
} }
} }
@@ -260,7 +260,7 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
mState->appendMeshQuad(nPenX, nPenY, u1, v2, mState->appendMeshQuad(nPenX, nPenY, u1, v2,
nPenX + width, nPenY, u2, v2, nPenX + width, nPenY, u2, v2,
nPenX + width, nPenY - height, u2, v1, nPenX + width, nPenY - height, u2, v1,
nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture); nPenX, nPenY - height, u1, v1, glyph->mCacheTexture);
} }
void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
@@ -271,7 +271,7 @@ void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
uint32_t endX = glyph->mStartX + glyph->mBitmapWidth; uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
uint32_t endY = glyph->mStartY + glyph->mBitmapHeight; uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture; CacheTexture *cacheTexture = glyph->mCacheTexture;
uint32_t cacheWidth = cacheTexture->mWidth; uint32_t cacheWidth = cacheTexture->mWidth;
const uint8_t* cacheBuffer = cacheTexture->mTexture; const uint8_t* cacheBuffer = cacheTexture->mTexture;
@@ -325,7 +325,7 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float
position->fY + destination[2].fY, u2, v1, position->fY + destination[2].fY, u2, v1,
position->fX + destination[3].fX, position->fX + destination[3].fX,
position->fY + destination[3].fY, u1, v1, position->fY + destination[3].fY, u1, v1,
glyph->mCachedTextureLine->mCacheTexture); glyph->mCacheTexture);
} }
CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) { CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
@@ -556,8 +556,8 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
glyph->mBitmapWidth = skiaGlyph.fWidth; glyph->mBitmapWidth = skiaGlyph.fWidth;
glyph->mBitmapHeight = skiaGlyph.fHeight; glyph->mBitmapHeight = skiaGlyph.fHeight;
uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth; uint32_t cacheWidth = glyph->mCacheTexture->mWidth;
uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight; uint32_t cacheHeight = glyph->mCacheTexture->mHeight;
glyph->mBitmapMinU = startX / (float) cacheWidth; glyph->mBitmapMinU = startX / (float) cacheWidth;
glyph->mBitmapMinV = startY / (float) cacheHeight; glyph->mBitmapMinV = startY / (float) cacheHeight;
@@ -620,10 +620,6 @@ FontRenderer::FontRenderer() {
mTextMeshPtr = NULL; mTextMeshPtr = NULL;
mCurrentCacheTexture = NULL; mCurrentCacheTexture = NULL;
mLastCacheTexture = NULL; mLastCacheTexture = NULL;
mCacheTextureSmall = NULL;
mCacheTexture128 = NULL;
mCacheTexture256 = NULL;
mCacheTexture512 = NULL;
mLinearFiltering = false; mLinearFiltering = false;
@@ -659,10 +655,10 @@ FontRenderer::FontRenderer() {
} }
FontRenderer::~FontRenderer() { FontRenderer::~FontRenderer() {
for (uint32_t i = 0; i < mCacheLines.size(); i++) { for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
delete mCacheLines[i]; delete mCacheTextures[i];
} }
mCacheLines.clear(); mCacheTextures.clear();
if (mInitialized) { if (mInitialized) {
// Unbinding the buffer shouldn't be necessary but it crashes with some drivers // Unbinding the buffer shouldn't be necessary but it crashes with some drivers
@@ -670,10 +666,6 @@ FontRenderer::~FontRenderer() {
glDeleteBuffers(1, &mIndexBufferID); glDeleteBuffers(1, &mIndexBufferID);
delete[] mTextMeshPtr; delete[] mTextMeshPtr;
delete mCacheTextureSmall;
delete mCacheTexture128;
delete mCacheTexture256;
delete mCacheTexture512;
} }
Vector<Font*> fontsToDereference = mActiveFonts; Vector<Font*> fontsToDereference = mActiveFonts;
@@ -692,29 +684,19 @@ void FontRenderer::flushAllAndInvalidate() {
mActiveFonts[i]->invalidateTextureCache(); mActiveFonts[i]->invalidateTextureCache();
} }
uint16_t totalGlyphs = 0; for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
for (uint32_t i = 0; i < mCacheLines.size(); i++) { mCacheTextures[i]->init();
totalGlyphs += mCacheLines[i]->mNumGlyphs;
mCacheLines[i]->init();
} }
#if DEBUG_FONT_RENDERER #if DEBUG_FONT_RENDERER
// Erase caches, just as a debugging facility uint16_t totalGlyphs = 0;
if (mCacheTextureSmall && mCacheTextureSmall->mTexture) { for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
memset(mCacheTextureSmall->mTexture, 0, totalGlyphs += mCacheTextures[i]->mNumGlyphs;
mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight); // Erase caches, just as a debugging facility
} if (mCacheTextures[i]->mTexture) {
if (mCacheTexture128 && mCacheTexture128->mTexture) { memset(mCacheTextures[i]->mTexture, 0,
memset(mCacheTexture128->mTexture, 0, mCacheTextures[i]->mWidth * mCacheTextures[i]->mHeight);
mCacheTexture128->mWidth * mCacheTexture128->mHeight); }
}
if (mCacheTexture256 && mCacheTexture256->mTexture) {
memset(mCacheTexture256->mTexture, 0,
mCacheTexture256->mWidth * mCacheTexture256->mHeight);
}
if (mCacheTexture512 && mCacheTexture512->mTexture) {
memset(mCacheTexture512->mTexture, 0,
mCacheTexture512->mWidth * mCacheTexture512->mHeight);
} }
ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs); ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs);
#endif #endif
@@ -730,38 +712,17 @@ void FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) {
} }
void FontRenderer::flushLargeCaches() { void FontRenderer::flushLargeCaches() {
if ((!mCacheTexture128 || !mCacheTexture128->mTexture) && // Start from 1; don't deallocate smallest/default texture
(!mCacheTexture256 || !mCacheTexture256->mTexture) && for (uint32_t i = 1; i < mCacheTextures.size(); i++) {
(!mCacheTexture512 || !mCacheTexture512->mTexture)) { CacheTexture* cacheTexture = mCacheTextures[i];
// Typical case; no large glyph caches allocated if (cacheTexture->mTexture != NULL) {
return; cacheTexture->init();
} for (uint32_t j = 0; j < mActiveFonts.size(); j++) {
mActiveFonts[j]->invalidateTextureCache(cacheTexture);
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
CacheTextureLine* cacheLine = mCacheLines[i];
if ((cacheLine->mCacheTexture == mCacheTexture128 ||
cacheLine->mCacheTexture == mCacheTexture256 ||
cacheLine->mCacheTexture == mCacheTexture512) &&
cacheLine->mCacheTexture->mTexture != NULL) {
#if DEBUG_FONT_RENDERER
if (cacheLine->mCacheTexture == mCacheTexture128) {
ALOGD("flushing cacheTexture128");
} else if (cacheLine->mCacheTexture == mCacheTexture256) {
ALOGD("flushing cacheTexture256");
} else {
ALOGD("flushing cacheTexture512");
}
#endif
cacheLine->init();
for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
mActiveFonts[i]->invalidateTextureCache(cacheLine);
} }
deallocateTextureMemory(cacheTexture);
} }
} }
deallocateTextureMemory(mCacheTexture128);
deallocateTextureMemory(mCacheTexture256);
deallocateTextureMemory(mCacheTexture512);
} }
void FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) { void FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) {
@@ -789,12 +750,24 @@ void FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} }
CacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph,
uint32_t* startX, uint32_t* startY) {
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
if (mCacheTextures[i]->fitBitmap(glyph, startX, startY)) {
return mCacheTextures[i];
}
}
// Could not fit glyph into current cache textures
return NULL;
}
void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
uint32_t* retOriginX, uint32_t* retOriginY) { uint32_t* retOriginX, uint32_t* retOriginY) {
checkInit(); checkInit();
cachedGlyph->mIsValid = false; cachedGlyph->mIsValid = false;
// If the glyph is too tall, don't cache it // If the glyph is too tall, don't cache it
if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
mCacheTextures[mCacheTextures.size() - 1]->mHeight) {
ALOGE("Font size too large to fit in cache. width, height = %i, %i", ALOGE("Font size too large to fit in cache. width, height = %i, %i",
(int) glyph.fWidth, (int) glyph.fHeight); (int) glyph.fWidth, (int) glyph.fHeight);
return; return;
@@ -804,36 +777,22 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
uint32_t startX = 0; uint32_t startX = 0;
uint32_t startY = 0; uint32_t startY = 0;
bool bitmapFit = false; CacheTexture* cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
CacheTextureLine *cacheLine;
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
if (bitmapFit) {
cacheLine = mCacheLines[i];
break;
}
}
// If the new glyph didn't fit, flush the state so far and invalidate everything // If the new glyph didn't fit, flush the state so far and invalidate everything
if (!bitmapFit) { if (!cacheTexture) {
flushAllAndInvalidate(); flushAllAndInvalidate();
// Try to fit it again // Try to fit it again
for (uint32_t i = 0; i < mCacheLines.size(); i++) { cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
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 we still don't fit, something is wrong and we shouldn't draw
if (!bitmapFit) { if (!cacheTexture) {
return; return;
} }
} }
cachedGlyph->mCachedTextureLine = cacheLine; cachedGlyph->mCacheTexture = cacheTexture;
*retOriginX = startX; *retOriginX = startX;
*retOriginY = startY; *retOriginY = startY;
@@ -841,9 +800,8 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
uint32_t endX = startX + glyph.fWidth; uint32_t endX = startX + glyph.fWidth;
uint32_t endY = startY + glyph.fHeight; uint32_t endY = startY + glyph.fHeight;
uint32_t cacheWidth = cacheLine->mMaxWidth; uint32_t cacheWidth = cacheTexture->mWidth;
CacheTexture* cacheTexture = cacheLine->mCacheTexture;
if (!cacheTexture->mTexture) { if (!cacheTexture->mTexture) {
// Large-glyph texture memory is allocated only as needed // Large-glyph texture memory is allocated only as needed
allocateTextureMemory(cacheTexture); allocateTextureMemory(cacheTexture);
@@ -896,17 +854,10 @@ CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool alloc
} }
void FontRenderer::initTextTexture() { void FontRenderer::initTextTexture() {
for (uint32_t i = 0; i < mCacheLines.size(); i++) { for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
delete mCacheLines[i]; delete mCacheTextures[i];
}
mCacheLines.clear();
if (mCacheTextureSmall) {
delete mCacheTextureSmall;
delete mCacheTexture128;
delete mCacheTexture256;
delete mCacheTexture512;
} }
mCacheTextures.clear();
// Next, use other, separate caches for large glyphs. // Next, use other, separate caches for large glyphs.
uint16_t maxWidth = 0; uint16_t maxWidth = 0;
@@ -918,35 +869,12 @@ void FontRenderer::initTextTexture() {
maxWidth = MAX_TEXT_CACHE_WIDTH; maxWidth = MAX_TEXT_CACHE_WIDTH;
} }
mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true);
mCacheTexture128 = createCacheTexture(maxWidth, 256, false);
mCacheTexture256 = createCacheTexture(maxWidth, 256, false);
mCacheTexture512 = createCacheTexture(maxWidth, 512, false);
mCurrentCacheTexture = mCacheTextureSmall;
mUploadTexture = false; mUploadTexture = false;
// Split up our default cache texture into lines of certain widths mCacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true));
int nextLine = 0; mCacheTextures.push(createCacheTexture(maxWidth, 256, false));
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, mCacheTextureSmall)); mCacheTextures.push(createCacheTexture(maxWidth, 256, false));
nextLine += mCacheLines.top()->mMaxHeight; mCacheTextures.push(createCacheTexture(maxWidth, 512, false));
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, mCacheTextureSmall)); mCurrentCacheTexture = mCacheTextures[0];
nextLine += mCacheLines.top()->mMaxHeight;
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, mCacheTextureSmall));
nextLine += mCacheLines.top()->mMaxHeight;
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, mCacheTextureSmall));
nextLine += mCacheLines.top()->mMaxHeight;
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, mCacheTextureSmall));
nextLine += mCacheLines.top()->mMaxHeight;
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, mCacheTextureSmall));
nextLine += mCacheLines.top()->mMaxHeight;
mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine,
nextLine, 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, mCacheTexture128));
mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, mCacheTexture128));
mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, mCacheTexture256));
mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, mCacheTexture512));
} }
// Avoid having to reallocate memory and render quad by quad // Avoid having to reallocate memory and render quad by quad
@@ -1001,16 +929,14 @@ void FontRenderer::checkTextureUpdate() {
Caches& caches = Caches::getInstance(); Caches& caches = Caches::getInstance();
GLuint lastTextureId = 0; GLuint lastTextureId = 0;
// Iterate over all the cache lines and see which ones need to be updated // Iterate over all the cache textures and see which ones need to be updated
for (uint32_t i = 0; i < mCacheLines.size(); i++) { for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
CacheTextureLine* cl = mCacheLines[i]; CacheTexture* cacheTexture = mCacheTextures[i];
if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) { if (cacheTexture->mDirty && cacheTexture->mTexture != NULL) {
CacheTexture* cacheTexture = cl->mCacheTexture;
uint32_t xOffset = 0; uint32_t xOffset = 0;
uint32_t yOffset = cl->mCurrentRow; uint32_t width = cacheTexture->mWidth;
uint32_t width = cl->mMaxWidth; uint32_t height = cacheTexture->mHeight;
uint32_t height = cl->mMaxHeight; void* textureData = cacheTexture->mTexture;
void* textureData = cacheTexture->mTexture + (yOffset * width);
if (cacheTexture->mTextureId != lastTextureId) { if (cacheTexture->mTextureId != lastTextureId) {
caches.activeTexture(0); caches.activeTexture(0);
@@ -1018,13 +944,13 @@ void FontRenderer::checkTextureUpdate() {
lastTextureId = cacheTexture->mTextureId; lastTextureId = cacheTexture->mTextureId;
} }
#if DEBUG_FONT_RENDERER #if DEBUG_FONT_RENDERER
ALOGD("glTextSubimage for cacheLine %d: xOff, yOff, width height = %d, %d, %d, %d", i, ALOGD("glTextSubimage for cacheTexture %d: xOff, width height = %d, %d, %d",
xOffset, yOffset, width, height); i, xOffset, width, height);
#endif #endif
glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, 0, width, height,
GL_ALPHA, GL_UNSIGNED_BYTE, textureData); GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
cl->mDirty = false; cacheTexture->mDirty = false;
} }
} }

View File

@@ -61,35 +61,14 @@ namespace uirenderer {
class FontRenderer; class FontRenderer;
class CacheTexture {
public:
CacheTexture(uint16_t width, uint16_t height) :
mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
mLinearFiltering(false) { }
~CacheTexture() {
if (mTexture) {
delete[] mTexture;
}
if (mTextureId) {
glDeleteTextures(1, &mTextureId);
}
}
uint8_t* mTexture;
GLuint mTextureId;
uint16_t mWidth;
uint16_t mHeight;
bool mLinearFiltering;
};
/** /**
* CacheBlock is a noce in a linked list of current free space areas in a CacheTextureLine. * CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
* Using CacheBlocks enables us to pack the cache line from top to bottom as well as left to right. * Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right.
* When we add a glyph to the cache, we see if it fits within one of the existing columns that * When we add a glyph to the cache, we see if it fits within one of the existing columns that
* have already been started (this is the case if the glyph fits vertically as well as * have already been started (this is the case if the glyph fits vertically as well as
* horizontally, and if its width is sufficiently close to the column width to avoid * horizontally, and if its width is sufficiently close to the column width to avoid
* sub-optimal packing of small glyphs into wide columns). If there is no column in which the * sub-optimal packing of small glyphs into wide columns). If there is no column in which the
* glyph fits, we check the final node, which is the remaining space in the cache line, creating * glyph fits, we check the final node, which is the remaining space in the cache, creating
* a new column as appropriate. * a new column as appropriate.
* *
* As columns fill up, we remove their CacheBlock from the list to avoid having to check * As columns fill up, we remove their CacheBlock from the list to avoid having to check
@@ -122,21 +101,22 @@ struct CacheBlock {
} }
}; };
class CacheTextureLine { class CacheTexture {
public: public:
CacheTextureLine(uint16_t maxWidth, uint16_t maxHeight, uint32_t currentRow, CacheTexture(uint16_t width, uint16_t height) :
CacheTexture* cacheTexture): mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
mMaxHeight(maxHeight), mLinearFiltering(false), mDirty(false), mNumGlyphs(0) {
mMaxWidth(maxWidth),
mCurrentRow(currentRow),
mDirty(false),
mNumGlyphs(0),
mCacheTexture(cacheTexture) {
mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
maxWidth - TEXTURE_BORDER_SIZE, maxHeight - TEXTURE_BORDER_SIZE, true); mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
} }
~CacheTextureLine() { ~CacheTexture() {
if (mTexture) {
delete[] mTexture;
}
if (mTextureId) {
glDeleteTextures(1, &mTextureId);
}
reset(); reset();
} }
@@ -154,17 +134,18 @@ public:
// reset, then create a new remainder space to start again // reset, then create a new remainder space to start again
reset(); reset();
mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
mMaxWidth - TEXTURE_BORDER_SIZE, mMaxHeight - TEXTURE_BORDER_SIZE, true); mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
} }
bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY); bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);
uint16_t mMaxHeight; uint8_t* mTexture;
uint16_t mMaxWidth; GLuint mTextureId;
uint32_t mCurrentRow; uint16_t mWidth;
uint16_t mHeight;
bool mLinearFiltering;
bool mDirty; bool mDirty;
uint16_t mNumGlyphs; uint16_t mNumGlyphs;
CacheTexture* mCacheTexture;
CacheBlock* mCacheBlocks; CacheBlock* mCacheBlocks;
}; };
@@ -193,7 +174,7 @@ struct CachedGlyphInfo {
// Auto-kerning // Auto-kerning
SkFixed mLsbDelta; SkFixed mLsbDelta;
SkFixed mRsbDelta; SkFixed mRsbDelta;
CacheTextureLine* mCachedTextureLine; CacheTexture* mCacheTexture;
}; };
@@ -260,7 +241,7 @@ protected:
// Cache of glyphs // Cache of glyphs
DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs; DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
void invalidateTextureCache(CacheTextureLine *cacheLine = NULL); void invalidateTextureCache(CacheTexture *cacheTexture = NULL);
CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph); CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph);
void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph); void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph);
@@ -364,17 +345,11 @@ public:
uint32_t getCacheSize() const { uint32_t getCacheSize() const {
uint32_t size = 0; uint32_t size = 0;
if (mCacheTextureSmall != NULL && mCacheTextureSmall->mTexture != NULL) { for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
size += mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight; CacheTexture* cacheTexture = mCacheTextures[i];
} if (cacheTexture != NULL && cacheTexture->mTexture != NULL) {
if (mCacheTexture128 != NULL && mCacheTexture128->mTexture != NULL) { size += cacheTexture->mWidth * cacheTexture->mHeight;
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; return size;
} }
@@ -390,6 +365,7 @@ protected:
CacheTexture* createCacheTexture(int width, int height, bool allocate); CacheTexture* createCacheTexture(int width, int height, bool allocate);
void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
uint32_t *retOriginX, uint32_t *retOriginY); uint32_t *retOriginX, uint32_t *retOriginY);
CacheTexture* cacheBitmapInTexture(const SkGlyph& glyph, uint32_t* startX, uint32_t* startY);
void flushAllAndInvalidate(); void flushAllAndInvalidate();
void initVertexArrayBuffers(); void initVertexArrayBuffers();
@@ -415,17 +391,13 @@ protected:
uint32_t mSmallCacheWidth; uint32_t mSmallCacheWidth;
uint32_t mSmallCacheHeight; uint32_t mSmallCacheHeight;
Vector<CacheTextureLine*> mCacheLines; Vector<CacheTexture*> mCacheTextures;
Font* mCurrentFont; Font* mCurrentFont;
Vector<Font*> mActiveFonts; Vector<Font*> mActiveFonts;
CacheTexture* mCurrentCacheTexture; CacheTexture* mCurrentCacheTexture;
CacheTexture* mLastCacheTexture; CacheTexture* mLastCacheTexture;
CacheTexture* mCacheTextureSmall;
CacheTexture* mCacheTexture128;
CacheTexture* mCacheTexture256;
CacheTexture* mCacheTexture512;
void checkTextureUpdate(); void checkTextureUpdate();
bool mUploadTexture; bool mUploadTexture;