diff options
-rw-r--r-- | include/core/SkPixelRef.h | 15 | ||||
-rw-r--r-- | src/core/SkPixelRef.cpp | 18 | ||||
-rw-r--r-- | src/image/SkImage.cpp | 2 | ||||
-rw-r--r-- | src/image/SkImagePriv.h | 8 | ||||
-rw-r--r-- | src/image/SkImage_Raster.cpp | 16 | ||||
-rw-r--r-- | src/image/SkSurface.cpp | 10 | ||||
-rw-r--r-- | src/image/SkSurface_Base.h | 8 | ||||
-rw-r--r-- | src/image/SkSurface_Raster.cpp | 21 | ||||
-rw-r--r-- | tests/DeferredCanvasTest.cpp | 3 | ||||
-rw-r--r-- | tests/SkImageTest.cpp | 3 |
10 files changed, 80 insertions, 24 deletions
diff --git a/include/core/SkPixelRef.h b/include/core/SkPixelRef.h index 4d84665a98..a67855de5f 100644 --- a/include/core/SkPixelRef.h +++ b/include/core/SkPixelRef.h @@ -152,7 +152,7 @@ public: /** Returns true if this pixelref is marked as immutable, meaning that the contents of its pixels will not change for the lifetime of the pixelref. */ - bool isImmutable() const { return fIsImmutable; } + bool isImmutable() const { return fMutability != kMutable; } /** Marks this pixelref is immutable, meaning that the contents of its pixels will not change for the lifetime of the pixelref. This state can @@ -366,8 +366,13 @@ private: // Set true by caches when they cache content that's derived from the current pixels. SkAtomic<bool> fAddedToCache; - // can go from false to true, but never from true to false - bool fIsImmutable; + + enum { + kMutable, // PixelRefs begin mutable. + kTemporarilyImmutable, // Considered immutable, but can revert to mutable. + kImmutable, // Once set to this state, it never leaves. + } fMutability : 8; // easily fits inside a byte + // only ever set in constructor, const after that bool fPreLocked; @@ -376,6 +381,10 @@ private: void setMutex(SkBaseMutex* mutex); + void setTemporarilyImmutable(); + void restoreMutability(); + friend class SkSurface_Raster; // For the two methods above. + // When copying a bitmap to another with the same shape and config, we can safely // clone the pixelref generation ID too, which makes them equivalent under caching. friend class SkBitmap; // only for cloneGenID diff --git a/src/core/SkPixelRef.cpp b/src/core/SkPixelRef.cpp index 6d36915d9a..56bcc9a792 100644 --- a/src/core/SkPixelRef.cpp +++ b/src/core/SkPixelRef.cpp @@ -106,7 +106,7 @@ SkPixelRef::SkPixelRef(const SkImageInfo& info) fRec.zero(); fLockCount = 0; this->needsNewGenID(); - fIsImmutable = false; + fMutability = kMutable; fPreLocked = false; fAddedToCache.store(false); } @@ -125,7 +125,7 @@ SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex) fRec.zero(); fLockCount = 0; this->needsNewGenID(); - fIsImmutable = false; + fMutability = kMutable; fPreLocked = false; fAddedToCache.store(false); } @@ -341,7 +341,7 @@ void SkPixelRef::callGenIDChangeListeners() { void SkPixelRef::notifyPixelsChanged() { #ifdef SK_DEBUG - if (fIsImmutable) { + if (this->isImmutable()) { SkDebugf("========== notifyPixelsChanged called on immutable pixelref"); } #endif @@ -355,7 +355,17 @@ void SkPixelRef::changeAlphaType(SkAlphaType at) { } void SkPixelRef::setImmutable() { - fIsImmutable = true; + fMutability = kImmutable; +} +void SkPixelRef::setTemporarilyImmutable() { + SkASSERT(fMutability != kImmutable); + fMutability = kTemporarilyImmutable; +} + +void SkPixelRef::restoreMutability() { + SkASSERT(fMutability != kImmutable); + fMutability = kMutable; + this->notifyPixelsChanged(); // This is just precautionary. } bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) { diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp index cde9d76172..081785f4b3 100644 --- a/src/image/SkImage.cpp +++ b/src/image/SkImage.cpp @@ -254,7 +254,7 @@ SkImage* SkImage::NewFromBitmap(const SkBitmap& bm) { #endif // This will check for immutable (share or copy) - return SkNewImageFromRasterBitmap(bm, false, nullptr, kUnlocked_SharedPixelRefMode); + return SkNewImageFromRasterBitmap(bm, nullptr, kUnlocked_SharedPixelRefMode); } bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const { diff --git a/src/image/SkImagePriv.h b/src/image/SkImagePriv.h index 876c4279b6..0626d6a3ce 100644 --- a/src/image/SkImagePriv.h +++ b/src/image/SkImagePriv.h @@ -39,8 +39,12 @@ enum SharedPixelRefMode { kLocked_SharedPixelRefMode, kUnlocked_SharedPixelRefMode }; -extern SkImage* SkNewImageFromRasterBitmap(const SkBitmap&, bool forceSharePixelRef, - const SkSurfaceProps*, SharedPixelRefMode); +enum ForceCopyMode { + kNo_ForceCopyMode, + kYes_ForceCopyMode, // must copy the pixels even if the bitmap is immutable +}; +extern SkImage* SkNewImageFromRasterBitmap(const SkBitmap&, const SkSurfaceProps*, + SharedPixelRefMode, ForceCopyMode = kNo_ForceCopyMode); static inline size_t SkImageMinRowBytes(const SkImageInfo& info) { size_t minRB = info.minRowBytes(); diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp index 41198c09ed..bde4c347aa 100644 --- a/src/image/SkImage_Raster.cpp +++ b/src/image/SkImage_Raster.cpp @@ -87,10 +87,13 @@ public: if (lockPixels) { fBitmap.lockPixels(); } + SkASSERT(fBitmap.isImmutable()); } private: - SkImage_Raster() : INHERITED(0, 0, NULL) {} + SkImage_Raster() : INHERITED(0, 0, NULL) { + fBitmap.setImmutable(); + } SkBitmap fBitmap; @@ -123,6 +126,7 @@ SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, const SkIPoint& fBitmap.setInfo(info, rowBytes); fBitmap.setPixelRef(pr, pixelRefOrigin); fBitmap.lockPixels(); + SkASSERT(fBitmap.isImmutable()); } SkImage_Raster::~SkImage_Raster() {} @@ -232,8 +236,8 @@ SkImage* SkNewImageFromPixelRef(const SkImageInfo& info, SkPixelRef* pr, return SkNEW_ARGS(SkImage_Raster, (info, pr, pixelRefOrigin, rowBytes, props)); } -SkImage* SkNewImageFromRasterBitmap(const SkBitmap& bm, bool forceSharePixelRef, - const SkSurfaceProps* props, SharedPixelRefMode mode) { +SkImage* SkNewImageFromRasterBitmap(const SkBitmap& bm, const SkSurfaceProps* props, + SharedPixelRefMode mode, ForceCopyMode forceCopy) { SkASSERT(NULL == bm.getTexture()); if (!SkImage_Raster::ValidArgs(bm.info(), bm.rowBytes(), NULL, NULL)) { @@ -241,9 +245,7 @@ SkImage* SkNewImageFromRasterBitmap(const SkBitmap& bm, bool forceSharePixelRef, } SkImage* image = NULL; - if (forceSharePixelRef || bm.isImmutable()) { - image = SkNEW_ARGS(SkImage_Raster, (bm, props, kLocked_SharedPixelRefMode == mode)); - } else { + if (kYes_ForceCopyMode == forceCopy || !bm.isImmutable()) { SkBitmap tmp(bm); tmp.lockPixels(); if (tmp.getPixels()) { @@ -255,6 +257,8 @@ SkImage* SkNewImageFromRasterBitmap(const SkBitmap& bm, bool forceSharePixelRef, if (image && props) { as_IB(image)->initWithProps(*props); } + } else { + image = SkNEW_ARGS(SkImage_Raster, (bm, props, kLocked_SharedPixelRefMode == mode)); } return image; } diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp index bfc019bd4f..8c356a8080 100644 --- a/src/image/SkSurface.cpp +++ b/src/image/SkSurface.cpp @@ -99,7 +99,8 @@ void SkSurface_Base::aboutToDraw(ContentChangeMode mode) { // the surface may need to fork its backend, if its sharing it with // the cached image. Note: we only call if there is an outstanding owner // on the image (besides us). - if (!fCachedImage->unique()) { + bool unique = fCachedImage->unique(); + if (!unique) { this->onCopyOnWrite(mode); } @@ -107,6 +108,13 @@ void SkSurface_Base::aboutToDraw(ContentChangeMode mode) { // that the next request will get our new contents. fCachedImage->unref(); fCachedImage = NULL; + + if (unique) { + // Our content isn't held by any image now, so we can consider that content mutable. + // Raster surfaces need to be told it's safe to consider its pixels mutable again. + // We make this call after the ->unref() so the subclass can assert there are no images. + this->onRestoreBackingMutability(); + } } else if (kDiscard_ContentChangeMode == mode) { this->onDiscard(); } diff --git a/src/image/SkSurface_Base.h b/src/image/SkSurface_Base.h index a52a2b44d9..8f0eef3b60 100644 --- a/src/image/SkSurface_Base.h +++ b/src/image/SkSurface_Base.h @@ -68,9 +68,17 @@ public: */ virtual void onCopyOnWrite(ContentChangeMode) = 0; + /** + * Signal the surface to remind its backing store that it's mutable again. + * Called only when we _didn't_ copy-on-write; we assume the copies start mutable. + */ + virtual void onRestoreBackingMutability() {} + inline SkCanvas* getCachedCanvas(); inline SkImage* getCachedImage(Budgeted); + bool hasCachedImage() const { return fCachedImage != NULL; } + // called by SkSurface to compute a new genID uint32_t newGenerationID(); diff --git a/src/image/SkSurface_Raster.cpp b/src/image/SkSurface_Raster.cpp index d59aef7c75..d0a65530f0 100644 --- a/src/image/SkSurface_Raster.cpp +++ b/src/image/SkSurface_Raster.cpp @@ -27,6 +27,7 @@ public: SkImage* onNewImageSnapshot(Budgeted) override; void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override; void onCopyOnWrite(ContentChangeMode) override; + void onRestoreBackingMutability() override; private: SkBitmap fBitmap; @@ -118,10 +119,24 @@ void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, } SkImage* SkSurface_Raster::onNewImageSnapshot(Budgeted) { + if (fWeOwnThePixels) { + // SkImage_raster requires these pixels are immutable for its full lifetime. + // We'll undo this via onRestoreBackingMutability() if we can avoid the COW. + if (SkPixelRef* pr = fBitmap.pixelRef()) { + pr->setTemporarilyImmutable(); + } + } // Our pixels are in memory, so read access on the snapshot SkImage could be cheap. // Lock the shared pixel ref to ensure peekPixels() is usable. - return SkNewImageFromRasterBitmap(fBitmap, fWeOwnThePixels, &this->props(), - kLocked_SharedPixelRefMode); + return SkNewImageFromRasterBitmap(fBitmap, &this->props(), kLocked_SharedPixelRefMode, + fWeOwnThePixels ? kNo_ForceCopyMode : kYes_ForceCopyMode); +} + +void SkSurface_Raster::onRestoreBackingMutability() { + SkASSERT(!this->hasCachedImage()); // Shouldn't be any snapshots out there. + if (SkPixelRef* pr = fBitmap.pixelRef()) { + pr->restoreMutability(); + } } void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) { @@ -158,7 +173,7 @@ SkSurface* SkSurface::NewRasterDirectReleaseProc(const SkImageInfo& info, void* if (NULL == pixels) { return NULL; } - + return SkNEW_ARGS(SkSurface_Raster, (info, pixels, rb, releaseProc, context, props)); } diff --git a/tests/DeferredCanvasTest.cpp b/tests/DeferredCanvasTest.cpp index 0aa0af68c1..882871fa4d 100644 --- a/tests/DeferredCanvasTest.cpp +++ b/tests/DeferredCanvasTest.cpp @@ -64,8 +64,7 @@ public: } SkImage* onNewImageSnapshot(Budgeted) override { - return SkNewImageFromRasterBitmap(fBitmap, true, &this->props(), - kUnlocked_SharedPixelRefMode); + return SkNewImageFromRasterBitmap(fBitmap, &this->props(), kUnlocked_SharedPixelRefMode); } void onCopyOnWrite(ContentChangeMode mode) override { diff --git a/tests/SkImageTest.cpp b/tests/SkImageTest.cpp index 508982cea6..d5c7eaa819 100644 --- a/tests/SkImageTest.cpp +++ b/tests/SkImageTest.cpp @@ -26,8 +26,7 @@ DEF_TEST(SkImageFromBitmap_extractSubset, reporter) { canvas.drawIRect(r, p); SkBitmap dstBitmap; srcBitmap.extractSubset(&dstBitmap, r); - image.reset(SkNewImageFromRasterBitmap(dstBitmap, true, NULL, - kUnlocked_SharedPixelRefMode)); + image.reset(SkNewImageFromRasterBitmap(dstBitmap, NULL, kUnlocked_SharedPixelRefMode)); } SkBitmap tgt; |