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
179fded232a9548a304e0145011df8849fba0dcda7Chris Craik#include "LayerCache.h"
18f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
19a1d3c91afbd52c7e8b01f4a9060c5459f02ae7a5Romain Guy#include "Caches.h"
20fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy#include "Properties.h"
21dda570201ac851dd85af3861f7e575721d3345daRomain Guy
229fded232a9548a304e0145011df8849fba0dcda7Chris Craik#include <utils/Log.h>
239fded232a9548a304e0145011df8849fba0dcda7Chris Craik
249fded232a9548a304e0145011df8849fba0dcda7Chris Craik#include <GLES2/gl2.h>
259fded232a9548a304e0145011df8849fba0dcda7Chris Craik
26dda570201ac851dd85af3861f7e575721d3345daRomain Guynamespace android {
27dda570201ac851dd85af3861f7e575721d3345daRomain Guynamespace uirenderer {
28dda570201ac851dd85af3861f7e575721d3345daRomain Guy
29dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
30dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Constructors/destructor
31dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
32dda570201ac851dd85af3861f7e575721d3345daRomain Guy
339fded232a9548a304e0145011df8849fba0dcda7Chris CraikLayerCache::LayerCache()
349fded232a9548a304e0145011df8849fba0dcda7Chris Craik        : mSize(0)
359fded232a9548a304e0145011df8849fba0dcda7Chris Craik        , mMaxSize(Properties::layerPoolSize) {}
36fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
37dda570201ac851dd85af3861f7e575721d3345daRomain GuyLayerCache::~LayerCache() {
385f0c6a483900f3989f4d2a8f913cf5b6a9777d03Romain Guy    clear();
39dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
40dda570201ac851dd85af3861f7e575721d3345daRomain Guy
41dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
42dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Size management
43dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
44dda570201ac851dd85af3861f7e575721d3345daRomain Guy
4517035b0211a3c9d45ea46a99217a6acbe76e8fbeJohn Recksize_t LayerCache::getCount() {
4617035b0211a3c9d45ea46a99217a6acbe76e8fbeJohn Reck    return mCache.size();
4717035b0211a3c9d45ea46a99217a6acbe76e8fbeJohn Reck}
4817035b0211a3c9d45ea46a99217a6acbe76e8fbeJohn Reck
49dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getSize() {
50dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return mSize;
51dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
52dda570201ac851dd85af3861f7e575721d3345daRomain Guy
53dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getMaxSize() {
54dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return mMaxSize;
55dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
56dda570201ac851dd85af3861f7e575721d3345daRomain Guy
57dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::setMaxSize(uint32_t maxSize) {
588550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    clear();
59dda570201ac851dd85af3861f7e575721d3345daRomain Guy    mMaxSize = maxSize;
60dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
61dda570201ac851dd85af3861f7e575721d3345daRomain Guy
62dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
63dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Caching
64dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
65dda570201ac851dd85af3861f7e575721d3345daRomain Guy
66e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guyint LayerCache::LayerEntry::compare(const LayerCache::LayerEntry& lhs,
67e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy        const LayerCache::LayerEntry& rhs) {
68e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    int deltaInt = int(lhs.mWidth) - int(rhs.mWidth);
69e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    if (deltaInt != 0) return deltaInt;
70e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy
71e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    return int(lhs.mHeight) - int(rhs.mHeight);
72e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy}
73e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy
74dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::deleteLayer(Layer* layer) {
75dda570201ac851dd85af3861f7e575721d3345daRomain Guy    if (layer) {
7607adacf4996c8ca494332ec938786fa15832c722Chris Craik        LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(),
7707adacf4996c8ca494332ec938786fa15832c722Chris Craik                layer->getFbo());
789ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        mSize -= layer->getWidth() * layer->getHeight() * 4;
79b9ce116dac378b4cf4490f265dcbd5704a1dd43cChris Craik        layer->state = Layer::State::DeletedFromCache;
80d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        layer->decStrong(nullptr);
81dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
82dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
83dda570201ac851dd85af3861f7e575721d3345daRomain Guy
84dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::clear() {
85bef837dc57b47fd7fcc17c86d741cf77eac4487bJohn Reck    for (auto entry : mCache) {
86bef837dc57b47fd7fcc17c86d741cf77eac4487bJohn Reck        deleteLayer(entry.mLayer);
878550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    }
88dda570201ac851dd85af3861f7e575721d3345daRomain Guy    mCache.clear();
89dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
90dda570201ac851dd85af3861f7e575721d3345daRomain Guy
913b20251a355c88193c439f928a84ae69483fb488John ReckLayer* LayerCache::get(RenderState& renderState, const uint32_t width, const uint32_t height) {
92d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    Layer* layer = nullptr;
938550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
948550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    LayerEntry entry(width, height);
95bef837dc57b47fd7fcc17c86d741cf77eac4487bJohn Reck    auto iter = mCache.find(entry);
96f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
97bef837dc57b47fd7fcc17c86d741cf77eac4487bJohn Reck    if (iter != mCache.end()) {
98bef837dc57b47fd7fcc17c86d741cf77eac4487bJohn Reck        entry = *iter;
99bef837dc57b47fd7fcc17c86d741cf77eac4487bJohn Reck        mCache.erase(iter);
1008550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
1018550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        layer = entry.mLayer;
102b9ce116dac378b4cf4490f265dcbd5704a1dd43cChris Craik        layer->state = Layer::State::RemovedFromCache;
1039ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        mSize -= layer->getWidth() * layer->getHeight() * 4;
1048550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
10507adacf4996c8ca494332ec938786fa15832c722Chris Craik        LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight());
106f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy    } else {
10707adacf4996c8ca494332ec938786fa15832c722Chris Craik        LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
108f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
109b9ce116dac378b4cf4490f265dcbd5704a1dd43cChris Craik        layer = new Layer(Layer::Type::DisplayList, renderState, entry.mWidth, entry.mHeight);
1109ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        layer->setBlend(true);
1119ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        layer->generateTexture();
1129ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        layer->bindTexture();
11339d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy        layer->setFilter(GL_NEAREST);
11439d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy        layer->setWrap(GL_CLAMP_TO_EDGE, false);
1150bb5667b4ef91fefd0500fae0186789d15d54e0eRomain Guy
116eb99356a0548684a501766e6a524529ab93304c8Romain Guy#if DEBUG_LAYERS
117eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy        dump();
118eb99356a0548684a501766e6a524529ab93304c8Romain Guy#endif
119dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
120f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
121dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return layer;
122dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
123dda570201ac851dd85af3861f7e575721d3345daRomain Guy
124eea60692b060737faeaa02bb30f5b79e2202b482Romain Guyvoid LayerCache::dump() {
125bef837dc57b47fd7fcc17c86d741cf77eac4487bJohn Reck    for (auto entry : mCache) {
12607adacf4996c8ca494332ec938786fa15832c722Chris Craik        ALOGD("  Layer size %dx%d", entry.mWidth, entry.mHeight);
127eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy    }
128eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy}
129eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy
1308550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guybool LayerCache::put(Layer* layer) {
1319ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    if (!layer->isCacheable()) return false;
132aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
1339ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    const uint32_t size = layer->getWidth() * layer->getHeight() * 4;
134dda570201ac851dd85af3861f7e575721d3345daRomain Guy    // Don't even try to cache a layer that's bigger than the cache
135dda570201ac851dd85af3861f7e575721d3345daRomain Guy    if (size < mMaxSize) {
1368550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        // TODO: Use an LRU
137dda570201ac851dd85af3861f7e575721d3345daRomain Guy        while (mSize + size > mMaxSize) {
138bef837dc57b47fd7fcc17c86d741cf77eac4487bJohn Reck            Layer* victim = mCache.begin()->mLayer;
139e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy            deleteLayer(victim);
140bef837dc57b47fd7fcc17c86d741cf77eac4487bJohn Reck            mCache.erase(mCache.begin());
1418550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
14207adacf4996c8ca494332ec938786fa15832c722Chris Craik            LAYER_LOGD("  Deleting layer %.2fx%.2f", victim->layer.getWidth(),
14307adacf4996c8ca494332ec938786fa15832c722Chris Craik                    victim->layer.getHeight());
144dda570201ac851dd85af3861f7e575721d3345daRomain Guy        }
145dda570201ac851dd85af3861f7e575721d3345daRomain Guy
146e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy        layer->cancelDefer();
1475c88fc744db977ef26887df9605beaa409394806Romain Guy
1488550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        LayerEntry entry(layer);
1498550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy
150bef837dc57b47fd7fcc17c86d741cf77eac4487bJohn Reck        mCache.insert(entry);
151dda570201ac851dd85af3861f7e575721d3345daRomain Guy        mSize += size;
152dda570201ac851dd85af3861f7e575721d3345daRomain Guy
153b9ce116dac378b4cf4490f265dcbd5704a1dd43cChris Craik        layer->state = Layer::State::InCache;
154dda570201ac851dd85af3861f7e575721d3345daRomain Guy        return true;
155dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
156bfd1cd620991ac2fa9202fdce6c00ec47d071935Chris Craik
157b9ce116dac378b4cf4490f265dcbd5704a1dd43cChris Craik    layer->state = Layer::State::FailedToCache;
158dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return false;
159dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
160dda570201ac851dd85af3861f7e575721d3345daRomain Guy
161dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace uirenderer
162dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace android
163