Allow texture-backed bitmaps to perform a read-back when lockPixels is called.
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 7 Jul 2011 13:42:37 +0000 (13:42 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 7 Jul 2011 13:42:37 +0000 (13:42 +0000)
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

include/core/SkBitmap.h
include/core/SkPixelRef.h
include/gpu/SkGrTexturePixelRef.h
src/core/SkBitmap.cpp
src/core/SkDevice.cpp
src/core/SkPixelRef.cpp
src/gpu/SkGpuDevice.cpp
src/gpu/SkGrTexturePixelRef.cpp

index 58af571b95a11fd98fb223bf084e56be5d20b4c1..de3e83ea28bf6773c279d059540a316eb9152994 100644 (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.
index 8fb368ac326e0ffaf0ff04c29be20708a849190d..17cf6b43912c9537b8e1884ad5052dc42169387f 100644 (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).
index 5bc64f532a230823163605a81705246672bcfdf3..2de842e3b44ff51879852d8b617c82b1e3ccd332 100644 (file)
 #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
index cdb74bb1d6ab28151bb1755c30db8f3fc797a10f..92ff88ae6660e7ab281826650d1258d64bba3d00 100644 (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;
index 78b2dcc2ef2aac5fae417e925b523862187485ce..b4f586698154df19bbe387f257873e4b108a97b1 100644 (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) {
index 967a8721b92a37aec5d412c9c209ce089aaedea3..f8508911e72061b460459e5dfc985b2357be12b5 100644 (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();
index b8cc2bb4cec20db64dcd5a0f511b51724987ff0c..508ace02460f9e063a7a0533df05d38a2a80f3df 100644 (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;
     }
 
index 8becfd42c74d350b0b3a9fac17214a09fcf5a2f4..4fc03ab1569c687ee0f3cacc509a801304dfe51e 100644 (file)
 
 
 #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;
     }
 }
+