11e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/* 21e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * Copyright (C) 2010 The Android Open Source Project 31e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * 41e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 51e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * you may not use this file except in compliance with the License. 61e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * You may obtain a copy of the License at 71e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * 81e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 91e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * 101e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * Unless required by applicable law or agreed to in writing, software 111e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 121e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * See the License for the specific language governing permissions and 141e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * limitations under the License. 151e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy */ 161e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 171e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy#define LOG_TAG "OpenGLRenderer" 181e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 19c9855a53edfac818dc68714557185977556f849dRomain Guy#include "Debug.h" 201e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy#include "TextDropShadowCache.h" 21b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy#include "Properties.h" 221e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 231e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guynamespace android { 241e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guynamespace uirenderer { 251e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 261e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 271e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy// Constructors/destructor 281e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 291e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 30fb8b763f762ae21923c58d64caa729b012f40e05Romain GuyTextDropShadowCache::TextDropShadowCache(): 31fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity), 32fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) { 33fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy char property[PROPERTY_VALUE_MAX]; 34fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) { 35c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting drop shadow cache size to %sMB", property); 36fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy setMaxSize(MB(atof(property))); 37fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy } else { 38c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Using default drop shadow cache size of %.2fMB", 39c9855a53edfac818dc68714557185977556f849dRomain Guy DEFAULT_DROP_SHADOW_CACHE_SIZE); 40fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy } 41fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy 4225dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy init(); 43fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy} 44fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy 451e45aae5de003657e5d18f74d34998f5de5db5b7Romain GuyTextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize): 461e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity), 471e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mSize(0), mMaxSize(maxByteSize) { 4825dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy init(); 491e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 501e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 511e45aae5de003657e5d18f74d34998f5de5db5b7Romain GuyTextDropShadowCache::~TextDropShadowCache() { 521e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mCache.clear(); 531e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 541e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 5525dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guyvoid TextDropShadowCache::init() { 5625dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy mCache.setOnEntryRemovedListener(this); 5725dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy mDebugEnabled = readDebugLevel() & kDebugMoreCaches; 5825dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy} 5925dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy 601e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 611e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy// Size management 621e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 631e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 641e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guyuint32_t TextDropShadowCache::getSize() { 651e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return mSize; 661e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 671e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 681e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guyuint32_t TextDropShadowCache::getMaxSize() { 691e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return mMaxSize; 701e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 711e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 721e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guyvoid TextDropShadowCache::setMaxSize(uint32_t maxSize) { 731e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mMaxSize = maxSize; 741e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy while (mSize > mMaxSize) { 751e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mCache.removeOldest(); 761e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 771e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 781e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 791e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 801e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy// Callbacks 811e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 821e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 831e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guyvoid TextDropShadowCache::operator()(ShadowText& text, ShadowTexture*& texture) { 841e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (texture) { 8525dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy mSize -= texture->bitmapSize; 8625dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy 8725dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy if (mDebugEnabled) { 885baa3a62a97544669fba6d65a11c07f252e654ddSteve Block ALOGD("Shadow texture deleted, size = %d", texture->bitmapSize); 8925dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy } 90f70a7e34953438dd70573dbb6fd3dd34a1bce831Romain Guy 911e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy glDeleteTextures(1, &texture->id); 921e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy delete texture; 931e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 941e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 951e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 961e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 971e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy// Caching 981e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 991e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1001e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guyvoid TextDropShadowCache::clear() { 1011e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mCache.clear(); 1021e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 1031e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1041e45aae5de003657e5d18f74d34998f5de5db5b7Romain GuyShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32_t len, 105416a847633680d94efb926837efdc18726d54918Raph Levien int numGlyphs, uint32_t radius, const float* positions) { 106416a847633680d94efb926837efdc18726d54918Raph Levien ShadowText entry(paint, radius, len, text, positions); 1071e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy ShadowTexture* texture = mCache.get(entry); 1081e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1091e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (!texture) { 1108b4072d3fb9bb49d774d97689a065204beca1752Raph Levien SkPaint paintCopy(*paint); 1118b4072d3fb9bb49d774d97689a065204beca1752Raph Levien paintCopy.setTextAlign(SkPaint::kLeft_Align); 1128b4072d3fb9bb49d774d97689a065204beca1752Raph Levien FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(&paintCopy, text, 0, 113416a847633680d94efb926837efdc18726d54918Raph Levien len, numGlyphs, radius, positions); 1141e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1151e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture = new ShadowTexture; 1161e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->left = shadow.penX; 1171e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->top = shadow.penY; 1181e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->width = shadow.width; 1191e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->height = shadow.height; 1201e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->generation = 0; 1211e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->blend = true; 1221e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1231e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint32_t size = shadow.width * shadow.height; 12425dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy texture->bitmapSize = size; 12525dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy 1261e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy // Don't even try to cache a bitmap that's bigger than the cache 1271e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (size < mMaxSize) { 1281e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy while (mSize + size > mMaxSize) { 1291e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mCache.removeOldest(); 1301e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 1311e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 1321e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1331e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy glGenTextures(1, &texture->id); 1341e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1351e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy glBindTexture(GL_TEXTURE_2D, texture->id); 1361e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy // Textures are Alpha8 1371e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 1381e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1391e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0, 1401e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image); 1411e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 14239d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy texture->setFilter(GL_LINEAR); 14339d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy texture->setWrap(GL_CLAMP_TO_EDGE); 1441e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1451e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (size < mMaxSize) { 14625dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy if (mDebugEnabled) { 1475baa3a62a97544669fba6d65a11c07f252e654ddSteve Block ALOGD("Shadow texture created, size = %d", texture->bitmapSize); 14825dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy } 149321dce646dc3c2ecfbd72a693d8d9294a6119736Romain Guy 150321dce646dc3c2ecfbd72a693d8d9294a6119736Romain Guy entry.copyTextLocally(); 151321dce646dc3c2ecfbd72a693d8d9294a6119736Romain Guy 1521e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mSize += size; 1531e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mCache.put(entry, texture); 1541e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } else { 1551e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->cleanup = true; 1561e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 1571e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1581e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy // Cleanup shadow 1591e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy delete[] shadow.image; 1601e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 1611e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1621e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return texture; 1631e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 1641e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1651e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy}; // namespace uirenderer 1661e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy}; // namespace android 167