Remove SkImageRef and related functionality.

From here on out, use SkDecodingImageGenerator+SkDiscardablePixelRef.

R=scroggo@google.com

Review URL: https://codereview.chromium.org/100183002
This commit is contained in:
Hal Canary 2014-06-04 14:38:48 -04:00
parent c3f100b0ff
commit 479bb60622
15 changed files with 0 additions and 1053 deletions

View File

@ -34,8 +34,6 @@
'sources': [
'../include/images/SkDecodingImageGenerator.h',
'../include/images/SkForceLinking.h',
'../include/images/SkImageRef.h',
'../include/images/SkImageRef_GlobalPool.h',
'../src/images/SkJpegUtility.h',
'../include/images/SkMovie.h',
'../include/images/SkPageFlipper.h',
@ -73,13 +71,6 @@
'../src/images/SkImageEncoder.cpp',
'../src/images/SkImageEncoder_Factory.cpp',
'../src/images/SkImageEncoder_argb.cpp',
'../src/images/SkImageRef.cpp',
'../src/images/SkImageRefPool.cpp',
'../src/images/SkImageRefPool.h',
'../src/images/SkImageRef_ashmem.h',
'../src/images/SkImageRef_ashmem.cpp',
'../src/images/SkImageRef_GlobalPool.cpp',
'../src/images/SkImages.cpp',
'../src/images/SkJpegUtility.cpp',
'../src/images/SkMovie.cpp',
'../src/images/SkMovie_gif.cpp',

View File

@ -62,12 +62,9 @@
'config/sk_stdint.h',
'config/SkUserConfig.h',
'pipe/SkGPipe.h',
'images/SkImageRef.h',
'images/SkMovie.h',
'images/SkPageFlipper.h',
'images/SkForceLinking.h',
'images/SkImageRef_GlobalPool.h',
'images/SkImages.h',
'effects/SkMorphologyImageFilter.h',
'effects/Sk2DPathEffect.h',
'effects/SkXfermodeImageFilter.h',

View File

@ -1,104 +0,0 @@
/*
* Copyright 2008 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImageRef_DEFINED
#define SkImageRef_DEFINED
#include "SkPixelRef.h"
#include "SkBitmap.h"
#include "SkImageDecoder.h"
#include "SkString.h"
class SkImageRefPool;
class SkStreamRewindable;
// define this to enable dumping whenever we add/remove/purge an imageref
//#define DUMP_IMAGEREF_LIFECYCLE
class SkImageRef : public SkPixelRef {
public:
/** Create a new imageref from a stream. NOTE: the stream is not copied, but
since it may be accessed from another thread, the caller must ensure
that this imageref is the only owner of the stream. i.e. - sole
ownership of the stream object is transferred to this imageref object.
@param stream The stream containing the encoded image data. This may be
retained (by calling ref()), so the caller should not
explicitly delete it.
@param config The preferred config of the decoded bitmap.
@param sampleSize Requested sampleSize for decoding. Defaults to 1.
*/
SkImageRef(const SkImageInfo&, SkStreamRewindable*, int sampleSize = 1,
SkBaseMutex* mutex = NULL);
virtual ~SkImageRef();
/** this value is passed onto the decoder. Default is true
*/
void setDitherImage(bool dither) { fDoDither = dither; }
/** Return true if the image can be decoded. If so, and bitmap is non-null,
call its setConfig() with the corresponding values, but explicitly will
not set its pixels or colortable. Use SkPixelRef::lockPixels() for that.
If there has been an error decoding the bitmap, this will return false
and ignore the bitmap parameter.
*/
bool getInfo(SkBitmap* bm);
/** Return true if the image can be decoded and is opaque. Calling this
method will decode and set the pixels in the specified bitmap and
sets the isOpaque flag.
*/
bool isOpaque(SkBitmap* bm);
SkImageDecoderFactory* getDecoderFactory() const { return fFactory; }
// returns the factory parameter
SkImageDecoderFactory* setDecoderFactory(SkImageDecoderFactory*);
protected:
/** Override if you want to install a custom allocator.
When this is called we will have already acquired the mutex!
*/
virtual bool onDecode(SkImageDecoder* codec, SkStreamRewindable*, SkBitmap*,
SkBitmap::Config, SkImageDecoder::Mode);
/* Overrides from SkPixelRef
When these are called, we will have already acquired the mutex!
*/
virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE;
// override this in your subclass to clean up when we're unlocking pixels
virtual void onUnlockPixels() SK_OVERRIDE {}
SkImageRef(SkReadBuffer&, SkBaseMutex* mutex = NULL);
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
SkBitmap fBitmap;
private:
SkStreamRewindable* setStream(SkStreamRewindable*);
// called with mutex already held. returns true if the bitmap is in the
// requested state (or further, i.e. has pixels)
bool prepareBitmap(SkImageDecoder::Mode);
SkImageDecoderFactory* fFactory; // may be null
SkStreamRewindable* fStream;
int fSampleSize;
bool fDoDither;
bool fErrorInDecoding;
friend class SkImageRefPool;
SkImageRef* fPrev, *fNext;
size_t ramUsed() const;
typedef SkPixelRef INHERITED;
};
#endif

