Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2010 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 #define LOG_TAG "OpenGLRenderer"
     18 
     19 #include "Debug.h"
     20 #include "TextDropShadowCache.h"
     21 #include "Properties.h"
     22 
     23 namespace android {
     24 namespace uirenderer {
     25 
     26 ///////////////////////////////////////////////////////////////////////////////
     27 // Constructors/destructor
     28 ///////////////////////////////////////////////////////////////////////////////
     29 
     30 TextDropShadowCache::TextDropShadowCache():
     31         mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity),
     32         mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) {
     33     char property[PROPERTY_VALUE_MAX];
     34     if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) {
     35         INIT_LOGD("  Setting drop shadow cache size to %sMB", property);
     36         setMaxSize(MB(atof(property)));
     37     } else {
     38         INIT_LOGD("  Using default drop shadow cache size of %.2fMB",
     39                 DEFAULT_DROP_SHADOW_CACHE_SIZE);
     40     }
     41 
     42     init();
     43 }
     44 
     45 TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize):
     46         mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity),
     47         mSize(0), mMaxSize(maxByteSize) {
     48     init();
     49 }
     50 
     51 TextDropShadowCache::~TextDropShadowCache() {
     52     mCache.clear();
     53 }
     54 
     55 void TextDropShadowCache::init() {
     56     mCache.setOnEntryRemovedListener(this);
     57     mDebugEnabled = readDebugLevel() & kDebugMoreCaches;
     58 }
     59 
     60 ///////////////////////////////////////////////////////////////////////////////
     61 // Size management
     62 ///////////////////////////////////////////////////////////////////////////////
     63 
     64 uint32_t TextDropShadowCache::getSize() {
     65     return mSize;
     66 }
     67 
     68 uint32_t TextDropShadowCache::getMaxSize() {
     69     return mMaxSize;
     70 }
     71 
     72 void TextDropShadowCache::setMaxSize(uint32_t maxSize) {
     73     mMaxSize = maxSize;
     74     while (mSize > mMaxSize) {
     75         mCache.removeOldest();
     76     }
     77 }
     78 
     79 ///////////////////////////////////////////////////////////////////////////////
     80 // Callbacks
     81 ///////////////////////////////////////////////////////////////////////////////
     82 
     83 void TextDropShadowCache::operator()(ShadowText& text, ShadowTexture*& texture) {
     84     if (texture) {
     85         mSize -= texture->bitmapSize;
     86 
     87         if (mDebugEnabled) {
     88             LOGD("Shadow texture deleted, size = %d", texture->bitmapSize);
     89         }
     90 
     91         glDeleteTextures(1, &texture->id);
     92         delete texture;
     93     }
     94 }
     95 
     96 ///////////////////////////////////////////////////////////////////////////////
     97 // Caching
     98 ///////////////////////////////////////////////////////////////////////////////
     99 
    100 void TextDropShadowCache::clear() {
    101     mCache.clear();
    102 }
    103 
    104 ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32_t len,
    105         int numGlyphs, uint32_t radius) {
    106     ShadowText entry(paint, radius, len, text);
    107     ShadowTexture* texture = mCache.get(entry);
    108 
    109     if (!texture) {
    110         FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(paint, text, 0,
    111                 len, numGlyphs, radius);
    112 
    113         texture = new ShadowTexture;
    114         texture->left = shadow.penX;
    115         texture->top = shadow.penY;
    116         texture->width = shadow.width;
    117         texture->height = shadow.height;
    118         texture->generation = 0;
    119         texture->blend = true;
    120 
    121         const uint32_t size = shadow.width * shadow.height;
    122         texture->bitmapSize = size;
    123 
    124         // Don't even try to cache a bitmap that's bigger than the cache
    125         if (size < mMaxSize) {
    126             while (mSize + size > mMaxSize) {
    127                 mCache.removeOldest();
    128             }
    129         }
    130 
    131         glGenTextures(1, &texture->id);
    132 
    133         glBindTexture(GL_TEXTURE_2D, texture->id);
    134         // Textures are Alpha8
    135         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    136 
    137         glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
    138                 GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image);
    139 
    140         texture->setFilter(GL_LINEAR, GL_LINEAR);
    141         texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
    142 
    143         if (size < mMaxSize) {
    144             if (mDebugEnabled) {
    145                 LOGD("Shadow texture created, size = %d", texture->bitmapSize);
    146             }
    147 
    148             entry.copyTextLocally();
    149 
    150             mSize += size;
    151             mCache.put(entry, texture);
    152         } else {
    153             texture->cleanup = true;
    154         }
    155 
    156         // Cleanup shadow
    157         delete[] shadow.image;
    158     }
    159 
    160     return texture;
    161 }
    162 
    163 }; // namespace uirenderer
    164 }; // namespace android
    165