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