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