diff options
Diffstat (limited to 'libs/hwui/font/CacheTexture.cpp')
-rw-r--r-- | libs/hwui/font/CacheTexture.cpp | 355 |
1 files changed, 0 insertions, 355 deletions
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp deleted file mode 100644 index 5dd8bb8119e9..000000000000 --- a/libs/hwui/font/CacheTexture.cpp +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <SkGlyph.h> - -#include "../Caches.h" -#include "../Debug.h" -#include "../Extensions.h" -#include "../PixelBuffer.h" -#include "CacheTexture.h" -#include "FontUtil.h" - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// CacheBlock -/////////////////////////////////////////////////////////////////////////////// - -/** - * Insert new block into existing linked list of blocks. Blocks are sorted in increasing-width - * order, except for the final block (the remainder space at the right, since we fill from the - * left). - */ -CacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock* newBlock) { -#if DEBUG_FONT_RENDERER - ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d", newBlock, newBlock->mX, - newBlock->mY, newBlock->mWidth, newBlock->mHeight); -#endif - - CacheBlock* currBlock = head; - CacheBlock* prevBlock = nullptr; - - while (currBlock && currBlock->mY != TEXTURE_BORDER_SIZE) { - if (newBlock->mWidth < currBlock->mWidth) { - newBlock->mNext = currBlock; - newBlock->mPrev = prevBlock; - currBlock->mPrev = newBlock; - - if (prevBlock) { - prevBlock->mNext = newBlock; - return head; - } else { - return newBlock; - } - } - - prevBlock = currBlock; - currBlock = currBlock->mNext; - } - - // new block larger than all others - insert at end (but before the remainder space, if there) - newBlock->mNext = currBlock; - newBlock->mPrev = prevBlock; - - if (currBlock) { - currBlock->mPrev = newBlock; - } - - if (prevBlock) { - prevBlock->mNext = newBlock; - return head; - } else { - return newBlock; - } -} - -CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) { -#if DEBUG_FONT_RENDERER - ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d", blockToRemove, blockToRemove->mX, - blockToRemove->mY, blockToRemove->mWidth, blockToRemove->mHeight); -#endif - - CacheBlock* newHead = head; - CacheBlock* nextBlock = blockToRemove->mNext; - CacheBlock* prevBlock = blockToRemove->mPrev; - - if (prevBlock) { - // If this doesn't hold, we have a use-after-free below. - LOG_ALWAYS_FATAL_IF(head == blockToRemove, - "removeBlock: head should not have a previous block"); - prevBlock->mNext = nextBlock; - } else { - newHead = nextBlock; - } - - if (nextBlock) { - nextBlock->mPrev = prevBlock; - } - - delete blockToRemove; - - return newHead; -} - -/////////////////////////////////////////////////////////////////////////////// -// CacheTexture -/////////////////////////////////////////////////////////////////////////////// - -CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) - : mTexture(Caches::getInstance()) - , mWidth(width) - , mHeight(height) - , mFormat(format) - , mMaxQuadCount(maxQuadCount) - , mCaches(Caches::getInstance()) { - mTexture.blend = true; - - mCacheBlocks = - new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, - getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE); - - // OpenGL ES 3.0+ lets us specify the row length for unpack operations such - // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture. - // With OpenGL ES 2.0 we have to upload entire stripes instead. - mHasUnpackRowLength = mCaches.extensions().hasUnpackRowLength(); -} - -CacheTexture::~CacheTexture() { - releaseMesh(); - releasePixelBuffer(); - reset(); -} - -void CacheTexture::reset() { - // Delete existing cache blocks - while (mCacheBlocks != nullptr) { - 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, - getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE); -} - -void CacheTexture::releaseMesh() { - delete[] mMesh; -} - -void CacheTexture::releasePixelBuffer() { - if (mPixelBuffer) { - delete mPixelBuffer; - mPixelBuffer = nullptr; - } - mTexture.deleteTexture(); - mDirty = false; - mCurrentQuad = 0; -} - -void CacheTexture::setLinearFiltering(bool linearFiltering) { - mTexture.setFilter(linearFiltering ? GL_LINEAR : GL_NEAREST); -} - -void CacheTexture::allocateMesh() { - if (!mMesh) { - mMesh = new TextureVertex[mMaxQuadCount * 4]; - } -} - -void CacheTexture::allocatePixelBuffer() { - if (!mPixelBuffer) { - mPixelBuffer = PixelBuffer::create(mFormat, getWidth(), getHeight()); - } - - GLint internalFormat = mFormat; - if (mFormat == GL_RGBA) { - internalFormat = mCaches.rgbaInternalFormat(); - } - - mTexture.resize(mWidth, mHeight, internalFormat, mFormat); - mTexture.setFilter(getLinearFiltering() ? GL_LINEAR : GL_NEAREST); - mTexture.setWrap(GL_CLAMP_TO_EDGE); -} - -bool CacheTexture::upload() { - const Rect& dirtyRect = mDirtyRect; - - // align the x direction to 32 and y direction to 4 for better performance - uint32_t x = (((uint32_t)dirtyRect.left) & (~0x1F)); - uint32_t y = (((uint32_t)dirtyRect.top) & (~0x3)); - uint32_t r = ((((uint32_t)dirtyRect.right) + 0x1F) & (~0x1F)) - x; - uint32_t b = ((((uint32_t)dirtyRect.bottom) + 0x3) & (~0x3)) - y; - uint32_t width = (r > getWidth() ? getWidth() : r); - uint32_t height = (b > getHeight() ? getHeight() : b); - - // The unpack row length only needs to be specified when a new - // texture is bound - if (mHasUnpackRowLength) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, getWidth()); - } else { - x = 0; - width = getWidth(); - } - - mPixelBuffer->upload(x, y, width, height); - setDirty(false); - - return mHasUnpackRowLength; -} - -void CacheTexture::setDirty(bool dirty) { - mDirty = dirty; - if (!dirty) { - mDirtyRect.setEmpty(); - } -} - -bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) { - switch (glyph.fMaskFormat) { - case SkMask::kA8_Format: - case SkMask::kBW_Format: - if (mFormat != GL_ALPHA) { -#if DEBUG_FONT_RENDERER - ALOGD("fitBitmap: texture format %x is inappropriate for monochromatic glyphs", - mFormat); -#endif - return false; - } - break; - case SkMask::kARGB32_Format: - if (mFormat != GL_RGBA) { -#if DEBUG_FONT_RENDERER - ALOGD("fitBitmap: texture format %x is inappropriate for colour glyphs", mFormat); -#endif - return false; - } - break; - default: -#if DEBUG_FONT_RENDERER - ALOGD("fitBitmap: unknown glyph format %x encountered", glyph.fMaskFormat); -#endif - return false; - } - - if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > getHeight()) { - return false; - } - - uint16_t glyphW = glyph.fWidth + TEXTURE_BORDER_SIZE; - uint16_t glyphH = glyph.fHeight + TEXTURE_BORDER_SIZE; - - // roundedUpW equals glyphW to the next multiple of CACHE_BLOCK_ROUNDING_SIZE. - // This columns for glyphs that are close but not necessarily exactly the same size. It trades - // off the loss of a few pixels for some glyphs against the ability to store more glyphs - // of varying sizes in one block. - uint16_t roundedUpW = (glyphW + CACHE_BLOCK_ROUNDING_SIZE - 1) & -CACHE_BLOCK_ROUNDING_SIZE; - - CacheBlock* cacheBlock = mCacheBlocks; - while (cacheBlock) { - // Store glyph in this block iff: it fits the block's remaining space and: - // it's the remainder space (mY == 0) or there's only enough height for this one glyph - // or it's within ROUNDING_SIZE of the block width - if (roundedUpW <= cacheBlock->mWidth && glyphH <= cacheBlock->mHeight && - (cacheBlock->mY == TEXTURE_BORDER_SIZE || - (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) { - if (cacheBlock->mHeight - glyphH < glyphH) { - // Only enough space for this glyph - don't bother rounding up the width - roundedUpW = glyphW; - } - - *retOriginX = cacheBlock->mX; - *retOriginY = cacheBlock->mY; - - // If this is the remainder space, create a new cache block for this column. Otherwise, - // adjust the info about this column. - if (cacheBlock->mY == TEXTURE_BORDER_SIZE) { - uint16_t oldX = cacheBlock->mX; - // Adjust remainder space dimensions - cacheBlock->mWidth -= roundedUpW; - cacheBlock->mX += roundedUpW; - - if (getHeight() - glyphH >= glyphH) { - // There's enough height left over to create a new CacheBlock - CacheBlock* newBlock = - new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE, roundedUpW, - getHeight() - glyphH - TEXTURE_BORDER_SIZE); -#if DEBUG_FONT_RENDERER - ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d", - newBlock, newBlock->mX, newBlock->mY, newBlock->mWidth, - newBlock->mHeight); -#endif - mCacheBlocks = CacheBlock::insertBlock(mCacheBlocks, newBlock); - } - } else { - // Insert into current column and adjust column dimensions - cacheBlock->mY += glyphH; - cacheBlock->mHeight -= glyphH; -#if DEBUG_FONT_RENDERER - ALOGD("fitBitmap: Added to existing block: this, x, y, w, h = %p, %d, %d, %d, %d", - cacheBlock, cacheBlock->mX, cacheBlock->mY, cacheBlock->mWidth, - cacheBlock->mHeight); -#endif - } - - if (cacheBlock->mHeight < std::min(glyphH, glyphW)) { - // If remaining space in this block is too small to be useful, remove it - mCacheBlocks = CacheBlock::removeBlock(mCacheBlocks, cacheBlock); - } - - mDirty = true; - const Rect r(*retOriginX - TEXTURE_BORDER_SIZE, *retOriginY - TEXTURE_BORDER_SIZE, - *retOriginX + glyphW, *retOriginY + glyphH); - mDirtyRect.unionWith(r); - mNumGlyphs++; - -#if DEBUG_FONT_RENDERER - ALOGD("fitBitmap: current block list:"); - mCacheBlocks->output(); -#endif - - return true; - } - cacheBlock = cacheBlock->mNext; - } -#if DEBUG_FONT_RENDERER - ALOGD("fitBitmap: returning false for glyph of size %d, %d", glyphW, glyphH); -#endif - return false; -} - -uint32_t CacheTexture::calculateFreeMemory() const { - CacheBlock* cacheBlock = mCacheBlocks; - uint32_t free = 0; - // currently only two formats are supported: GL_ALPHA or GL_RGBA; - uint32_t bpp = mFormat == GL_RGBA ? 4 : 1; - while (cacheBlock) { - free += bpp * cacheBlock->mWidth * cacheBlock->mHeight; - cacheBlock = cacheBlock->mNext; - } - return free; -} - -}; // namespace uirenderer -}; // namespace android |