LayerCache.cpp revision 07adacf4996c8ca494332ec938786fa15832c722
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
23a1d3c91afbd52c7e8b01f4a9060c5459f02ae7a5Romain Guy#include "Caches.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
5217035b0211a3c9d45ea46a99217a6acbe76e8fbeJohn Recksize_t LayerCache::getCount() {
5317035b0211a3c9d45ea46a99217a6acbe76e8fbeJohn Reck    return mCache.size();
5417035b0211a3c9d45ea46a99217a6acbe76e8fbeJohn Reck}
5517035b0211a3c9d45ea46a99217a6acbe76e8fbeJohn Reck
56dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getSize() {
57dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return mSize;
58dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
59dda570201ac851dd85af3861f7e575721d3345daRomain Guy
60dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getMaxSize() {
61dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return mMaxSize;
62dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
63dda570201ac851dd85af3861f7e575721d3345daRomain Guy
64dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::setMaxSize(uint32_t maxSize) {
658550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    clear();
66dda570201ac851dd85af3861f7e575721d3345daRomain Guy    mMaxSize = maxSize;
67dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
68dda570201ac851dd85af3861f7e575721d3345daRomain Guy
69dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
70dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Caching
71dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
72dda570201ac851dd85af3861f7e575721d3345daRomain Guy
73e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guyint LayerCache::LayerEntry::compare(const LayerCache::LayerEntry& lhs,
74e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy        const LayerCache::LayerEntry& rhs) {
75e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    int deltaInt = int(lhs.mWidth) - int(rhs.mWidth);
76e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    if (deltaInt != 0) return deltaInt;
77e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy
78e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    return int(lhs.mHeight) - int(rhs.mHeight);
79e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy}
80e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy
81dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::deleteLayer(Layer* layer) {
82dda570201ac851dd85af3861f7e575721d3345daRomain Guy    if (layer) {
8307adacf4996c8ca494332ec938786fa15832c722Chris Craik        LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(),
8407adacf4996c8ca494332ec938786fa15832c722Chris Craik                layer->getFbo());
859ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        mSize -= layer->getWidth() * layer->getHeight() * 4;
86bfd1cd620991ac2fa9202fdce6c00ec47d071935Chris Craik        layer->state = Layer::kState_DeletedFromCache;
870e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck        layer->decStrong(0);
88dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
89dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
90dda570201ac851dd85af3861f7e575721d3345daRomain Guy
91dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::clear() {
928550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    size_t count = mCache.size();
938550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    for (size_t i = 0; i < count; i++) {
948550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        deleteLayer(mCache.itemAt(i).mLayer);
958550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    }
96dda570201ac851dd85af3861f7e575721d3345daRomain Guy    mCache.clear();
97dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
98dda570201ac851dd85af3861f7e575721d3345daRomain Guy
993b20251a355c88193c439f928a84ae69483fb488John ReckLayer* LayerCache::get(RenderState& renderState, const uint32_t width, const uint32_t height) {
1008550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    Layer* layer = NULL;
1018550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
1028550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    LayerEntry entry(width, height);
1038550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    ssize_t index = mCache.indexOf(entry);
104f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
1058550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    if (index >= 0) {
1068550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        entry = mCache.itemAt(index);
1078550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        mCache.removeAt(index);
1088550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
1098550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        layer = entry.mLayer;
110bfd1cd620991ac2fa9202fdce6c00ec47d071935Chris Craik        layer->state = Layer::kState_RemovedFromCache;
1119ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        mSize -= layer->getWidth() * layer->getHeight() * 4;
1128550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
11307adacf4996c8ca494332ec938786fa15832c722Chris Craik        LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight());
114f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy    } else {
11507adacf4996c8ca494332ec938786fa15832c722Chris Craik        LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
116f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
1178a226d24b8b2fde4c855d0051cb7bfc5b5813c36Chris Craik        layer = new Layer(Layer::kType_DisplayList, renderState, entry.mWidth, entry.mHeight);
1189ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        layer->setBlend(true);
1199ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        layer->setEmpty(true);
1209ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        layer->setFbo(0);
1219ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
1229ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        layer->generateTexture();
1239ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        layer->bindTexture();
12439d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy        layer->setFilter(GL_NEAREST);
12539d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy        layer->setWrap(GL_CLAMP_TO_EDGE, false);
1260bb5667b4ef91fefd0500fae0186789d15d54e0eRomain Guy        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1270bb5667b4ef91fefd0500fae0186789d15d54e0eRomain Guy
128eb99356a0548684a501766e6a524529ab93304c8Romain Guy#if DEBUG_LAYERS
129eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy        dump();
130eb99356a0548684a501766e6a524529ab93304c8Romain Guy#endif
131dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
132f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
133dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return layer;
134dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
135dda570201ac851dd85af3861f7e575721d3345daRomain Guy
136eea60692b060737faeaa02bb30f5b79e2202b482Romain Guyvoid LayerCache::dump() {
137eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy    size_t size = mCache.size();
138eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy    for (size_t i = 0; i < size; i++) {
139eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy        const LayerEntry& entry = mCache.itemAt(i);
14007adacf4996c8ca494332ec938786fa15832c722Chris Craik        ALOGD("  Layer size %dx%d", entry.mWidth, entry.mHeight);
141eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy    }
142eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy}
143eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy
1448550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guybool LayerCache::put(Layer* layer) {
1459ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    if (!layer->isCacheable()) return false;
146aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
1479ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    const uint32_t size = layer->getWidth() * layer->getHeight() * 4;
148dda570201ac851dd85af3861f7e575721d3345daRomain Guy    // Don't even try to cache a layer that's bigger than the cache
149dda570201ac851dd85af3861f7e575721d3345daRomain Guy    if (size < mMaxSize) {
1508550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        // TODO: Use an LRU
151dda570201ac851dd85af3861f7e575721d3345daRomain Guy        while (mSize + size > mMaxSize) {
152e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            size_t position = 0;
15328d8ff6dbcc1b137131c70b72b4dbd211db7fbd9Romain Guy#if LAYER_REMOVE_BIGGEST_FIRST
154e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            position = mCache.size() - 1;
155e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy#endif
156e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            Layer* victim = mCache.itemAt(position).mLayer;
157e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            deleteLayer(victim);
158e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            mCache.removeAt(position);
1598550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
16007adacf4996c8ca494332ec938786fa15832c722Chris Craik            LAYER_LOGD("  Deleting layer %.2fx%.2f", victim->layer.getWidth(),
16107adacf4996c8ca494332ec938786fa15832c722Chris Craik                    victim->layer.getHeight());
162dda570201ac851dd85af3861f7e575721d3345daRomain Guy        }
163dda570201ac851dd85af3861f7e575721d3345daRomain Guy
164e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy        layer->cancelDefer();
1655c88fc744db977ef26887df9605beaa409394806Romain Guy
1668550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        LayerEntry entry(layer);
1678550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
1688550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        mCache.add(entry);
169dda570201ac851dd85af3861f7e575721d3345daRomain Guy        mSize += size;
170dda570201ac851dd85af3861f7e575721d3345daRomain Guy
171bfd1cd620991ac2fa9202fdce6c00ec47d071935Chris Craik        layer->state = Layer::kState_InCache;
172dda570201ac851dd85af3861f7e575721d3345daRomain Guy        return true;
173dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
174bfd1cd620991ac2fa9202fdce6c00ec47d071935Chris Craik
175bfd1cd620991ac2fa9202fdce6c00ec47d071935Chris Craik    layer->state = Layer::kState_FailedToCache;
176dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return false;
177dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
178dda570201ac851dd85af3861f7e575721d3345daRomain Guy
179dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace uirenderer
180dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace android
181