summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/hwui/GenerationCache.h9
-rw-r--r--libs/hwui/OpenGLRenderer.cpp20
-rw-r--r--libs/hwui/TextureCache.cpp69
-rw-r--r--libs/hwui/TextureCache.h48
4 files changed, 129 insertions, 17 deletions
diff --git a/libs/hwui/GenerationCache.h b/libs/hwui/GenerationCache.h
index 4a3ca77571a5..e215dafd8f55 100644
--- a/libs/hwui/GenerationCache.h
+++ b/libs/hwui/GenerationCache.h
@@ -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();
}
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 8b4fb9bca24a..095d58b81a89 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -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;
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 7b8b31398188..10e4f9e5df53 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -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() {
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index bf680616c4f0..c974b65b5432 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -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