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:
parent
c3f100b0ff
commit
479bb60622
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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
|
@ -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
|
@ -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();
|
||||
};
|
@ -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());
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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() {}
|
||||
|
Loading…
Reference in New Issue
Block a user