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