Add a render buffer cache to reuse stencil buffers
Bug #7146141 This new cache is used in a similar way to LayerCache. It helps reuse already allocated stencil buffers and thus avoid churning memory on every frame. Change-Id: I19551d72da52c40039e65904563600e492c8b193
This commit is contained in:
@@ -48,7 +48,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
import static javax.microedition.khronos.egl.EGL10.*;
|
||||
|
||||
/**
|
||||
* Interface for rendering a ViewAncestor using hardware acceleration.
|
||||
* Interface for rendering a view hierarchy using hardware acceleration.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
|
||||
PathTessellator.cpp \
|
||||
Program.cpp \
|
||||
ProgramCache.cpp \
|
||||
RenderBufferCache.cpp \
|
||||
ResourceCache.cpp \
|
||||
ShapeCache.cpp \
|
||||
SkiaColorFilter.cpp \
|
||||
|
||||
@@ -186,6 +186,8 @@ void Caches::dumpMemoryUsage(String8 &log) {
|
||||
textureCache.getSize(), textureCache.getMaxSize());
|
||||
log.appendFormat(" LayerCache %8d / %8d\n",
|
||||
layerCache.getSize(), layerCache.getMaxSize());
|
||||
log.appendFormat(" RenderBufferCache %8d / %8d\n",
|
||||
renderBufferCache.getSize(), renderBufferCache.getMaxSize());
|
||||
log.appendFormat(" GradientCache %8d / %8d\n",
|
||||
gradientCache.getSize(), gradientCache.getMaxSize());
|
||||
log.appendFormat(" PathCache %8d / %8d\n",
|
||||
@@ -215,6 +217,7 @@ void Caches::dumpMemoryUsage(String8 &log) {
|
||||
uint32_t total = 0;
|
||||
total += textureCache.getSize();
|
||||
total += layerCache.getSize();
|
||||
total += renderBufferCache.getSize();
|
||||
total += gradientCache.getSize();
|
||||
total += pathCache.getSize();
|
||||
total += dropShadowCache.getSize();
|
||||
@@ -298,6 +301,7 @@ void Caches::flush(FlushMode mode) {
|
||||
// fall through
|
||||
case kFlushMode_Layers:
|
||||
layerCache.clear();
|
||||
renderBufferCache.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "GammaFontRenderer.h"
|
||||
#include "TextureCache.h"
|
||||
#include "LayerCache.h"
|
||||
#include "RenderBufferCache.h"
|
||||
#include "GradientCache.h"
|
||||
#include "PatchCache.h"
|
||||
#include "ProgramCache.h"
|
||||
@@ -249,6 +250,7 @@ public:
|
||||
|
||||
TextureCache textureCache;
|
||||
LayerCache layerCache;
|
||||
RenderBufferCache renderBufferCache;
|
||||
GradientCache gradientCache;
|
||||
ProgramCache programCache;
|
||||
PathCache pathCache;
|
||||
|
||||
@@ -44,6 +44,9 @@
|
||||
// Turn on to display info about layers
|
||||
#define DEBUG_LAYERS 0
|
||||
|
||||
// Turn on to display info about render buffers
|
||||
#define DEBUG_RENDER_BUFFERS 0
|
||||
|
||||
// Turn on to make stencil operations easier to debug
|
||||
#define DEBUG_STENCIL 0
|
||||
|
||||
|
||||
@@ -101,14 +101,13 @@ bool Layer::resize(const uint32_t width, const uint32_t height) {
|
||||
|
||||
void Layer::removeFbo(bool flush) {
|
||||
if (stencil) {
|
||||
// TODO: recycle & cache instead of simply deleting
|
||||
GLuint previousFbo;
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
|
||||
if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||
if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
|
||||
|
||||
delete stencil;
|
||||
Caches::getInstance().renderBufferCache.put(stencil);
|
||||
stencil = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "Caches.h"
|
||||
#include "Debug.h"
|
||||
#include "LayerCache.h"
|
||||
#include "Properties.h"
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "Debug.h"
|
||||
#include "Layer.h"
|
||||
#include "Properties.h"
|
||||
#include "utils/SortedList.h"
|
||||
|
||||
namespace android {
|
||||
@@ -54,7 +53,7 @@ public:
|
||||
* size of the cache goes down.
|
||||
*
|
||||
* @param width The desired width of the layer
|
||||
* @param width The desired height of the layer
|
||||
* @param height The desired height of the layer
|
||||
*/
|
||||
Layer* get(const uint32_t width, const uint32_t height);
|
||||
|
||||
@@ -91,6 +90,7 @@ public:
|
||||
*/
|
||||
void dump();
|
||||
|
||||
private:
|
||||
struct LayerEntry {
|
||||
LayerEntry():
|
||||
mLayer(NULL), mWidth(0), mHeight(0) {
|
||||
@@ -115,12 +115,19 @@ public:
|
||||
return compare(*this, other) != 0;
|
||||
}
|
||||
|
||||
friend inline int strictly_order_type(const LayerEntry& lhs, const LayerEntry& rhs) {
|
||||
return LayerEntry::compare(lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
friend inline int compare_type(const LayerEntry& lhs, const LayerEntry& rhs) {
|
||||
return LayerEntry::compare(lhs, rhs);
|
||||
}
|
||||
|
||||
Layer* mLayer;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
}; // struct LayerEntry
|
||||
|
||||
private:
|
||||
void deleteLayer(Layer* layer);
|
||||
|
||||
SortedList<LayerEntry> mCache;
|
||||
@@ -129,15 +136,6 @@ private:
|
||||
uint32_t mMaxSize;
|
||||
}; // class LayerCache
|
||||
|
||||
inline int strictly_order_type(const LayerCache::LayerEntry& lhs,
|
||||
const LayerCache::LayerEntry& rhs) {
|
||||
return LayerCache::LayerEntry::compare(lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
inline int compare_type(const LayerCache::LayerEntry& lhs, const LayerCache::LayerEntry& rhs) {
|
||||
return LayerCache::LayerEntry::compare(lhs, rhs);
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
|
||||
@@ -1273,11 +1273,8 @@ void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
|
||||
// attach the new render buffer then turn tiling back on
|
||||
endTiling();
|
||||
|
||||
RenderBuffer* buffer = new RenderBuffer(
|
||||
RenderBuffer* buffer = mCaches.renderBufferCache.get(
|
||||
Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
|
||||
buffer->bind();
|
||||
buffer->allocate();
|
||||
|
||||
layer->setStencilRenderBuffer(buffer);
|
||||
|
||||
startTiling(layer->clipRect, layer->layer.getHeight());
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
// Textures used by layers must have dimensions multiples of this number
|
||||
#define LAYER_SIZE 64
|
||||
|
||||
// Defines the size in bits of the stencil buffer
|
||||
// Defines the size in bits of the stencil buffer for the framebuffer
|
||||
// Note: Only 1 bit is required for clipping but more bits are required
|
||||
// to properly implement the winding fill rule when rasterizing paths
|
||||
// to properly implement overdraw debugging
|
||||
#define STENCIL_BUFFER_SIZE 8
|
||||
|
||||
/**
|
||||
@@ -85,6 +85,7 @@ enum DebugLevel {
|
||||
// These properties are defined in mega-bytes
|
||||
#define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
|
||||
#define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"
|
||||
#define PROPERTY_RENDER_BUFFER_CACHE_SIZE "ro.hwui.r_buffer_cache_size"
|
||||
#define PROPERTY_GRADIENT_CACHE_SIZE "ro.hwui.gradient_cache_size"
|
||||
#define PROPERTY_PATH_CACHE_SIZE "ro.hwui.path_cache_size"
|
||||
#define PROPERTY_SHAPE_CACHE_SIZE "ro.hwui.shape_cache_size"
|
||||
@@ -130,6 +131,7 @@ enum DebugLevel {
|
||||
|
||||
#define DEFAULT_TEXTURE_CACHE_SIZE 24.0f
|
||||
#define DEFAULT_LAYER_CACHE_SIZE 16.0f
|
||||
#define DEFAULT_RENDER_BUFFER_CACHE_SIZE 2.0f
|
||||
#define DEFAULT_PATH_CACHE_SIZE 4.0f
|
||||
#define DEFAULT_SHAPE_CACHE_SIZE 1.0f
|
||||
#define DEFAULT_PATCH_CACHE_SIZE 512
|
||||
|
||||
@@ -39,7 +39,7 @@ struct RenderBuffer {
|
||||
}
|
||||
|
||||
~RenderBuffer() {
|
||||
if (mName && mAllocated) {
|
||||
if (mName) {
|
||||
glDeleteRenderbuffers(1, &mName);
|
||||
}
|
||||
}
|
||||
@@ -154,6 +154,29 @@ struct RenderBuffer {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the specified render buffer format.
|
||||
*/
|
||||
static const char* formatName(GLenum format) {
|
||||
switch (format) {
|
||||
case GL_STENCIL_INDEX8:
|
||||
return "STENCIL_8";
|
||||
case GL_STENCIL_INDEX1_OES:
|
||||
return "STENCIL_1";
|
||||
case GL_STENCIL_INDEX4_OES:
|
||||
return "STENCIL_4";
|
||||
case GL_DEPTH_COMPONENT16:
|
||||
return "DEPTH_16";
|
||||
case GL_RGBA4:
|
||||
return "RGBA_444";
|
||||
case GL_RGB565:
|
||||
return "RGB_565";
|
||||
case GL_RGB5_A1:
|
||||
return "RGBA_5551";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
private:
|
||||
GLenum mFormat;
|
||||
|
||||
|
||||
166
libs/hwui/RenderBufferCache.cpp
Normal file
166
libs/hwui/RenderBufferCache.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "OpenGLRenderer"
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "Debug.h"
|
||||
#include "Properties.h"
|
||||
#include "RenderBufferCache.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Defines
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Debug
|
||||
#if DEBUG_RENDER_BUFFERS
|
||||
#define RENDER_BUFFER_LOGD(...) ALOGD(__VA_ARGS__)
|
||||
#else
|
||||
#define RENDER_BUFFER_LOGD(...)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Constructors/destructor
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RenderBufferCache::RenderBufferCache(): mSize(0), mMaxSize(MB(DEFAULT_RENDER_BUFFER_CACHE_SIZE)) {
|
||||
char property[PROPERTY_VALUE_MAX];
|
||||
if (property_get(PROPERTY_RENDER_BUFFER_CACHE_SIZE, property, NULL) > 0) {
|
||||
INIT_LOGD(" Setting render buffer cache size to %sMB", property);
|
||||
setMaxSize(MB(atof(property)));
|
||||
} else {
|
||||
INIT_LOGD(" Using default render buffer cache size of %.2fMB",
|
||||
DEFAULT_RENDER_BUFFER_CACHE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
RenderBufferCache::~RenderBufferCache() {
|
||||
clear();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Size management
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32_t RenderBufferCache::getSize() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
uint32_t RenderBufferCache::getMaxSize() {
|
||||
return mMaxSize;
|
||||
}
|
||||
|
||||
void RenderBufferCache::setMaxSize(uint32_t maxSize) {
|
||||
clear();
|
||||
mMaxSize = maxSize;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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() {
|
||||
size_t count = mCache.size();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
deleteBuffer(mCache.itemAt(i).mBuffer);
|
||||
}
|
||||
mCache.clear();
|
||||
}
|
||||
|
||||
RenderBuffer* RenderBufferCache::get(GLenum format, const uint32_t width, const uint32_t height) {
|
||||
RenderBuffer* buffer = NULL;
|
||||
|
||||
RenderBufferEntry entry(format, width, height);
|
||||
ssize_t index = mCache.indexOf(entry);
|
||||
|
||||
if (index >= 0) {
|
||||
entry = mCache.itemAt(index);
|
||||
mCache.removeAt(index);
|
||||
|
||||
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) {
|
||||
size_t position = 0;
|
||||
|
||||
RenderBuffer* victim = mCache.itemAt(position).mBuffer;
|
||||
deleteBuffer(victim);
|
||||
mCache.removeAt(position);
|
||||
}
|
||||
|
||||
RenderBufferEntry entry(buffer);
|
||||
|
||||
mCache.add(entry);
|
||||
mSize += size;
|
||||
|
||||
RENDER_BUFFER_LOGD("Added %s render buffer (%dx%d)",
|
||||
RenderBuffer::formatName(buffer->getFormat()),
|
||||
buffer->getWidth(), buffer->getHeight());
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
130
libs/hwui/RenderBufferCache.h
Normal file
130
libs/hwui/RenderBufferCache.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_HWUI_RENDER_BUFFER_CACHE_H
|
||||
#define ANDROID_HWUI_RENDER_BUFFER_CACHE_H
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#include "RenderBuffer.h"
|
||||
#include "utils/SortedList.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class RenderBufferCache {
|
||||
public:
|
||||
RenderBufferCache();
|
||||
~RenderBufferCache();
|
||||
|
||||
/**
|
||||
* Returns a buffer with the exact specified dimensions. If no suitable
|
||||
* buffer can be found, a new one is created and returned. If creating a
|
||||
* new buffer fails, NULL is returned.
|
||||
*
|
||||
* When a buffer is obtained from the cache, it is removed and the total
|
||||
* size of the cache goes down.
|
||||
*
|
||||
* The returned buffer is always allocated and bound
|
||||
* (see RenderBuffer::isAllocated()).
|
||||
*
|
||||
* @param format The desired render buffer format
|
||||
* @param width The desired width of the buffer
|
||||
* @param height The desired height of the buffer
|
||||
*/
|
||||
RenderBuffer* get(GLenum format, const uint32_t width, const uint32_t height);
|
||||
|
||||
/**
|
||||
* Adds the buffer to the cache. The buffer will not be added if there is
|
||||
* not enough space available. Adding a buffer can cause other buffer to
|
||||
* be removed from the cache.
|
||||
*
|
||||
* @param buffer The render buffer to add to the cache
|
||||
*
|
||||
* @return True if the buffer was added, false otherwise.
|
||||
*/
|
||||
bool put(RenderBuffer* buffer);
|
||||
/**
|
||||
* Clears the cache. This causes all layers to be deleted.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Sets the maximum size of the cache in bytes.
|
||||
*/
|
||||
void setMaxSize(uint32_t maxSize);
|
||||
/**
|
||||
* Returns the maximum size of the cache in bytes.
|
||||
*/
|
||||
uint32_t getMaxSize();
|
||||
/**
|
||||
* Returns the current size of the cache in bytes.
|
||||
*/
|
||||
uint32_t getSize();
|
||||
|
||||
private:
|
||||
struct RenderBufferEntry {
|
||||
RenderBufferEntry():
|
||||
mBuffer(NULL), mWidth(0), mHeight(0) {
|
||||
}
|
||||
|
||||
RenderBufferEntry(GLenum format, const uint32_t width, const uint32_t height):
|
||||
mBuffer(NULL), mFormat(format), mWidth(width), mHeight(height) {
|
||||
}
|
||||
|
||||
RenderBufferEntry(RenderBuffer* buffer):
|
||||
mBuffer(buffer), mFormat(buffer->getFormat()),
|
||||
mWidth(buffer->getWidth()), mHeight(buffer->getHeight()) {
|
||||
}
|
||||
|
||||
static int compare(const RenderBufferEntry& lhs, const RenderBufferEntry& rhs);
|
||||
|
||||
bool operator==(const RenderBufferEntry& other) const {
|
||||
return compare(*this, other) == 0;
|
||||
}
|
||||
|
||||
bool operator!=(const RenderBufferEntry& other) const {
|
||||
return compare(*this, other) != 0;
|
||||
}
|
||||
|
||||
friend inline int strictly_order_type(const RenderBufferEntry& lhs,
|
||||
const RenderBufferEntry& rhs) {
|
||||
return RenderBufferEntry::compare(lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
friend inline int compare_type(const RenderBufferEntry& lhs,
|
||||
const RenderBufferEntry& rhs) {
|
||||
return RenderBufferEntry::compare(lhs, rhs);
|
||||
}
|
||||
|
||||
RenderBuffer* mBuffer;
|
||||
GLenum mFormat;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
}; // struct RenderBufferEntry
|
||||
|
||||
void deleteBuffer(RenderBuffer* buffer);
|
||||
|
||||
SortedList<RenderBufferEntry> mCache;
|
||||
|
||||
uint32_t mSize;
|
||||
uint32_t mMaxSize;
|
||||
}; // class RenderBufferCache
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_RENDER_BUFFER_CACHE_H
|
||||
Reference in New Issue
Block a user