CacheTexture.cpp revision 2dc236b2bae13b9a0ed9b3f7320502aecd7983b3
19f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy/*
29f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Copyright (C) 2012 The Android Open Source Project
39f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *
49f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Licensed under the Apache License, Version 2.0 (the "License");
59f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * you may not use this file except in compliance with the License.
69f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * You may obtain a copy of the License at
79f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *
89f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *      http://www.apache.org/licenses/LICENSE-2.0
99f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *
109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Unless required by applicable law or agreed to in writing, software
119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * distributed under the License is distributed on an "AS IS" BASIS,
129f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * See the License for the specific language governing permissions and
149f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * limitations under the License.
159f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy */
169f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
17ca79cf69d09efa0c327e9b1237d86a119aea5da7Derek Sollenberger#include <SkGlyph.h>
189f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
199f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include "CacheTexture.h"
202dc236b2bae13b9a0ed9b3f7320502aecd7983b3Tom Hudson#include "FontUtil.h"
218aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy#include "../Caches.h"
220908764b2b3cf5075df4178a5f0a8547dcb7b317Romain Guy#include "../Debug.h"
23cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy#include "../Extensions.h"
24cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy#include "../PixelBuffer.h"
259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
269f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace android {
279f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace uirenderer {
289f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
299f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
309f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy// CacheBlock
319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy/**
349f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Insert new block into existing linked list of blocks. Blocks are sorted in increasing-width
359f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * order, except for the final block (the remainder space at the right, since we fill from the
369f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * left).
379f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy */
38e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain GuyCacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock* newBlock) {
399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock, newBlock->mX, newBlock->mY,
429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock->mWidth, newBlock->mHeight);
439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
449b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
45e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    CacheBlock* currBlock = head;
46e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    CacheBlock* prevBlock = NULL;
479b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
489f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    while (currBlock && currBlock->mY != TEXTURE_BORDER_SIZE) {
499f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (newBlock->mWidth < currBlock->mWidth) {
509f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock->mNext = currBlock;
519f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock->mPrev = prevBlock;
529f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            currBlock->mPrev = newBlock;
539b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
549f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (prevBlock) {
559f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                prevBlock->mNext = newBlock;
569f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                return head;
579f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            } else {
589f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                return newBlock;
599f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
609f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
619b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
629f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        prevBlock = currBlock;
639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        currBlock = currBlock->mNext;
649f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
659b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // new block larger than all others - insert at end (but before the remainder space, if there)
679f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    newBlock->mNext = currBlock;
689f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    newBlock->mPrev = prevBlock;
699b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (currBlock) {
719f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        currBlock->mPrev = newBlock;
729f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
739b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (prevBlock) {
759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        prevBlock->mNext = newBlock;
769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return head;
779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    } else {
789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return newBlock;
799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
819f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
82e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain GuyCacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) {
839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            blockToRemove, blockToRemove->mX, blockToRemove->mY,
869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            blockToRemove->mWidth, blockToRemove->mHeight);
879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
889b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* newHead = head;
909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* nextBlock = blockToRemove->mNext;
919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* prevBlock = blockToRemove->mPrev;
929b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (prevBlock) {
949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        prevBlock->mNext = nextBlock;
959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    } else {
969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        newHead = nextBlock;
979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
989b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (nextBlock) {
1009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        nextBlock->mPrev = prevBlock;
1019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
1029b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
1039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    delete blockToRemove;
1049b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
1059f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    return newHead;
1069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
1079f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1089f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
1099f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy// CacheTexture
1109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
1119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1121e546815bbb736c50679a8aefc25f48561026fc5Victoria LeaseCacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) :
1131e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), mFormat(format),
114661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy            mLinearFiltering(false), mDirty(false), mNumGlyphs(0),
1158aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy            mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount),
1168aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy            mCaches(Caches::getInstance()) {
117661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
118e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik            mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE);
119cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
120cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // OpenGL ES 3.0+ lets us specify the row length for unpack operations such
121cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
122cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // With OpenGL ES 2.0 we have to upload entire stripes instead.
123318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    mHasUnpackRowLength = Extensions::getInstance().hasUnpackRowLength();
124661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
125661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
126661a87ec28a49458f1faf533783abf2ab9927cabRomain GuyCacheTexture::~CacheTexture() {
127661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    releaseMesh();
128661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    releaseTexture();
129661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    reset();
130661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
131661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
132661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::reset() {
133661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    // Delete existing cache blocks
134661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    while (mCacheBlocks != NULL) {
135661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        CacheBlock* tmpBlock = mCacheBlocks;
136661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        mCacheBlocks = mCacheBlocks->mNext;
137661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        delete tmpBlock;
138661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
139661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mNumGlyphs = 0;
140661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCurrentQuad = 0;
141661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
142661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
143661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::init() {
144661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    // reset, then create a new remainder space to start again
145661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    reset();
146661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
147e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik            mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE);
148661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
149661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
150661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::releaseMesh() {
151661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    delete[] mMesh;
152661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
153661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
154661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::releaseTexture() {
155661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (mTexture) {
156cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        delete mTexture;
157661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        mTexture = NULL;
158661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
159661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (mTextureId) {
160be1b127c7bec252e0c6ab0e06ed6babed07d496fRomain Guy        mCaches.deleteTexture(mTextureId);
161661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        mTextureId = 0;
162661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
163661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mDirty = false;
164661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCurrentQuad = 0;
165661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
166661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
167cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guyvoid CacheTexture::setLinearFiltering(bool linearFiltering, bool bind) {
168cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy   if (linearFiltering != mLinearFiltering) {
169cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy       mLinearFiltering = linearFiltering;
170cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
171cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy       const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
1728aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy       if (bind) mCaches.bindTexture(getTextureId());
173cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
174cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
175cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy   }
176cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy}
177cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
178661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::allocateMesh() {
179661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (!mMesh) {
180661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        mMesh = new TextureVertex[mMaxQuadCount * 4];
181661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
182661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
183661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
184661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::allocateTexture() {
185661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (!mTexture) {
1861e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        mTexture = PixelBuffer::create(mFormat, mWidth, mHeight);
187661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
188661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
189661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (!mTextureId) {
190661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glGenTextures(1, &mTextureId);
191661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
1928aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy        mCaches.bindTexture(mTextureId);
193661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
194661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        // Initialize texture dimensions
1951e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
1961e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                mFormat, GL_UNSIGNED_BYTE, 0);
197661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
198661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
199661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
200661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
201661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
202661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
203661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
204661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
205661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
206661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
207cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guybool CacheTexture::upload() {
208cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    const Rect& dirtyRect = mDirtyRect;
209cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
210318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    uint32_t x = mHasUnpackRowLength ? dirtyRect.left : 0;
211cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    uint32_t y = dirtyRect.top;
212318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    uint32_t width = mHasUnpackRowLength ? dirtyRect.getWidth() : mWidth;
213cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    uint32_t height = dirtyRect.getHeight();
214cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
215cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // The unpack row length only needs to be specified when a new
216cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // texture is bound
217318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    if (mHasUnpackRowLength) {
218cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        glPixelStorei(GL_UNPACK_ROW_LENGTH, mWidth);
219cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    }
220cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
2211e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    mTexture->upload(x, y, width, height);
222cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    setDirty(false);
223cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
224318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    return mHasUnpackRowLength;
225cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy}
226cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
227cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guyvoid CacheTexture::setDirty(bool dirty) {
228cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    mDirty = dirty;
229cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    if (!dirty) {
230cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        mDirtyRect.setEmpty();
231cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    }
232cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy}
233cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
234e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guybool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
2351e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    switch (glyph.fMaskFormat) {
2361e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        case SkMask::kA8_Format:
237723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease        case SkMask::kBW_Format:
2381e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            if (mFormat != GL_ALPHA) {
2391e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#if DEBUG_FONT_RENDERER
240723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease                ALOGD("fitBitmap: texture format %x is inappropriate for monochromatic glyphs",
241723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease                        mFormat);
2421e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#endif
2431e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                return false;
2441e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            }
2451e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            break;
2461e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        case SkMask::kARGB32_Format:
2471e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            if (mFormat != GL_RGBA) {
2481e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#if DEBUG_FONT_RENDERER
249723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease                ALOGD("fitBitmap: texture format %x is inappropriate for colour glyphs", mFormat);
2501e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#endif
2511e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                return false;
2521e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            }
2531e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            break;
2541e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        default:
2551e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#if DEBUG_FONT_RENDERER
2561e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            ALOGD("fitBitmap: unknown glyph format %x encountered", glyph.fMaskFormat);
2571e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#endif
2581e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            return false;
2591e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    }
2601e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
261e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mHeight) {
2629f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return false;
2639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
2649f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2659f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t glyphW = glyph.fWidth + TEXTURE_BORDER_SIZE;
2669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t glyphH = glyph.fHeight + TEXTURE_BORDER_SIZE;
2679b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
2689f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // roundedUpW equals glyphW to the next multiple of CACHE_BLOCK_ROUNDING_SIZE.
2699f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // This columns for glyphs that are close but not necessarily exactly the same size. It trades
2709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // off the loss of a few pixels for some glyphs against the ability to store more glyphs
2719f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // of varying sizes in one block.
272e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    uint16_t roundedUpW = (glyphW + CACHE_BLOCK_ROUNDING_SIZE - 1) & -CACHE_BLOCK_ROUNDING_SIZE;
2739b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
274e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    CacheBlock* cacheBlock = mCacheBlocks;
2759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    while (cacheBlock) {
2769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // Store glyph in this block iff: it fits the block's remaining space and:
2779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // it's the remainder space (mY == 0) or there's only enough height for this one glyph
2789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // or it's within ROUNDING_SIZE of the block width
2799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (roundedUpW <= cacheBlock->mWidth && glyphH <= cacheBlock->mHeight &&
2809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                (cacheBlock->mY == TEXTURE_BORDER_SIZE ||
2819f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) {
2829f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (cacheBlock->mHeight - glyphH < glyphH) {
2839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // Only enough space for this glyph - don't bother rounding up the width
2849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                roundedUpW = glyphW;
2859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
2869b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
2879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            *retOriginX = cacheBlock->mX;
2889f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            *retOriginY = cacheBlock->mY;
2899b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
2909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            // If this is the remainder space, create a new cache block for this column. Otherwise,
2919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            // adjust the info about this column.
2929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (cacheBlock->mY == TEXTURE_BORDER_SIZE) {
2939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                uint16_t oldX = cacheBlock->mX;
2949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // Adjust remainder space dimensions
2959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mWidth -= roundedUpW;
2969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mX += roundedUpW;
2979b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
2989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                if (mHeight - glyphH >= glyphH) {
2999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    // There's enough height left over to create a new CacheBlock
300e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy                    CacheBlock* newBlock = new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE,
3019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                            roundedUpW, mHeight - glyphH - TEXTURE_BORDER_SIZE);
3029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
3039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
3049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                            newBlock, newBlock->mX, newBlock->mY,
3059f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                            newBlock->mWidth, newBlock->mHeight);
3069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
3079f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    mCacheBlocks = CacheBlock::insertBlock(mCacheBlocks, newBlock);
3089f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                }
3099f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            } else {
3109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // Insert into current column and adjust column dimensions
3119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mY += glyphH;
3129f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mHeight -= glyphH;
3139f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
3149f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                ALOGD("fitBitmap: Added to existing block: this, x, y, w, h = %p, %d, %d, %d, %d",
3159f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        cacheBlock, cacheBlock->mX, cacheBlock->mY,
3169f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        cacheBlock->mWidth, cacheBlock->mHeight);
3179f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
3189f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
3199b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
3209f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (cacheBlock->mHeight < fmin(glyphH, glyphW)) {
3219f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // If remaining space in this block is too small to be useful, remove it
3229f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                mCacheBlocks = CacheBlock::removeBlock(mCacheBlocks, cacheBlock);
3239f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
3249b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
3259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            mDirty = true;
326b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase            const Rect r(*retOriginX - TEXTURE_BORDER_SIZE, *retOriginY - TEXTURE_BORDER_SIZE,
327b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase                    *retOriginX + glyphW, *retOriginY + glyphH);
328b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase            mDirtyRect.unionWith(r);
3299b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy            mNumGlyphs++;
3309b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
3319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
3329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            ALOGD("fitBitmap: current block list:");
3339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            mCacheBlocks->output();
3349f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
3359b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
3369f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            return true;
3379f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
3389f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        cacheBlock = cacheBlock->mNext;
3399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
3409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
3419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    ALOGD("fitBitmap: returning false for glyph of size %d, %d", glyphW, glyphH);
3429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
3439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    return false;
3449f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
3459f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3469f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace uirenderer
3479f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace android
348