blob: 57429415254f51f34c53c81fa5b1d93dd112a089 [file] [log] [blame]
Romain Guy9f5dab32012-09-04 12:55:44 -07001/*
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 <GLES2/gl2.h>
21
22#include <SkScalerContext.h>
23
24#include <utils/Log.h>
25
26#include "FontUtil.h"
Romain Guy661a87e2013-03-19 15:24:36 -070027#include "../Rect.h"
28#include "../Vertex.h"
Romain Guy9f5dab32012-09-04 12:55:44 -070029
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):
Romain Guy9b1204b2012-09-04 15:22:57 -070055 mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL) {
Romain Guy9f5dab32012-09-04 12:55:44 -070056 }
57
Romain Guye43f7852012-09-04 18:58:46 -070058 static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock);
Romain Guye43f7852012-09-04 18:58:46 -070059 static CacheBlock* removeBlock(CacheBlock* head, CacheBlock* blockToRemove);
Romain Guy9f5dab32012-09-04 12:55:44 -070060
61 void output() {
Romain Guye43f7852012-09-04 18:58:46 -070062 CacheBlock* currBlock = this;
Romain Guy9f5dab32012-09-04 12:55:44 -070063 while (currBlock) {
64 ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d",
Romain Guy661a87e2013-03-19 15:24:36 -070065 currBlock, currBlock->mX, currBlock->mY,
66 currBlock->mWidth, currBlock->mHeight);
Romain Guy9f5dab32012-09-04 12:55:44 -070067 currBlock = currBlock->mNext;
68 }
69 }
70};
71
72class CacheTexture {
73public:
Romain Guy661a87e2013-03-19 15:24:36 -070074 CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount);
75 ~CacheTexture();
Romain Guy9f5dab32012-09-04 12:55:44 -070076
Romain Guy661a87e2013-03-19 15:24:36 -070077 void reset();
78 void init();
Romain Guy9f5dab32012-09-04 12:55:44 -070079
Romain Guy661a87e2013-03-19 15:24:36 -070080 void releaseMesh();
81 void releaseTexture();
Romain Guy9f5dab32012-09-04 12:55:44 -070082
Romain Guy661a87e2013-03-19 15:24:36 -070083 void allocateTexture();
84 void allocateMesh();
Romain Guy80872462012-09-04 16:42:01 -070085
Romain Guye43f7852012-09-04 18:58:46 -070086 bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
Romain Guy9f5dab32012-09-04 12:55:44 -070087
Romain Guy80872462012-09-04 16:42:01 -070088 inline uint16_t getWidth() const {
89 return mWidth;
90 }
91
92 inline uint16_t getHeight() const {
93 return mHeight;
94 }
95
Chet Haaseb92d8f72012-09-21 08:40:46 -070096 inline const Rect* getDirtyRect() const {
97 return &mDirtyRect;
98 }
99
Romain Guy80872462012-09-04 16:42:01 -0700100 inline uint8_t* getTexture() const {
101 return mTexture;
102 }
103
Romain Guy574cf602012-09-23 14:45:31 -0700104 GLuint getTextureId() {
105 allocateTexture();
Romain Guy80872462012-09-04 16:42:01 -0700106 return mTextureId;
107 }
108
109 inline bool isDirty() const {
110 return mDirty;
111 }
112
113 inline void setDirty(bool dirty) {
114 mDirty = dirty;
Chet Haaseb92d8f72012-09-21 08:40:46 -0700115 if (!dirty) {
116 mDirtyRect.setEmpty();
117 }
Romain Guy80872462012-09-04 16:42:01 -0700118 }
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
Romain Guy661a87e2013-03-19 15:24:36 -0700142 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
Romain Guy80872462012-09-04 16:42:01 -0700178private:
Romain Guy9f5dab32012-09-04 12:55:44 -0700179 uint8_t* mTexture;
180 GLuint mTextureId;
181 uint16_t mWidth;
182 uint16_t mHeight;
183 bool mLinearFiltering;
184 bool mDirty;
185 uint16_t mNumGlyphs;
Romain Guy661a87e2013-03-19 15:24:36 -0700186 TextureVertex* mMesh;
187 uint32_t mCurrentQuad;
188 uint32_t mMaxQuadCount;
Romain Guy9f5dab32012-09-04 12:55:44 -0700189 CacheBlock* mCacheBlocks;
Chet Haaseb92d8f72012-09-21 08:40:46 -0700190 Rect mDirtyRect;
Romain Guy9f5dab32012-09-04 12:55:44 -0700191};
192
193}; // namespace uirenderer
194}; // namespace android
195
196#endif // ANDROID_HWUI_CACHE_TEXTURE_H