Merge "Track the size in memory of the texture cache."

This commit is contained in:
Romain Guy
2010-07-01 18:29:42 -07:00
committed by Android (Google) Code Review
4 changed files with 129 additions and 17 deletions

View File

@@ -36,6 +36,10 @@ public:
GenerationCache(unsigned int maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) { };
~GenerationCache() { clear(); };
enum Capacity {
kUnlimitedCapacity,
};
void setOnEntryRemovedListener(OnEntryRemoved<K*, V*>* listener);
void clear();
@@ -44,12 +48,11 @@ public:
V* get(K* key);
void put(K* key, V* value);
V* remove(K* key);
void removeOldest();
unsigned int size() const;
private:
void removeOldest();
template<typename EntryKey, typename EntryValue>
struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > {
Entry() { }
@@ -124,7 +127,7 @@ V* GenerationCache<K, V>::get(K* key) {
template<typename K, typename V>
void GenerationCache<K, V>::put(K* key, V* value) {
if (mCache.size() >= mMaxCapacity) {
if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) {
removeOldest();
}

View File

@@ -22,6 +22,7 @@
#include <SkCanvas.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include "OpenGLRenderer.h"
@@ -33,7 +34,15 @@ namespace uirenderer {
// Defines
///////////////////////////////////////////////////////////////////////////////
#define MAX_TEXTURE_COUNT 128
// 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"
// Converts a number of mega-bytes into bytes
#define MB(s) s * 1024 * 1024
#define DEFAULT_TEXTURE_CACHE_SIZE MB(20)
#define DEFAULT_LAYER_CACHE_SIZE MB(10)
#define SV(x, y) { { x, y } }
#define FV(x, y, u, v) { { x, y }, { u, v } }
@@ -83,9 +92,14 @@ static const Blender gBlends[] = {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
OpenGLRenderer::OpenGLRenderer(): mTextureCache(MAX_TEXTURE_COUNT) {
OpenGLRenderer::OpenGLRenderer(): mTextureCache(DEFAULT_TEXTURE_CACHE_SIZE) {
LOGD("Create OpenGLRenderer");
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) {
mTextureCache.setMaxSize(MB(atoi(property)));
}
mDrawColorShader = new DrawColorProgram;
mDrawTextureShader = new DrawTextureProgram;
@@ -397,6 +411,8 @@ bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom)
void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
const Texture* texture = mTextureCache.get(bitmap);
LOGD("Texture cache size %d", mTextureCache.getSize());
LOGD(" max size %d", mTextureCache.getMaxSize());
int alpha;
SkXfermode::Mode mode;

View File

@@ -14,6 +14,8 @@
* limitations under the License.
*/
#define LOG_TAG "OpenGLRenderer"
#include <GLES2/gl2.h>
#include "TextureCache.h"
@@ -21,7 +23,13 @@
namespace android {
namespace uirenderer {
TextureCache::TextureCache(unsigned int maxEntries): mCache(maxEntries) {
///////////////////////////////////////////////////////////////////////////////
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
TextureCache::TextureCache(unsigned int maxByteSize):
mCache(GenerationCache<SkBitmap, Texture>::kUnlimitedCapacity),
mSize(0), mMaxSize(maxByteSize) {
mCache.setOnEntryRemovedListener(this);
}
@@ -29,28 +37,71 @@ TextureCache::~TextureCache() {
mCache.clear();
}
void TextureCache::operator()(SkBitmap* key, Texture* value) {
LOGD("Entry removed");
if (value) {
glDeleteTextures(1, &value->id);
delete value;
///////////////////////////////////////////////////////////////////////////////
// Size management
///////////////////////////////////////////////////////////////////////////////
unsigned int TextureCache::getSize() {
return mSize;
}
unsigned int TextureCache::getMaxSize() {
return mMaxSize;
}
void TextureCache::setMaxSize(unsigned int maxSize) {
mMaxSize = maxSize;
while (mSize > mMaxSize) {
mCache.removeOldest();
}
}
///////////////////////////////////////////////////////////////////////////////
// Callbacks
///////////////////////////////////////////////////////////////////////////////
void TextureCache::operator()(SkBitmap* bitmap, Texture* texture) {
if (bitmap) {
const unsigned int size = bitmap->rowBytes() * bitmap->height();
mSize -= size;
}
if (texture) {
glDeleteTextures(1, &texture->id);
delete texture;
}
}
///////////////////////////////////////////////////////////////////////////////
// Caching
///////////////////////////////////////////////////////////////////////////////
Texture* TextureCache::get(SkBitmap* bitmap) {
Texture* texture = mCache.get(bitmap);
if (!texture) {
const unsigned int size = bitmap->rowBytes() * bitmap->height();
// Don't even try to cache a bitmap that's bigger than the cache
if (size < mMaxSize) {
while (mSize + size > mMaxSize) {
mCache.removeOldest();
}
}
texture = new Texture;
generateTexture(bitmap, texture, false);
mCache.put(bitmap, texture);
if (size < mMaxSize) {
mSize += size;
mCache.put(bitmap, texture);
}
} else if (bitmap->getGenerationID() != texture->generation) {
generateTexture(bitmap, texture, true);
}
return texture;
}
Texture* TextureCache::remove(SkBitmap* bitmap) {
return mCache.remove(bitmap);
void TextureCache::remove(SkBitmap* bitmap) {
mCache.remove(bitmap);
}
void TextureCache::clear() {

View File

@@ -25,21 +25,63 @@
namespace android {
namespace uirenderer {
/**
* A simple LRU texture cache. The cache has a maximum size expressed in bytes.
* Any texture added to the cache causing the cache to grow beyond the maximum
* allowed size will also cause the oldest texture to be kicked out.
*/
class TextureCache: public OnEntryRemoved<SkBitmap*, Texture*> {
public:
TextureCache(unsigned int maxEntries);
TextureCache(unsigned int maxByteSize);
~TextureCache();
void operator()(SkBitmap* key, Texture* value);
/**
* Used as a callback when an entry is removed from the cache.
* Do not invoke directly.
*/
void operator()(SkBitmap* bitmap, Texture* texture);
/**
* Returns the texture associated with the specified bitmap. If the texture
* cannot be found in the cache, a new texture is generated.
*/
Texture* get(SkBitmap* bitmap);
Texture* remove(SkBitmap* bitmap);
/**
* Removes the texture associated with the specified bitmap. Returns NULL
* if the texture cannot be found. Upon remove the texture is freed.
*/
void remove(SkBitmap* bitmap);
/**
* Clears the cache. This causes all textures to be deleted.
*/
void clear();
/**
* Sets the maximum size of the cache in bytes.
*/
void setMaxSize(unsigned int maxSize);
/**
* Returns the maximum size of the cache in bytes.
*/
unsigned int getMaxSize();
/**
* Returns the current size of the cache in bytes.
*/
unsigned int getSize();
private:
/**
* Generates the texture from a bitmap into the specified texture structure.
*
* @param regenerate If true, the bitmap data is reuploaded into the texture, but
* no new texture is generated.
*/
void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false);
GenerationCache<SkBitmap, Texture> mCache;
unsigned int mSize;
unsigned int mMaxSize;
}; // class TextureCache
}; // namespace uirenderer