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 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 51 RenderBufferCache::RenderBufferCache() : mSize(0), mMaxSize(calculateRboCacheSize()) {} 52 53 RenderBufferCache::~RenderBufferCache() { 54 clear(); 55 } 56 57 /////////////////////////////////////////////////////////////////////////////// 58 // Size management 59 /////////////////////////////////////////////////////////////////////////////// 60 61 uint32_t RenderBufferCache::getSize() { 62 return mSize; 63 } 64 65 uint32_t RenderBufferCache::getMaxSize() { 66 return mMaxSize; 67 } 68 69 /////////////////////////////////////////////////////////////////////////////// 70 // Caching 71 /////////////////////////////////////////////////////////////////////////////// 72 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 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 95 void RenderBufferCache::clear() { 96 for (auto entry : mCache) { 97 deleteBuffer(entry.mBuffer); 98 } 99 mCache.clear(); 100 } 101 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 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