LayerCache.cpp revision bef837dc57b47fd7fcc17c86d741cf77eac4487b
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#include <GLES2/gl2.h>
18
19#include <utils/Log.h>
20
21#include "Caches.h"
22#include "LayerCache.h"
23#include "Properties.h"
24
25namespace android {
26namespace uirenderer {
27
28///////////////////////////////////////////////////////////////////////////////
29// Constructors/destructor
30///////////////////////////////////////////////////////////////////////////////
31
32LayerCache::LayerCache(): mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
33    char property[PROPERTY_VALUE_MAX];
34    if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, nullptr) > 0) {
35        INIT_LOGD("  Setting layer cache size to %sMB", property);
36        setMaxSize(MB(atof(property)));
37    } else {
38        INIT_LOGD("  Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE);
39    }
40}
41
42LayerCache::~LayerCache() {
43    clear();
44}
45
46///////////////////////////////////////////////////////////////////////////////
47// Size management
48///////////////////////////////////////////////////////////////////////////////
49
50size_t LayerCache::getCount() {
51    return mCache.size();
52}
53
54uint32_t LayerCache::getSize() {
55    return mSize;
56}
57
58uint32_t LayerCache::getMaxSize() {
59    return mMaxSize;
60}
61
62void LayerCache::setMaxSize(uint32_t maxSize) {
63    clear();
64    mMaxSize = maxSize;
65}
66
67///////////////////////////////////////////////////////////////////////////////
68// Caching
69///////////////////////////////////////////////////////////////////////////////
70
71int LayerCache::LayerEntry::compare(const LayerCache::LayerEntry& lhs,
72        const LayerCache::LayerEntry& rhs) {
73    int deltaInt = int(lhs.mWidth) - int(rhs.mWidth);
74    if (deltaInt != 0) return deltaInt;
75
76    return int(lhs.mHeight) - int(rhs.mHeight);
77}
78
79void LayerCache::deleteLayer(Layer* layer) {
80    if (layer) {
81        LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(),
82                layer->getFbo());
83        mSize -= layer->getWidth() * layer->getHeight() * 4;
84        layer->state = Layer::kState_DeletedFromCache;
85        layer->decStrong(nullptr);
86    }
87}
88
89void LayerCache::clear() {
90    for (auto entry : mCache) {
91        deleteLayer(entry.mLayer);
92    }
93    mCache.clear();
94}
95
96Layer* LayerCache::get(RenderState& renderState, const uint32_t width, const uint32_t height) {
97    Layer* layer = nullptr;
98
99    LayerEntry entry(width, height);
100    auto iter = mCache.find(entry);
101
102    if (iter != mCache.end()) {
103        entry = *iter;
104        mCache.erase(iter);
105
106        layer = entry.mLayer;
107        layer->state = Layer::kState_RemovedFromCache;
108        mSize -= layer->getWidth() * layer->getHeight() * 4;
109
110        LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight());
111    } else {
112        LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
113
114        layer = new Layer(Layer::kType_DisplayList, renderState, entry.mWidth, entry.mHeight);
115        layer->setBlend(true);
116        layer->generateTexture();
117        layer->bindTexture();
118        layer->setFilter(GL_NEAREST);
119        layer->setWrap(GL_CLAMP_TO_EDGE, false);
120        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
121
122#if DEBUG_LAYERS
123        dump();
124#endif
125    }
126
127    return layer;
128}
129
130void LayerCache::dump() {
131    for (auto entry : mCache) {
132        ALOGD("  Layer size %dx%d", entry.mWidth, entry.mHeight);
133    }
134}
135
136bool LayerCache::put(Layer* layer) {
137    if (!layer->isCacheable()) return false;
138
139    const uint32_t size = layer->getWidth() * layer->getHeight() * 4;
140    // Don't even try to cache a layer that's bigger than the cache
141    if (size < mMaxSize) {
142        // TODO: Use an LRU
143        while (mSize + size > mMaxSize) {
144            Layer* victim = mCache.begin()->mLayer;
145            deleteLayer(victim);
146            mCache.erase(mCache.begin());
147
148            LAYER_LOGD("  Deleting layer %.2fx%.2f", victim->layer.getWidth(),
149                    victim->layer.getHeight());
150        }
151
152        layer->cancelDefer();
153
154        LayerEntry entry(layer);
155
156        mCache.insert(entry);
157        mSize += size;
158
159        layer->state = Layer::kState_InCache;
160        return true;
161    }
162
163    layer->state = Layer::kState_FailedToCache;
164    return false;
165}
166
167}; // namespace uirenderer
168}; // namespace android
169