LayerCache.cpp revision fb8b763f762ae21923c58d64caa729b012f40e05
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
23dda570201ac851dd85af3861f7e575721d3345daRomain Guy#include "LayerCache.h"
24fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy#include "Properties.h"
25dda570201ac851dd85af3861f7e575721d3345daRomain Guy
26dda570201ac851dd85af3861f7e575721d3345daRomain Guynamespace android {
27dda570201ac851dd85af3861f7e575721d3345daRomain Guynamespace uirenderer {
28dda570201ac851dd85af3861f7e575721d3345daRomain Guy
29dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
30dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Constructors/destructor
31dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
32dda570201ac851dd85af3861f7e575721d3345daRomain Guy
33fb8b763f762ae21923c58d64caa729b012f40e05Romain GuyLayerCache::LayerCache():
34fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity),
35fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        mIdGenerator(1), mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
36fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    char property[PROPERTY_VALUE_MAX];
37fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) {
38fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        LOGD("  Setting layer cache size to %sMB", property);
39fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        setMaxSize(MB(atof(property)));
40fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    } else {
41fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        LOGD("  Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE);
42fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    }
43fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy}
44fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
45dda570201ac851dd85af3861f7e575721d3345daRomain GuyLayerCache::LayerCache(uint32_t maxByteSize):
466c81893c626499e58c8eeb20d6c35ec4e1ce808bRomain Guy        mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity),
476c81893c626499e58c8eeb20d6c35ec4e1ce808bRomain Guy        mIdGenerator(1), mSize(0), mMaxSize(maxByteSize) {
48dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
49dda570201ac851dd85af3861f7e575721d3345daRomain Guy
50dda570201ac851dd85af3861f7e575721d3345daRomain GuyLayerCache::~LayerCache() {
515f0c6a483900f3989f4d2a8f913cf5b6a9777d03Romain Guy    clear();
52dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
53dda570201ac851dd85af3861f7e575721d3345daRomain Guy
54dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
55dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Size management
56dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
57dda570201ac851dd85af3861f7e575721d3345daRomain Guy
58dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getSize() {
59dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return mSize;
60dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
61dda570201ac851dd85af3861f7e575721d3345daRomain Guy
62dda570201ac851dd85af3861f7e575721d3345daRomain Guyuint32_t LayerCache::getMaxSize() {
63dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return mMaxSize;
64dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
65dda570201ac851dd85af3861f7e575721d3345daRomain Guy
66dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::setMaxSize(uint32_t maxSize) {
67dda570201ac851dd85af3861f7e575721d3345daRomain Guy    mMaxSize = maxSize;
68dda570201ac851dd85af3861f7e575721d3345daRomain Guy    while (mSize > mMaxSize) {
69dda570201ac851dd85af3861f7e575721d3345daRomain Guy        Layer* oldest = mCache.removeOldest();
70dda570201ac851dd85af3861f7e575721d3345daRomain Guy        deleteLayer(oldest);
71dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
72dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
73dda570201ac851dd85af3861f7e575721d3345daRomain Guy
74dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
75dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Callbacks
76dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
77dda570201ac851dd85af3861f7e575721d3345daRomain Guy
78dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::operator()(LayerSize& size, Layer*& layer) {
79dda570201ac851dd85af3861f7e575721d3345daRomain Guy    deleteLayer(layer);
80dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
81dda570201ac851dd85af3861f7e575721d3345daRomain Guy
82dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
83dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Caching
84dda570201ac851dd85af3861f7e575721d3345daRomain Guy///////////////////////////////////////////////////////////////////////////////
85dda570201ac851dd85af3861f7e575721d3345daRomain Guy
86dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::deleteLayer(Layer* layer) {
87dda570201ac851dd85af3861f7e575721d3345daRomain Guy    if (layer) {
88dda570201ac851dd85af3861f7e575721d3345daRomain Guy        mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
89dda570201ac851dd85af3861f7e575721d3345daRomain Guy
90dda570201ac851dd85af3861f7e575721d3345daRomain Guy        glDeleteFramebuffers(1, &layer->fbo);
91dda570201ac851dd85af3861f7e575721d3345daRomain Guy        glDeleteTextures(1, &layer->texture);
92dda570201ac851dd85af3861f7e575721d3345daRomain Guy        delete layer;
93dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
94dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
95dda570201ac851dd85af3861f7e575721d3345daRomain Guy
96dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid LayerCache::clear() {
97dda570201ac851dd85af3861f7e575721d3345daRomain Guy    mCache.setOnEntryRemovedListener(this);
98dda570201ac851dd85af3861f7e575721d3345daRomain Guy    mCache.clear();
99dda570201ac851dd85af3861f7e575721d3345daRomain Guy    mCache.setOnEntryRemovedListener(NULL);
100dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
101dda570201ac851dd85af3861f7e575721d3345daRomain Guy
102f18fd99b5c182329cd8936a9611f0103d8ece44aRomain GuyLayer* LayerCache::get(LayerSize& size, GLuint previousFbo) {
103dda570201ac851dd85af3861f7e575721d3345daRomain Guy    Layer* layer = mCache.remove(size);
104dda570201ac851dd85af3861f7e575721d3345daRomain Guy    if (layer) {
105f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        LAYER_LOGD("Reusing layer");
106f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
107dda570201ac851dd85af3861f7e575721d3345daRomain Guy        mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
108f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy    } else {
109f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        LAYER_LOGD("Creating new layer");
110f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
111f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        layer = new Layer;
112f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        layer->blend = true;
113f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
114f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        // Generate the FBO and attach the texture
115f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glGenFramebuffers(1, &layer->fbo);
116f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
117f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
118f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        // Generate the texture in which the FBO will draw
119f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glGenTextures(1, &layer->texture);
120f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glBindTexture(GL_TEXTURE_2D, layer->texture);
121f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
122f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        // The FBO will not be scaled, so we can use lower quality filtering
123f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
124f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
125f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
126f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
127f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
128f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
129f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0,
130f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
131f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
132f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        // Bind texture to FBO
133f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
134f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy                layer->texture, 0);
135f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
136f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
137f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        if (status != GL_FRAMEBUFFER_COMPLETE) {
138f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy            LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
139f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
140f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy            glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
141f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
142f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy            glDeleteFramebuffers(1, &layer->fbo);
143f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy            glDeleteTextures(1, &layer->texture);
144f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy            delete layer;
145f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
146f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy            return NULL;
147f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        }
148dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
149f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy
150dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return layer;
151dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
152dda570201ac851dd85af3861f7e575721d3345daRomain Guy
153dda570201ac851dd85af3861f7e575721d3345daRomain Guybool LayerCache::put(LayerSize& layerSize, Layer* layer) {
154dda570201ac851dd85af3861f7e575721d3345daRomain Guy    const uint32_t size = layerSize.width * layerSize.height * 4;
155dda570201ac851dd85af3861f7e575721d3345daRomain Guy    // Don't even try to cache a layer that's bigger than the cache
156dda570201ac851dd85af3861f7e575721d3345daRomain Guy    if (size < mMaxSize) {
157dda570201ac851dd85af3861f7e575721d3345daRomain Guy        while (mSize + size > mMaxSize) {
158dda570201ac851dd85af3861f7e575721d3345daRomain Guy            Layer* oldest = mCache.removeOldest();
159dda570201ac851dd85af3861f7e575721d3345daRomain Guy            deleteLayer(oldest);
160dda570201ac851dd85af3861f7e575721d3345daRomain Guy        }
161dda570201ac851dd85af3861f7e575721d3345daRomain Guy
1626c81893c626499e58c8eeb20d6c35ec4e1ce808bRomain Guy        layerSize.id = mIdGenerator++;
163dda570201ac851dd85af3861f7e575721d3345daRomain Guy        mCache.put(layerSize, layer);
164dda570201ac851dd85af3861f7e575721d3345daRomain Guy        mSize += size;
165dda570201ac851dd85af3861f7e575721d3345daRomain Guy
166dda570201ac851dd85af3861f7e575721d3345daRomain Guy        return true;
167dda570201ac851dd85af3861f7e575721d3345daRomain Guy    }
168dda570201ac851dd85af3861f7e575721d3345daRomain Guy    return false;
169dda570201ac851dd85af3861f7e575721d3345daRomain Guy}
170dda570201ac851dd85af3861f7e575721d3345daRomain Guy
171dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace uirenderer
172dda570201ac851dd85af3861f7e575721d3345daRomain Guy}; // namespace android
173