blob: 2f8ddfe6d6606d49104da459224c86d4080a88bc [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Debug.h"
#include "Properties.h"
#include "RenderBufferCache.h"
#include "DeviceInfo.h"
#include <utils/Log.h>
#include <cstdlib>
namespace android {
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
// Defines
///////////////////////////////////////////////////////////////////////////////
// Debug
#if DEBUG_RENDER_BUFFERS
#define RENDER_BUFFER_LOGD(...) ALOGD(__VA_ARGS__)
#else
#define RENDER_BUFFER_LOGD(...)
#endif
static uint32_t calculateRboCacheSize() {
// TODO: Do we need to use extensions().has4BitStencil() here?
// The tuning guide recommends it, but all real devices are configured
// with a larger cache than necessary by 4x, so keep the 2x for now regardless
return DeviceInfo::multiplyByResolution(2);
}
///////////////////////////////////////////////////////////////////////////////
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
RenderBufferCache::RenderBufferCache()
: mSize(0)
, mMaxSize(calculateRboCacheSize()) {}
RenderBufferCache::~RenderBufferCache() {
clear();
}
///////////////////////////////////////////////////////////////////////////////
// Size management
///////////////////////////////////////////////////////////////////////////////
uint32_t RenderBufferCache::getSize() {
return mSize;
}
uint32_t RenderBufferCache::getMaxSize() {
return mMaxSize;
}
///////////////////////////////////////////////////////////////////////////////
// Caching
///////////////////////////////////////////////////////////////////////////////
int RenderBufferCache::RenderBufferEntry::compare(
const RenderBufferCache::RenderBufferEntry& lhs,
const RenderBufferCache::RenderBufferEntry& rhs) {
int deltaInt = int(lhs.mWidth) - int(rhs.mWidth);
if (deltaInt != 0) return deltaInt;
deltaInt = int(lhs.mHeight) - int(rhs.mHeight);
if (deltaInt != 0) return deltaInt;
return int(lhs.mFormat) - int(rhs.mFormat);
}
void RenderBufferCache::deleteBuffer(RenderBuffer* buffer) {
if (buffer) {
RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d)",
RenderBuffer::formatName(buffer->getFormat()),
buffer->getWidth(), buffer->getHeight());
mSize -= buffer->getSize();
delete buffer;
}
}
void RenderBufferCache::clear() {
for (auto entry : mCache) {
deleteBuffer(entry.mBuffer);
}
mCache.clear();
}
RenderBuffer* RenderBufferCache::get(GLenum format, const uint32_t width, const uint32_t height) {
RenderBuffer* buffer = nullptr;
RenderBufferEntry entry(format, width, height);
auto iter = mCache.find(entry);
if (iter != mCache.end()) {
entry = *iter;
mCache.erase(iter);
buffer = entry.mBuffer;
mSize -= buffer->getSize();
RENDER_BUFFER_LOGD("Found %s render buffer (%dx%d)",
RenderBuffer::formatName(format), width, height);
} else {
buffer = new RenderBuffer(format, width, height);
RENDER_BUFFER_LOGD("Created new %s render buffer (%dx%d)",
RenderBuffer::formatName(format), width, height);
}
buffer->bind();
buffer->allocate();
return buffer;
}
bool RenderBufferCache::put(RenderBuffer* buffer) {
if (!buffer) return false;
const uint32_t size = buffer->getSize();
if (size < mMaxSize) {
while (mSize + size > mMaxSize) {
RenderBuffer* victim = mCache.begin()->mBuffer;
deleteBuffer(victim);
mCache.erase(mCache.begin());
}
RenderBufferEntry entry(buffer);
mCache.insert(entry);
mSize += size;
RENDER_BUFFER_LOGD("Added %s render buffer (%dx%d)",
RenderBuffer::formatName(buffer->getFormat()),
buffer->getWidth(), buffer->getHeight());
return true;
} else {
RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d) Size=%d, MaxSize=%d",
RenderBuffer::formatName(buffer->getFormat()),
buffer->getWidth(), buffer->getHeight(), size, mMaxSize);
delete buffer;
}
return false;
}
}; // namespace uirenderer
}; // namespace android