CacheTexture.h revision 8087246d9964b11de8ce116bc63b156faa4197e0
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
179f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#ifndef ANDROID_HWUI_CACHE_TEXTURE_H
189f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#define ANDROID_HWUI_CACHE_TEXTURE_H
199f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
209f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include <GLES2/gl2.h>
219f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
229f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include <SkScalerContext.h>
239f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
249f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include <utils/Log.h>
259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
269f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include "FontUtil.h"
279f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
289f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace android {
299f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace uirenderer {
309f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy/**
329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right.
349f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * When we add a glyph to the cache, we see if it fits within one of the existing columns that
359f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * have already been started (this is the case if the glyph fits vertically as well as
369f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * horizontally, and if its width is sufficiently close to the column width to avoid
379f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * sub-optimal packing of small glyphs into wide columns). If there is no column in which the
389f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * glyph fits, we check the final node, which is the remaining space in the cache, creating
399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * a new column as appropriate.
409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *
419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * As columns fill up, we remove their CacheBlock from the list to avoid having to check
429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * small blocks in the future.
439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy */
449f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guystruct CacheBlock {
459f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t mX;
469f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t mY;
479f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t mWidth;
489f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t mHeight;
499f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* mNext;
509f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* mPrev;
519f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
529f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height, bool empty = false):
539b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy            mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL) {
549f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
559f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
569f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    static CacheBlock* insertBlock(CacheBlock* head, CacheBlock *newBlock);
579f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
589f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    static CacheBlock* removeBlock(CacheBlock* head, CacheBlock *blockToRemove);
599f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
609f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    void output() {
619f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        CacheBlock *currBlock = this;
629f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        while (currBlock) {
639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d",
649f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    currBlock, currBlock->mX, currBlock->mY, currBlock->mWidth, currBlock->mHeight);
659f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            currBlock = currBlock->mNext;
669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
679f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
689f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy};
699f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyclass CacheTexture {
719f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guypublic:
729f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheTexture(uint16_t width, uint16_t height) :
739f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            mLinearFiltering(false), mDirty(false), mNumGlyphs(0) {
759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    ~CacheTexture() {
809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (mTexture) {
819f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            delete[] mTexture;
829f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (mTextureId) {
849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            glDeleteTextures(1, &mTextureId);
859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        reset();
879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
889f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    void reset() {
909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // Delete existing cache blocks
919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        while (mCacheBlocks != NULL) {
929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            CacheBlock* tmpBlock = mCacheBlocks;
939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            mCacheBlocks = mCacheBlocks->mNext;
949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            delete tmpBlock;
959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        mNumGlyphs = 0;
979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    void init() {
1009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // reset, then create a new remainder space to start again
1019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        reset();
1029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
1039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
1049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
1059f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1068087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    void releaseTexture() {
1078087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        if (mTexture) {
1088087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            glDeleteTextures(1, &mTextureId);
1098087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            delete[] mTexture;
1108087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            mTexture = NULL;
1118087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            mTextureId = 0;
1128087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        }
1138087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1148087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1158087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    /**
1168087246d9964b11de8ce116bc63b156faa4197e0Romain Guy     * This method assumes that the proper texture unit is active.
1178087246d9964b11de8ce116bc63b156faa4197e0Romain Guy     */
1188087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    void allocateTexture() {
1198087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        int width = mWidth;
1208087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        int height = mHeight;
1218087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1228087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        mTexture = new uint8_t[width * height];
1238087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1248087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        if (!mTextureId) {
1258087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            glGenTextures(1, &mTextureId);
1268087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        }
1278087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1288087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        glBindTexture(GL_TEXTURE_2D, mTextureId);
1298087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1308087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        // Initialize texture dimensions
1318087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
1328087246d9964b11de8ce116bc63b156faa4197e0Romain Guy                GL_ALPHA, GL_UNSIGNED_BYTE, 0);
1338087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1348087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
1358087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
1368087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
1378087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1388087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1398087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1408087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1418087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);
1439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1448087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline uint16_t getWidth() const {
1458087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mWidth;
1468087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1478087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1488087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline uint16_t getHeight() const {
1498087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mHeight;
1508087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1518087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1528087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline uint8_t* getTexture() const {
1538087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mTexture;
1548087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1558087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1568087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline GLuint getTextureId() const {
1578087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mTextureId;
1588087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1598087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1608087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline bool isDirty() const {
1618087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mDirty;
1628087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1638087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1648087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline void setDirty(bool dirty) {
1658087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        mDirty = dirty;
1668087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1678087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1688087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline bool getLinearFiltering() const {
1698087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mLinearFiltering;
1708087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1718087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1728087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    /**
1738087246d9964b11de8ce116bc63b156faa4197e0Romain Guy     * This method assumes that the proper texture unit is active.
1748087246d9964b11de8ce116bc63b156faa4197e0Romain Guy     */
1758087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    void setLinearFiltering(bool linearFiltering, bool bind = true) {
1768087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        if (linearFiltering != mLinearFiltering) {
1778087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            mLinearFiltering = linearFiltering;
1788087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1798087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
1808087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            if (bind) glBindTexture(GL_TEXTURE_2D, getTextureId());
1818087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
1828087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
1838087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        }
1848087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1858087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1868087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline uint16_t getGlyphCount() const {
1878087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mNumGlyphs;
1888087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1898087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1908087246d9964b11de8ce116bc63b156faa4197e0Romain Guyprivate:
1919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint8_t* mTexture;
1929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    GLuint mTextureId;
1939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t mWidth;
1949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t mHeight;
1959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    bool mLinearFiltering;
1969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    bool mDirty;
1979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t mNumGlyphs;
1989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* mCacheBlocks;
1999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy};
2009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace uirenderer
2029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace android
2039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif // ANDROID_HWUI_CACHE_TEXTURE_H
205