summaryrefslogtreecommitdiff
path: root/libs/hwui/font/CacheTexture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/font/CacheTexture.cpp')
-rw-r--r--libs/hwui/font/CacheTexture.cpp355
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