View File

@ -1,62 +0,0 @@
/*
* Copyright 2008 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImageRef_GlobalPool_DEFINED
#define SkImageRef_GlobalPool_DEFINED
#include "SkImageRef.h"
class SkImageRef_GlobalPool : public SkImageRef {
public:
// if pool is null, use the global pool
SkImageRef_GlobalPool(const SkImageInfo&, SkStreamRewindable*,
int sampleSize = 1);
virtual ~SkImageRef_GlobalPool();
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkImageRef_GlobalPool)
// API to control the global pool
/** Return the amount specified as the budget for the cache (in bytes).
*/
static size_t GetRAMBudget();
/** Set a new budget value for the cache.
*/
static void SetRAMBudget(size_t);
/** Return how much ram is currently in use by the global cache.
*/
static size_t GetRAMUsed();
/** Free up (approximately) enough such that the amount used by the cache
is <= the specified amount. Since some images may be "in use", the
amount actually freed may not always result in a ram usage value <=
to the requested amount. In addition, because of the
chunky nature of the cache, the resulting usage may be < the requested
amount.
*/
static void SetRAMUsed(size_t usageInBytes);
static void DumpPool();
protected:
virtual bool onDecode(SkImageDecoder* codec, SkStreamRewindable* stream,
SkBitmap* bitmap, SkBitmap::Config config,
SkImageDecoder::Mode mode);
virtual void onUnlockPixels();
SkImageRef_GlobalPool(SkReadBuffer&);
private:
typedef SkImageRef INHERITED;
};
#endif

View File

@ -1,14 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
class SkImages {
public:
/**
* Initializes flattenables in the images project.
*/
static void InitializeFlattenables();
};

View File

