diff options
| -rw-r--r-- | libs/hwui/FontRenderer.cpp | 121 | ||||
| -rw-r--r-- | libs/hwui/FontRenderer.h | 33 | ||||
| -rw-r--r-- | libs/hwui/font/CacheTexture.cpp | 78 | ||||
| -rw-r--r-- | libs/hwui/font/CacheTexture.h | 117 |
4 files changed, 170 insertions, 179 deletions
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 0c70e272d0a5..009dcb97aa0e 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -55,10 +55,7 @@ FontRenderer::FontRenderer() : mGammaTable = NULL; mInitialized = false; mMaxNumberOfQuads = 1024; - mCurrentQuadIndex = 0; - mLastQuadIndex = 0; - mTextMesh = NULL; mCurrentCacheTexture = NULL; mLinearFiltering = false; @@ -114,8 +111,6 @@ FontRenderer::~FontRenderer() { // Unbinding the buffer shouldn't be necessary but it crashes with some drivers Caches::getInstance().unbindIndicesBuffer(); glDeleteBuffers(1, &mIndexBufferID); - - delete[] mTextMesh; } LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts); @@ -126,9 +121,7 @@ FontRenderer::~FontRenderer() { } void FontRenderer::flushAllAndInvalidate() { - if (mCurrentQuadIndex != 0) { - issueDrawCommand(); - } + issueDrawCommand(); LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts); while (it.next()) { @@ -236,6 +229,9 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp // Large-glyph texture memory is allocated only as needed cacheTexture->allocateTexture(); } + if (!cacheTexture->mesh()) { + cacheTexture->allocateMesh(); + } // Tells us whether the glyphs is B&W (1 bit per pixel) // or anti-aliased (8 bits per pixel) @@ -307,11 +303,12 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp } CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) { - CacheTexture* cacheTexture = new CacheTexture(width, height); + CacheTexture* cacheTexture = new CacheTexture(width, height, mMaxNumberOfQuads); if (allocate) { Caches::getInstance().activeTexture(0); cacheTexture->allocateTexture(); + cacheTexture->allocateMesh(); } return cacheTexture; @@ -356,12 +353,6 @@ void FontRenderer::initVertexArrayBuffers() { glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW); free(indexBufferData); - - uint32_t coordSize = 2; - uint32_t uvSize = 2; - uint32_t vertsPerQuad = 4; - uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize; - mTextMesh = new float[vertexBufferSize]; } // We don't want to allocate anything unless we actually draw text @@ -376,15 +367,6 @@ void FontRenderer::checkInit() { mInitialized = true; } -void FontRenderer::updateDrawParams() { - if (mCurrentQuadIndex != mLastQuadIndex) { - uint16_t* offset = (uint16_t*)(mLastQuadIndex * sizeof(uint16_t) * 6); - uint32_t count = mCurrentQuadIndex - mLastQuadIndex; - mDrawBatch.add(TextBatch(offset, count, mCurrentCacheTexture)); - mLastQuadIndex = mCurrentQuadIndex; - } -} - void FontRenderer::checkTextureUpdate() { if (!mUploadTexture) { return; @@ -424,77 +406,58 @@ void FontRenderer::checkTextureUpdate() { } void FontRenderer::issueDrawCommand() { - updateDrawParams(); - checkTextureUpdate(); + bool first = true; + bool force = false; + GLuint lastId = 0; Caches& caches = Caches::getInstance(); - caches.bindIndicesBuffer(mIndexBufferID); - if (!mDrawn) { - float* buffer = mTextMesh; - int offset = 2; - bool force = caches.unbindMeshBuffer(); - caches.bindPositionVertexPointer(force, buffer); - caches.bindTexCoordsVertexPointer(force, buffer + offset); - } + for (uint32_t i = 0; i < mCacheTextures.size(); i++) { + CacheTexture* texture = mCacheTextures[i]; + if (texture->canDraw()) { + if (first) { + checkTextureUpdate(); + caches.bindIndicesBuffer(mIndexBufferID); + + if (!mDrawn) { + // If returns true, a VBO was bound and we must + // rebind our vertex attrib pointers even if + // they have the same values as the current pointers + force = caches.unbindMeshBuffer(); + } - caches.activeTexture(0); - GLuint lastId = 0; + caches.activeTexture(0); + first = false; + } - for (uint32_t i = 0; i < mDrawBatch.size(); i++) { - const TextBatch& batch = mDrawBatch[i]; + glBindTexture(GL_TEXTURE_2D, texture->getTextureId()); + texture->setLinearFiltering(mLinearFiltering, false); - GLuint id = batch.texture->getTextureId(); - if (id != lastId) { - glBindTexture(GL_TEXTURE_2D, id); - batch.texture->setLinearFiltering(mLinearFiltering, false); - lastId = id; - } + TextureVertex* mesh = texture->mesh(); + caches.bindPositionVertexPointer(force, &mesh[0].position[0]); + caches.bindTexCoordsVertexPointer(force, &mesh[0].texture[0]); + force = false; + + glDrawElements(GL_TRIANGLES, texture->meshElementCount(), + GL_UNSIGNED_SHORT, texture->indices()); - glDrawElements(GL_TRIANGLES, batch.count * 6, GL_UNSIGNED_SHORT, batch.offset); + texture->resetMesh(); + } } mDrawn = true; - - mCurrentQuadIndex = 0; - mLastQuadIndex = 0; - mDrawBatch.clear(); } void FontRenderer::appendMeshQuadNoClip(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, CacheTexture* texture) { if (texture != mCurrentCacheTexture) { - updateDrawParams(); // Now use the new texture id mCurrentCacheTexture = texture; } - const uint32_t vertsPerQuad = 4; - const uint32_t floatsPerVert = 4; - float* currentPos = mTextMesh + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; - - (*currentPos++) = x1; - (*currentPos++) = y1; - (*currentPos++) = u1; - (*currentPos++) = v1; - - (*currentPos++) = x2; - (*currentPos++) = y2; - (*currentPos++) = u2; - (*currentPos++) = v2; - - (*currentPos++) = x3; - (*currentPos++) = y3; - (*currentPos++) = u3; - (*currentPos++) = v3; - - (*currentPos++) = x4; - (*currentPos++) = y4; - (*currentPos++) = u4; - (*currentPos++) = v4; - - mCurrentQuadIndex++; + mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2, + x3, y3, u3, v3, x4, y4, u4, v4); } void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1, @@ -515,7 +478,7 @@ void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1, mBounds->bottom = fmax(mBounds->bottom, y1); } - if (mCurrentQuadIndex == mMaxNumberOfQuads) { + if (mCurrentCacheTexture->endOfMesh()) { issueDrawCommand(); } } @@ -533,7 +496,7 @@ void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1, mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4)))); } - if (mCurrentQuadIndex == mMaxNumberOfQuads) { + if (mCurrentCacheTexture->endOfMesh()) { issueDrawCommand(); } } @@ -610,9 +573,7 @@ void FontRenderer::finishRender() { mBounds = NULL; mClip = NULL; - if (mCurrentQuadIndex != 0) { - issueDrawCommand(); - } + issueDrawCommand(); } void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix) { diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index 442f4e2714a2..080cc713b0a6 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -144,7 +144,6 @@ private: void removeFont(const Font* font); - void updateDrawParams(); void checkTextureUpdate(); void setTextureDirty() { @@ -165,12 +164,7 @@ private: bool mUploadTexture; - // Pointer to vertex data to speed up frame to frame work - float* mTextMesh; - uint32_t mCurrentQuadIndex; - uint32_t mLastQuadIndex; uint32_t mMaxNumberOfQuads; - uint32_t mIndexBufferID; const Rect* mClip; @@ -181,33 +175,6 @@ private: bool mLinearFiltering; - struct TextBatch { - TextBatch(): offset(NULL), count(0), texture(NULL) { - } - - TextBatch(uint16_t* offset, uint32_t count, CacheTexture* texture): - offset(offset), count(count), texture(texture) { - } - - static int compare(const TextBatch& lhs, const TextBatch& rhs) { - return lhs.texture->getTextureId() - rhs.texture->getTextureId(); - } - - friend inline int strictly_order_type(const TextBatch& lhs, const TextBatch& rhs) { - return compare(lhs, rhs) < 0; - } - - friend inline int compare_type(const TextBatch& lhs, const TextBatch& rhs) { - return compare(lhs, rhs); - } - - uint16_t* offset; - uint32_t count; - CacheTexture* texture; - }; - - SortedList<TextBatch> mDrawBatch; - // RS constructs sp<RSC::RS> mRs; sp<const RSC::Element> mRsElement; diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp index 24b0523cc7e1..109664282374 100644 --- a/libs/hwui/font/CacheTexture.cpp +++ b/libs/hwui/font/CacheTexture.cpp @@ -106,6 +106,84 @@ CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) // CacheTexture /////////////////////////////////////////////////////////////////////////////// +CacheTexture::CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount) : + mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), + mLinearFiltering(false), mDirty(false), mNumGlyphs(0), + mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount) { + mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, + mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true); +} + +CacheTexture::~CacheTexture() { + releaseMesh(); + releaseTexture(); + reset(); +} + +void CacheTexture::reset() { + // Delete existing cache blocks + while (mCacheBlocks != NULL) { + CacheBlock* tmpBlock = mCacheBlocks; + mCacheBlocks = mCacheBlocks->mNext; + delete tmpBlock; + } + mNumGlyphs = 0; + mCurrentQuad = 0; +} + +void CacheTexture::init() { + // reset, then create a new remainder space to start again + reset(); + mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, + mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true); +} + +void CacheTexture::releaseMesh() { + delete[] mMesh; +} + +void CacheTexture::releaseTexture() { + if (mTexture) { + delete[] mTexture; + mTexture = NULL; + } + if (mTextureId) { + glDeleteTextures(1, &mTextureId); + mTextureId = 0; + } + mDirty = false; + mCurrentQuad = 0; +} + +void CacheTexture::allocateMesh() { + if (!mMesh) { + mMesh = new TextureVertex[mMaxQuadCount * 4]; + } +} + +void CacheTexture::allocateTexture() { + if (!mTexture) { + mTexture = new uint8_t[mWidth * mHeight]; + } + + if (!mTextureId) { + glGenTextures(1, &mTextureId); + + glBindTexture(GL_TEXTURE_2D, mTextureId); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + // Initialize texture dimensions + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mWidth, mHeight, 0, + GL_ALPHA, GL_UNSIGNED_BYTE, 0); + + const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } +} + bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) { if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mHeight) { return false; diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h index fdd16232bc41..57429415254f 100644 --- a/libs/hwui/font/CacheTexture.h +++ b/libs/hwui/font/CacheTexture.h @@ -24,7 +24,8 @@ #include <utils/Log.h> #include "FontUtil.h" -#include "Rect.h" +#include "../Rect.h" +#include "../Vertex.h" namespace android { namespace uirenderer { @@ -55,14 +56,14 @@ struct CacheBlock { } static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock); - static CacheBlock* removeBlock(CacheBlock* head, CacheBlock* blockToRemove); void output() { CacheBlock* currBlock = this; while (currBlock) { ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d", - currBlock, currBlock->mX, currBlock->mY, currBlock->mWidth, currBlock->mHeight); + currBlock, currBlock->mX, currBlock->mY, + currBlock->mWidth, currBlock->mHeight); currBlock = currBlock->mNext; } } @@ -70,72 +71,17 @@ struct CacheBlock { class CacheTexture { public: - CacheTexture(uint16_t width, uint16_t height) : - mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), - mLinearFiltering(false), mDirty(false), mNumGlyphs(0) { - mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, - mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true); - } + CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount); + ~CacheTexture(); - ~CacheTexture() { - releaseTexture(); - reset(); - } - - void reset() { - // Delete existing cache blocks - while (mCacheBlocks != NULL) { - CacheBlock* tmpBlock = mCacheBlocks; - mCacheBlocks = mCacheBlocks->mNext; - delete tmpBlock; - } - mNumGlyphs = 0; - } + void reset(); + void init(); - void init() { - // reset, then create a new remainder space to start again - reset(); - mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, - mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true); - } + void releaseMesh(); + void releaseTexture(); - void releaseTexture() { - if (mTexture) { - delete[] mTexture; - mTexture = NULL; - } - if (mTextureId) { - glDeleteTextures(1, &mTextureId); - mTextureId = 0; - } - mDirty = false; - } - - /** - * This method assumes that the proper texture unit is active. - */ - void allocateTexture() { - if (!mTexture) { - mTexture = new uint8_t[mWidth * mHeight]; - } - - if (!mTextureId) { - glGenTextures(1, &mTextureId); - - glBindTexture(GL_TEXTURE_2D, mTextureId); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // Initialize texture dimensions - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mWidth, mHeight, 0, - GL_ALPHA, GL_UNSIGNED_BYTE, 0); - - const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - } + void allocateTexture(); + void allocateMesh(); bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY); @@ -193,6 +139,42 @@ public: return mNumGlyphs; } + TextureVertex* mesh() const { + return mMesh; + } + + uint32_t meshElementCount() const { + return mCurrentQuad * 6; + } + + uint16_t* indices() const { + return (uint16_t*) 0; + } + + void resetMesh() { + mCurrentQuad = 0; + } + + inline void addQuad(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) { + TextureVertex* mesh = mMesh + mCurrentQuad * 4; + TextureVertex::set(mesh++, x1, y1, u1, v1); + TextureVertex::set(mesh++, x2, y2, u2, v2); + TextureVertex::set(mesh++, x3, y3, u3, v3); + TextureVertex::set(mesh++, x4, y4, u4, v4); + mCurrentQuad++; + } + + bool canDraw() const { + return mCurrentQuad > 0; + } + + bool endOfMesh() const { + return mCurrentQuad == mMaxQuadCount; + } + private: uint8_t* mTexture; GLuint mTextureId; @@ -201,6 +183,9 @@ private: bool mLinearFiltering; bool mDirty; uint16_t mNumGlyphs; + TextureVertex* mMesh; + uint32_t mCurrentQuad; + uint32_t mMaxQuadCount; CacheBlock* mCacheBlocks; Rect mDirtyRect; }; |