diff options
Diffstat (limited to 'libs/hwui/TextureCache.cpp')
-rw-r--r-- | libs/hwui/TextureCache.cpp | 100 |
1 files changed, 73 insertions, 27 deletions
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index a9ab2c63435b..60b4b96012f5 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -34,7 +34,7 @@ namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// TextureCache::TextureCache(): - mCache(LruCache<SkBitmap*, Texture*>::kUnlimitedCapacity), + mCache(LruCache<const SkPixelRef*, Texture*>::kUnlimitedCapacity), mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)), mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE) { char property[PROPERTY_VALUE_MAX]; @@ -58,7 +58,7 @@ TextureCache::TextureCache(): } TextureCache::TextureCache(uint32_t maxByteSize): - mCache(LruCache<SkBitmap*, Texture*>::kUnlimitedCapacity), + mCache(LruCache<const SkPixelRef*, Texture*>::kUnlimitedCapacity), mSize(0), mMaxSize(maxByteSize) { init(); } @@ -103,7 +103,7 @@ void TextureCache::setFlushRate(float flushRate) { // Callbacks /////////////////////////////////////////////////////////////////////////////// -void TextureCache::operator()(SkBitmap*& bitmap, Texture*& texture) { +void TextureCache::operator()(const SkPixelRef*&, Texture*& texture) { // This will be called already locked if (texture) { mSize -= texture->bitmapSize; @@ -121,47 +121,93 @@ void TextureCache::operator()(SkBitmap*& bitmap, Texture*& texture) { // Caching /////////////////////////////////////////////////////////////////////////////// -Texture* TextureCache::get(SkBitmap* bitmap) { - Texture* texture = mCache.get(bitmap); +void TextureCache::resetMarkInUse() { + LruCache<const SkPixelRef*, Texture*>::Iterator iter(mCache); + while (iter.next()) { + iter.value()->isInUse = false; + } +} + +bool TextureCache::canMakeTextureFromBitmap(const SkBitmap* bitmap) { + if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) { + ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)", + bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize); + return false; + } + return true; +} + +// Returns a prepared Texture* that either is already in the cache or can fit +// in the cache (and is thus added to the cache) +Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) { + Texture* texture = mCache.get(bitmap->pixelRef()); if (!texture) { - if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) { - ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)", - bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize); + if (!canMakeTextureFromBitmap(bitmap)) { return NULL; } const uint32_t size = bitmap->rowBytes() * bitmap->height(); + bool canCache = size < mMaxSize; // Don't even try to cache a bitmap that's bigger than the cache - if (size < mMaxSize) { - while (mSize + size > mMaxSize) { + while (canCache && mSize + size > mMaxSize) { + Texture* oldest = mCache.peekOldestValue(); + if (oldest && !oldest->isInUse) { mCache.removeOldest(); + } else { + canCache = false; } } - texture = new Texture(); - texture->bitmapSize = size; - generateTexture(bitmap, texture, false); + if (canCache) { + texture = new Texture(); + texture->bitmapSize = size; + generateTexture(bitmap, texture, false); - if (size < mMaxSize) { mSize += size; TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d", bitmap, texture->id, size, mSize); if (mDebugEnabled) { ALOGD("Texture created, size = %d", size); } - mCache.put(bitmap, texture); - } else { - texture->cleanup = true; + mCache.put(bitmap->pixelRef(), texture); } - } else if (bitmap->getGenerationID() != texture->generation) { + } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) { + // Texture was in the cache but is dirty, re-upload + // TODO: Re-adjust the cache size if the bitmap's dimensions have changed generateTexture(bitmap, texture, true); } return texture; } -Texture* TextureCache::getTransient(SkBitmap* bitmap) { +bool TextureCache::prefetchAndMarkInUse(const SkBitmap* bitmap) { + Texture* texture = getCachedTexture(bitmap); + if (texture) { + texture->isInUse = true; + } + return texture; +} + +Texture* TextureCache::get(const SkBitmap* bitmap) { + Texture* texture = getCachedTexture(bitmap); + + if (!texture) { + if (!canMakeTextureFromBitmap(bitmap)) { + return NULL; + } + + const uint32_t size = bitmap->rowBytes() * bitmap->height(); + texture = new Texture(); + texture->bitmapSize = size; + generateTexture(bitmap, texture, false); + texture->cleanup = true; + } + + return texture; +} + +Texture* TextureCache::getTransient(const SkBitmap* bitmap) { Texture* texture = new Texture(); texture->bitmapSize = bitmap->rowBytes() * bitmap->height(); texture->cleanup = true; @@ -171,11 +217,11 @@ Texture* TextureCache::getTransient(SkBitmap* bitmap) { return texture; } -void TextureCache::remove(SkBitmap* bitmap) { - mCache.remove(bitmap); +void TextureCache::remove(const SkBitmap* bitmap) { + mCache.remove(bitmap->pixelRef()); } -void TextureCache::removeDeferred(SkBitmap* bitmap) { +void TextureCache::removeDeferred(const SkBitmap* bitmap) { Mutex::Autolock _l(mLock); mGarbage.push(bitmap); } @@ -185,7 +231,7 @@ void TextureCache::clearGarbage() { size_t count = mGarbage.size(); for (size_t i = 0; i < count; i++) { const SkBitmap* bitmap = mGarbage.itemAt(i); - mCache.remove(bitmap); + mCache.remove(bitmap->pixelRef()); delete bitmap; } mGarbage.clear(); @@ -211,7 +257,7 @@ void TextureCache::flush() { } } -void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate) { +void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate) { SkAutoLockPixels alp(*bitmap); if (!bitmap->readyToDraw()) { @@ -239,7 +285,7 @@ void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool rege Caches::getInstance().bindTexture(texture->id); - switch (bitmap->getConfig()) { + switch (bitmap->config()) { case SkBitmap::kA8_Config: glPixelStorei(GL_UNPACK_ALIGNMENT, 1); uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), @@ -267,7 +313,7 @@ void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool rege texture->blend = !bitmap->isOpaque(); break; default: - ALOGW("Unsupported bitmap config: %d", bitmap->getConfig()); + ALOGW("Unsupported bitmap config: %d", bitmap->config()); break; } @@ -284,7 +330,7 @@ void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool rege } } -void TextureCache::uploadLoFiTexture(bool resize, SkBitmap* bitmap, +void TextureCache::uploadLoFiTexture(bool resize, const SkBitmap* bitmap, uint32_t width, uint32_t height) { SkBitmap rgbaBitmap; rgbaBitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0, bitmap->alphaType()); |