@ -1,212 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkImageRef.h"
#include "SkBitmap.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
#include "SkImageDecoder.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkThread.h"
//#define DUMP_IMAGEREF_LIFECYCLE
///////////////////////////////////////////////////////////////////////////////
SkImageRef::SkImageRef(const SkImageInfo& info, SkStreamRewindable* stream,
int sampleSize, SkBaseMutex* mutex)
: INHERITED(info, mutex), fErrorInDecoding(false)
{
SkASSERT(stream);
stream->ref();
fStream = stream;
fSampleSize = sampleSize;
fDoDither = true;
fPrev = fNext = NULL;
fFactory = NULL;
// This sets the colortype/alphatype to exactly match our info, so that this
// can get communicated down to the codec.
fBitmap.setInfo(info);
#ifdef DUMP_IMAGEREF_LIFECYCLE
SkDebugf("add ImageRef %p [%d] data=%d\n",
this, this->info().fColorType, (int)stream->getLength());
#endif
}
SkImageRef::~SkImageRef() {
#ifdef DUMP_IMAGEREF_LIFECYCLE
SkDebugf("delete ImageRef %p [%d] data=%d\n",
this, this->info().fColorType, (int)fStream->getLength());
#endif
fStream->unref();
SkSafeUnref(fFactory);
}
bool SkImageRef::getInfo(SkBitmap* bitmap) {
SkAutoMutexAcquire ac(this->mutex());
if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) {
return false;
}
SkASSERT(SkBitmap::kNo_Config != fBitmap.config());
if (bitmap) {
bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height());
}
return true;
}
bool SkImageRef::isOpaque(SkBitmap* bitmap) {
if (bitmap && bitmap->pixelRef() == this) {
bitmap->lockPixels();
// what about colortables??????
bitmap->setAlphaType(fBitmap.alphaType());
bitmap->unlockPixels();
return true;
}
return false;
}
SkImageDecoderFactory* SkImageRef::setDecoderFactory(
SkImageDecoderFactory* fact) {
SkRefCnt_SafeAssign(fFactory, fact);
return fact;
}
///////////////////////////////////////////////////////////////////////////////
bool SkImageRef::onDecode(SkImageDecoder* codec, SkStreamRewindable* stream,
SkBitmap* bitmap, SkBitmap::Config config,
SkImageDecoder::Mode mode) {
return codec->decode(stream, bitmap, config, mode);
}
bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) {
if (fErrorInDecoding) {
return false;
}
if (NULL != fBitmap.getPixels() ||
(SkBitmap::kNo_Config != fBitmap.config() &&
SkImageDecoder::kDecodeBounds_Mode == mode)) {
return true;
}
SkASSERT(fBitmap.getPixels() == NULL);
if (!fStream->rewind()) {
SkDEBUGF(("Failed to rewind SkImageRef stream!"));
return false;
}
SkImageDecoder* codec;
if (fFactory) {
codec = fFactory->newDecoder(fStream);
} else {
codec = SkImageDecoder::Factory(fStream);
}
if (codec) {
SkAutoTDelete<SkImageDecoder> ad(codec);
codec->setSampleSize(fSampleSize);
codec->setDitherImage(fDoDither);
codec->setRequireUnpremultipliedColors(this->info().fAlphaType == kUnpremul_SkAlphaType);
if (this->onDecode(codec, fStream, &fBitmap, fBitmap.config(), mode)) {
if (kOpaque_SkAlphaType == fBitmap.alphaType()) {
this->changeAlphaType(kOpaque_SkAlphaType);
}
SkASSERT(this->info() == fBitmap.info());
return true;
}
}
#ifdef DUMP_IMAGEREF_LIFECYCLE
if (NULL == codec) {
SkDebugf("--- ImageRef: <%s> failed to find codec\n", this->getURI());
} else {
SkDebugf("--- ImageRef: <%s> failed in codec for %d mode\n",
this->getURI(), mode);
}
#endif
fErrorInDecoding = true;
fBitmap.reset();
return false;
}
bool SkImageRef::onNewLockPixels(LockRec* rec) {
if (NULL == fBitmap.getPixels()) {
(void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
}
if (NULL == fBitmap.getPixels()) {
return false;
}
rec->fPixels = fBitmap.getPixels();
rec->fColorTable = NULL;
rec->fRowBytes = fBitmap.rowBytes();
return true;
}
size_t SkImageRef::ramUsed() const {
size_t size = 0;
if (fBitmap.getPixels()) {
size = fBitmap.getSize();
if (fBitmap.getColorTable()) {
size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
}
}
return size;
}
///////////////////////////////////////////////////////////////////////////////
SkImageRef::SkImageRef(SkReadBuffer& buffer, SkBaseMutex* mutex)
: INHERITED(buffer, mutex), fErrorInDecoding(false) {
fSampleSize = buffer.readInt();
fDoDither = buffer.readBool();
size_t length = buffer.getArrayCount();
if (buffer.validateAvailable(length)) {
fStream = SkNEW_ARGS(SkMemoryStream, (length));
buffer.readByteArray((void*)fStream->getMemoryBase(), length);
} else {
fStream = NULL;
}
fPrev = fNext = NULL;
fFactory = NULL;
// This sets the colortype/alphatype to exactly match our info, so that this
// can get communicated down to the codec.
fBitmap.setInfo(this->info());
}
void SkImageRef::flatten(SkWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
buffer.writeInt(fSampleSize);
buffer.writeBool(fDoDither);
// FIXME: Consider moving this logic should go into writeStream itself.
// writeStream currently has no other callers, so this may be fine for
// now.
if (!fStream->rewind()) {
SkDEBUGF(("Failed to rewind SkImageRef stream!"));
buffer.write32(0);
} else {
// FIXME: Handle getLength properly here. Perhaps this class should
// take an SkStreamAsset.
buffer.writeStream(fStream, fStream->getLength());
}
}

View File

@ -1,192 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkImageRefPool.h"
#include "SkImageRef.h"
#include "SkThread.h"
SkImageRefPool::SkImageRefPool() {
fRAMBudget = 0; // means no explicit limit
fRAMUsed = 0;
fCount = 0;
fHead = fTail = NULL;
}
SkImageRefPool::~SkImageRefPool() {
// SkASSERT(NULL == fHead);
}
void SkImageRefPool::setRAMBudget(size_t size) {
if (fRAMBudget != size) {
fRAMBudget = size;
this->purgeIfNeeded();
}
}
void SkImageRefPool::justAddedPixels(SkImageRef* ref) {
#ifdef DUMP_IMAGEREF_LIFECYCLE
SkDebugf("=== ImagePool: add pixels %s [%d %d %d] bytes=%d heap=%d\n",
ref->getURI(),
ref->fBitmap.width(), ref->fBitmap.height(),
ref->fBitmap.bytesPerPixel(),
ref->fBitmap.getSize(), (int)fRAMUsed);
#endif
fRAMUsed += ref->ramUsed();
this->purgeIfNeeded();
}
void SkImageRefPool::canLosePixels(SkImageRef* ref) {
// the refs near fHead have recently been released (used)
// if we purge, we purge from the tail
this->detach(ref);
this->addToHead(ref);
this->purgeIfNeeded();
}
void SkImageRefPool::purgeIfNeeded() {
// do nothing if we have a zero-budget (i.e. unlimited)
if (fRAMBudget != 0) {
this->setRAMUsed(fRAMBudget);
}
}
void SkImageRefPool::setRAMUsed(size_t limit) {
SkImageRef* ref = fTail;
while (NULL != ref && fRAMUsed > limit) {
// only purge it if its pixels are unlocked
if (!ref->isLocked() && ref->fBitmap.getPixels()) {
size_t size = ref->ramUsed();
SkASSERT(size <= fRAMUsed);
fRAMUsed -= size;
#ifdef DUMP_IMAGEREF_LIFECYCLE
SkDebugf("=== ImagePool: purge %s [%d %d %d] bytes=%d heap=%d\n",
ref->getURI(),
ref->fBitmap.width(), ref->fBitmap.height(),
ref->fBitmap.bytesPerPixel(),
(int)size, (int)fRAMUsed);
#endif
// remember the bitmap config (don't call reset),
// just clear the pixel memory
ref->fBitmap.setPixels(NULL);
SkASSERT(NULL == ref->fBitmap.getPixels());
}
ref = ref->fPrev;
}
}
///////////////////////////////////////////////////////////////////////////////
void SkImageRefPool::addToHead(SkImageRef* ref) {
ref->fNext = fHead;
ref->fPrev = NULL;
if (fHead) {
SkASSERT(NULL == fHead->fPrev);
fHead->fPrev = ref;
}
fHead = ref;
if (NULL == fTail) {
fTail = ref;
}
fCount += 1;
SkASSERT(computeCount() == fCount);
fRAMUsed += ref->ramUsed();
}
void SkImageRefPool::addToTail(SkImageRef* ref) {
ref->fNext = NULL;
ref->fPrev = fTail;
if (fTail) {
SkASSERT(NULL == fTail->fNext);
fTail->fNext = ref;
}
fTail = ref;
if (NULL == fHead) {
fHead = ref;
}
fCount += 1;
SkASSERT(computeCount() == fCount);
fRAMUsed += ref->ramUsed();
}
void SkImageRefPool::detach(SkImageRef* ref) {
SkASSERT(fCount > 0);
if (fHead == ref) {
fHead = ref->fNext;
}
if (fTail == ref) {
fTail = ref->fPrev;
}
if (ref->fPrev) {
ref->fPrev->fNext = ref->fNext;
}
if (ref->fNext) {
ref->fNext->fPrev = ref->fPrev;
}
ref->fNext = ref->fPrev = NULL;
fCount -= 1;
SkASSERT(computeCount() == fCount);
SkASSERT(fRAMUsed >= ref->ramUsed());
fRAMUsed -= ref->ramUsed();
}
int SkImageRefPool::computeCount() const {
SkImageRef* ref = fHead;
int count = 0;
while (ref != NULL) {
count += 1;
ref = ref->fNext;
}
#ifdef SK_DEBUG
ref = fTail;
int count2 = 0;
while (ref != NULL) {
count2 += 1;
ref = ref->fPrev;
}
SkASSERT(count2 == count);
#endif
return count;
}
///////////////////////////////////////////////////////////////////////////////
#include "SkStream.h"
void SkImageRefPool::dump() const {
#if defined(SK_DEBUG) || defined(DUMP_IMAGEREF_LIFECYCLE)
SkDebugf("ImagePool dump: bugdet: %d used: %d count: %d\n",
(int)fRAMBudget, (int)fRAMUsed, fCount);
SkImageRef* ref = fHead;
while (ref != NULL) {
SkDebugf(" [%3d %3d %d] ram=%d data=%d locked=%d %s\n", ref->fBitmap.width(),
ref->fBitmap.height(), ref->fBitmap.config(),
ref->ramUsed(), (int)ref->fStream->getLength(),
ref->isLocked(), ref->getURI());
ref = ref->fNext;
}
#endif
}

View File

@ -1,49 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImageRefPool_DEFINED
#define SkImageRefPool_DEFINED
#include "SkTypes.h"
class SkImageRef;
class SkImageRef_GlobalPool;
class SkImageRefPool {
public:
SkImageRefPool();
~SkImageRefPool();
size_t getRAMBudget() const { return fRAMBudget; }
void setRAMBudget(size_t);
size_t getRAMUsed() const { return fRAMUsed; }
void setRAMUsed(size_t limit);
void addToHead(SkImageRef*);
void addToTail(SkImageRef*);
void detach(SkImageRef*);
void dump() const;
private:
size_t fRAMBudget;
size_t fRAMUsed;
int fCount;
SkImageRef* fHead, *fTail;
int computeCount() const;
friend class SkImageRef_GlobalPool;
void justAddedPixels(SkImageRef*);
void canLosePixels(SkImageRef*);
void purgeIfNeeded();
};
#endif

View File

@ -1,100 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkImageRef_GlobalPool.h"
#include "SkImageRefPool.h"
#include "SkThread.h"
SK_DECLARE_STATIC_MUTEX(gGlobalPoolMutex);
/*
* This returns the lazily-allocated global pool. It must be called
* from inside the guard mutex, so we safely only ever allocate 1.
*/
static SkImageRefPool* GetGlobalPool() {
static SkImageRefPool* gPool;
if (NULL == gPool) {
gPool = SkNEW(SkImageRefPool);
// call sk_atexit(...) when we have that, to free the global pool
}
return gPool;
}
SkImageRef_GlobalPool::SkImageRef_GlobalPool(const SkImageInfo& info,
SkStreamRewindable* stream,
int sampleSize)
: SkImageRef(info, stream, sampleSize, &gGlobalPoolMutex) {
SkASSERT(&gGlobalPoolMutex == this->mutex());
SkAutoMutexAcquire ac(gGlobalPoolMutex);
GetGlobalPool()->addToHead(this);
}
SkImageRef_GlobalPool::~SkImageRef_GlobalPool() {
SkASSERT(&gGlobalPoolMutex == this->mutex());
SkAutoMutexAcquire ac(gGlobalPoolMutex);
GetGlobalPool()->detach(this);
}
/* By design, onUnlockPixels() already is inside the mutex-lock,
* and it is the (indirect) caller of onDecode(), therefore we can assume
* that we also are already inside the mutex. Hence, we can reference
* the global-pool directly.
*/
bool SkImageRef_GlobalPool::onDecode(SkImageDecoder* codec, SkStreamRewindable* stream,
SkBitmap* bitmap, SkBitmap::Config config,
SkImageDecoder::Mode mode) {
if (!this->INHERITED::onDecode(codec, stream, bitmap, config, mode)) {
return false;
}
if (mode == SkImageDecoder::kDecodePixels_Mode) {
// no need to grab the mutex here, it has already been acquired.
GetGlobalPool()->justAddedPixels(this);
}
return true;
}
void SkImageRef_GlobalPool::onUnlockPixels() {
this->INHERITED::onUnlockPixels();
// by design, onUnlockPixels() already is inside the mutex-lock
GetGlobalPool()->canLosePixels(this);
}
SkImageRef_GlobalPool::SkImageRef_GlobalPool(SkReadBuffer& buffer)
: INHERITED(buffer, &gGlobalPoolMutex) {
SkASSERT(&gGlobalPoolMutex == this->mutex());
SkAutoMutexAcquire ac(gGlobalPoolMutex);
GetGlobalPool()->addToHead(this);
}
///////////////////////////////////////////////////////////////////////////////
// global imagerefpool wrappers
size_t SkImageRef_GlobalPool::GetRAMBudget() {
SkAutoMutexAcquire ac(gGlobalPoolMutex);
return GetGlobalPool()->getRAMBudget();
}
void SkImageRef_GlobalPool::SetRAMBudget(size_t size) {
SkAutoMutexAcquire ac(gGlobalPoolMutex);
GetGlobalPool()->setRAMBudget(size);
}
size_t SkImageRef_GlobalPool::GetRAMUsed() {
SkAutoMutexAcquire ac(gGlobalPoolMutex);
return GetGlobalPool()->getRAMUsed();
}
void SkImageRef_GlobalPool::SetRAMUsed(size_t usage) {
SkAutoMutexAcquire ac(gGlobalPoolMutex);
GetGlobalPool()->setRAMUsed(usage);
}
void SkImageRef_GlobalPool::DumpPool() {
SkAutoMutexAcquire ac(gGlobalPoolMutex);
GetGlobalPool()->dump();
}

View File

@ -1,230 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkImageRef_ashmem.h"
#include "SkImageDecoder.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
#include "SkThread.h"
#include "android/ashmem.h"
#include <sys/mman.h>
#include <unistd.h>
//#define TRACE_ASH_PURGE // just trace purges
#ifdef DUMP_IMAGEREF_LIFECYCLE
#define DUMP_ASHMEM_LIFECYCLE
#else
// #define DUMP_ASHMEM_LIFECYCLE
#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;
// SkDebugf("---- oldsize %d newsize %d\n", size, newsize);
return newsize;
}
SkImageRef_ashmem::SkImageRef_ashmem(const SkImageInfo& info,
SkStreamRewindable* stream,
int sampleSize)
: SkImageRef(info, stream, sampleSize)
{
fRec.fFD = -1;
fRec.fAddr = NULL;
fRec.fSize = 0;
fRec.fPinned = false;
fCT = NULL;
}
SkImageRef_ashmem::~SkImageRef_ashmem() {
SkSafeUnref(fCT);
this->closeFD();
}
void SkImageRef_ashmem::closeFD() {
if (-1 != fRec.fFD) {
#ifdef DUMP_ASHMEM_LIFECYCLE
SkDebugf("=== ashmem close %d\n", fRec.fFD);
#endif
SkASSERT(fRec.fAddr);
SkASSERT(fRec.fSize);
munmap(fRec.fAddr, fRec.fSize);
close(fRec.fFD);
fRec.fFD = -1;
}
}
///////////////////////////////////////////////////////////////////////////////
class AshmemAllocator : public SkBitmap::Allocator {
public:
AshmemAllocator(SkAshmemRec* rec, const char name[])
: fRec(rec), fName(name) {}
virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) {
const size_t size = roundToPageSize(bm->getSize());
int fd = fRec->fFD;
void* addr = fRec->fAddr;
SkASSERT(!fRec->fPinned);
if (-1 == fd) {
SkASSERT(NULL == addr);
SkASSERT(0 == fRec->fSize);
fd = ashmem_create_region(fName, size);
#ifdef DUMP_ASHMEM_LIFECYCLE
SkDebugf("=== ashmem_create_region %s size=%d fd=%d\n", fName, size, fd);
#endif
if (-1 == fd) {
SkDebugf("------- imageref_ashmem create failed <%s> %d\n",
fName, size);
return false;
}
int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
if (err) {
SkDebugf("------ ashmem_set_prot_region(%d) failed %d\n",
fd, err);
close(fd);
return false;
}
addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (-1 == (long)addr) {
SkDebugf("---------- mmap failed for imageref_ashmem size=%d\n",
size);
close(fd);
return false;
}
fRec->fFD = fd;
fRec->fAddr = addr;
fRec->fSize = size;
} else {
SkASSERT(addr);
SkASSERT(size == fRec->fSize);
(void)ashmem_pin_region(fd, 0, 0);
}
bm->setPixels(addr, ct);
fRec->fPinned = true;
return true;
}
private:
// we just point to our caller's memory, these are not copies
SkAshmemRec* fRec;
const char* fName;
};
bool SkImageRef_ashmem::onDecode(SkImageDecoder* codec, SkStreamRewindable* stream,
SkBitmap* bitmap, SkBitmap::Config config,
SkImageDecoder::Mode mode) {
if (SkImageDecoder::kDecodeBounds_Mode == mode) {
return this->INHERITED::onDecode(codec, stream, bitmap, config, mode);
}
// Ashmem memory is guaranteed to be initialized to 0.
codec->setSkipWritingZeroes(true);
AshmemAllocator alloc(&fRec, this->getURI());
codec->setAllocator(&alloc);
bool success = this->INHERITED::onDecode(codec, stream, bitmap, config,
mode);
// remove the allocator, since its on the stack
codec->setAllocator(NULL);
if (success) {
// remember the colortable (if any)
SkRefCnt_SafeAssign(fCT, bitmap->getColorTable());
return true;
} else {
if (fRec.fPinned) {
ashmem_unpin_region(fRec.fFD, 0, 0);
fRec.fPinned = false;
}
this->closeFD();
return false;
}
}
bool SkImageRef_ashmem::onNewLockPixels(LockRec* rec) {
SkASSERT(fBitmap.getPixels() == NULL);
SkASSERT(fBitmap.getColorTable() == NULL);
// fast case: check if we can just pin and get the cached data
if (-1 != fRec.fFD) {
SkASSERT(fRec.fAddr);
SkASSERT(!fRec.fPinned);
int pin = ashmem_pin_region(fRec.fFD, 0, 0);
if (ASHMEM_NOT_PURGED == pin) { // yea, fast case!
fBitmap.setPixels(fRec.fAddr, fCT);
fRec.fPinned = true;
} else if (ASHMEM_WAS_PURGED == pin) {
ashmem_unpin_region(fRec.fFD, 0, 0);
// let go of our colortable if we lost the pixels. Well get it back
// again when we re-decode
if (fCT) {
fCT->unref();
fCT = NULL;
}
#if defined(DUMP_ASHMEM_LIFECYCLE) || defined(TRACE_ASH_PURGE)
SkDebugf("===== ashmem purged %d\n", fBitmap.getSize());
#endif
} else {
SkDebugf("===== ashmem pin_region(%d) returned %d\n", fRec.fFD, pin);
return false;
}
} else {
// no FD, will create an ashmem region in allocator
}
return this->INHERITED::onNewLockPixels(rec);
}
void SkImageRef_ashmem::onUnlockPixels() {
this->INHERITED::onUnlockPixels();
if (-1 != fRec.fFD) {
SkASSERT(fRec.fAddr);
SkASSERT(fRec.fPinned);
ashmem_unpin_region(fRec.fFD, 0, 0);
fRec.fPinned = false;
}
// we clear this with or without an error, since we've either closed or
// unpinned the region
fBitmap.setPixels(NULL, NULL);
}
void SkImageRef_ashmem::flatten(SkWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
buffer.writeString(getURI());
}
SkImageRef_ashmem::SkImageRef_ashmem(SkReadBuffer& buffer)
: INHERITED(buffer) {
fRec.fFD = -1;
fRec.fAddr = NULL;
fRec.fSize = 0;
fRec.fPinned = false;
fCT = NULL;
SkString uri;
buffer.readString(&uri);
this->setURI(uri);
}

