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 #include "Debug.h"
18 #include "Properties.h"
19 #include "RenderBufferCache.h"
20 
21 #include <utils/Log.h>
22 
23 #include <cstdlib>
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()
44         : mSize(0)
45         , mMaxSize(Properties::renderBufferCacheSize) {}
46 
~RenderBufferCache()47 RenderBufferCache::~RenderBufferCache() {
48     clear();
49 }
50 
51 ///////////////////////////////////////////////////////////////////////////////
52 // Size management
53 ///////////////////////////////////////////////////////////////////////////////
54 
getSize()55 uint32_t RenderBufferCache::getSize() {
56     return mSize;
57 }
58 
getMaxSize()59 uint32_t RenderBufferCache::getMaxSize() {
60     return mMaxSize;
61 }
62 
63 ///////////////////////////////////////////////////////////////////////////////
64 // Caching
65 ///////////////////////////////////////////////////////////////////////////////
66 
compare(const RenderBufferCache::RenderBufferEntry & lhs,const RenderBufferCache::RenderBufferEntry & rhs)67 int RenderBufferCache::RenderBufferEntry::compare(
68         const RenderBufferCache::RenderBufferEntry& lhs,
69         const RenderBufferCache::RenderBufferEntry& rhs) {
70     int deltaInt = int(lhs.mWidth) - int(rhs.mWidth);
71     if (deltaInt != 0) return deltaInt;
72 
73     deltaInt = int(lhs.mHeight) - int(rhs.mHeight);
74     if (deltaInt != 0) return deltaInt;
75 
76     return int(lhs.mFormat) - int(rhs.mFormat);
77 }
78 
deleteBuffer(RenderBuffer * buffer)79 void RenderBufferCache::deleteBuffer(RenderBuffer* buffer) {
80     if (buffer) {
81         RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d)",
82                 RenderBuffer::formatName(buffer->getFormat()),
83                 buffer->getWidth(), buffer->getHeight());
84 
85         mSize -= buffer->getSize();
86         delete buffer;
87     }
88 }
89 
clear()90 void RenderBufferCache::clear() {
91     for (auto entry : mCache) {
92         deleteBuffer(entry.mBuffer);
93     }
94     mCache.clear();
95 }
96 
get(GLenum format,const uint32_t width,const uint32_t height)97 RenderBuffer* RenderBufferCache::get(GLenum format, const uint32_t width, const uint32_t height) {
98     RenderBuffer* buffer = nullptr;
99 
100     RenderBufferEntry entry(format, width, height);
101     auto iter = mCache.find(entry);
102 
103     if (iter != mCache.end()) {
104         entry = *iter;
105         mCache.erase(iter);
106 
107         buffer = entry.mBuffer;
108         mSize -= buffer->getSize();
109 
110         RENDER_BUFFER_LOGD("Found %s render buffer (%dx%d)",
111                 RenderBuffer::formatName(format), width, height);
112     } else {
113         buffer = new RenderBuffer(format, width, height);
114 
115         RENDER_BUFFER_LOGD("Created new %s render buffer (%dx%d)",
116                 RenderBuffer::formatName(format), width, height);
117     }
118 
119     buffer->bind();
120     buffer->allocate();
121 
122     return buffer;
123 }
124 
put(RenderBuffer * buffer)125 bool RenderBufferCache::put(RenderBuffer* buffer) {
126     if (!buffer) return false;
127 
128     const uint32_t size = buffer->getSize();
129     if (size < mMaxSize) {
130         while (mSize + size > mMaxSize) {
131             RenderBuffer* victim = mCache.begin()->mBuffer;
132             deleteBuffer(victim);
133             mCache.erase(mCache.begin());
134         }
135 
136         RenderBufferEntry entry(buffer);
137 
138         mCache.insert(entry);
139         mSize += size;
140 
141         RENDER_BUFFER_LOGD("Added %s render buffer (%dx%d)",
142                 RenderBuffer::formatName(buffer->getFormat()),
143                 buffer->getWidth(), buffer->getHeight());
144 
145         return true;
146     } else {
147         RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d) Size=%d, MaxSize=%d",
148         RenderBuffer::formatName(buffer->getFormat()),
149                  buffer->getWidth(), buffer->getHeight(), size, mMaxSize);
150         delete buffer;
151     }
152     return false;
153 }
154 
155 }; // namespace uirenderer
156 }; // namespace android
157