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 "PixelBuffer.h"
     21 #include "Rect.h"
     22 #include "Texture.h"
     23 #include "Vertex.h"
     24 
     25 #include <GLES3/gl3.h>
     26 #include <SkGlyph.h>
     27 #include <utils/Log.h>
     28 
     29 
     30 namespace android {
     31 namespace uirenderer {
     32 
     33 class Caches;
     34 
     35 /**
     36  * CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
     37  * Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right.
     38  * When we add a glyph to the cache, we see if it fits within one of the existing columns that
     39  * have already been started (this is the case if the glyph fits vertically as well as
     40  * horizontally, and if its width is sufficiently close to the column width to avoid
     41  * sub-optimal packing of small glyphs into wide columns). If there is no column in which the
     42  * glyph fits, we check the final node, which is the remaining space in the cache, creating
     43  * a new column as appropriate.
     44  *
     45  * As columns fill up, we remove their CacheBlock from the list to avoid having to check
     46  * small blocks in the future.
     47  */
     48 struct CacheBlock {
     49     uint16_t mX;
     50     uint16_t mY;
     51     uint16_t mWidth;
     52     uint16_t mHeight;
     53     CacheBlock* mNext;
     54     CacheBlock* mPrev;
     55 
     56     CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height):
     57             mX(x), mY(y), mWidth(width), mHeight(height), mNext(nullptr), mPrev(nullptr) {
     58     }
     59 
     60     static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock);
     61     static CacheBlock* removeBlock(CacheBlock* head, CacheBlock* blockToRemove);
     62 
     63     void output() {
     64         CacheBlock* currBlock = this;
     65         while (currBlock) {
     66             ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d",
     67                     currBlock, currBlock->mX, currBlock->mY,
     68                     currBlock->mWidth, currBlock->mHeight);
     69             currBlock = currBlock->mNext;
     70         }
     71     }
     72 };
     73 
     74 class CacheTexture {
     75 public:
     76     CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount);
     77     ~CacheTexture();
     78 
     79     void reset();
     80     void init();
     81 
     82     void releaseMesh();
     83     void releasePixelBuffer();
     84 
     85     void allocatePixelBuffer();
     86     void allocateMesh();
     87 
     88     // Returns true if glPixelStorei(GL_UNPACK_ROW_LENGTH) must be reset
     89     // This method will also call setDirty(false)
     90     bool upload();
     91 
     92     bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
     93 
     94     inline uint16_t getWidth() const {
     95         return mWidth;
     96     }
     97 
     98     inline uint16_t getHeight() const {
     99         return mHeight;
    100     }
    101 
    102     inline GLenum getFormat() const {
    103         return mFormat;
    104     }
    105 
    106     inline uint32_t getOffset(uint16_t x, uint16_t y) const {
    107         return (y * getWidth() + x) * PixelBuffer::formatSize(mFormat);
    108     }
    109 
    110     inline const Rect* getDirtyRect() const {
    111         return &mDirtyRect;
    112     }
    113 
    114     inline PixelBuffer* getPixelBuffer() const {
    115         return mPixelBuffer;
    116     }
    117 
    118     Texture& getTexture() {
    119         allocatePixelBuffer();
    120         return mTexture;
    121     }
    122 
    123     GLuint getTextureId() {
    124         allocatePixelBuffer();
    125         return mTexture.id();
    126     }
    127 
    128     inline bool isDirty() const {
    129         return mDirty;
    130     }
    131 
    132     inline bool getLinearFiltering() const {
    133         return mLinearFiltering;
    134     }
    135 
    136     /**
    137      * This method assumes that the proper texture unit is active.
    138      */
    139     void setLinearFiltering(bool linearFiltering);
    140 
    141     inline uint16_t getGlyphCount() const {
    142         return mNumGlyphs;
    143     }
    144 
    145     TextureVertex* mesh() const {
    146         return mMesh;
    147     }
    148 
    149     uint32_t meshElementCount() const {
    150         return mCurrentQuad * 6;
    151     }
    152 
    153     uint16_t* indices() const {
    154         return (uint16_t*) nullptr;
    155     }
    156 
    157     void resetMesh() {
    158         mCurrentQuad = 0;
    159     }
    160 
    161     inline void addQuad(float x1, float y1, float u1, float v1,
    162             float x2, float y2, float u2, float v2,
    163             float x3, float y3, float u3, float v3,
    164             float x4, float y4, float u4, float v4) {
    165         TextureVertex* mesh = mMesh + mCurrentQuad * 4;
    166         TextureVertex::set(mesh++, x2, y2, u2, v2);
    167         TextureVertex::set(mesh++, x3, y3, u3, v3);
    168         TextureVertex::set(mesh++, x1, y1, u1, v1);
    169         TextureVertex::set(mesh++, x4, y4, u4, v4);
    170         mCurrentQuad++;
    171     }
    172 
    173     bool canDraw() const {
    174         return mCurrentQuad > 0;
    175     }
    176 
    177     bool endOfMesh() const {
    178         return mCurrentQuad == mMaxQuadCount;
    179     }
    180 
    181 private:
    182     void setDirty(bool dirty);
    183 
    184     PixelBuffer* mPixelBuffer = nullptr;
    185     Texture mTexture;
    186     uint32_t mWidth, mHeight;
    187     GLenum mFormat;
    188     bool mLinearFiltering = false;
    189     bool mDirty = false;
    190     uint16_t mNumGlyphs = 0;
    191     TextureVertex* mMesh = nullptr;
    192     uint32_t mCurrentQuad = 0;
    193     uint32_t mMaxQuadCount;
    194     Caches& mCaches;
    195     CacheBlock* mCacheBlocks;
    196     bool mHasUnpackRowLength;
    197     Rect mDirtyRect;
    198 };
    199 
    200 }; // namespace uirenderer
    201 }; // namespace android
    202 
    203 #endif // ANDROID_HWUI_CACHE_TEXTURE_H
    204