View File

@ -1,47 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImageRef_ashmem_DEFINED
#define SkImageRef_ashmem_DEFINED
#include "SkImageRef.h"
struct SkAshmemRec {
int fFD;
void* fAddr;
size_t fSize;
bool fPinned;
};
class SkImageRef_ashmem : public SkImageRef {
public:
SkImageRef_ashmem(const SkImageInfo&, SkStreamRewindable*, int sampleSize = 1);
virtual ~SkImageRef_ashmem();
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkImageRef_ashmem)
protected:
SkImageRef_ashmem(SkReadBuffer&);
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
virtual bool onDecode(SkImageDecoder* codec, SkStreamRewindable* stream,
SkBitmap* bitmap, SkBitmap::Config config,
SkImageDecoder::Mode mode);
virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE;
virtual void onUnlockPixels() SK_OVERRIDE;
private:
void closeFD();
SkColorTable* fCT;
SkAshmemRec fRec;
typedef SkImageRef INHERITED;
};
#endif

View File

@ -1,21 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkFlattenable.h"
#include "SkImageRef_GlobalPool.h"
#include "SkImages.h"
#ifdef SK_BUILD_FOR_ANDROID
#include "SkImageRef_ashmem.h"
#endif
void SkImages::InitializeFlattenables() {
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageRef_GlobalPool)
#ifdef SK_BUILD_FOR_ANDROID
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageRef_ashmem)
#endif
}

