Merge "Free resources only from the GL context thread. Bug #3179882"

This commit is contained in:
Romain Guy
2010-11-11 15:42:35 -08:00
committed by Android (Google) Code Review
13 changed files with 122 additions and 66 deletions

View File

@@ -36,7 +36,7 @@ public:
static void finalizer(JNIEnv* env, jobject clazz, SkPath* obj) {
#ifdef USE_OPENGL_RENDERER
if (android::uirenderer::Caches::hasInstance()) {
android::uirenderer::Caches::getInstance().pathCache.remove(obj);
android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj);
}
#endif
delete obj;

View File

@@ -94,6 +94,16 @@ void Caches::dumpMemoryUsage() {
LOGD("\n");
}
///////////////////////////////////////////////////////////////////////////////
// Memory management
///////////////////////////////////////////////////////////////////////////////
void Caches::clearGarbage() {
textureCache.clearGarbage();
gradientCache.clearGarbage();
pathCache.clearGarbage();
}
///////////////////////////////////////////////////////////////////////////////
// VBO
///////////////////////////////////////////////////////////////////////////////

View File

@@ -100,6 +100,12 @@ public:
return mDebugLevel;
}
/**
* Call this on each frame to ensure that garbage is deleted from
* GPU memory.
*/
void clearGarbage();
/**
* Binds the VBO used to render simple textured quads.
*/

View File

