diff options
author | scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-02-22 21:38:35 +0000 |
---|---|---|
committer | scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-02-22 21:38:35 +0000 |
commit | f8d7d2731318cdf510ab68e6b3f5ec68ab22c8e2 (patch) | |
tree | b62a29fabe0b0af3f8f17ffbe8d607508c1d2c00 /src/ports | |
parent | 5c90e291425b2788f47679266d9584845ceefc2e (diff) |
Create SkLazyPixelRef which performs lazy decoding.
The new pixel ref behaves similarly to SkImageRef, with some key differences:
It does not depend on the images project.
It requires an SkImageCache, which handles allocation and caching of the pixel
memory.
It takes a function signature for decoding which decodes into already allocated
pixel memory rather than into an SkBitmap.
Add two implementations of SkImageCache: SkLruImageCache and SkAshmemImageCache.
Replace SkSerializationHelpers::DecodeBitmap with SkPicture::InstallPixelRefProc,
and update sites that referenced it.
SkBitmapFactory now sets the pixel ref to a new object of the new
class SkLazyPixelRef, provided it has an SkImageCache for caching.
Provide an option to do lazy decodes in render_pictures and bench_pictures.
SkPicture:
Eliminate the default parameters in the constructor.
If a proc for decoding bitmaps is installed, use it to decode any encoded
data in subpictures.
When parsing deserializing subpictures, check for success.
When serializing subpictures, pass the picture's bitmap encoder to the
subpicture's call to serialize.
Update BitmapFactoryTest to test its new behavior.
BUG=https://code.google.com/p/skia/issues/detail?id=1008
BUG=https://code.google.com/p/skia/issues/detail?id=1009
Review URL: https://codereview.appspot.com/7060052
git-svn-id: http://skia.googlecode.com/svn/trunk@7835 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/ports')
-rw-r--r-- | src/ports/SkAshmemImageCache.cpp | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/src/ports/SkAshmemImageCache.cpp b/src/ports/SkAshmemImageCache.cpp new file mode 100644 index 0000000000..a85542271d --- /dev/null +++ b/src/ports/SkAshmemImageCache.cpp @@ -0,0 +1,155 @@ +/* + * 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) { + AshmemRec rec; + rec.fSize = roundToPageSize(bytes); + + SkAutoMutexAcquire ac(&gAshmemMutex); + + 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)); + SkASSERT(ID != NULL); + *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; + } + // Purged. Remove the associated AshmemRec: + this->removeRec(rec); + 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); +#ifdef SK_DEBUG + SkASSERT(!rec->fPinned); +#endif + this->removeRec(rec); +} + +void SkAshmemImageCache::removeRec(SkAshmemImageCache::AshmemRec* rec) { + munmap(rec->fAddr, rec->fSize); + close(rec->fFD); +#ifdef SK_DEBUG + 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 |