View File

@ -37,7 +37,6 @@
#include "SkEmbossMaskFilter.h"
#include "SkFlattenable.h"
#include "SkGradientShader.h"
#include "SkImages.h"
#include "SkLayerDrawLooper.h"
#include "SkLayerRasterizer.h"
#include "SkLerpXfermode.h"
@ -115,7 +114,6 @@ static void InitializeFlattenables() {
SkBlurMaskFilter::InitializeFlattenables();
SkColorFilter::InitializeFlattenables();
SkGradientShader::InitializeFlattenables();
SkImages::InitializeFlattenables();
SkLightingImageFilter::InitializeFlattenables();
SkTableColorFilter::InitializeFlattenables();
SkXfermode::InitializeFlattenables();

View File

@ -37,7 +37,6 @@
#include "SkEmbossMaskFilter.h"
#include "SkFlattenable.h"
#include "SkGradientShader.h"
#include "SkImages.h"
#include "SkLayerDrawLooper.h"
#include "SkLayerRasterizer.h"
#include "SkLerpXfermode.h"
@ -115,7 +114,6 @@ static void InitializeFlattenables() {
SkBlurMaskFilter::InitializeFlattenables();
SkColorFilter::InitializeFlattenables();
SkGradientShader::InitializeFlattenables();
SkImages::InitializeFlattenables();
SkLightingImageFilter::InitializeFlattenables();
SkTableColorFilter::InitializeFlattenables();
SkXfermode::InitializeFlattenables();

View File

@ -147,9 +147,3 @@ bool SkImageEncoder::encodeFile(const char file[], const SkBitmap& bm, int quali
return false;
}
/////////////////////////////////////////////////////////////////////////
// Empty implementation for SkImages.
#include "SkImages.h"
void SkImages::InitializeFlattenables() {}