Loading libs/hwui/FontRenderer.cpp +41 −80 Original line number Diff line number Diff line Loading @@ -55,10 +55,7 @@ FontRenderer::FontRenderer() : mGammaTable = NULL; mInitialized = false; mMaxNumberOfQuads = 1024; mCurrentQuadIndex = 0; mLastQuadIndex = 0; mTextMesh = NULL; mCurrentCacheTexture = NULL; mLinearFiltering = false; Loading Loading @@ -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); Loading @@ -126,9 +121,7 @@ FontRenderer::~FontRenderer() { } void FontRenderer::flushAllAndInvalidate() { if (mCurrentQuadIndex != 0) { issueDrawCommand(); } LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts); while (it.next()) { Loading Loading @@ -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) Loading Loading @@ -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; Loading Loading @@ -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 Loading @@ -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; Loading Loading @@ -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(); for (uint32_t i = 0; i < mCacheTextures.size(); i++) { CacheTexture* texture = mCacheTextures[i]; if (texture->canDraw()) { if (first) { checkTextureUpdate(); caches.bindIndicesBuffer(mIndexBufferID); if (!mDrawn) { float* buffer = mTextMesh; int offset = 2; bool force = caches.unbindMeshBuffer(); caches.bindPositionVertexPointer(force, buffer); caches.bindTexCoordsVertexPointer(force, buffer + offset); 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; 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, batch.count * 6, GL_UNSIGNED_SHORT, batch.offset); glDrawElements(GL_TRIANGLES, texture->meshElementCount(), GL_UNSIGNED_SHORT, texture->indices()); 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, Loading @@ -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(); } } Loading @@ -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(); } } Loading Loading @@ -610,10 +573,8 @@ void FontRenderer::finishRender() { mBounds = NULL; mClip = NULL; if (mCurrentQuadIndex != 0) { issueDrawCommand(); } } void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix) { Font* font = Font::create(this, paint, matrix); Loading libs/hwui/FontRenderer.h +0 −33 Original line number Diff line number Diff line Loading @@ -144,7 +144,6 @@ private: void removeFont(const Font* font); void updateDrawParams(); void checkTextureUpdate(); void setTextureDirty() { Loading @@ -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; Loading @@ -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; Loading libs/hwui/font/CacheTexture.cpp +78 −0 Original line number Diff line number Diff line Loading @@ -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; Loading libs/hwui/font/CacheTexture.h +51 −66 Original line number Diff line number Diff line Loading @@ -24,7 +24,8 @@ #include <utils/Log.h> #include "FontUtil.h" #include "Rect.h" #include "../Rect.h" #include "../Vertex.h" namespace android { namespace uirenderer { Loading Loading @@ -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; } } Loading @@ -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); Loading Loading @@ -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; Loading @@ -201,6 +183,9 @@ private: bool mLinearFiltering; bool mDirty; uint16_t mNumGlyphs; TextureVertex* mMesh; uint32_t mCurrentQuad; uint32_t mMaxQuadCount; CacheBlock* mCacheBlocks; Rect mDirtyRect; }; Loading Loading
libs/hwui/FontRenderer.cpp +41 −80 Original line number Diff line number Diff line Loading @@ -55,10 +55,7 @@ FontRenderer::FontRenderer() : mGammaTable = NULL; mInitialized = false; mMaxNumberOfQuads = 1024; mCurrentQuadIndex = 0; mLastQuadIndex = 0; mTextMesh = NULL; mCurrentCacheTexture = NULL; mLinearFiltering = false; Loading Loading @@ -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); Loading @@ -126,9 +121,7 @@ FontRenderer::~FontRenderer() { } void FontRenderer::flushAllAndInvalidate() { if (mCurrentQuadIndex != 0) { issueDrawCommand(); } LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts); while (it.next()) { Loading Loading @@ -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) Loading Loading @@ -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; Loading Loading @@ -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 Loading @@ -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; Loading Loading @@ -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(); for (uint32_t i = 0; i < mCacheTextures.size(); i++) { CacheTexture* texture = mCacheTextures[i]; if (texture->canDraw()) { if (first) { checkTextureUpdate(); caches.bindIndicesBuffer(mIndexBufferID); if (!mDrawn) { float* buffer = mTextMesh; int offset = 2; bool force = caches.unbindMeshBuffer(); caches.bindPositionVertexPointer(force, buffer); caches.bindTexCoordsVertexPointer(force, buffer + offset); 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; 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, batch.count * 6, GL_UNSIGNED_SHORT, batch.offset); glDrawElements(GL_TRIANGLES, texture->meshElementCount(), GL_UNSIGNED_SHORT, texture->indices()); 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, Loading @@ -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(); } } Loading @@ -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(); } } Loading Loading @@ -610,10 +573,8 @@ void FontRenderer::finishRender() { mBounds = NULL; mClip = NULL; if (mCurrentQuadIndex != 0) { issueDrawCommand(); } } void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix) { Font* font = Font::create(this, paint, matrix); Loading
libs/hwui/FontRenderer.h +0 −33 Original line number Diff line number Diff line Loading @@ -144,7 +144,6 @@ private: void removeFont(const Font* font); void updateDrawParams(); void checkTextureUpdate(); void setTextureDirty() { Loading @@ -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; Loading @@ -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; Loading
libs/hwui/font/CacheTexture.cpp +78 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
libs/hwui/font/CacheTexture.h +51 −66 Original line number Diff line number Diff line Loading @@ -24,7 +24,8 @@ #include <utils/Log.h> #include "FontUtil.h" #include "Rect.h" #include "../Rect.h" #include "../Vertex.h" namespace android { namespace uirenderer { Loading Loading @@ -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; } } Loading @@ -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); Loading Loading @@ -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; Loading @@ -201,6 +183,9 @@ private: bool mLinearFiltering; bool mDirty; uint16_t mNumGlyphs; TextureVertex* mMesh; uint32_t mCurrentQuad; uint32_t mMaxQuadCount; CacheBlock* mCacheBlocks; Rect mDirtyRect; }; Loading