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() {
81574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy        releaseTexture();
829f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        reset();
839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    void reset() {
869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // Delete existing cache blocks
879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        while (mCacheBlocks != NULL) {
889f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            CacheBlock* tmpBlock = mCacheBlocks;
899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            mCacheBlocks = mCacheBlocks->mNext;
909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            delete tmpBlock;
919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        mNumGlyphs = 0;
939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    void init() {
969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // reset, then create a new remainder space to start again
979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        reset();
989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
1009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
1019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1028087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    void releaseTexture() {
1038087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        if (mTexture) {
1048087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            delete[] mTexture;
1058087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            mTexture = NULL;
106574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy        }
107574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy        if (mTextureId) {
108574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy            glDeleteTextures(1, &mTextureId);
1098087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            mTextureId = 0;
1108087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        }
111574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy        mDirty = false;
1128087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1138087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1148087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    /**
1158087246d9964b11de8ce116bc63b156faa4197e0Romain Guy     * This method assumes that the proper texture unit is active.
1168087246d9964b11de8ce116bc63b156faa4197e0Romain Guy     */
1178087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    void allocateTexture() {
118574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy        if (!mTexture) {
119574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy            mTexture = new uint8_t[mWidth * mHeight];
120574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy        }
1218087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1228087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        if (!mTextureId) {
1238087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            glGenTextures(1, &mTextureId);
1248087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
125574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy            glBindTexture(GL_TEXTURE_2D, mTextureId);
126574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
127574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy            // Initialize texture dimensions
128574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy            glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mWidth, mHeight, 0,
129574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy                    GL_ALPHA, GL_UNSIGNED_BYTE, 0);
1308087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
131574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy            const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
132574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
133574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
1348087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
135574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
136574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
137574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy        }
1388087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1398087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
140e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
1419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1428087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline uint16_t getWidth() const {
1438087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mWidth;
1448087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1458087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1468087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline uint16_t getHeight() const {
1478087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mHeight;
1488087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1498087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
150b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase    inline const Rect* getDirtyRect() const {
151b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase        return &mDirtyRect;
152b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase    }
153b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase
1548087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline uint8_t* getTexture() const {
1558087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mTexture;
1568087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1578087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
158574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy    GLuint getTextureId() {
159574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy        allocateTexture();
1608087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mTextureId;
1618087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1628087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1638087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline bool isDirty() const {
1648087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mDirty;
1658087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1668087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1678087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline void setDirty(bool dirty) {
1688087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        mDirty = dirty;
169b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase        if (!dirty) {
170b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase            mDirtyRect.setEmpty();
171b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase        }
1728087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1738087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1748087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline bool getLinearFiltering() const {
1758087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mLinearFiltering;
1768087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1778087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1788087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    /**
1798087246d9964b11de8ce116bc63b156faa4197e0Romain Guy     * This method assumes that the proper texture unit is active.
1808087246d9964b11de8ce116bc63b156faa4197e0Romain Guy     */
1818087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    void setLinearFiltering(bool linearFiltering, bool bind = true) {
1828087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        if (linearFiltering != mLinearFiltering) {
1838087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            mLinearFiltering = linearFiltering;
1848087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1858087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
1868087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            if (bind) glBindTexture(GL_TEXTURE_2D, getTextureId());
1878087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
1888087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
1898087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        }
1908087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1918087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1928087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    inline uint16_t getGlyphCount() const {
1938087246d9964b11de8ce116bc63b156faa4197e0Romain Guy        return mNumGlyphs;
1948087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    }
1958087246d9964b11de8ce116bc63b156faa4197e0Romain Guy
1968087246d9964b11de8ce116bc63b156faa4197e0Romain Guyprivate:
1979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint8_t* mTexture;
1989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    GLuint mTextureId;
1999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t mWidth;
2009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t mHeight;
2019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    bool mLinearFiltering;
2029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    bool mDirty;
2039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t mNumGlyphs;
2049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* mCacheBlocks;
205b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase    Rect mDirtyRect;
2069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy};
2079f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2089f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace uirenderer
2099f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace android
2109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif // ANDROID_HWUI_CACHE_TEXTURE_H
212