blob: bcda45e74e140ca59c4e9d6ebc2c15e9475fe675 [file] [log] [blame]
Romain Guydda57022010-07-06 11:39:32 -07001/*
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#define LOG_TAG "OpenGLRenderer"
18
19#include <GLES2/gl2.h>
20
Romain Guyf18fd992010-07-08 11:45:51 -070021#include <utils/Log.h>
22
Romain Guydda57022010-07-06 11:39:32 -070023#include "LayerCache.h"
24
25namespace android {
26namespace uirenderer {
27
28///////////////////////////////////////////////////////////////////////////////
29// Constructors/destructor
30///////////////////////////////////////////////////////////////////////////////
31
32LayerCache::LayerCache(uint32_t maxByteSize):
Romain Guy6c818932010-07-07 15:15:32 -070033 mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity),
34 mIdGenerator(1), mSize(0), mMaxSize(maxByteSize) {
Romain Guydda57022010-07-06 11:39:32 -070035}
36
37LayerCache::~LayerCache() {
Romain Guy5f0c6a42010-07-07 13:06:26 -070038 clear();
Romain Guydda57022010-07-06 11:39:32 -070039}
40
41///////////////////////////////////////////////////////////////////////////////
42// Size management
43///////////////////////////////////////////////////////////////////////////////
44
45uint32_t LayerCache::getSize() {
46 return mSize;
47}
48
49uint32_t LayerCache::getMaxSize() {
50 return mMaxSize;
51}
52
53void LayerCache::setMaxSize(uint32_t maxSize) {
54 mMaxSize = maxSize;
55 while (mSize > mMaxSize) {
56 Layer* oldest = mCache.removeOldest();
57 deleteLayer(oldest);
58 }
59}
60
61///////////////////////////////////////////////////////////////////////////////
62// Callbacks
63///////////////////////////////////////////////////////////////////////////////
64
65void LayerCache::operator()(LayerSize& size, Layer*& layer) {
66 deleteLayer(layer);
67}
68
69///////////////////////////////////////////////////////////////////////////////
70// Caching
71///////////////////////////////////////////////////////////////////////////////
72
73void LayerCache::deleteLayer(Layer* layer) {
74 if (layer) {
75 mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
76
77 glDeleteFramebuffers(1, &layer->fbo);
78 glDeleteTextures(1, &layer->texture);
79 delete layer;
80 }
81}
82
83void LayerCache::clear() {
84 mCache.setOnEntryRemovedListener(this);
85 mCache.clear();
86 mCache.setOnEntryRemovedListener(NULL);
87}
88
Romain Guyf18fd992010-07-08 11:45:51 -070089Layer* LayerCache::get(LayerSize& size, GLuint previousFbo) {
Romain Guydda57022010-07-06 11:39:32 -070090 Layer* layer = mCache.remove(size);
91 if (layer) {
Romain Guyf18fd992010-07-08 11:45:51 -070092 LAYER_LOGD("Reusing layer");
93
Romain Guydda57022010-07-06 11:39:32 -070094 mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
Romain Guyf18fd992010-07-08 11:45:51 -070095 } else {
96 LAYER_LOGD("Creating new layer");
97
98 layer = new Layer;
99 layer->blend = true;
100
101 // Generate the FBO and attach the texture
102 glGenFramebuffers(1, &layer->fbo);
103 glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
104
105 // Generate the texture in which the FBO will draw
106 glGenTextures(1, &layer->texture);
107 glBindTexture(GL_TEXTURE_2D, layer->texture);
108
109 // The FBO will not be scaled, so we can use lower quality filtering
110 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
111 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
112
113 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
115
116 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0,
117 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
118 glBindTexture(GL_TEXTURE_2D, 0);
119
120 // Bind texture to FBO
121 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
122 layer->texture, 0);
123
124 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
125 if (status != GL_FRAMEBUFFER_COMPLETE) {
126 LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
127
128 glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
129
130 glDeleteFramebuffers(1, &layer->fbo);
131 glDeleteTextures(1, &layer->texture);
132 delete layer;
133
134 return NULL;
135 }
Romain Guydda57022010-07-06 11:39:32 -0700136 }
Romain Guyf18fd992010-07-08 11:45:51 -0700137
Romain Guydda57022010-07-06 11:39:32 -0700138 return layer;
139}
140
141bool LayerCache::put(LayerSize& layerSize, Layer* layer) {
142 const uint32_t size = layerSize.width * layerSize.height * 4;
143 // Don't even try to cache a layer that's bigger than the cache
144 if (size < mMaxSize) {
145 while (mSize + size > mMaxSize) {
146 Layer* oldest = mCache.removeOldest();
147 deleteLayer(oldest);
148 }
149
Romain Guy6c818932010-07-07 15:15:32 -0700150 layerSize.id = mIdGenerator++;
Romain Guydda57022010-07-06 11:39:32 -0700151 mCache.put(layerSize, layer);
152 mSize += size;
153
154 return true;
155 }
156 return false;
157}
158
159}; // namespace uirenderer
160}; // namespace android