diff options
author | bsalomon <bsalomon@google.com> | 2016-02-22 11:02:58 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-22 11:02:58 -0800 |
commit | f47b9a3b88a037a481eb70f01a4cf9f5be34dc28 (patch) | |
tree | 99856c248a165000a16d96722170198bc248c745 /src | |
parent | 8d9f2e474ac9d175c28079357b022d31408e2fe4 (diff) |
Allow client to force an SkImage snapshot to be unique (and uniquely own its backing store).
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1686163002
Review URL: https://codereview.chromium.org/1686163002
Diffstat (limited to 'src')
-rw-r--r-- | src/image/SkSurface.cpp | 10 | ||||
-rw-r--r-- | src/image/SkSurface_Base.h | 26 | ||||
-rw-r--r-- | src/image/SkSurface_Gpu.cpp | 23 | ||||
-rw-r--r-- | src/image/SkSurface_Gpu.h | 2 | ||||
-rw-r--r-- | src/image/SkSurface_Raster.cpp | 15 |
5 files changed, 56 insertions, 20 deletions
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp index fed13a284b..711dfda6a4 100644 --- a/src/image/SkSurface.cpp +++ b/src/image/SkSurface.cpp @@ -164,9 +164,13 @@ SkCanvas* SkSurface::getCanvas() { } SkImage* SkSurface::newImageSnapshot(Budgeted budgeted) { - SkImage* image = asSB(this)->getCachedImage(budgeted); - SkSafeRef(image); // the caller will call unref() to balance this - return image; + // the caller will call unref() to balance this + return asSB(this)->refCachedImage(budgeted, kNo_ForceUnique); +} + +SkImage* SkSurface::newImageSnapshot(Budgeted budgeted, ForceUnique unique) { + // the caller will call unref() to balance this + return asSB(this)->refCachedImage(budgeted, unique); } SkSurface* SkSurface::newSurface(const SkImageInfo& info) { diff --git a/src/image/SkSurface_Base.h b/src/image/SkSurface_Base.h index 7658409ad7..aaa19cf592 100644 --- a/src/image/SkSurface_Base.h +++ b/src/image/SkSurface_Base.h @@ -9,6 +9,7 @@ #define SkSurface_Base_DEFINED #include "SkCanvas.h" +#include "SkImagePriv.h" #include "SkSurface.h" #include "SkSurfacePriv.h" @@ -42,7 +43,7 @@ public: * must faithfully represent the current contents, even if the surface * is changed after this called (e.g. it is drawn to via its canvas). */ - virtual SkImage* onNewImageSnapshot(Budgeted) = 0; + virtual SkImage* onNewImageSnapshot(Budgeted, ForceCopyMode) = 0; /** * Default implementation: @@ -75,7 +76,7 @@ public: virtual void onRestoreBackingMutability() {} inline SkCanvas* getCachedCanvas(); - inline SkImage* getCachedImage(Budgeted); + inline SkImage* refCachedImage(Budgeted, ForceUnique); bool hasCachedImage() const { return fCachedImage != nullptr; } @@ -108,12 +109,23 @@ SkCanvas* SkSurface_Base::getCachedCanvas() { return fCachedCanvas; } -SkImage* SkSurface_Base::getCachedImage(Budgeted budgeted) { - if (nullptr == fCachedImage) { - fCachedImage = this->onNewImageSnapshot(budgeted); - SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this); +SkImage* SkSurface_Base::refCachedImage(Budgeted budgeted, ForceUnique unique) { + SkImage* snap = fCachedImage; + if (kYes_ForceUnique == unique && snap && !snap->unique()) { + snap = nullptr; } - return fCachedImage; + if (snap) { + return SkRef(snap); + } + ForceCopyMode fcm = (kYes_ForceUnique == unique) ? kYes_ForceCopyMode : + kNo_ForceCopyMode; + snap = this->onNewImageSnapshot(budgeted, fcm); + if (kNo_ForceUnique == unique) { + SkASSERT(!fCachedImage); + fCachedImage = SkSafeRef(snap); + } + SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this); + return snap; } #endif diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp index 24ac6d3312..03fdecef3a 100644 --- a/src/image/SkSurface_Gpu.cpp +++ b/src/image/SkSurface_Gpu.cpp @@ -76,10 +76,27 @@ SkSurface* SkSurface_Gpu::onNewSurface(const SkImageInfo& info) { &this->props()); } -SkImage* SkSurface_Gpu::onNewImageSnapshot(Budgeted budgeted) { +SkImage* SkSurface_Gpu::onNewImageSnapshot(Budgeted budgeted, ForceCopyMode forceCopyMode) { + GrRenderTarget* rt = fDevice->accessRenderTarget(); + SkASSERT(rt); + GrTexture* tex = rt->asTexture(); + SkAutoTUnref<GrTexture> copy; + // TODO: Force a copy when the rt is an external resource. + if (kYes_ForceCopyMode == forceCopyMode || !tex) { + GrSurfaceDesc desc = fDevice->accessRenderTarget()->desc(); + GrContext* ctx = fDevice->context(); + desc.fFlags = desc.fFlags & !kRenderTarget_GrSurfaceFlag; + copy.reset(ctx->textureProvider()->createTexture(desc, kYes_Budgeted == budgeted)); + if (!copy) { + return nullptr; + } + if (!ctx->copySurface(copy, rt)) { + return nullptr; + } + tex = copy; + } const SkImageInfo info = fDevice->imageInfo(); SkImage* image = nullptr; - GrTexture* tex = fDevice->accessRenderTarget()->asTexture(); if (tex) { image = new SkImage_Gpu(info.width(), info.height(), kNeedNewImageUniqueID, info.alphaType(), tex, budgeted); @@ -94,7 +111,7 @@ void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) { GrRenderTarget* rt = fDevice->accessRenderTarget(); // are we sharing our render target with the image? Note this call should never create a new // image because onCopyOnWrite is only called when there is a cached image. - SkImage* image = this->getCachedImage(kNo_Budgeted); + SkAutoTUnref<SkImage> image(this->refCachedImage(kNo_Budgeted, kNo_ForceUnique)); SkASSERT(image); if (rt->asTexture() == as_IB(image)->getTexture()) { this->fDevice->replaceRenderTarget(SkSurface::kRetain_ContentChangeMode == mode); diff --git a/src/image/SkSurface_Gpu.h b/src/image/SkSurface_Gpu.h index 23241540bf..23aed2cd3c 100644 --- a/src/image/SkSurface_Gpu.h +++ b/src/image/SkSurface_Gpu.h @@ -23,7 +23,7 @@ public: bool onGetRenderTargetHandle(GrBackendObject*, BackendHandleAccess) override; SkCanvas* onNewCanvas() override; SkSurface* onNewSurface(const SkImageInfo&) override; - SkImage* onNewImageSnapshot(Budgeted) override; + SkImage* onNewImageSnapshot(Budgeted, ForceCopyMode) override; void onCopyOnWrite(ContentChangeMode) override; void onDiscard() override; diff --git a/src/image/SkSurface_Raster.cpp b/src/image/SkSurface_Raster.cpp index d9763c0c95..37790a0dd9 100644 --- a/src/image/SkSurface_Raster.cpp +++ b/src/image/SkSurface_Raster.cpp @@ -24,7 +24,7 @@ public: SkCanvas* onNewCanvas() override; SkSurface* onNewSurface(const SkImageInfo&) override; - SkImage* onNewImageSnapshot(Budgeted) override; + SkImage* onNewImageSnapshot(Budgeted, ForceCopyMode) override; void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override; void onCopyOnWrite(ContentChangeMode) override; void onRestoreBackingMutability() override; @@ -118,18 +118,20 @@ void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, canvas->drawBitmap(fBitmap, x, y, paint); } -SkImage* SkSurface_Raster::onNewImageSnapshot(Budgeted) { +SkImage* SkSurface_Raster::onNewImageSnapshot(Budgeted, ForceCopyMode forceCopyMode) { 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(); } + } else { + forceCopyMode = kYes_ForceCopyMode; } + // 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 ? kNo_ForceCopyMode : kYes_ForceCopyMode); + return SkNewImageFromRasterBitmap(fBitmap, forceCopyMode); } void SkSurface_Raster::onRestoreBackingMutability() { @@ -141,8 +143,9 @@ void SkSurface_Raster::onRestoreBackingMutability() { void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) { // are we sharing pixelrefs with the image? - SkASSERT(this->getCachedImage(kNo_Budgeted)); - if (SkBitmapImageGetPixelRef(this->getCachedImage(kNo_Budgeted)) == fBitmap.pixelRef()) { + SkAutoTUnref<SkImage> cached(this->refCachedImage(kNo_Budgeted, kNo_ForceUnique)); + SkASSERT(cached); + if (SkBitmapImageGetPixelRef(cached) == fBitmap.pixelRef()) { SkASSERT(fWeOwnThePixels); if (kDiscard_ContentChangeMode == mode) { fBitmap.allocPixels(); |