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