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
diff --git a/src/lazy/SkPurgeableImageCache.cpp b/src/lazy/SkPurgeableImageCache.cpp
new file mode 100644
index 0000000..0f2c5e3
--- /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);
+}