Home | History | Annotate | Download | only in font
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ANDROID_HWUI_CACHE_TEXTURE_H
     18 #define ANDROID_HWUI_CACHE_TEXTURE_H
     19 
     20 #include <GLES3/gl3.h>
     21 
     22 #include <SkScalerContext.h>
     23 
     24 #include <utils/Log.h>
     25 
     26 #include "FontUtil.h"
     27 #include "../PixelBuffer.h"
     28 #include "../Rect.h"
     29 #include "../Vertex.h"
     30 
     31 namespace android {
     32 namespace uirenderer {
     33 
     34 class Caches;
     35 
     36 /**
     37  * CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
     38  * Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right.
     39  * When we add a glyph to the cache, we see if it fits within one of the existing columns that
     40  * have already been started (this is the case if the glyph fits vertically as well as
     41  * horizontally, and if its width is sufficiently close to the column width to avoid
     42  * sub-optimal packing of small glyphs into wide columns). If there is no column in which the
     43  * glyph fits, we check the final node, which is the remaining space in the cache, creating
     44  * a new column as appropriate.
     45  *
     46  * As columns fill up, we remove their CacheBlock from the list to avoid having to check
     47  * small blocks in the future.
     48  */
     49 struct CacheBlock {
     50     uint16_t mX;
     51     uint16_t mY;
     52     uint16_t mWidth;
     53     uint16_t mHeight;
     54     CacheBlock* mNext;
     55     CacheBlock* mPrev;
     56 
     57     CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height, bool empty = false):
     58             mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL) {
     59     }
     60 
     61     static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock);
     62     static CacheBlock* removeBlock(CacheBlock* head, CacheBlock* blockToRemove);
     63 
     64     void output() {
     65         CacheBlock* currBlock = this;
     66         while (currBlock) {
     67             ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d",
     68                     currBlock, currBlock->mX, currBlock->mY,
     69                     currBlock->mWidth, currBlock->mHeight);
     70             currBlock = currBlock->mNext;
     71         }
     72     }
     73 };
     74 
     75 class CacheTexture {
     76 public:
     77     CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount);
     78     ~CacheTexture();
     79 
     80     void reset();
     81     void init();
     82 
     83     void releaseMesh();
     84     void releaseTexture();
     85 
     86     void allocateTexture();
     87     void allocateMesh();
     88 
     89     // Returns true if glPixelStorei(GL_UNPACK_ROW_LENGTH) must be reset
     90     // This method will also call setDirty(false)
     91     bool upload();
     92 
     93     bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
     94 
     95     inline uint16_t getWidth() const {
     96         return mWidth;
     97     }
     98 
     99     inline uint16_t getHeight() const {
    100         return mHeight;
    101     }
    102 
    103     inline GLenum getFormat() const {
    104         return mFormat;
    105     }
    106 
    107     inline uint32_t getOffset(uint16_t x, uint16_t y) const {
    108         return (y * mWidth + x) * PixelBuffer::formatSize(mFormat);
    109     }
    110 
    111     inline const Rect* getDirtyRect() const {
    112         return &mDirtyRect;
    113     }
    114 
    115     inline PixelBuffer* getPixelBuffer() const {
    116         return mTexture;
    117     }
    118 
    119     GLuint getTextureId() {
    120         allocateTexture();
    121         return mTextureId;
    122     }
    123 
    124     inline bool isDirty() const {
    125         return mDirty;
    126     }
    127 
    128     inline bool getLinearFiltering() const {
    129         return mLinearFiltering;
    130     }
    131 
    132     /**
    133      * This method assumes that the proper texture unit is active.
    134      */
    135     void setLinearFiltering(bool linearFiltering, bool bind = true);
    136 
    137     inline uint16_t getGlyphCount() const {
    138         return mNumGlyphs;
    139     }
    140 
    141     TextureVertex* mesh() const {
    142         return mMesh;
    143     }
    144 
    145     uint32_t meshElementCount() const {
    146         return mCurrentQuad * 6;
    147     }
    148 
    149     uint16_t* indices() const {
    150         return (uint16_t*) 0;
    151     }
    152 
    153     void resetMesh() {
    154         mCurrentQuad = 0;
    155     }
    156 
    157     inline void addQuad(float x1, float y1, float u1, float v1,
    158             float x2, float y2, float u2, float v2,
    159             float x3, float y3, float u3, float v3,
    160             float x4, float y4, float u4, float v4) {
    161         TextureVertex* mesh = mMesh + mCurrentQuad * 4;
    162         TextureVertex::set(mesh++, x2, y2, u2, v2);
    163         TextureVertex::set(mesh++, x3, y3, u3, v3);
    164         TextureVertex::set(mesh++, x1, y1, u1, v1);
    165         TextureVertex::set(mesh++, x4, y4, u4, v4);
    166         mCurrentQuad++;
    167     }
    168 
    169     bool canDraw() const {
    170         return mCurrentQuad > 0;
    171     }
    172 
    173     bool endOfMesh() const {
    174         return mCurrentQuad == mMaxQuadCount;
    175     }
    176 
    177 private:
    178     void setDirty(bool dirty);
    179 
    180     PixelBuffer* mTexture;
    181     GLuint mTextureId;
    182     uint16_t mWidth;
    183     uint16_t mHeight;
    184     GLenum mFormat;
    185     bool mLinearFiltering;
    186     bool mDirty;
    187     uint16_t mNumGlyphs;
    188     TextureVertex* mMesh;
    189     uint32_t mCurrentQuad;
    190     uint32_t mMaxQuadCount;
    191     Caches& mCaches;
    192     CacheBlock* mCacheBlocks;
    193     bool mHasUnpackRowLength;
    194     Rect mDirtyRect;
    195 };
    196 
    197 }; // namespace uirenderer
    198 }; // namespace android
    199 
    200 #endif // ANDROID_HWUI_CACHE_TEXTURE_H
    201