19f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy/* 29f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Copyright (C) 2012 The Android Open Source Project 39f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * 49f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 59f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * you may not use this file except in compliance with the License. 69f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * You may obtain a copy of the License at 79f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * 89f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * http://www.apache.org/licenses/LICENSE-2.0 99f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * 109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Unless required by applicable law or agreed to in writing, software 119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * distributed under the License is distributed on an "AS IS" BASIS, 129f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * See the License for the specific language governing permissions and 149f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * limitations under the License. 159f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy */ 169f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 179f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#ifndef ANDROID_HWUI_CACHE_TEXTURE_H 189f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#define ANDROID_HWUI_CACHE_TEXTURE_H 199f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 209f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include <GLES2/gl2.h> 219f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 229f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include <SkScalerContext.h> 239f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 249f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include <utils/Log.h> 259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 269f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include "FontUtil.h" 27b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase#include "Rect.h" 289f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 299f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace android { 309f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace uirenderer { 319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy/** 339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * CacheBlock is a node in a linked list of current free space areas in a CacheTexture. 349f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right. 359f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * When we add a glyph to the cache, we see if it fits within one of the existing columns that 369f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * have already been started (this is the case if the glyph fits vertically as well as 379f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * horizontally, and if its width is sufficiently close to the column width to avoid 389f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * sub-optimal packing of small glyphs into wide columns). If there is no column in which the 399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * glyph fits, we check the final node, which is the remaining space in the cache, creating 409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * a new column as appropriate. 419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * 429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * As columns fill up, we remove their CacheBlock from the list to avoid having to check 439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * small blocks in the future. 449f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy */ 459f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guystruct CacheBlock { 469f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy uint16_t mX; 479f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy uint16_t mY; 489f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy uint16_t mWidth; 499f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy uint16_t mHeight; 509f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy CacheBlock* mNext; 519f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy CacheBlock* mPrev; 529f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 539f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height, bool empty = false): 549b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL) { 559f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy } 569f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 57e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock); 589f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 59e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy static CacheBlock* removeBlock(CacheBlock* head, CacheBlock* blockToRemove); 609f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 619f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy void output() { 62e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy CacheBlock* currBlock = this; 639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy while (currBlock) { 649f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d", 659f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy currBlock, currBlock->mX, currBlock->mY, currBlock->mWidth, currBlock->mHeight); 669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy currBlock = currBlock->mNext; 679f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy } 689f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy } 699f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; 709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 719f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyclass CacheTexture { 729f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guypublic: 739f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy CacheTexture(uint16_t width, uint16_t height) : 749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), 759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mLinearFiltering(false), mDirty(false), mNumGlyphs(0) { 769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, 779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true); 789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy } 799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy ~CacheTexture() { 81574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy releaseTexture(); 829f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy reset(); 839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy } 849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy void reset() { 869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy // Delete existing cache blocks 879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy while (mCacheBlocks != NULL) { 889f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy CacheBlock* tmpBlock = mCacheBlocks; 899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mCacheBlocks = mCacheBlocks->mNext; 909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy delete tmpBlock; 919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy } 929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mNumGlyphs = 0; 939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy } 949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy void init() { 969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy // reset, then create a new remainder space to start again 979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy reset(); 989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, 999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true); 1009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy } 1019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 1028087246d9964b11de8ce116bc63b156faa4197e0Romain Guy void releaseTexture() { 1038087246d9964b11de8ce116bc63b156faa4197e0Romain Guy if (mTexture) { 1048087246d9964b11de8ce116bc63b156faa4197e0Romain Guy delete[] mTexture; 1058087246d9964b11de8ce116bc63b156faa4197e0Romain Guy mTexture = NULL; 106574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy } 107574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy if (mTextureId) { 108574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy glDeleteTextures(1, &mTextureId); 1098087246d9964b11de8ce116bc63b156faa4197e0Romain Guy mTextureId = 0; 1108087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 111574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy mDirty = false; 1128087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1138087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 1148087246d9964b11de8ce116bc63b156faa4197e0Romain Guy /** 1158087246d9964b11de8ce116bc63b156faa4197e0Romain Guy * This method assumes that the proper texture unit is active. 1168087246d9964b11de8ce116bc63b156faa4197e0Romain Guy */ 1178087246d9964b11de8ce116bc63b156faa4197e0Romain Guy void allocateTexture() { 118574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy if (!mTexture) { 119574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy mTexture = new uint8_t[mWidth * mHeight]; 120574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy } 1218087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 1228087246d9964b11de8ce116bc63b156faa4197e0Romain Guy if (!mTextureId) { 1238087246d9964b11de8ce116bc63b156faa4197e0Romain Guy glGenTextures(1, &mTextureId); 1248087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 125574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy glBindTexture(GL_TEXTURE_2D, mTextureId); 126574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 127574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy // Initialize texture dimensions 128574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mWidth, mHeight, 0, 129574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, 0); 1308087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 131574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST; 132574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 133574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 1348087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 135574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 136574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 137574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy } 1388087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1398087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 140e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY); 1419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 1428087246d9964b11de8ce116bc63b156faa4197e0Romain Guy inline uint16_t getWidth() const { 1438087246d9964b11de8ce116bc63b156faa4197e0Romain Guy return mWidth; 1448087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1458087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 1468087246d9964b11de8ce116bc63b156faa4197e0Romain Guy inline uint16_t getHeight() const { 1478087246d9964b11de8ce116bc63b156faa4197e0Romain Guy return mHeight; 1488087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1498087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 150b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase inline const Rect* getDirtyRect() const { 151b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase return &mDirtyRect; 152b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase } 153b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase 1548087246d9964b11de8ce116bc63b156faa4197e0Romain Guy inline uint8_t* getTexture() const { 1558087246d9964b11de8ce116bc63b156faa4197e0Romain Guy return mTexture; 1568087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1578087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 158574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy GLuint getTextureId() { 159574cf6070d34e66dfd6f2006937986eddd1f09e7Romain Guy allocateTexture(); 1608087246d9964b11de8ce116bc63b156faa4197e0Romain Guy return mTextureId; 1618087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1628087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 1638087246d9964b11de8ce116bc63b156faa4197e0Romain Guy inline bool isDirty() const { 1648087246d9964b11de8ce116bc63b156faa4197e0Romain Guy return mDirty; 1658087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1668087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 1678087246d9964b11de8ce116bc63b156faa4197e0Romain Guy inline void setDirty(bool dirty) { 1688087246d9964b11de8ce116bc63b156faa4197e0Romain Guy mDirty = dirty; 169b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase if (!dirty) { 170b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase mDirtyRect.setEmpty(); 171b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase } 1728087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1738087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 1748087246d9964b11de8ce116bc63b156faa4197e0Romain Guy inline bool getLinearFiltering() const { 1758087246d9964b11de8ce116bc63b156faa4197e0Romain Guy return mLinearFiltering; 1768087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1778087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 1788087246d9964b11de8ce116bc63b156faa4197e0Romain Guy /** 1798087246d9964b11de8ce116bc63b156faa4197e0Romain Guy * This method assumes that the proper texture unit is active. 1808087246d9964b11de8ce116bc63b156faa4197e0Romain Guy */ 1818087246d9964b11de8ce116bc63b156faa4197e0Romain Guy void setLinearFiltering(bool linearFiltering, bool bind = true) { 1828087246d9964b11de8ce116bc63b156faa4197e0Romain Guy if (linearFiltering != mLinearFiltering) { 1838087246d9964b11de8ce116bc63b156faa4197e0Romain Guy mLinearFiltering = linearFiltering; 1848087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 1858087246d9964b11de8ce116bc63b156faa4197e0Romain Guy const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST; 1868087246d9964b11de8ce116bc63b156faa4197e0Romain Guy if (bind) glBindTexture(GL_TEXTURE_2D, getTextureId()); 1878087246d9964b11de8ce116bc63b156faa4197e0Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 1888087246d9964b11de8ce116bc63b156faa4197e0Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 1898087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1908087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1918087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 1928087246d9964b11de8ce116bc63b156faa4197e0Romain Guy inline uint16_t getGlyphCount() const { 1938087246d9964b11de8ce116bc63b156faa4197e0Romain Guy return mNumGlyphs; 1948087246d9964b11de8ce116bc63b156faa4197e0Romain Guy } 1958087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 1968087246d9964b11de8ce116bc63b156faa4197e0Romain Guyprivate: 1979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy uint8_t* mTexture; 1989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy GLuint mTextureId; 1999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy uint16_t mWidth; 2009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy uint16_t mHeight; 2019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy bool mLinearFiltering; 2029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy bool mDirty; 2039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy uint16_t mNumGlyphs; 2049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy CacheBlock* mCacheBlocks; 205b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase Rect mDirtyRect; 2069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; 2079f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 2089f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace uirenderer 2099f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace android 2109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 2119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif // ANDROID_HWUI_CACHE_TEXTURE_H 212