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 "RenderBufferCache.h"
18 #include "Debug.h"
19 #include "DeviceInfo.h"
20 #include "Properties.h"
21 
22 #include <utils/Log.h>
23 
24 #include <cstdlib>
25 
26 namespace android {
27 namespace uirenderer {
28 
29 ///////////////////////////////////////////////////////////////////////////////
30 // Defines
31 ///////////////////////////////////////////////////////////////////////////////
32 
33 // Debug
34 #if DEBUG_RENDER_BUFFERS
35 #define RENDER_BUFFER_LOGD(...) ALOGD(__VA_ARGS__)
36 #else
37 #define RENDER_BUFFER_LOGD(...)
38 #endif
39 
calculateRboCacheSize()40 static uint32_t calculateRboCacheSize() {
41     // TODO: Do we need to use extensions().has4BitStencil() here?
42     // The tuning guide recommends it, but all real devices are configured
43     // with a larger cache than necessary by 4x, so keep the 2x for now regardless
44     return DeviceInfo::multiplyByResolution(2);
45 }
46 
47 ///////////////////////////////////////////////////////////////////////////////
48 // Constructors/destructor
49 ///////////////////////////////////////////////////////////////////////////////
50 
RenderBufferCache()51 RenderBufferCache::RenderBufferCache() : mSize(0), mMaxSize(calculateRboCacheSize()) {}
52 
~RenderBufferCache()53 RenderBufferCache::~RenderBufferCache() {
54     clear();
55 }
56 
57 ///////////////////////////////////////////////////////////////////////////////
58 // Size management
59 ///////////////////////////////////////////////////////////////////////////////
60 
getSize()61 uint32_t RenderBufferCache::getSize() {
62     return mSize;
63 }
64 
getMaxSize()65 uint32_t RenderBufferCache::getMaxSize() {
66     return mMaxSize;
67 }
68 
69 ///////////////////////////////////////////////////////////////////////////////
70 // Caching
71 ///////////////////////////////////////////////////////////////////////////////
72 
compare(const RenderBufferCache::RenderBufferEntry & lhs,const RenderBufferCache::RenderBufferEntry & rhs)73 int RenderBufferCache::RenderBufferEntry::compare(const RenderBufferCache::RenderBufferEntry& lhs,
74                                                   const RenderBufferCache::RenderBufferEntry& rhs) {
75     int deltaInt = int(lhs.mWidth) - int(rhs.mWidth);
76     if (deltaInt != 0) return deltaInt;
77 
78     deltaInt = int(lhs.mHeight) - int(rhs.mHeight);
79     if (deltaInt != 0) return deltaInt;
80 
81     return int(lhs.mFormat) - int(rhs.mFormat);
82 }
83 
deleteBuffer(RenderBuffer * buffer)84 void RenderBufferCache::deleteBuffer(RenderBuffer* buffer) {
85     if (buffer) {
86         RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d)",
87                            RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(),
88                            buffer->getHeight());
89 
90         mSize -= buffer->getSize();
91         delete buffer;
92     }
93 }
94 
clear()95 void RenderBufferCache::clear() {
96     for (auto entry : mCache) {
97         deleteBuffer(entry.mBuffer);
98     }
99     mCache.clear();
100 }
101 
get(GLenum format,const uint32_t width,const uint32_t height)102 RenderBuffer* RenderBufferCache::get(GLenum format, const uint32_t width, const uint32_t height) {
103     RenderBuffer* buffer = nullptr;
104 
105     RenderBufferEntry entry(format, width, height);
106     auto iter = mCache.find(entry);
107 
108     if (iter != mCache.end()) {
109         entry = *iter;
110         mCache.erase(iter);
111 
112         buffer = entry.mBuffer;
113         mSize -= buffer->getSize();
114 
115         RENDER_BUFFER_LOGD("Found %s render buffer (%dx%d)", RenderBuffer::formatName(format),
116                            width, height);
117     } else {
118         buffer = new RenderBuffer(format, width, height);
119 
120         RENDER_BUFFER_LOGD("Created new %s render buffer (%dx%d)", RenderBuffer::formatName(format),
121                            width, height);
122     }
123 
124     buffer->bind();
125     buffer->allocate();
126 
127     return buffer;
128 }
129 
put(RenderBuffer * buffer)130 bool RenderBufferCache::put(RenderBuffer* buffer) {
131     if (!buffer) return false;
132 
133     const uint32_t size = buffer->getSize();
134     if (size < mMaxSize) {
135         while (mSize + size > mMaxSize) {
136             RenderBuffer* victim = mCache.begin()->mBuffer;
137             deleteBuffer(victim);
138             mCache.erase(mCache.begin());
139         }
140 
141         RenderBufferEntry entry(buffer);
142 
143         mCache.insert(entry);
144         mSize += size;
145 
146         RENDER_BUFFER_LOGD("Added %s render buffer (%dx%d)",
147                            RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(),
148                            buffer->getHeight());
149 
150         return true;
151     } else {
152         RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d) Size=%d, MaxSize=%d",
153                            RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(),
154                            buffer->getHeight(), size, mMaxSize);
155         delete buffer;
156     }
157     return false;
158 }
159 
160 };  // namespace uirenderer
161 };  // namespace android
162