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 
CacheBlockCacheBlock56     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 
outputCacheBlock63     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 
getWidth()94     inline uint16_t getWidth() const {
95         return mWidth;
96     }
97 
getHeight()98     inline uint16_t getHeight() const {
99         return mHeight;
100     }
101 
getFormat()102     inline GLenum getFormat() const {
103         return mFormat;
104     }
105 
getOffset(uint16_t x,uint16_t y)106     inline uint32_t getOffset(uint16_t x, uint16_t y) const {
107         return (y * getWidth() + x) * PixelBuffer::formatSize(mFormat);
108     }
109 
getDirtyRect()110     inline const Rect* getDirtyRect() const {
111         return &mDirtyRect;
112     }
113 
getPixelBuffer()114     inline PixelBuffer* getPixelBuffer() const {
115         return mPixelBuffer;
116     }
117 
getTexture()118     Texture& getTexture() {
119         allocatePixelBuffer();
120         return mTexture;
121     }
122 
getTextureId()123     GLuint getTextureId() {
124         allocatePixelBuffer();
125         return mTexture.id();
126     }
127 
isDirty()128     inline bool isDirty() const {
129         return mDirty;
130     }
131 
getLinearFiltering()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 
getGlyphCount()141     inline uint16_t getGlyphCount() const {
142         return mNumGlyphs;
143     }
144 
mesh()145     TextureVertex* mesh() const {
146         return mMesh;
147     }
148 
meshElementCount()149     uint32_t meshElementCount() const {
150         return mCurrentQuad * 6;
151     }
152 
indices()153     uint16_t* indices() const {
154         return (uint16_t*) nullptr;
155     }
156 
resetMesh()157     void resetMesh() {
158         mCurrentQuad = 0;
159     }
160 
addQuad(float x1,float y1,float u1,float v1,float x2,float y2,float u2,float v2,float x3,float y3,float u3,float v3,float x4,float y4,float u4,float v4)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 
canDraw()173     bool canDraw() const {
174         return mCurrentQuad > 0;
175     }
176 
endOfMesh()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