Allow texture-backed bitmaps to perform a read-back when lockPixels is called.

This means we have to be even more cautious about when we call lock, and we should
always check getTexture() first if we can handle a texture directly, rather than
forcing the read-back to get the bits.



git-svn-id: http://skia.googlecode.com/svn/trunk@1815 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2011-07-07 13:42:37 +00:00
parent 63e5e34c4e
commit 9c49bc3e64
8 changed files with 127 additions and 35 deletions

View File

@ -330,6 +330,14 @@ public:
*/
void unlockPixels() const;
/**
* Some bitmaps can return a copy of their pixels for lockPixels(), but
* that copy, if modified, will not be pushed back. These bitmaps should
* not be used as targets for a raster device/canvas (since all pixels
* modifications will be lost when unlockPixels() is called.)
*/
bool lockPixelsAreWritable() const;
/** Call this to be sure that the bitmap is valid enough to be drawn (i.e.
it has non-null pixels, and if required by its config, it has a
non-null colortable. Returns true if all of the above are met.
@ -713,17 +721,23 @@ private:
void inval16BitCache();
};
class SkAutoLockPixels {
class SkAutoLockPixels : public SkNoncopyable {
public:
SkAutoLockPixels(const SkBitmap& bitmap) : fBitmap(bitmap) {
bitmap.lockPixels();
SkAutoLockPixels(const SkBitmap& bm, bool doLock = true) : fBitmap(bm) {
fDidLock = doLock;
if (doLock) {
bm.lockPixels();
}
}
~SkAutoLockPixels() {
fBitmap.unlockPixels();
if (fDidLock) {
fBitmap.unlockPixels();
}
}
private:
const SkBitmap& fBitmap;
bool fDidLock;
};
/** Helper class that performs the lock/unlockColors calls on a colortable.

View File

@ -66,6 +66,14 @@ public:
*/
void unlockPixels();
/**
* Some bitmaps can return a copy of their pixels for lockPixels(), but
* that copy, if modified, will not be pushed back. These bitmaps should
* not be used as targets for a raster device/canvas (since all pixels
* modifications will be lost when unlockPixels() is called.)
*/
bool lockPixelsAreWritable() const;
/** Returns a non-zero, unique value corresponding to the pixels in this
pixelref. Each time the pixels are changed (and notifyPixelsChanged is
called), a different generation ID will be returned.
@ -161,6 +169,9 @@ protected:
*/
virtual void onUnlockPixels() = 0;
/** Default impl returns true */
virtual bool onLockPixelsAreWritable() const;
/**
* For pixelrefs that don't have access to their raw pixels, they may be
* able to make a copy of them (e.g. if the pixels are on the GPU).

View File

@ -18,36 +18,54 @@
#ifndef SkGrTexturePixelRef_DEFINED
#define SkGrTexturePixelRef_DEFINED
#include "SkBitmap.h"
#include "SkPixelRef.h"
#include "GrGpu.h"
class SkGrTexturePixelRef : public SkPixelRef {
/**
* Common baseclass that implements onLockPixels() by calling onReadPixels().
* Since it has a copy, it always returns false for onLockPixelsAreWritable().
*/
class SkROLockPixelsPixelRef : public SkPixelRef {
public:
SkROLockPixelsPixelRef();
virtual ~SkROLockPixelsPixelRef();
protected:
// override from SkPixelRef
virtual void* onLockPixels(SkColorTable** ptr);
virtual void onUnlockPixels();
virtual bool onLockPixelsAreWritable() const; // return false;
private:
SkBitmap fBitmap;
typedef SkPixelRef INHERITED;
};
/**
* PixelRef that wraps a GrTexture
*/
class SkGrTexturePixelRef : public SkROLockPixelsPixelRef {
public:
SkGrTexturePixelRef(GrTexture*);
virtual ~SkGrTexturePixelRef();
// override from SkPixelRef
virtual SkGpuTexture* getTexture() { return (SkGpuTexture*)fTexture; }
virtual SkGpuTexture* getTexture();
protected:
// override from SkPixelRef
virtual void* onLockPixels(SkColorTable** ptr) {
if (ptr) {
*ptr = NULL;
}
return NULL;
}
// override from SkPixelRef
virtual void onUnlockPixels() {}
virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subset);
private:
GrTexture* fTexture;
typedef SkPixelRef INHERITED;
typedef SkROLockPixelsPixelRef INHERITED;
};
class SkGrRenderTargetPixelRef : public SkPixelRef {
/**
* PixelRef that wraps a GrRenderTarget
*/
class SkGrRenderTargetPixelRef : public SkROLockPixelsPixelRef {
public:
SkGrRenderTargetPixelRef(GrRenderTarget* rt);
virtual ~SkGrRenderTargetPixelRef();
@ -57,20 +75,11 @@ public:
protected:
// override from SkPixelRef
virtual void* onLockPixels(SkColorTable** ptr) {
if (ptr) {
*ptr = NULL;
}
return NULL;
}
// override from SkPixelRef
virtual void onUnlockPixels() {}
virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subset);
private:
GrRenderTarget* fRenderTarget;
typedef SkPixelRef INHERITED;
typedef SkROLockPixelsPixelRef INHERITED;
};
#endif

