diff options
author | 2013-03-18 21:37:39 +0000 | |
---|---|---|
committer | 2013-03-18 21:37:39 +0000 | |
commit | bb281f7f963ea9ae6d735ca8430396cfabaa73ca (patch) | |
tree | 4e3576fe1a3bdd0afad6915958644c71654b3519 | |
parent | e1575aa21619e252f6c6514317041c32d00ce5a6 (diff) |
Improvements/additions to SkImageCache/SkLazyPixelRef.
SkPurgeableImageCache:
New image cache that uses virtual memory to store the pixels. Combines
features of SkAshmemImageCache (which has been removed) with SkPurgeableMemoryBlock, which has android and Mac versions.
SkImageCache:
Modified the API. pinCache now returns a status out parameter which
states whether the pinned memory retained the old data. This allows
allocAndPinCache to only be used for allocations.
Add a new debug only interface to purge unpinned data.
Updates to documentation, clarifying behavior.
Changed CachedStatus to MemoryStatus
SkLruImageCache:
Implement the new function purgeAllUnpinnedCaches and change implementation
of pinCache for the new behavior.
SkLazyPixelRef:
Rewrite onLockPixels to account for the new behavior of pinCache.
BitmapFactoryTest:
Test the new SkPurgeableImageCache.
Write tests which directly test the SkImageCaches.
Create a larger bitmap, since some of the SkImageCaches are designed
to handle large bitmaps.
bench_ and render_pictures:
Consolidate lazy_decode_bitmap into one function.
Allow using a flag to specify using the purgeable image cache.
Clean up some #includes.
Review URL: https://codereview.chromium.org/12433020
git-svn-id: http://skia.googlecode.com/svn/trunk@8207 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | gyp/core.gypi | 2 | ||||
-rw-r--r-- | gyp/ports.gyp | 5 | ||||
-rw-r--r-- | gyp/tools.gyp | 2 | ||||
-rw-r--r-- | include/lazy/SkBitmapFactory.h | 21 | ||||
-rw-r--r-- | include/lazy/SkImageCache.h | 77 | ||||
-rw-r--r-- | include/lazy/SkLruImageCache.h | 7 | ||||
-rw-r--r-- | include/lazy/SkPurgeableImageCache.h | 45 | ||||
-rw-r--r-- | include/ports/SkAshmemImageCache.h | 72 | ||||
-rw-r--r-- | src/lazy/SkBitmapFactory.cpp | 8 | ||||
-rw-r--r-- | src/lazy/SkLazyPixelRef.cpp | 62 | ||||
-rw-r--r-- | src/lazy/SkLazyPixelRef.h | 1 | ||||
-rw-r--r-- | src/lazy/SkLruImageCache.cpp | 25 | ||||
-rw-r--r-- | src/lazy/SkPurgeableImageCache.cpp | 159 | ||||
-rw-r--r-- | src/ports/SkAshmemImageCache.cpp | 161 | ||||
-rw-r--r-- | tests/BitmapFactoryTest.cpp | 131 | ||||
-rw-r--r-- | tools/PictureRenderingFlags.cpp | 59 | ||||
-rw-r--r-- | tools/PictureRenderingFlags.h | 2 | ||||
-rw-r--r-- | tools/bench_pictures_main.cpp | 24 | ||||
-rw-r--r-- | tools/render_pictures_main.cpp | 35 |
19 files changed, 531 insertions, 367 deletions
diff --git a/gyp/core.gypi b/gyp/core.gypi index 23a652acb8..3810334e62 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -288,6 +288,7 @@ '<(skia_include_path)/lazy/SkBitmapFactory.h', '<(skia_include_path)/lazy/SkImageCache.h', '<(skia_include_path)/lazy/SkLruImageCache.h', + '<(skia_include_path)/lazy/SkPurgeableImageCache.h', '<(skia_src_path)/lazy/SkBitmapFactory.cpp', '<(skia_src_path)/lazy/SkLazyPixelRef.h', @@ -295,6 +296,7 @@ '<(skia_src_path)/lazy/SkLruImageCache.cpp', '<(skia_src_path)/lazy/SkPurgeableMemoryBlock.h', '<(skia_src_path)/lazy/SkPurgeableMemoryBlock_common.cpp', + '<(skia_src_path)/lazy/SkPurgeableImageCache.cpp', ], } diff --git a/gyp/ports.gyp b/gyp/ports.gyp index 7814148efb..db4ea7aeb6 100644 --- a/gyp/ports.gyp +++ b/gyp/ports.gyp @@ -167,16 +167,13 @@ '../src/ports/SkPurgeableMemoryBlock_none.cpp', ], 'sources': [ - '../include/ports/SkAshmemImageCache.h', - + '../src/ports/FontHostConfiguration_android.cpp', '../src/ports/SkDebug_android.cpp', '../src/ports/SkThread_pthread.cpp', '../src/ports/SkFontHost_android.cpp', '../src/ports/SkFontHost_FreeType.cpp', '../src/ports/SkFontHost_FreeType_common.cpp', '../src/ports/SkPurgeableMemoryBlock_android.cpp', - '../src/ports/FontHostConfiguration_android.cpp', - '../src/ports/SkAshmemImageCache.cpp', ], 'dependencies': [ 'freetype.gyp:freetype', diff --git a/gyp/tools.gyp b/gyp/tools.gyp index 4e3bc5361b..9cbaf932b9 100644 --- a/gyp/tools.gyp +++ b/gyp/tools.gyp @@ -100,6 +100,7 @@ 'skia_base_libs.gyp:skia_base_libs', 'tools.gyp:picture_renderer', 'tools.gyp:picture_utils', + 'ports.gyp:ports', ], }, { @@ -123,6 +124,7 @@ 'tools.gyp:picture_utils', 'tools.gyp:picture_renderer', 'bench.gyp:bench_timer', + 'ports.gyp:ports', ], }, { diff --git a/include/lazy/SkBitmapFactory.h b/include/lazy/SkBitmapFactory.h index bebd3a7cee..eb427ee390 100644 --- a/include/lazy/SkBitmapFactory.h +++ b/include/lazy/SkBitmapFactory.h @@ -67,20 +67,29 @@ public: bool installPixelRef(SkData*, SkBitmap*); /** - * A function for selecting an SkImageCache to use based on an SkImage::Info. + * An object for selecting an SkImageCache to use based on an SkImage::Info. */ - typedef SkImageCache* (*CacheSelector)(const SkImage::Info&); + class CacheSelector : public SkRefCnt { + + public: + /** + * Return an SkImageCache to use based on the provided SkImage::Info. If the caller decides + * to hang on to the result, it will call ref, so the implementation should not add a ref + * as a result of this call. + */ + virtual SkImageCache* selectCache(const SkImage::Info&) = 0; + }; /** * Set the function to be used to select which SkImageCache to use. Mutually exclusive with * fImageCache. */ - void setCacheSelector(CacheSelector); + void setCacheSelector(CacheSelector*); private: - DecodeProc fDecodeProc; - SkImageCache* fImageCache; - CacheSelector fCacheSelector; + DecodeProc fDecodeProc; + SkImageCache* fImageCache; + CacheSelector* fCacheSelector; }; #endif // SkBitmapFactory_DEFINED diff --git a/include/lazy/SkImageCache.h b/include/lazy/SkImageCache.h index 6cd064ba5b..bfd5269ee9 100644 --- a/include/lazy/SkImageCache.h +++ b/include/lazy/SkImageCache.h @@ -22,22 +22,45 @@ public: * call to releaseCache and a call to throwAwayCache. * @param bytes Number of bytes needed. * @param ID Output parameter which must not be NULL. On success, ID will be set to a value - * associated with that memory which can be used as a parameter to the other functions - * in SkImageCache. On failure, ID is unchanged. + * associated with that memory which can be used as a parameter to the other functions + * in SkImageCache. On failure, ID is unchanged. * @return Pointer to the newly allocated memory, or NULL. This memory is safe to use until - * releaseCache is called with ID. + * releaseCache is called with ID. */ virtual void* allocAndPinCache(size_t bytes, intptr_t* ID) = 0; /** - * Re-request the memory associated with ID. + * Output parameter for pinCache, stating whether the memory still contains the data it held + * when releaseCache was last called for the same ID. + */ + enum DataStatus { + /** + * The data has been purged, and therefore needs to be rewritten to the returned memory. + */ + kUninitialized_DataStatus, + + /** + * The memory still contains the data it held when releaseCache was last called with the + * same ID. + */ + kRetained_DataStatus, + }; + + /** + * Re-request the memory associated with ID and pin it so that it will not be reclaimed until + * the next call to releaseCache with the same ID. * @param ID Unique ID for the memory block. + * @param status Output parameter which must not be NULL. On success (i.e. the return value is + * not NULL), status will be set to one of two states representing the cached memory. If + * status is set to kRetained_DataStatus, the memory contains the same data it did + * before releaseCache was called with this ID. If status is set to + * kUninitialized_DataStatus, the memory is still pinned, but the previous data is no + * longer available. If the return value is NULL, status is unchanged. * @return Pointer: If non-NULL, points to the previously allocated memory, in which case - * this call must be balanced with a call to releaseCache. If NULL, the memory - * has been reclaimed, so allocAndPinCache must be called again with a pointer to - * the same ID. + * this call must be balanced with a call to releaseCache. If NULL, the memory + * has been reclaimed, and throwAwayCache MUST NOT be called. */ - virtual void* pinCache(intptr_t ID) = 0; + virtual void* pinCache(intptr_t ID, DataStatus* status) = 0; /** * Inform the cache that it is safe to free the block of memory corresponding to ID. After @@ -61,16 +84,42 @@ public: static const intptr_t UNINITIALIZED_ID = 0; #ifdef SK_DEBUG - enum CacheStatus { - kPinned_CacheStatus, - kUnpinned_CacheStatus, - kThrownAway_CacheStatus, + /** + * Debug only status of a memory block. + */ + enum MemoryStatus { + /** + * It is safe to use the pointer returned by the most recent of allocAndPinCache(ID) or + * pinCache(ID) with the same ID. + */ + kPinned_MemoryStatus, + + /** + * The pointer returned by the most recent call to allocAndPinCache(ID) or pinCache(ID) has + * since been released by releaseCache(ID). In order to reuse it, pinCache(ID) must be + * called again. Note that after calling releaseCache(ID), the status of that particular + * ID may not be kUnpinned_MemoryStatus, depending on the implementation, but it will not + * be kPinned_MemoryStatus. + */ + kUnpinned_MemoryStatus, + + /** + * The memory associated with ID has been thrown away. No calls should be made using the + * same ID. + */ + kFreed_MemoryStatus, }; /** - * Debug only function to get the status of a particular block of memory. + * Debug only function to get the status of a particular block of memory. Safe to call after + * throwAwayCache has been called with this ID. + */ + virtual MemoryStatus getMemoryStatus(intptr_t ID) const = 0; + + /** + * Debug only function to clear all unpinned caches. */ - virtual CacheStatus getCacheStatus(intptr_t ID) const = 0; + virtual void purgeAllUnpinnedCaches() = 0; #endif }; #endif // SkImageCache_DEFINED diff --git a/include/lazy/SkLruImageCache.h b/include/lazy/SkLruImageCache.h index 05d28150b0..f655230a93 100644 --- a/include/lazy/SkLruImageCache.h +++ b/include/lazy/SkLruImageCache.h @@ -25,7 +25,8 @@ public: virtual ~SkLruImageCache(); #ifdef SK_DEBUG - CacheStatus getCacheStatus(intptr_t ID) const SK_OVERRIDE; + virtual MemoryStatus getMemoryStatus(intptr_t ID) const SK_OVERRIDE; + virtual void purgeAllUnpinnedCaches() SK_OVERRIDE; #endif /** @@ -45,7 +46,7 @@ public: size_t getImageCacheUsed() const { return fRamUsed; } virtual void* allocAndPinCache(size_t bytes, intptr_t* ID) SK_OVERRIDE; - virtual void* pinCache(intptr_t ID) SK_OVERRIDE; + virtual void* pinCache(intptr_t ID, SkImageCache::DataStatus*) SK_OVERRIDE; virtual void releaseCache(intptr_t ID) SK_OVERRIDE; virtual void throwAwayCache(intptr_t ID) SK_OVERRIDE; @@ -55,7 +56,7 @@ private: typedef SkTInternalLList<CachedPixels>::Iter Iter; #ifdef SK_DEBUG - // fMutex is mutable so that getCacheStatus can be const + // fMutex is mutable so that getMemoryStatus can be const mutable #endif SkMutex fMutex; diff --git a/include/lazy/SkPurgeableImageCache.h b/include/lazy/SkPurgeableImageCache.h new file mode 100644 index 0000000000..0516ff18ef --- /dev/null +++ b/include/lazy/SkPurgeableImageCache.h @@ -0,0 +1,45 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPurgeableImageCache_DEFINED +#define SkPurgeableImageCache_DEFINED + +#include "SkImageCache.h" + +#ifdef SK_DEBUG + #include "SkTDArray.h" +#endif + +/** + * Implementation for SkImageCache that uses system defined purgeable memory. + */ +class SkPurgeableImageCache : public SkImageCache { + +public: + static SkImageCache* Create(); + + virtual void* allocAndPinCache(size_t bytes, intptr_t* ID) SK_OVERRIDE; + virtual void* pinCache(intptr_t ID, SkImageCache::DataStatus*) SK_OVERRIDE; + virtual void releaseCache(intptr_t ID) SK_OVERRIDE; + virtual void throwAwayCache(intptr_t ID) SK_OVERRIDE; + +#ifdef SK_DEBUG + virtual MemoryStatus getMemoryStatus(intptr_t ID) const SK_OVERRIDE; + virtual void purgeAllUnpinnedCaches() SK_OVERRIDE; + virtual ~SkPurgeableImageCache(); +#endif + +private: + SkPurgeableImageCache(); + +#ifdef SK_DEBUG + SkTDArray<intptr_t> fRecs; + int findRec(intptr_t) const; +#endif + void removeRec(intptr_t); +}; +#endif // SkPurgeableImageCache_DEFINED diff --git a/include/ports/SkAshmemImageCache.h b/include/ports/SkAshmemImageCache.h deleted file mode 100644 index 817e702490..0000000000 --- a/include/ports/SkAshmemImageCache.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkAshmemImageCache_DEFINED -#define SkAshmemImageCache_DEFINED - -#include "SkImageCache.h" -#include "SkTDArray.h" -#include "SkTypes.h" - -class SkAshmemImageCache : public SkImageCache { - -public: - /** - * Get a pointer to the single global instance of SkAshmemImageCache. - */ - static SkAshmemImageCache* GetAshmemImageCache(); - - virtual void* allocAndPinCache(size_t bytes, intptr_t* ID) SK_OVERRIDE; - virtual void* pinCache(intptr_t ID) SK_OVERRIDE; - virtual void releaseCache(intptr_t ID) SK_OVERRIDE; - virtual void throwAwayCache(intptr_t ID) SK_OVERRIDE; - -#ifdef SK_DEBUG - SkImageCache::CacheStatus getCacheStatus(intptr_t ID) const SK_OVERRIDE; - - virtual ~SkAshmemImageCache(); -#endif - -private: - struct AshmemRec { - int fFD; - void* fAddr; - size_t fSize; -#ifdef SK_DEBUG - bool fPinned; - - static int Compare(const AshmemRec*, const AshmemRec*); -#endif - }; - - /** - * Constructor is private. The correct way to get this cache is through - * GetAshmemImageCache, so that all callers can get the single global. - */ - SkAshmemImageCache(); - -#ifdef SK_DEBUG - // Stores a list of AshmemRecs to track deletion. - SkTDArray<AshmemRec*> fRecs; - - /** - * Debug only function to add an AshmemRec to the list. - */ - void appendRec(AshmemRec*); - - /** - * Return the index of AshmemRec. - */ - int findRec(const AshmemRec*) const; -#endif - - /** - * Deletes AshmemRec. In debug, also removes from the list. - */ - void removeRec(AshmemRec*); -}; -#endif // SkAshmemImageCache_DEFINED diff --git a/src/lazy/SkBitmapFactory.cpp b/src/lazy/SkBitmapFactory.cpp index d67e019755..60c4993e3c 100644 --- a/src/lazy/SkBitmapFactory.cpp +++ b/src/lazy/SkBitmapFactory.cpp @@ -22,17 +22,19 @@ SkBitmapFactory::SkBitmapFactory(SkBitmapFactory::DecodeProc proc) SkBitmapFactory::~SkBitmapFactory() { SkSafeUnref(fImageCache); + SkSafeUnref(fCacheSelector); } void SkBitmapFactory::setImageCache(SkImageCache *cache) { SkRefCnt_SafeAssign(fImageCache, cache); if (cache != NULL) { + SkSafeUnref(fCacheSelector); fCacheSelector = NULL; } } -void SkBitmapFactory::setCacheSelector(CacheSelector selector) { - fCacheSelector = selector; +void SkBitmapFactory::setCacheSelector(CacheSelector* selector) { + SkRefCnt_SafeAssign(fCacheSelector, selector); if (selector != NULL) { SkSafeUnref(fImageCache); fImageCache = NULL; @@ -63,7 +65,7 @@ bool SkBitmapFactory::installPixelRef(SkData* data, SkBitmap* dst) { // fImageCache and fCacheSelector are mutually exclusive. SkASSERT(NULL == fImageCache || NULL == fCacheSelector); - SkImageCache* cache = NULL == fCacheSelector ? fImageCache : fCacheSelector(info); + SkImageCache* cache = NULL == fCacheSelector ? fImageCache : fCacheSelector->selectCache(info); if (cache != NULL) { // Now set a new LazyPixelRef on dst. diff --git a/src/lazy/SkLazyPixelRef.cpp b/src/lazy/SkLazyPixelRef.cpp index 9ae22f2207..dc9aef9f06 100644 --- a/src/lazy/SkLazyPixelRef.cpp +++ b/src/lazy/SkLazyPixelRef.cpp @@ -24,7 +24,8 @@ SkLazyPixelRef::SkLazyPixelRef(SkData* data, SkBitmapFactory::DecodeProc proc, S : INHERITED(NULL) , fDecodeProc(proc) , fImageCache(cache) - , fCacheId(SkImageCache::UNINITIALIZED_ID) { + , fCacheId(SkImageCache::UNINITIALIZED_ID) + , fRowBytes(0) { SkASSERT(fDecodeProc != NULL); if (NULL == data) { fData = SkData::NewEmpty(); @@ -71,37 +72,54 @@ void* SkLazyPixelRef::onLockPixels(SkColorTable**) { if (SkImageCache::UNINITIALIZED_ID == fCacheId) { target.fAddr = NULL; } else { - target.fAddr = fImageCache->pinCache(fCacheId); - if (NULL != target.fAddr) { + SkImageCache::DataStatus status; + target.fAddr = fImageCache->pinCache(fCacheId, &status); + if (target.fAddr == NULL) { + fCacheId = SkImageCache::UNINITIALIZED_ID; + } else { + if (SkImageCache::kRetained_DataStatus == status) { #if LAZY_CACHE_STATS - sk_atomic_inc(&gCacheHits); + sk_atomic_inc(&gCacheHits); #endif - return target.fAddr; + return target.fAddr; + } + SkASSERT(SkImageCache::kUninitialized_DataStatus == status); } + // Cache miss. Either pinCache returned NULL or it returned a memory address without the old + // data #if LAZY_CACHE_STATS sk_atomic_inc(&gCacheMisses); #endif } - SkASSERT(NULL == target.fAddr); SkImage::Info info; SkASSERT(fData != NULL && fData->size() > 0); - // FIXME: As an optimization, only do this part once. - fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NULL); - if (fErrorInDecoding) { - // In case a previous call to allocAndPinCache succeeded. - fImageCache->throwAwayCache(fCacheId); - fCacheId = SkImageCache::UNINITIALIZED_ID; - return NULL; - } - // Allocate the memory. - size_t bytes = ComputeMinRowBytesAndSize(info, &target.fRowBytes); - - target.fAddr = fImageCache->allocAndPinCache(bytes, &fCacheId); if (NULL == target.fAddr) { - // Space could not be allocated. - fCacheId = SkImageCache::UNINITIALIZED_ID; - return NULL; + // Determine the size of the image in order to determine how much memory to allocate. + // FIXME: As an optimization, only do this part once. + fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NULL); + if (fErrorInDecoding) { + // We can only reach here if fCacheId was already set to UNINITIALIZED_ID, or if + // pinCache returned NULL, in which case it was reset to UNINITIALIZED_ID. + SkASSERT(SkImageCache::UNINITIALIZED_ID == fCacheId); + return NULL; + } + + size_t bytes = ComputeMinRowBytesAndSize(info, &target.fRowBytes); + target.fAddr = fImageCache->allocAndPinCache(bytes, &fCacheId); + if (NULL == target.fAddr) { + // Space could not be allocated. + // Just like the last assert, fCacheId must be UNINITIALIZED_ID. + SkASSERT(SkImageCache::UNINITIALIZED_ID == fCacheId); + return NULL; + } + } else { + // pinCache returned purged memory to which target.fAddr already points. Set + // target.fRowBytes properly. + target.fRowBytes = fRowBytes; + // Assume that the size is correct, since it was determined by this same function + // previously. } + SkASSERT(target.fAddr != NULL); SkASSERT(SkImageCache::UNINITIALIZED_ID != fCacheId); fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, &target); if (fErrorInDecoding) { @@ -109,6 +127,8 @@ void* SkLazyPixelRef::onLockPixels(SkColorTable**) { fCacheId = SkImageCache::UNINITIALIZED_ID; return NULL; } + // Upon success, store fRowBytes so it can be used in case pinCache later returns purged memory. + fRowBytes = target.fRowBytes; return target.fAddr; } diff --git a/src/lazy/SkLazyPixelRef.h b/src/lazy/SkLazyPixelRef.h index af85f90552..fd41dd4682 100644 --- a/src/lazy/SkLazyPixelRef.h +++ b/src/lazy/SkLazyPixelRef.h @@ -68,6 +68,7 @@ private: SkBitmapFactory::DecodeProc fDecodeProc; SkImageCache* fImageCache; intptr_t fCacheId; + size_t fRowBytes; #if LAZY_CACHE_STATS static int32_t gCacheHits; diff --git a/src/lazy/SkLruImageCache.cpp b/src/lazy/SkLruImageCache.cpp index 54f26fb5dc..26f7ef5483 100644 --- a/src/lazy/SkLruImageCache.cpp +++ b/src/lazy/SkLruImageCache.cpp @@ -74,16 +74,24 @@ SkLruImageCache::~SkLruImageCache() { } #ifdef SK_DEBUG -SkImageCache::CacheStatus SkLruImageCache::getCacheStatus(intptr_t ID) const { +SkImageCache::MemoryStatus SkLruImageCache::getMemoryStatus(intptr_t ID) const { + if (SkImageCache::UNINITIALIZED_ID == ID) { + return SkImageCache::kFreed_MemoryStatus; + } SkAutoMutexAcquire ac(&fMutex); CachedPixels* pixels = this->findByID(ID); if (NULL == pixels) { - return SkImageCache::kThrownAway_CacheStatus; + return SkImageCache::kFreed_MemoryStatus; } if (pixels->isLocked()) { - return SkImageCache::kPinned_CacheStatus; + return SkImageCache::kPinned_MemoryStatus; } - return SkImageCache::kUnpinned_CacheStatus; + return SkImageCache::kUnpinned_MemoryStatus; +} + +void SkLruImageCache::purgeAllUnpinnedCaches() { + SkAutoMutexAcquire ac(&fMutex); + this->purgeTilAtOrBelow(0); } #endif @@ -108,7 +116,7 @@ void* SkLruImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) { return pixels->getData(); } -void* SkLruImageCache::pinCache(intptr_t ID) { +void* SkLruImageCache::pinCache(intptr_t ID, SkImageCache::DataStatus* status) { SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); SkAutoMutexAcquire ac(&fMutex); CachedPixels* pixels = this->findByID(ID); @@ -119,6 +127,9 @@ void* SkLruImageCache::pinCache(intptr_t ID) { fLRU.remove(pixels); fLRU.addToHead(pixels); } + SkASSERT(status != NULL); + // This cache will never return pinned memory whose data has been overwritten. + *status = SkImageCache::kRetained_DataStatus; pixels->lock(); return pixels->getData(); } @@ -133,6 +144,7 @@ void SkLruImageCache::releaseCache(intptr_t ID) { } void SkLruImageCache::throwAwayCache(intptr_t ID) { + SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); SkAutoMutexAcquire ac(&fMutex); CachedPixels* pixels = this->findByID(ID); if (pixels != NULL) { @@ -155,9 +167,6 @@ void SkLruImageCache::removePixels(CachedPixels* pixels) { CachedPixels* SkLruImageCache::findByID(intptr_t ID) const { // Mutex is already locked. - if (SkImageCache::UNINITIALIZED_ID == ID) { - return NULL; - } Iter iter; // Start from the head, most recently used. CachedPixels* pixels = iter.init(fLRU, Iter::kHead_IterStart); diff --git a/src/lazy/SkPurgeableImageCache.cpp b/src/lazy/SkPurgeableImageCache.cpp new file mode 100644 index 0000000000..0f2c5e3c8e --- /dev/null +++ b/src/lazy/SkPurgeableImageCache.cpp @@ -0,0 +1,159 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkThread.h" +#include "SkPurgeableImageCache.h" +#include "SkPurgeableMemoryBlock.h" + +#ifdef SK_DEBUG + #include "SkTSearch.h" +#endif + +SK_DECLARE_STATIC_MUTEX(gPurgeableImageMutex); + +SkImageCache* SkPurgeableImageCache::Create() { + if (!SkPurgeableMemoryBlock::IsSupported()) { + return NULL; + } + SkAutoMutexAcquire ac(&gPurgeableImageMutex); + static SkPurgeableImageCache gCache; + gCache.ref(); + return &gCache; +} + +SkPurgeableImageCache::SkPurgeableImageCache() {} + +#ifdef SK_DEBUG +SkPurgeableImageCache::~SkPurgeableImageCache() { + SkASSERT(fRecs.count() == 0); +} +#endif + + +void* SkPurgeableImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) { + SkAutoMutexAcquire ac(&gPurgeableImageMutex); + + SkPurgeableMemoryBlock* block = SkPurgeableMemoryBlock::Create(bytes); + if (NULL == block) { + return NULL; + } + + SkPurgeableMemoryBlock::PinResult pinResult; + void* data = block->pin(&pinResult); + if (NULL == data) { + SkDELETE(block); + return NULL; + } + + SkASSERT(ID != NULL); + *ID = reinterpret_cast<intptr_t>(block); +#ifdef SK_DEBUG + // Insert into the array of all recs: + int index = this->findRec(*ID); + SkASSERT(index < 0); + fRecs.insert(~index, 1, ID); +#endif + return data; +} + +void* SkPurgeableImageCache::pinCache(intptr_t ID, SkImageCache::DataStatus* status) { + SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); + SkAutoMutexAcquire ac(&gPurgeableImageMutex); + + SkASSERT(this->findRec(ID) >= 0); + SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID); + SkPurgeableMemoryBlock::PinResult pinResult; + void* data = block->pin(&pinResult); + if (NULL == data) { + this->removeRec(ID); + return NULL; + } + + switch (pinResult) { + case SkPurgeableMemoryBlock::kRetained_PinResult: + *status = SkImageCache::kRetained_DataStatus; + break; + + case SkPurgeableMemoryBlock::kUninitialized_PinResult: + *status = SkImageCache::kUninitialized_DataStatus; + break; + + default: + // Invalid value. Treat as a failure to pin. + SkASSERT(false); + this->removeRec(ID); + return NULL; + } + + return data; +} + +void SkPurgeableImageCache::releaseCache(intptr_t ID) { + SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); + SkAutoMutexAcquire ac(&gPurgeableImageMutex); + + SkASSERT(this->findRec(ID) >= 0); + SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID); + block->unpin(); +} + +void SkPurgeableImageCache::throwAwayCache(intptr_t ID) { + SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); + SkAutoMutexAcquire ac(&gPurgeableImageMutex); + + this->removeRec(ID); +} + +#ifdef SK_DEBUG +SkImageCache::MemoryStatus SkPurgeableImageCache::getMemoryStatus(intptr_t ID) const { + SkAutoMutexAcquire ac(&gPurgeableImageMutex); + if (SkImageCache::UNINITIALIZED_ID == ID || this->findRec(ID) < 0) { + return SkImageCache::kFreed_MemoryStatus; + } + + SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID); + if (block->isPinned()) { + return SkImageCache::kPinned_MemoryStatus; + } + return SkImageCache::kUnpinned_MemoryStatus; +} + +void SkPurgeableImageCache::purgeAllUnpinnedCaches() { + SkAutoMutexAcquire ac(&gPurgeableImageMutex); + if (SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks()) { + SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks(); + } else { + // Go through the blocks, and purge them individually. + // Rather than deleting the blocks, which would interfere with further calls, purge them + // and keep them around. + for (int i = 0; i < fRecs.count(); i++) { + SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(fRecs[i]); + if (!block->isPinned()) { + if (!block->purge()) { + // FIXME: This should be more meaningful (which one, etc...) + SkDebugf("Failed to purge\n"); + } + } + } + } +} + +int SkPurgeableImageCache::findRec(intptr_t rec) const { + return SkTSearch(fRecs.begin(), fRecs.count(), rec, sizeof(intptr_t)); +} +#endif + +void SkPurgeableImageCache::removeRec(intptr_t ID) { +#ifdef SK_DEBUG + int index = this->findRec(ID); + SkASSERT(index >= 0); + fRecs.remove(index); +#endif + SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID); + SkASSERT(!block->isPinned()); + SkDELETE(block); +} diff --git a/src/ports/SkAshmemImageCache.cpp b/src/ports/SkAshmemImageCache.cpp deleted file mode 100644 index b7c6c7058b..0000000000 --- a/src/ports/SkAshmemImageCache.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkAshmemImageCache.h" -#include "SkThread.h" - -#ifdef SK_DEBUG - #include "SkTSearch.h" -#endif - -#include "android/ashmem.h" -#include <sys/mman.h> -#include <unistd.h> - - -SkAshmemImageCache::SkAshmemImageCache() {} - -SK_DECLARE_STATIC_MUTEX(gAshmemMutex); - -SkAshmemImageCache* SkAshmemImageCache::GetAshmemImageCache() { - SkAutoMutexAcquire ac(&gAshmemMutex); - static SkAshmemImageCache gCache; - return &gCache; -} - -#ifdef SK_DEBUG -SkAshmemImageCache::~SkAshmemImageCache() { - SkASSERT(fRecs.count() == 0); -} -#endif - -// ashmem likes lengths on page boundaries. -static size_t roundToPageSize(size_t size) { - const size_t mask = getpagesize() - 1; - size_t newSize = (size + mask) & ~mask; - return newSize; -} - -void* SkAshmemImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) { - SkASSERT(ID != NULL); - - SkAutoMutexAcquire ac(&gAshmemMutex); - - if (*ID != SkImageCache::UNINITIALIZED_ID) { - // This rec was previously allocated, but pinCache subsequently - // failed. - AshmemRec* pRec = reinterpret_cast<AshmemRec*>(*ID); - SkASSERT(roundToPageSize(bytes) == pRec->fSize); - SkASSERT(pRec->fFD != -1); - (void) ashmem_pin_region(pRec->fFD, 0, 0); -#ifdef SK_DEBUG - pRec->fPinned = true; -#endif - return pRec->fAddr; - } - - AshmemRec rec; - rec.fSize = roundToPageSize(bytes); - - rec.fFD = ashmem_create_region(NULL, rec.fSize); - if (-1 == rec.fFD) { - SkDebugf("ashmem_create_region failed\n"); - return NULL; - } - int err = ashmem_set_prot_region(rec.fFD, PROT_READ | PROT_WRITE); - if (err != 0) { - SkDebugf("ashmem_set_prot_region failed\n"); - close(rec.fFD); - return NULL; - } - rec.fAddr = mmap(NULL, rec.fSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, rec.fFD, 0); - if (-1 == (long) rec.fAddr) { - SkDebugf("mmap failed\n"); - close(rec.fFD); - return NULL; - } - (void) ashmem_pin_region(rec.fFD, 0, 0); -#ifdef SK_DEBUG - rec.fPinned = true; -#endif - // In release mode, we do not keep a pointer to this object. It will be destroyed - // either when pinCache returns NULL or when throwAwayCache is called. - AshmemRec* pRec = SkNEW_ARGS(AshmemRec, (rec)); - *ID = reinterpret_cast<intptr_t>(pRec); -#ifdef SK_DEBUG - this->appendRec(pRec); -#endif - return rec.fAddr; -} - -void* SkAshmemImageCache::pinCache(intptr_t ID) { - SkAutoMutexAcquire ac(&gAshmemMutex); - AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); - const int fd = rec->fFD; - int pin = ashmem_pin_region(fd, 0, 0); - if (ASHMEM_NOT_PURGED == pin) { -#ifdef SK_DEBUG - rec->fPinned = true; -#endif - return rec->fAddr; - } - ashmem_unpin_region(fd, 0, 0); - return NULL; -} - -void SkAshmemImageCache::releaseCache(intptr_t ID) { - SkAutoMutexAcquire ac(&gAshmemMutex); - AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); - ashmem_unpin_region(rec->fFD, 0, 0); -#ifdef SK_DEBUG - rec->fPinned = false; -#endif -} - -void SkAshmemImageCache::throwAwayCache(intptr_t ID) { - SkAutoMutexAcquire ac(&gAshmemMutex); - AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); - munmap(rec->fAddr, rec->fSize); - close(rec->fFD); -#ifdef SK_DEBUG - SkASSERT(!rec->fPinned); - int index = this->findRec(rec); - SkASSERT(index >= 0); - fRecs.remove(index); -#endif - SkDELETE(rec); -} - -#ifdef SK_DEBUG -void SkAshmemImageCache::appendRec(SkAshmemImageCache::AshmemRec* rec) { - int index = this->findRec(rec); - // Should not already exist. - SkASSERT(index < 0); - fRecs.insert(~index, 1, &rec); -} - -int SkAshmemImageCache::AshmemRec::Compare(const SkAshmemImageCache::AshmemRec* a, - const SkAshmemImageCache::AshmemRec* b) { - return reinterpret_cast<intptr_t>(a) - reinterpret_cast<intptr_t>(b); -} - -int SkAshmemImageCache::findRec(const SkAshmemImageCache::AshmemRec* rec) const { - return SkTSearch<AshmemRec>((const AshmemRec**)fRecs.begin(), fRecs.count(), rec, - sizeof(intptr_t), AshmemRec::Compare); -} - -SkImageCache::CacheStatus SkAshmemImageCache::getCacheStatus(intptr_t ID) const { - SkAutoMutexAcquire ac(&gAshmemMutex); - AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); - int index = this->findRec(rec); - if (index < 0) { - return SkImageCache::kThrownAway_CacheStatus; - } - return rec->fPinned ? SkImageCache::kPinned_CacheStatus - : SkImageCache::kUnpinned_CacheStatus; -} -#endif diff --git a/tests/BitmapFactoryTest.cpp b/tests/BitmapFactoryTest.cpp index 8bfbaf1c4f..216903a6ac 100644 --- a/tests/BitmapFactoryTest.cpp +++ b/tests/BitmapFactoryTest.cpp @@ -17,17 +17,15 @@ #include "SkLazyPixelRef.h" #include "SkLruImageCache.h" #include "SkPaint.h" +#include "SkPurgeableImageCache.h" #include "SkStream.h" #include "SkTemplates.h" #include "Test.h" -#ifdef SK_BUILD_FOR_ANDROID -#include "SkAshmemImageCache.h" -#endif - static SkBitmap* create_bitmap() { SkBitmap* bm = SkNEW(SkBitmap); - const int W = 100, H = 100; + // Use a large bitmap. + const int W = 1000, H = 1000; bm->setConfig(SkBitmap::kARGB_8888_Config, W, H); bm->allocPixels(); bm->eraseColor(SK_ColorBLACK); @@ -52,7 +50,53 @@ static void assert_bounds_equal(skiatest::Reporter* reporter, const SkBitmap& bm REPORTER_ASSERT(reporter, bm1.height() == bm2.height()); } -static void test_cache(skiatest::Reporter* reporter, SkImageCache* cache, SkData* encodedData, +static void test_cache(skiatest::Reporter* reporter, SkImageCache* cache) { + // Test the cache directly: + cache->purgeAllUnpinnedCaches(); + intptr_t ID = SkImageCache::UNINITIALIZED_ID; + const size_t size = 1000; + char buffer[size]; + sk_bzero((void*) buffer, size); + void* memory = cache->allocAndPinCache(size, &ID); + if (memory != NULL) { + memcpy(memory, (void*)buffer, size); + REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) == SkImageCache::kPinned_MemoryStatus); + cache->releaseCache(ID); + REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) != SkImageCache::kPinned_MemoryStatus); + SkImageCache::DataStatus dataStatus; + memory = cache->pinCache(ID, &dataStatus); + if (memory != NULL) { + REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) + == SkImageCache::kPinned_MemoryStatus); + if (SkImageCache::kRetained_DataStatus == dataStatus) { + REPORTER_ASSERT(reporter, !memcmp(memory, (void*) buffer, size)); + } + cache->releaseCache(ID); + REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) + != SkImageCache::kPinned_MemoryStatus); + cache->purgeAllUnpinnedCaches(); + REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) + != SkImageCache::kPinned_MemoryStatus); + memory = cache->pinCache(ID, &dataStatus); + if (memory != NULL) { + // Since the cache was thrown away, and ID was not pinned, it should have + // been purged. + REPORTER_ASSERT(reporter, SkImageCache::kUninitialized_DataStatus == dataStatus); + cache->releaseCache(ID); + REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) + != SkImageCache::kPinned_MemoryStatus); + cache->throwAwayCache(ID); + REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) + == SkImageCache::kFreed_MemoryStatus); + } else { + REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) + == SkImageCache::kFreed_MemoryStatus); + } + } + } +} + +static void test_factory(skiatest::Reporter* reporter, SkImageCache* cache, SkData* encodedData, const SkBitmap& origBitmap) { SkBitmapFactory factory(&SkImageDecoder::DecodeMemoryToTarget); factory.setImageCache(cache); @@ -72,41 +116,80 @@ static void test_cache(skiatest::Reporter* reporter, SkImageCache* cache, SkData // Lazy decoding REPORTER_ASSERT(reporter, !bitmapFromFactory->readyToDraw()); SkLazyPixelRef* lazyRef = static_cast<SkLazyPixelRef*>(pixelRef); - int32_t cacheID = lazyRef->getCacheId(); - REPORTER_ASSERT(reporter, cache->getCacheStatus(cacheID) - != SkImageCache::kPinned_CacheStatus); + intptr_t cacheID = lazyRef->getCacheId(); + REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) + != SkImageCache::kPinned_MemoryStatus); { SkAutoLockPixels alp(*bitmapFromFactory.get()); REPORTER_ASSERT(reporter, bitmapFromFactory->readyToDraw()); cacheID = lazyRef->getCacheId(); - REPORTER_ASSERT(reporter, cache->getCacheStatus(cacheID) - == SkImageCache::kPinned_CacheStatus); + REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) + == SkImageCache::kPinned_MemoryStatus); } REPORTER_ASSERT(reporter, !bitmapFromFactory->readyToDraw()); - REPORTER_ASSERT(reporter, cache->getCacheStatus(cacheID) - != SkImageCache::kPinned_CacheStatus); + REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) + != SkImageCache::kPinned_MemoryStatus); bitmapFromFactory.free(); - REPORTER_ASSERT(reporter, cache->getCacheStatus(cacheID) - == SkImageCache::kThrownAway_CacheStatus); + REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) + == SkImageCache::kFreed_MemoryStatus); } } +class ImageCacheHolder : public SkNoncopyable { + +public: + ~ImageCacheHolder() { + fCaches.safeUnrefAll(); + } + + void addImageCache(SkImageCache* cache) { + SkSafeRef(cache); + *fCaches.append() = cache; + } + + int count() const { return fCaches.count(); } + + SkImageCache* getAt(int i) { + if (i < 0 || i > fCaches.count()) { + return NULL; + } + return fCaches.getAt(i); + } + +private: + SkTDArray<SkImageCache*> fCaches; +}; + static void TestBitmapFactory(skiatest::Reporter* reporter) { SkAutoTDelete<SkBitmap> bitmap(create_bitmap()); SkASSERT(bitmap.get() != NULL); SkAutoDataUnref encodedBitmap(create_data_from_bitmap(*bitmap.get())); - if (encodedBitmap.get() == NULL) { - // Encoding failed. - return; - } + bool encodeSucceeded = encodedBitmap.get() != NULL; + SkASSERT(encodeSucceeded); + + ImageCacheHolder cacheHolder; SkAutoTUnref<SkLruImageCache> lruCache(SkNEW_ARGS(SkLruImageCache, (1024 * 1024))); - test_cache(reporter, lruCache, encodedBitmap, *bitmap.get()); - test_cache(reporter, NULL, encodedBitmap, *bitmap.get()); -#ifdef SK_BUILD_FOR_ANDROID - test_cache(reporter, SkAshmemImageCache::GetAshmemImageCache(), encodedBitmap, *bitmap.get()); -#endif + cacheHolder.addImageCache(lruCache); + + cacheHolder.addImageCache(NULL); + + SkImageCache* purgeableCache = SkPurgeableImageCache::Create(); + if (purgeableCache != NULL) { + cacheHolder.addImageCache(purgeableCache); + purgeableCache->unref(); + } + + for (int i = 0; i < cacheHolder.count(); i++) { + SkImageCache* cache = cacheHolder.getAt(i); + if (cache != NULL) { + test_cache(reporter, cache); + } + if (encodeSucceeded) { + test_factory(reporter, cache, encodedBitmap, *bitmap.get()); + } + } } #include "TestClassDef.h" diff --git a/tools/PictureRenderingFlags.cpp b/tools/PictureRenderingFlags.cpp index 3cb1e96b74..29046aec71 100644 --- a/tools/PictureRenderingFlags.cpp +++ b/tools/PictureRenderingFlags.cpp @@ -11,7 +11,14 @@ #include "PictureRenderer.h" #include "picture_utils.h" +#include "SkBitmapFactory.h" +#include "SkData.h" #include "SkFlags.h" +#include "SkImage.h" +#include "SkImageDecoder.h" +#include "SkLruImageCache.h" +#include "SkPurgeableImageCache.h" +#include "SkString.h" // Alphabetized list of flags used by this file or bench_ and render_pictures. DEFINE_string(bbh, "none", "bbhType [width height]: Set the bounding box hierarchy type to " @@ -57,6 +64,9 @@ DEFINE_string(r, "", "skp files or directories of skp files to process."); DEFINE_double(scale, 1, "Set the scale factor."); DEFINE_string(tiles, "", "Used with --mode copyTile to specify number of tiles per larger tile " "in the x and y directions."); +DEFINE_bool(useVolatileCache, false, "Use a volatile cache for deferred image decoding pixels. " + "Only meaningful if --deferImageDecoding is set to true and the platform has an " + "implementation."); DEFINE_string(viewport, "", "width height: Set the viewport."); sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) { @@ -308,3 +318,52 @@ sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) { return renderer.detach(); } + +SkLruImageCache gLruImageCache(1024*1024); + +// Simple cache selector to choose between a purgeable cache for large images and the standard one +// for smaller images. +class MyCacheSelector : public SkBitmapFactory::CacheSelector { + +public: + MyCacheSelector() { + fPurgeableImageCache = SkPurgeableImageCache::Create(); + } + + ~MyCacheSelector() { + SkSafeUnref(fPurgeableImageCache); + } + + virtual SkImageCache* selectCache(const SkImage::Info& info) SK_OVERRIDE { + if (info.fWidth * info.fHeight > 32 * 1024 && fPurgeableImageCache != NULL) { + return fPurgeableImageCache; + } + return &gLruImageCache; + } +private: + SkImageCache* fPurgeableImageCache; +}; + +static MyCacheSelector gCacheSelector; +static SkBitmapFactory gFactory(&SkImageDecoder::DecodeMemoryToTarget); + +bool lazy_decode_bitmap(const void* buffer, size_t size, SkBitmap* bitmap); +bool lazy_decode_bitmap(const void* buffer, size_t size, SkBitmap* bitmap) { + void* copiedBuffer = sk_malloc_throw(size); + memcpy(copiedBuffer, buffer, size); + SkAutoDataUnref data(SkData::NewFromMalloc(copiedBuffer, size)); + + static bool gOnce; + if (!gOnce) { + // Only use the cache selector if there is a purgeable image cache to use for large + // images. + if (FLAGS_useVolatileCache && SkAutoTUnref<SkImageCache>( + SkPurgeableImageCache::Create()).get() != NULL) { + gFactory.setCacheSelector(&gCacheSelector); + } else { + gFactory.setImageCache(&gLruImageCache); + } + gOnce = true; + } + return gFactory.installPixelRef(data, bitmap); +} diff --git a/tools/PictureRenderingFlags.h b/tools/PictureRenderingFlags.h index 9e49d30dfb..e8909f9f4c 100644 --- a/tools/PictureRenderingFlags.h +++ b/tools/PictureRenderingFlags.h @@ -8,7 +8,7 @@ #ifndef PICTURE_RENDERING_FLAGS #define PICTURE_RENDERING_FLAGS -#include "SkString.h" +class SkString; namespace sk_tools { class PictureRenderer; diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp index d027db9633..31ef48449a 100644 --- a/tools/bench_pictures_main.cpp +++ b/tools/bench_pictures_main.cpp @@ -10,16 +10,17 @@ #include "PictureBenchmark.h" #include "PictureRenderingFlags.h" #include "SkBenchLogger.h" -#include "SkBitmapFactory.h" -#include "SkCanvas.h" #include "SkFlags.h" #include "SkGraphics.h" #include "SkImageDecoder.h" +#if LAZY_CACHE_STATS + #include "SkLazyPixelRef.h" +#endif +#include "SkLruImageCache.h" #include "SkMath.h" #include "SkOSFile.h" #include "SkPicture.h" #include "SkStream.h" -#include "SkTArray.h" #include "picture_utils.h" @@ -142,20 +143,9 @@ static SkString filterFlagsUsage() { return result; } -#include "SkData.h" -#include "SkLruImageCache.h" -#include "SkLazyPixelRef.h" - -static SkLruImageCache gLruImageCache(1024*1024); - -static bool lazy_decode_bitmap(const void* buffer, size_t size, SkBitmap* bitmap) { - void* copiedBuffer = sk_malloc_throw(size); - memcpy(copiedBuffer, buffer, size); - SkAutoDataUnref data(SkData::NewFromMalloc(copiedBuffer, size)); - SkBitmapFactory factory(&SkImageDecoder::DecodeMemoryToTarget); - factory.setImageCache(&gLruImageCache); - return factory.installPixelRef(data, bitmap); -} +// These are defined in PictureRenderingFlags.cpp +extern SkLruImageCache gLruImageCache; +extern bool lazy_decode_bitmap(const void* buffer, size_t size, SkBitmap* bitmap); #if LAZY_CACHE_STATS static int32_t gTotalCacheHits; diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp index b289d39fc7..5e0ac99945 100644 --- a/tools/render_pictures_main.cpp +++ b/tools/render_pictures_main.cpp @@ -7,8 +7,6 @@ #include "CopyTilesRenderer.h" #include "SkBitmap.h" -#include "SkBitmapFactory.h" -#include "SkCanvas.h" #include "SkDevice.h" #include "SkFlags.h" #include "SkGraphics.h" @@ -19,7 +17,6 @@ #include "SkPicture.h" #include "SkStream.h" #include "SkString.h" -#include "SkTArray.h" #include "PictureRenderer.h" #include "PictureRenderingFlags.h" #include "picture_utils.h" @@ -45,36 +42,8 @@ static void make_output_filepath(SkString* path, const SkString& dir, path->remove(path->size() - 4, 4); } -#include "SkData.h" -#include "SkLruImageCache.h" - -static SkLruImageCache gLruImageCache(1024*1024); - -#ifdef SK_BUILD_FOR_ANDROID -#include "SkAshmemImageCache.h" -#include "SkImage.h" - -static SkImageCache* cache_selector(const SkImage::Info& info) { - if (info.fWidth * info.fHeight > 32 * 1024) { - return SkAshmemImageCache::GetAshmemImageCache(); - } - return &gLruImageCache; -} - -#endif - -static bool lazy_decode_bitmap(const void* buffer, size_t size, SkBitmap* bitmap) { - void* copiedBuffer = sk_malloc_throw(size); - memcpy(copiedBuffer, buffer, size); - SkAutoDataUnref data(SkData::NewFromMalloc(copiedBuffer, size)); - SkBitmapFactory factory(&SkImageDecoder::DecodeMemoryToTarget); -#ifdef SK_BUILD_FOR_ANDROID - factory.setCacheSelector(&cache_selector); -#else - factory.setImageCache(&gLruImageCache); -#endif - return factory.installPixelRef(data, bitmap); -} +// Defined in PictureRenderingFlags.cpp +extern bool lazy_decode_bitmap(const void* buffer, size_t size, SkBitmap* bitmap); static bool render_picture(const SkString& inputPath, const SkString* outputDir, sk_tools::PictureRenderer& renderer, |