LayerCache.cpp revision aa6c24c21c727a196451332448d4e3b11a80be69
1dda570201ac851dd85af3861f7e575721d3345daRomain Guy/*
2dda570201ac851dd85af3861f7e575721d3345daRomain Guy * Copyright (C) 2010 The Android Open Source Project
3dda570201ac851dd85af3861f7e575721d3345daRomain Guy *
4dda570201ac851dd85af3861f7e575721d3345daRomain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5dda570201ac851dd85af3861f7e575721d3345daRomain Guy * you may not use this file except in compliance with the License.
6dda570201ac851dd85af3861f7e575721d3345daRomain Guy * You may obtain a copy of the License at
7dda570201ac851dd85af3861f7e575721d3345daRomain Guy *
8dda570201ac851dd85af3861f7e575721d3345daRomain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9dda570201ac851dd85af3861f7e575721d3345daRomain Guy *
10dda570201ac851dd85af3861f7e575721d3345daRomain Guy * Unless required by applicable law or agreed to in writing, software
11dda570201ac851dd85af3861f7e575721d3345daRomain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12dda570201ac851dd85af3861f7e575721d3345daRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dda570201ac851dd85af3861f7e575721d3345daRomain Guy * See the License for the specific language governing permissions and
14dda570201ac851dd85af3861f7e575721d3345daRomain Guy * limitations under the License.
15dda570201ac851dd85af3861f7e575721d3345daRomain Guy */
16dda570201ac851dd85af3861f7e575721d3345daRomain Guy
17dda570201ac851dd85af3861f7e575721d3345daRomain Guy#define LOG_TAG "OpenGLRenderer"
18dda570201ac851dd85af3861f7e575721d3345daRomain Guy
19dda570201ac851dd85af3861f7e575721d3345daRomain Guy#include <GLES2/gl2.h>
20dda570201ac851dd85af3861f7e575721d3345daRomain Guy
21f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy#include <utils/Log.h>
22f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
23c9855a53edfac818dc68714557185977556f849dRomain Guy#include "Debug.h"
24dda570201ac851dd85af3861f7e575721d3345daRomain Guy#include "LayerCache.h"
25fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy#include "Properties.h"
26dda570201ac851dd85af3861f7e575721d3345daRomain Guy
27dda570201ac851dd85af3861f7e575721d3345daRomain Guynamespace android {
28dda570201ac851dd85af3861f7e575721d3345daRomain Guynamespace uirenderer {
29dda570201ac851dd85af3861f7e575721d3345daRomain Guy
30dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
31dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Constructors/destructor
32dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
33dda570201ac851dd85af3861f7e575721d3345daRomain Guy
348550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain GuyLayerCache::LayerCache(): mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
35fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    char property[PROPERTY_VALUE_MAX];
36fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) {
37c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("  Setting layer cache size to %sMB", property);
38fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        setMaxSize(MB(atof(property)));
39fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    } else {
40c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("  Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE);
41fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    }
42fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy}
43fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
44dda570201ac851dd85af3861f7e575721d3345daRomain GuyLayerCache::~LayerCache() {
455f0c6a483900f3989f4d2a8f913cf5b6a9777d03Romain Guy    clear();
46dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
47dda570201ac851dd85af3861f7e575721d3345daRomain Guy
48dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
49dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Size management
50dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
51dda570201ac851dd85af3861f7e575721d3345daRomain Guy
52dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getSize() {
53dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return mSize;
54dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
55dda570201ac851dd85af3861f7e575721d3345daRomain Guy
56dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getMaxSize() {
57dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return mMaxSize;
58dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
59dda570201ac851dd85af3861f7e575721d3345daRomain Guy
60dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::setMaxSize(uint32_t maxSize) {
618550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    clear();
62dda570201ac851dd85af3861f7e575721d3345daRomain Guy    mMaxSize = maxSize;
63dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
64dda570201ac851dd85af3861f7e575721d3345daRomain Guy
65dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
66dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Caching
67dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
68dda570201ac851dd85af3861f7e575721d3345daRomain Guy
69dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::deleteLayer(Layer* layer) {
70dda570201ac851dd85af3861f7e575721d3345daRomain Guy    if (layer) {
718550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        mSize -= layer->width * layer->height * 4;
72dda570201ac851dd85af3861f7e575721d3345daRomain Guy        glDeleteTextures(1, &layer->texture);
73dda570201ac851dd85af3861f7e575721d3345daRomain Guy        delete layer;
74dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
75dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
76dda570201ac851dd85af3861f7e575721d3345daRomain Guy
77dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::clear() {
788550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    size_t count = mCache.size();
798550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    for (size_t i = 0; i < count; i++) {
808550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        deleteLayer(mCache.itemAt(i).mLayer);
818550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    }
82dda570201ac851dd85af3861f7e575721d3345daRomain Guy    mCache.clear();
83dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
84dda570201ac851dd85af3861f7e575721d3345daRomain Guy
858550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain GuyLayer* LayerCache::get(const uint32_t width, const uint32_t height) {
868550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    Layer* layer = NULL;
878550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
888550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    LayerEntry entry(width, height);
898550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    ssize_t index = mCache.indexOf(entry);
90f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
918550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    if (index >= 0) {
928550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        entry = mCache.itemAt(index);
938550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        mCache.removeAt(index);
948550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
958550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        layer = entry.mLayer;
968550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        mSize -= layer->width * layer->height * 4;
978550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
988550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        LAYER_LOGD("Reusing layer %dx%d", layer->width, layer->height);
99f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy    } else {
1008550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
101f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
1028550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        layer = new Layer(entry.mWidth, entry.mHeight);
103f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        layer->blend = true;
10438c85b907a478af96d71b9a5df5a2066b8475311Romain Guy        layer->empty = true;
105eb99356a0548684a501766e6a524529ab93304c8Romain Guy        layer->fbo = 0;
106171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy        layer->colorFilter = NULL;
107f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
108f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glGenTextures(1, &layer->texture);
109f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glBindTexture(GL_TEXTURE_2D, layer->texture);
110f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
1110bb5667b4ef91fefd0500fae0186789d15d54e0eRomain Guy        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1120bb5667b4ef91fefd0500fae0186789d15d54e0eRomain Guy
11338c85b907a478af96d71b9a5df5a2066b8475311Romain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
11438c85b907a478af96d71b9a5df5a2066b8475311Romain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
115f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
116f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
117f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
118eb99356a0548684a501766e6a524529ab93304c8Romain Guy
119eb99356a0548684a501766e6a524529ab93304c8Romain Guy#if DEBUG_LAYERS
1208550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        size_t size = mCache.size();
1218550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        for (size_t i = 0; i < size; i++) {
1228550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy            const LayerEntry& entry = mCache.itemAt(i);
1238550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy            LAYER_LOGD("  Layer size %dx%d", entry.mWidth, entry.mHeight);
124eb99356a0548684a501766e6a524529ab93304c8Romain Guy        }
125eb99356a0548684a501766e6a524529ab93304c8Romain Guy#endif
126dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
127f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
128dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return layer;
129dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
130dda570201ac851dd85af3861f7e575721d3345daRomain Guy
13109b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guybool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t height) {
13209b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    // TODO: We should be smarter and see if we have a texture of the appropriate
13309b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    //       size already in the cache, and reuse it instead of creating a new one
13409b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy
13509b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    LayerEntry entry(width, height);
13609b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    if (entry.mWidth <= layer->width && entry.mHeight <= layer->height) {
13709b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy        return true;
13809b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    }
13909b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy
14009b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    glActiveTexture(GL_TEXTURE0);
14109b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    glBindTexture(GL_TEXTURE_2D, layer->texture);
14209b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy
14309b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entry.mWidth, entry.mHeight, 0,
14409b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy            GL_RGBA, GL_UNSIGNED_BYTE, NULL);
14509b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy
14609b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    if (glGetError() != GL_NO_ERROR) {
14709b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy        return false;
14809b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    }
14909b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy
15009b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    layer->width = entry.mWidth;
15109b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    layer->height = entry.mHeight;
15209b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy
15309b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy    return true;
15409b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy}
15509b7c91de73b59aa3f679b3ae3ba299f82ec9f8aRomain Guy
1568550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guybool LayerCache::put(Layer* layer) {
157aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    if (!layer->isCacheable) return false;
158aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
1598550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    const uint32_t size = layer->width * layer->height * 4;
160dda570201ac851dd85af3861f7e575721d3345daRomain Guy    // Don't even try to cache a layer that's bigger than the cache
161dda570201ac851dd85af3861f7e575721d3345daRomain Guy    if (size < mMaxSize) {
1628550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        // TODO: Use an LRU
163dda570201ac851dd85af3861f7e575721d3345daRomain Guy        while (mSize + size > mMaxSize) {
164e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            size_t position = 0;
165e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy#if LAYER_REMOVE_BIGGEST
166e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            position = mCache.size() - 1;
167e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy#endif
168e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            Layer* victim = mCache.itemAt(position).mLayer;
169e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            deleteLayer(victim);
170e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            mCache.removeAt(position);
1718550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
172e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            LAYER_LOGD("  Deleting layer %.2fx%.2f", victim->layer.getWidth(),
173e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy                    victim->layer.getHeight());
174dda570201ac851dd85af3861f7e575721d3345daRomain Guy        }
175dda570201ac851dd85af3861f7e575721d3345daRomain Guy
1768550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        LayerEntry entry(layer);
1778550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
1788550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        mCache.add(entry);
179dda570201ac851dd85af3861f7e575721d3345daRomain Guy        mSize += size;
180dda570201ac851dd85af3861f7e575721d3345daRomain Guy
181dda570201ac851dd85af3861f7e575721d3345daRomain Guy        return true;
182dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
183dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return false;
184dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
185dda570201ac851dd85af3861f7e575721d3345daRomain Guy
186dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace uirenderer
187dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace android
188