View File

@ -350,6 +350,14 @@ void SkBitmap::unlockPixels() const {
SkDEBUGCODE(this->validate();)
}
bool SkBitmap::lockPixelsAreWritable() const {
if (fPixelRef) {
return fPixelRef->lockPixelsAreWritable();
} else {
return fPixels != NULL;
}
}
void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
this->freePixels();
fPixels = p;

View File

@ -57,11 +57,15 @@ SkMetaData& SkDevice::getMetaData() {
}
void SkDevice::lockPixels() {
fBitmap.lockPixels();
if (fBitmap.lockPixelsAreWritable()) {
fBitmap.lockPixels();
}
}
void SkDevice::unlockPixels() {
fBitmap.unlockPixels();
if (fBitmap.lockPixelsAreWritable()) {
fBitmap.unlockPixels();
}
}
const SkBitmap& SkDevice::accessBitmap(bool changePixels) {

View File

@ -4,7 +4,8 @@
static SkMutex gPixelRefMutex;
extern int32_t SkNextPixelRefGenerationID() {
extern int32_t SkNextPixelRefGenerationID();
int32_t SkNextPixelRefGenerationID() {
static int32_t gPixelRefGenerationID;
// do a loop in case our global wraps around, as we never want to
// return a 0
@ -63,6 +64,14 @@ void SkPixelRef::unlockPixels() {
}
}
bool SkPixelRef::lockPixelsAreWritable() const {
return this->onLockPixelsAreWritable();
}
bool SkPixelRef::onLockPixelsAreWritable() const {
return true;
}
uint32_t SkPixelRef::getGenerationID() const {
if (0 == fGenerationID) {
fGenerationID = SkNextPixelRefGenerationID();

View File

@ -1088,8 +1088,9 @@ void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
bitmap.height() <= fContext->getMaxTextureSize());
SkAutoLockPixels alp(bitmap);
SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
SkDebugf("nothing to draw\n");
return;
}

View File

@ -16,11 +16,42 @@
#include "SkGrTexturePixelRef.h"
#include "GrTexture.h"
#include "SkRect.h"
#include "SkBitmap.h"
// since we call lockPixels recursively on fBitmap, we need a distinct mutex,
// to avoid deadlock with the default one provided by SkPixelRef.
static SkMutex gROLockPixelsPixelRefMutex;
SkROLockPixelsPixelRef::SkROLockPixelsPixelRef() : INHERITED(&gROLockPixelsPixelRefMutex) {
}
SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {
}
void* SkROLockPixelsPixelRef::onLockPixels(SkColorTable** ctable) {
if (ctable) {
*ctable = NULL;
}
fBitmap.reset();
// SkDebugf("---------- calling readpixels in support of lockpixels\n");
if (!this->onReadPixels(&fBitmap, NULL)) {
SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n");
return NULL;
}
fBitmap.lockPixels();
return fBitmap.getPixels();
}
void SkROLockPixelsPixelRef::onUnlockPixels() {
fBitmap.unlockPixels();
}
bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const {
return false;
}
///////////////////////////////////////////////////////////////////////////////
SkGrTexturePixelRef::SkGrTexturePixelRef(GrTexture* tex) {
fTexture = tex;
@ -31,6 +62,10 @@ SkGrTexturePixelRef::~SkGrTexturePixelRef() {
GrSafeUnref(fTexture);
}
SkGpuTexture* SkGrTexturePixelRef::getTexture() {
return (SkGpuTexture*)fTexture;
}
bool SkGrTexturePixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
if (NULL != fTexture && fTexture->isValid()) {
int left, top, width, height;
@ -57,7 +92,7 @@ bool SkGrTexturePixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
}
}
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
SkGrRenderTargetPixelRef::SkGrRenderTargetPixelRef(GrRenderTarget* rt) {
fRenderTarget = rt;
@ -100,3 +135,4 @@ bool SkGrRenderTargetPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset
return false;
}
}