*/
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.
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.
*/
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.
*/
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).
#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();
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
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;
}
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) {
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
}
}
+bool SkPixelRef::lockPixelsAreWritable() const {
+ return this->onLockPixelsAreWritable();
+}
+
+bool SkPixelRef::onLockPixelsAreWritable() const {
+ return true;
+}
+
uint32_t SkPixelRef::getGenerationID() const {
if (0 == fGenerationID) {
fGenerationID = SkNextPixelRefGenerationID();
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;
}
#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;
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;
}
}
-////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
SkGrRenderTargetPixelRef::SkGrRenderTargetPixelRef(GrRenderTarget* rt) {
fRenderTarget = rt;
return false;
}
}
+