CacheTexture.h revision d392b87e3d30cd4f0836623d848019c5724efce8
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 <GLES2/gl2.h> 21 22#include <SkScalerContext.h> 23 24#include <utils/Log.h> 25 26#include "FontUtil.h" 27#include "Rect.h" 28 29namespace android { 30namespace uirenderer { 31 32/** 33 * CacheBlock is a node in a linked list of current free space areas in a CacheTexture. 34 * Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right. 35 * When we add a glyph to the cache, we see if it fits within one of the existing columns that 36 * have already been started (this is the case if the glyph fits vertically as well as 37 * horizontally, and if its width is sufficiently close to the column width to avoid 38 * sub-optimal packing of small glyphs into wide columns). If there is no column in which the 39 * glyph fits, we check the final node, which is the remaining space in the cache, creating 40 * a new column as appropriate. 41 * 42 * As columns fill up, we remove their CacheBlock from the list to avoid having to check 43 * small blocks in the future. 44 */ 45struct CacheBlock { 46 uint16_t mX; 47 uint16_t mY; 48 uint16_t mWidth; 49 uint16_t mHeight; 50 CacheBlock* mNext; 51 CacheBlock* mPrev; 52 53 CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height, bool empty = false): 54 mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL) { 55 } 56 57 static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock); 58 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, currBlock->mWidth, currBlock->mHeight); 66 currBlock = currBlock->mNext; 67 } 68 } 69}; 70 71class CacheTexture { 72public: 73 CacheTexture(uint16_t width, uint16_t height) : 74 mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), 75 mLinearFiltering(false), mDirty(false), mNumGlyphs(0) { 76 mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, 77 mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true); 78 } 79 80 ~CacheTexture() { 81 releaseTexture(); 82 reset(); 83 } 84 85 void reset() { 86 // Delete existing cache blocks 87 while (mCacheBlocks != NULL) { 88 CacheBlock* tmpBlock = mCacheBlocks; 89 mCacheBlocks = mCacheBlocks->mNext; 90 delete tmpBlock; 91 } 92 mNumGlyphs = 0; 93 } 94 95 void init() { 96 // reset, then create a new remainder space to start again 97 reset(); 98 mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, 99 mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true); 100 } 101 102 void releaseTexture() { 103 if (mTexture) { 104 delete[] mTexture; 105 mTexture = NULL; 106 } 107 if (mTextureId) { 108 glDeleteTextures(1, &mTextureId); 109 mTextureId = 0; 110 } 111 mDirty = false; 112 } 113 114 /** 115 * This method assumes that the proper texture unit is active. 116 */ 117 void allocateTexture() { 118 if (!mTexture) { 119 mTexture = new uint8_t[mWidth * mHeight]; 120 } 121 122 if (!mTextureId) { 123 glGenTextures(1, &mTextureId); 124 125 glBindTexture(GL_TEXTURE_2D, mTextureId); 126 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 127 // Initialize texture dimensions 128 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mWidth, mHeight, 0, 129 GL_ALPHA, GL_UNSIGNED_BYTE, 0); 130 131 const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST; 132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 133 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 134 135 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 137 } 138 } 139 140 bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY); 141 142 inline uint16_t getWidth() const { 143 return mWidth; 144 } 145 146 inline uint16_t getHeight() const { 147 return mHeight; 148 } 149 150 inline const Rect* getDirtyRect() const { 151 return &mDirtyRect; 152 } 153 154 inline uint8_t* getTexture() const { 155 return mTexture; 156 } 157 158 GLuint getTextureId() { 159 allocateTexture(); 160 return mTextureId; 161 } 162 163 inline bool isDirty() const { 164 return mDirty; 165 } 166 167 inline void setDirty(bool dirty) { 168 mDirty = dirty; 169 if (!dirty) { 170 mDirtyRect.setEmpty(); 171 } 172 } 173 174 inline bool getLinearFiltering() const { 175 return mLinearFiltering; 176 } 177 178 /** 179 * This method assumes that the proper texture unit is active. 180 */ 181 void setLinearFiltering(bool linearFiltering, bool bind = true) { 182 if (linearFiltering != mLinearFiltering) { 183 mLinearFiltering = linearFiltering; 184 185 const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST; 186 if (bind) glBindTexture(GL_TEXTURE_2D, getTextureId()); 187 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 188 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 189 } 190 } 191 192 inline uint16_t getGlyphCount() const { 193 return mNumGlyphs; 194 } 195 196private: 197 uint8_t* mTexture; 198 GLuint mTextureId; 199 uint16_t mWidth; 200 uint16_t mHeight; 201 bool mLinearFiltering; 202 bool mDirty; 203 uint16_t mNumGlyphs; 204 CacheBlock* mCacheBlocks; 205 Rect mDirtyRect; 206}; 207 208}; // namespace uirenderer 209}; // namespace android 210 211#endif // ANDROID_HWUI_CACHE_TEXTURE_H 212