@@ -153,13 +153,13 @@ DisplayList::~DisplayList() {
mPaints.clear();
for (size_t i = 0; i < mMatrices.size(); i++) {
delete mMatrices.itemAt(i);
delete mMatrices.itemAt(i);
}
mMatrices.clear();
if (mPathHeap) {
for (int i = 0; i < mPathHeap->count(); i++) {
caches.pathCache.remove(&(*mPathHeap)[i]);
caches.pathCache.removeDeferred(&(*mPathHeap)[i]);
}
mPathHeap->safeUnref();
}

View File

@@ -54,7 +54,6 @@ GradientCache::GradientCache(uint32_t maxByteSize):
}
GradientCache::~GradientCache() {
Mutex::Autolock _l(mLock);
mCache.clear();
}
@@ -63,17 +62,14 @@ GradientCache::~GradientCache() {
///////////////////////////////////////////////////////////////////////////////
uint32_t GradientCache::getSize() {
Mutex::Autolock _l(mLock);
return mSize;
}
uint32_t GradientCache::getMaxSize() {
Mutex::Autolock _l(mLock);
return mMaxSize;
}
void GradientCache::setMaxSize(uint32_t maxSize) {
Mutex::Autolock _l(mLock);
mMaxSize = maxSize;
while (mSize > mMaxSize) {
mCache.removeOldest();
@@ -102,17 +98,28 @@ void GradientCache::operator()(SkShader*& shader, Texture*& texture) {
///////////////////////////////////////////////////////////////////////////////
Texture* GradientCache::get(SkShader* shader) {
Mutex::Autolock _l(mLock);
return mCache.get(shader);
}
void GradientCache::remove(SkShader* shader) {
Mutex::Autolock _l(mLock);
mCache.remove(shader);
}
void GradientCache::clear() {
void GradientCache::removeDeferred(SkShader* shader) {
Mutex::Autolock _l(mLock);
mGarbage.push(shader);
}
void GradientCache::clearGarbage() {
Mutex::Autolock _l(mLock);
size_t count = mGarbage.size();
for (size_t i = 0; i < count; i++) {
mCache.remove(mGarbage.itemAt(i));
}
mGarbage.clear();
}
void GradientCache::clear() {
mCache.clear();
}
@@ -138,21 +145,17 @@ Texture* GradientCache::addLinearGradient(SkShader* shader, uint32_t* colors,
canvas.drawRectCoords(0.0f, 0.0f, bitmap.width(), 1.0f, p);
mLock.lock();
// Asume the cache is always big enough
const uint32_t size = bitmap.rowBytes() * bitmap.height();
while (mSize + size > mMaxSize) {
mCache.removeOldest();
}
mLock.unlock();
Texture* texture = new Texture;
generateTexture(&bitmap, texture);
mLock.lock();
mSize += size;
mCache.put(shader, texture);
mLock.unlock();
return texture;
}

View File

@@ -19,6 +19,8 @@
#include <SkShader.h>
#include <utils/Vector.h>
#include "Texture.h"
#include "utils/GenerationCache.h"
@@ -53,10 +55,19 @@ public:
*/
Texture* get(SkShader* shader);
/**
* Removes the texture associated with the specified shader. Returns NULL
* if the texture cannot be found. Upon remove the texture is freed.
* Removes the texture associated with the specified shader.
* Upon remove the texture is freed.
*/
void remove(SkShader* shader);
/**
* Removes the texture associated with the specified shader. This is meant
* to be called from threads that are not the EGL context thread.
*/
void removeDeferred(SkShader* shader);
/**
* Process deferred removals.
*/
void clearGarbage();
/**
* Clears the cache. This causes all textures to be deleted.
*/
@@ -83,10 +94,7 @@ private:
uint32_t mSize;
uint32_t mMaxSize;
/**
* Used to access mCache and mSize. All methods are accessed from a single
* thread except for remove().
*/
Vector<SkShader*> mGarbage;
mutable Mutex mLock;
}; // class GradientCache

View File

@@ -135,6 +135,8 @@ void OpenGLRenderer::setViewport(int width, int height) {
}
void OpenGLRenderer::prepare(bool opaque) {
mCaches.clearGarbage();
mSnapshot = new Snapshot(mFirstSnapshot,
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
mSaveCount = 1;

View File

@@ -53,7 +53,6 @@ PathCache::PathCache(uint32_t maxByteSize):
}
PathCache::~PathCache() {
Mutex::Autolock _l(mLock);
mCache.clear();
}
@@ -72,17 +71,14 @@ void PathCache::init() {
///////////////////////////////////////////////////////////////////////////////
uint32_t PathCache::getSize() {
Mutex::Autolock _l(mLock);
return mSize;
}
uint32_t PathCache::getMaxSize() {
Mutex::Autolock _l(mLock);
return mMaxSize;
}
void PathCache::setMaxSize(uint32_t maxSize) {
Mutex::Autolock _l(mLock);
mMaxSize = maxSize;
while (mSize > mMaxSize) {
mCache.removeOldest();
@@ -94,6 +90,14 @@ void PathCache::setMaxSize(uint32_t maxSize) {
///////////////////////////////////////////////////////////////////////////////
void PathCache::operator()(PathCacheEntry& path, PathTexture*& texture) {
removeTexture(texture);
}
///////////////////////////////////////////////////////////////////////////////
// Caching
///////////////////////////////////////////////////////////////////////////////
void PathCache::removeTexture(PathTexture* texture) {
if (texture) {
const uint32_t size = texture->width * texture->height;
mSize -= size;
@@ -109,39 +113,46 @@ void PathCache::operator()(PathCacheEntry& path, PathTexture*& texture) {
}
}
///////////////////////////////////////////////////////////////////////////////
// Caching
///////////////////////////////////////////////////////////////////////////////
void PathCache::remove(SkPath* path) {
Mutex::Autolock _l(mLock);
// TODO: Linear search...
Vector<uint32_t> pathsToRemove;
for (uint32_t i = 0; i < mCache.size(); i++) {
if (mCache.getKeyAt(i).path == path) {
pathsToRemove.push(i);
removeTexture(mCache.getValueAt(i));
}
}
mCache.setOnEntryRemovedListener(NULL);
for (size_t i = 0; i < pathsToRemove.size(); i++) {
mCache.removeAt(pathsToRemove.itemAt(i));
}
mCache.setOnEntryRemovedListener(this);
}
void PathCache::removeDeferred(SkPath* path) {
Mutex::Autolock _l(mLock);
mGarbage.push(path);
}
void PathCache::clearGarbage() {
Mutex::Autolock _l(mLock);
size_t count = mGarbage.size();
for (size_t i = 0; i < count; i++) {
remove(mGarbage.itemAt(i));
}
mGarbage.clear();
}
PathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
PathCacheEntry entry(path, paint);
mLock.lock();
PathTexture* texture = mCache.get(entry);
mLock.unlock();
if (!texture) {
texture = addTexture(entry, path, paint);
} else if (path->getGenerationID() != texture->generation) {
mLock.lock();
mCache.remove(entry);
mLock.unlock();
texture = addTexture(entry, path, paint);
}
@@ -167,11 +178,9 @@ PathTexture* PathCache::addTexture(const PathCacheEntry& entry,
const uint32_t size = width * height;
// Don't even try to cache a bitmap that's bigger than the cache
if (size < mMaxSize) {
mLock.lock();
while (mSize + size > mMaxSize) {
mCache.removeOldest();
}
mLock.unlock();
}
PathTexture* texture = new PathTexture;
@@ -200,7 +209,6 @@ PathTexture* PathCache::addTexture(const PathCacheEntry& entry,
generateTexture(bitmap, texture);
if (size < mMaxSize) {
mLock.lock();
mSize += size;
PATH_LOGD("PathCache::get: create path: name, size, mSize = %d, %d, %d",
texture->id, size, mSize);
@@ -208,7 +216,6 @@ PathTexture* PathCache::addTexture(const PathCacheEntry& entry,
LOGD("Path created, size = %d", size);
}
mCache.put(entry, texture);
mLock.unlock();
} else {
texture->cleanup = true;
}
@@ -217,7 +224,6 @@ PathTexture* PathCache::addTexture(const PathCacheEntry& entry,
}
void PathCache::clear() {
Mutex::Autolock _l(mLock);
mCache.clear();
}

View File

@@ -21,6 +21,8 @@
#include <SkPaint.h>
#include <SkPath.h>
#include <utils/Vector.h>
#include "Debug.h"
#include "Texture.h"
#include "utils/Compare.h"
@@ -146,6 +148,15 @@ public:
* Removes an entry.
*/
void remove(SkPath* path);
/**
* Removes the specified path. This is meant to be called from threads
* that are not the EGL context thread.
*/
void removeDeferred(SkPath* path);
/**
* Process deferred removals.
*/
void clearGarbage();
/**
* Sets the maximum size of the cache in bytes.
@@ -166,6 +177,8 @@ private:
*/
void generateTexture(SkBitmap& bitmap, Texture* texture);
void removeTexture(PathTexture* texture);
PathTexture* addTexture(const PathCacheEntry& entry, const SkPath *path, const SkPaint* paint);
void init();
@@ -178,10 +191,7 @@ private:
bool mDebugEnabled;
/**
* Used to access mCache and mSize. All methods are accessed from a single
* thread except for remove().
*/
Vector<SkPath*> mGarbage;
mutable Mutex mLock;
}; // class PathCache

View File

@@ -126,7 +126,7 @@ void ResourceCache::destructor(SkBitmap* resource) {
if (ref == NULL) {
// If we're not tracking this resource, just delete it
if (Caches::hasInstance()) {
Caches::getInstance().textureCache.remove(resource);
Caches::getInstance().textureCache.removeDeferred(resource);
}
delete resource;
return;
@@ -143,7 +143,7 @@ void ResourceCache::destructor(SkiaShader* resource) {
if (ref == NULL) {
// If we're not tracking this resource, just delete it
if (Caches::hasInstance()) {
Caches::getInstance().gradientCache.remove(resource->getSkShader());
Caches::getInstance().gradientCache.removeDeferred(resource->getSkShader());
}
delete resource;
return;
@@ -179,7 +179,7 @@ void ResourceCache::deleteResourceReference(void* resource, ResourceReference* r
{
SkBitmap* bitmap = (SkBitmap*)resource;
if (Caches::hasInstance()) {
Caches::getInstance().textureCache.remove(bitmap);
Caches::getInstance().textureCache.removeDeferred(bitmap);
}
delete bitmap;
}
@@ -188,7 +188,7 @@ void ResourceCache::deleteResourceReference(void* resource, ResourceReference* r
{
SkiaShader* shader = (SkiaShader*)resource;
if (Caches::hasInstance()) {
Caches::getInstance().gradientCache.remove(shader->getSkShader());
Caches::getInstance().gradientCache.removeDeferred(shader->getSkShader());
}
delete shader;
}

View File

@@ -53,7 +53,6 @@ TextureCache::TextureCache(uint32_t maxByteSize):
}
TextureCache::~TextureCache() {
Mutex::Autolock _l(mLock);
mCache.clear();
}
@@ -71,17 +70,14 @@ void TextureCache::init() {
///////////////////////////////////////////////////////////////////////////////
uint32_t TextureCache::getSize() {
Mutex::Autolock _l(mLock);
return mSize;
}
uint32_t TextureCache::getMaxSize() {
Mutex::Autolock _l(mLock);
return mMaxSize;
}
void TextureCache::setMaxSize(uint32_t maxSize) {
Mutex::Autolock _l(mLock);
mMaxSize = maxSize;
while (mSize > mMaxSize) {
mCache.removeOldest();
@@ -111,9 +107,7 @@ void TextureCache::operator()(SkBitmap*& bitmap, Texture*& texture) {
///////////////////////////////////////////////////////////////////////////////
Texture* TextureCache::get(SkBitmap* bitmap) {
mLock.lock();
Texture* texture = mCache.get(bitmap);
mLock.unlock();
if (!texture) {
if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
@@ -124,11 +118,9 @@ Texture* TextureCache::get(SkBitmap* bitmap) {
const uint32_t size = bitmap->rowBytes() * bitmap->height();
// Don't even try to cache a bitmap that's bigger than the cache
if (size < mMaxSize) {
mLock.lock();
while (mSize + size > mMaxSize) {
mCache.removeOldest();
}
mLock.unlock();
}
texture = new Texture;
@@ -136,7 +128,6 @@ Texture* TextureCache::get(SkBitmap* bitmap) {
generateTexture(bitmap, texture, false);
if (size < mMaxSize) {
mLock.lock();
mSize += size;
TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
bitmap, texture->id, size, mSize);
@@ -144,7 +135,6 @@ Texture* TextureCache::get(SkBitmap* bitmap) {
LOGD("Texture created, size = %d", size);
}
mCache.put(bitmap, texture);
mLock.unlock();
} else {
texture->cleanup = true;
}
@@ -156,12 +146,24 @@ Texture* TextureCache::get(SkBitmap* bitmap) {
}
void TextureCache::remove(SkBitmap* bitmap) {
Mutex::Autolock _l(mLock);
mCache.remove(bitmap);
}
void TextureCache::clear() {
void TextureCache::removeDeferred(SkBitmap* bitmap) {
Mutex::Autolock _l(mLock);
mGarbage.push(bitmap);
}
void TextureCache::clearGarbage() {
Mutex::Autolock _l(mLock);
size_t count = mGarbage.size();
for (size_t i = 0; i < count; i++) {
mCache.remove(mGarbage.itemAt(i));
}
mGarbage.clear();
}
void TextureCache::clear() {
mCache.clear();
TEXTURE_LOGD("TextureCache:clear(), miSize = %d", mSize);
}

View File

@@ -19,6 +19,8 @@
#include <SkBitmap.h>
#include <utils/Vector.h>
#include "Debug.h"
#include "Texture.h"
#include "utils/GenerationCache.h"
@@ -64,10 +66,20 @@ public:
*/
Texture* get(SkBitmap* bitmap);
/**
* Removes the texture associated with the specified bitmap. Returns NULL
* if the texture cannot be found. Upon remove the texture is freed.
* Removes the texture associated with the specified bitmap.
* Upon remove the texture is freed.
*/
void remove(SkBitmap* bitmap);
/**
* Removes the texture associated with the specified bitmap. This is meant
* to be called from threads that are not the EGL context thread.
*/
void removeDeferred(SkBitmap* bitmap);
/**
* Process deferred removals.
*/
void clearGarbage();
/**
* Clears the cache. This causes all textures to be deleted.
*/
@@ -109,10 +121,7 @@ private:
bool mDebugEnabled;
/**
* Used to access mCache and mSize. All methods are accessed from a single
* thread except for remove().
*/
Vector<SkBitmap*> mGarbage;
mutable Mutex mLock;
}; // class TextureCache

View File

@@ -130,7 +130,7 @@ K GenerationCache<K, V>::getKeyAt(uint32_t index) const {
template<typename K, typename V>
V GenerationCache<K, V>::getValueAt(uint32_t index) const {
return mCache.valueAt(index);
return mCache.valueAt(index)->value;
}
template<typename K, typename V>