1 /*
2  * Copyright (C) 2013 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 <utils/Log.h>
20 
21 #include "Debug.h"
22 #include "Properties.h"
23 #include "RenderBufferCache.h"
24 
25 namespace android {
26 namespace uirenderer {
27 
28 ///////////////////////////////////////////////////////////////////////////////
29 // Defines
30 ///////////////////////////////////////////////////////////////////////////////
31 
32 // Debug
33 #if DEBUG_RENDER_BUFFERS
34     #define RENDER_BUFFER_LOGD(...) ALOGD(__VA_ARGS__)
35 #else
36     #define RENDER_BUFFER_LOGD(...)
37 #endif
38 
39 ///////////////////////////////////////////////////////////////////////////////
40 // Constructors/destructor
41 ///////////////////////////////////////////////////////////////////////////////
42 
RenderBufferCache()43 RenderBufferCache::RenderBufferCache(): mSize(0), mMaxSize(MB(DEFAULT_RENDER_BUFFER_CACHE_SIZE)) {
44     char property[PROPERTY_VALUE_MAX];
45     if (property_get(PROPERTY_RENDER_BUFFER_CACHE_SIZE, property, NULL) > 0) {
46         INIT_LOGD("  Setting render buffer cache size to %sMB", property);
47         setMaxSize(MB(atof(property)));
48     } else {
49         INIT_LOGD("  Using default render buffer cache size of %.2fMB",
50                 DEFAULT_RENDER_BUFFER_CACHE_SIZE);
51     }
52 }
53 
~RenderBufferCache()54 RenderBufferCache::~RenderBufferCache() {
55     clear();
56 }
57 
58 ///////////////////////////////////////////////////////////////////////////////
59 // Size management
60 ///////////////////////////////////////////////////////////////////////////////
61 
getSize()62 uint32_t RenderBufferCache::getSize() {
63     return mSize;
64 }
65 
getMaxSize()66 uint32_t RenderBufferCache::getMaxSize() {
67     return mMaxSize;
68 }
69 
setMaxSize(uint32_t maxSize)70 void RenderBufferCache::setMaxSize(uint32_t maxSize) {
71     clear();
72     mMaxSize = maxSize;
73 }
74 
75 ///////////////////////////////////////////////////////////////////////////////
76 // Caching
77 ///////////////////////////////////////////////////////////////////////////////
78 
compare(const RenderBufferCache::RenderBufferEntry & lhs,const RenderBufferCache::RenderBufferEntry & rhs)79 int RenderBufferCache::RenderBufferEntry::compare(
80         const RenderBufferCache::RenderBufferEntry& lhs,
81         const RenderBufferCache::RenderBufferEntry& rhs) {
82     int deltaInt = int(lhs.mWidth) - int(rhs.mWidth);
83     if (deltaInt != 0) return deltaInt;
84 
85     deltaInt = int(lhs.mHeight) - int(rhs.mHeight);
86     if (deltaInt != 0) return deltaInt;
87 
88     return int(lhs.mFormat) - int(rhs.mFormat);
89 }
90 
deleteBuffer(RenderBuffer * buffer)91 void RenderBufferCache::deleteBuffer(RenderBuffer* buffer) {
92     if (buffer) {
93         RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d)",
94                 RenderBuffer::formatName(buffer->getFormat()),
95                 buffer->getWidth(), buffer->getHeight());
96 
97         mSize -= buffer->getSize();
98         delete buffer;
99     }
100 }
101 
clear()102 void RenderBufferCache::clear() {
103     size_t count = mCache.size();
104     for (size_t i = 0; i < count; i++) {
105         deleteBuffer(mCache.itemAt(i).mBuffer);
106     }
107     mCache.clear();
108 }
109 
get(GLenum format,const uint32_t width,const uint32_t height)110 RenderBuffer* RenderBufferCache::get(GLenum format, const uint32_t width, const uint32_t height) {
111     RenderBuffer* buffer = NULL;
112 
113     RenderBufferEntry entry(format, width, height);
114     ssize_t index = mCache.indexOf(entry);
115 
116     if (index >= 0) {
117         entry = mCache.itemAt(index);
118         mCache.removeAt(index);
119 
120         buffer = entry.mBuffer;
121         mSize -= buffer->getSize();
122 
123         RENDER_BUFFER_LOGD("Found %s render buffer (%dx%d)",
124                 RenderBuffer::formatName(format), width, height);
125     } else {
126         buffer = new RenderBuffer(format, width, height);
127 
128         RENDER_BUFFER_LOGD("Created new %s render buffer (%dx%d)",
129                 RenderBuffer::formatName(format), width, height);
130     }
131 
132     buffer->bind();
133     buffer->allocate();
134 
135     return buffer;
136 }
137 
put(RenderBuffer * buffer)138 bool RenderBufferCache::put(RenderBuffer* buffer) {
139     if (!buffer) return false;
140 
141     const uint32_t size = buffer->getSize();
142     if (size < mMaxSize) {
143         while (mSize + size > mMaxSize) {
144             size_t position = 0;
145 
146             RenderBuffer* victim = mCache.itemAt(position).mBuffer;
147             deleteBuffer(victim);
148             mCache.removeAt(position);
149         }
150 
151         RenderBufferEntry entry(buffer);
152 
153         mCache.add(entry);
154         mSize += size;
155 
156         RENDER_BUFFER_LOGD("Added %s render buffer (%dx%d)",
157                 RenderBuffer::formatName(buffer->getFormat()),
158                 buffer->getWidth(), buffer->getHeight());
159 
160         return true;
161     }
162     return false;
163 }
164 
165 }; // namespace uirenderer
166 }; // namespace android
167