aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-03-18 21:37:39 +0000
committerGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-03-18 21:37:39 +0000
commitbb281f7f963ea9ae6d735ca8430396cfabaa73ca (patch)
tree4e3576fe1a3bdd0afad6915958644c71654b3519
parente1575aa21619e252f6c6514317041c32d00ce5a6 (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.gypi2
-rw-r--r--gyp/ports.gyp5
-rw-r--r--gyp/tools.gyp2
-rw-r--r--include/lazy/SkBitmapFactory.h21
-rw-r--r--include/lazy/SkImageCache.h77
-rw-r--r--include/lazy/SkLruImageCache.h7
-rw-r--r--include/lazy/SkPurgeableImageCache.h45
-rw-r--r--include/ports/SkAshmemImageCache.h72
-rw-r--r--src/lazy/SkBitmapFactory.cpp8
-rw-r--r--src/lazy/SkLazyPixelRef.cpp62
-rw-r--r--src/lazy/SkLazyPixelRef.h1
-rw-r--r--src/lazy/SkLruImageCache.cpp25
-rw-r--r--src/lazy/SkPurgeableImageCache.cpp159
-rw-r--r--src/ports/SkAshmemImageCache.cpp161
-rw-r--r--tests/BitmapFactoryTest.cpp131
-rw-r--r--tools/PictureRenderingFlags.cpp59
-rw-r--r--tools/PictureRenderingFlags.h2
-rw-r--r--tools/bench_pictures_main.cpp24
-rw-r--r--tools/render_pictures_main.cpp35
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,