CacheTexture.h revision cf51a4199835e9604aa4c8b3854306f8fbabbf33
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
33class PixelBuffer;
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 */
48struct 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, bool empty = false):
57            mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL) {
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
74class CacheTexture {
75public:
76    CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount);
77    ~CacheTexture();
78
79    void reset();
80    void init();
81
82    void releaseMesh();
83    void releaseTexture();
84
85    void allocateTexture();
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 const Rect* getDirtyRect() const {
103        return &mDirtyRect;
104    }
105
106    inline PixelBuffer* getPixelBuffer() const {
107        return mTexture;
108    }
109
110    GLuint getTextureId() {
111        allocateTexture();
112        return mTextureId;
113    }
114
115    inline bool isDirty() const {
116        return mDirty;
117    }
118
119    inline bool getLinearFiltering() const {
120        return mLinearFiltering;
121    }
122
123    /**
124     * This method assumes that the proper texture unit is active.
125     */
126    void setLinearFiltering(bool linearFiltering, bool bind = true);
127
128    inline uint16_t getGlyphCount() const {
129        return mNumGlyphs;
130    }
131
132    TextureVertex* mesh() const {
133        return mMesh;
134    }
135
136    uint32_t meshElementCount() const {
137        return mCurrentQuad * 6;
138    }
139
140    uint16_t* indices() const {
141        return (uint16_t*) 0;
142    }
143
144    void resetMesh() {
145        mCurrentQuad = 0;
146    }
147
148    inline void addQuad(float x1, float y1, float u1, float v1,
149            float x2, float y2, float u2, float v2,
150            float x3, float y3, float u3, float v3,
151            float x4, float y4, float u4, float v4) {
152        TextureVertex* mesh = mMesh + mCurrentQuad * 4;
153        TextureVertex::set(mesh++, x1, y1, u1, v1);
154        TextureVertex::set(mesh++, x2, y2, u2, v2);
155        TextureVertex::set(mesh++, x3, y3, u3, v3);
156        TextureVertex::set(mesh++, x4, y4, u4, v4);
157        mCurrentQuad++;
158    }
159
160    bool canDraw() const {
161        return mCurrentQuad > 0;
162    }
163
164    bool endOfMesh() const {
165        return mCurrentQuad == mMaxQuadCount;
166    }
167
168private:
169    void setDirty(bool dirty);
170
171    PixelBuffer* mTexture;
172    GLuint mTextureId;
173    uint16_t mWidth;
174    uint16_t mHeight;
175    bool mLinearFiltering;
176    bool mDirty;
177    uint16_t mNumGlyphs;
178    TextureVertex* mMesh;
179    uint32_t mCurrentQuad;
180    uint32_t mMaxQuadCount;
181    CacheBlock* mCacheBlocks;
182    Rect mDirtyRect;
183    bool mHasES3;
184};
185
186}; // namespace uirenderer
187}; // namespace android
188
189#endif // ANDROID_HWUI_CACHE_TEXTURE_H
190