From 2d5b7147032e3806b5895667a899440119707c2d Mon Sep 17 00:00:00 2001 From: reed Date: Wed, 17 Aug 2016 11:12:33 -0700 Subject: pin as texture api BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2241353002 Review-Url: https://codereview.chromium.org/2241353002 --- src/core/SkImagePriv.h | 25 +++++++++++++ src/gpu/GrImageIDTextureAdjuster.cpp | 11 ------ src/gpu/GrImageIDTextureAdjuster.h | 5 --- src/gpu/SkGpuDevice.cpp | 19 +++++++--- src/image/SkImage.cpp | 14 +++++++ src/image/SkImage_Base.h | 5 +++ src/image/SkImage_Gpu.cpp | 5 ++- src/image/SkImage_Gpu.h | 4 ++ src/image/SkImage_Raster.cpp | 72 +++++++++++++++++++++++++++++++++++- 9 files changed, 135 insertions(+), 25 deletions(-) diff --git a/src/core/SkImagePriv.h b/src/core/SkImagePriv.h index 3077f34367..0377762def 100644 --- a/src/core/SkImagePriv.h +++ b/src/core/SkImagePriv.h @@ -77,4 +77,29 @@ extern void SkTextureImageSetTexture(SkImage* image, GrTexture* texture); GrTexture* GrDeepCopyTexture(GrTexture* src, SkBudgeted); +/** + * Will attempt to upload and lock the contents of the image as a texture, so that subsequent + * draws to a gpu-target will come from that texture (and not by looking at the original image + * src). In particular this is intended to use the texture even if the image's original content + * changes subsequent to this call (i.e. the src is mutable!). + * + * This must be balanced by an equal number of calls to SkImage_unpinAsTexture() -- calls can be + * nested. + * + * Once in this "pinned" state, the image has all of the same thread restrictions that exist + * for a natively created gpu image (e.g. SkImage::MakeFromTexture) + * - all drawing, pinning, unpinning must happen in the same thread as the GrContext. + */ +void SkImage_pinAsTexture(const SkImage*, GrContext*); + +/** + * The balancing call to SkImage_pinAsTexture. When a balanced number of calls have been made, then + * the "pinned" texture is free to be purged, etc. This also means that a subsequent "pin" call + * will look at the original content again, and if its uniqueID/generationID has changed, then + * a newer texture will be uploaded/pinned. + * + * The context passed to unpin must match the one passed to pin. + */ +void SkImage_unpinAsTexture(const SkImage*, GrContext*); + #endif diff --git a/src/gpu/GrImageIDTextureAdjuster.cpp b/src/gpu/GrImageIDTextureAdjuster.cpp index 2bfa21c729..f9aaae1282 100644 --- a/src/gpu/GrImageIDTextureAdjuster.cpp +++ b/src/gpu/GrImageIDTextureAdjuster.cpp @@ -17,17 +17,6 @@ static bool bmp_is_alpha_only(const SkBitmap& bm) { return kAlpha_8_SkColorType == bm.colorType(); } -// By construction this texture adjuster always represents an entire SkImage, so use the -// image's dimensions for the key's rectangle. -GrImageTextureAdjuster::GrImageTextureAdjuster(const SkImage_Base* img) - : GrTextureAdjuster(img->peekTexture(), SkIRect::MakeSize(img->dimensions()), img->uniqueID(), - img->onImageInfo().colorSpace()) -{ - SkASSERT(img->peekTexture()); -} - -////////////////////////////////////////////////////////////////////////////// - GrBitmapTextureMaker::GrBitmapTextureMaker(GrContext* context, const SkBitmap& bitmap) : INHERITED(context, bitmap.width(), bitmap.height(), bmp_is_alpha_only(bitmap)) , fBitmap(bitmap) diff --git a/src/gpu/GrImageIDTextureAdjuster.h b/src/gpu/GrImageIDTextureAdjuster.h index 327bf8fb5e..25b866bbc0 100644 --- a/src/gpu/GrImageIDTextureAdjuster.h +++ b/src/gpu/GrImageIDTextureAdjuster.h @@ -15,11 +15,6 @@ class SkBitmap; class SkImage_Base; class SkImageCacherator; -class GrImageTextureAdjuster : public GrTextureAdjuster { -public: - explicit GrImageTextureAdjuster(const SkImage_Base* img); -}; - /** This class manages the conversion of SW-backed bitmaps to GrTextures. If the input bitmap is non-volatile the texture is cached using a key created from the pixels' image id and the subset of the pixelref specified by the bitmap. */ diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index e9ab62db69..44d4354d45 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1315,9 +1315,11 @@ void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x ASSERT_SINGLE_OWNER SkMatrix viewMatrix = *draw.fMatrix; viewMatrix.preTranslate(x, y); - if (as_IB(image)->peekTexture()) { + uint32_t pinnedUniqueID; + if (sk_sp tex = as_IB(image)->refPinnedTexture(&pinnedUniqueID)) { CHECK_SHOULD_DRAW(draw); - GrImageTextureAdjuster adjuster(as_IB(image)); + GrTextureAdjuster adjuster(tex.get(), image->bounds(), pinnedUniqueID, + as_IB(image)->onImageInfo().colorSpace()); this->drawTextureProducer(&adjuster, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, viewMatrix, fClip, paint); return; @@ -1345,9 +1347,11 @@ void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { ASSERT_SINGLE_OWNER - if (as_IB(image)->peekTexture()) { + uint32_t pinnedUniqueID; + if (sk_sp tex = as_IB(image)->refPinnedTexture(&pinnedUniqueID)) { CHECK_SHOULD_DRAW(draw); - GrImageTextureAdjuster adjuster(as_IB(image)); + GrTextureAdjuster adjuster(tex.get(), image->bounds(), pinnedUniqueID, + as_IB(image)->onImageInfo().colorSpace()); this->drawTextureProducer(&adjuster, src, &dst, constraint, *draw.fMatrix, fClip, paint); return; } @@ -1414,8 +1418,11 @@ void SkGpuDevice::drawProducerNine(const SkDraw& draw, GrTextureProducer* produc void SkGpuDevice::drawImageNine(const SkDraw& draw, const SkImage* image, const SkIRect& center, const SkRect& dst, const SkPaint& paint) { ASSERT_SINGLE_OWNER - if (as_IB(image)->peekTexture()) { - GrImageTextureAdjuster adjuster(as_IB(image)); + uint32_t pinnedUniqueID; + if (sk_sp tex = as_IB(image)->refPinnedTexture(&pinnedUniqueID)) { + CHECK_SHOULD_DRAW(draw); + GrTextureAdjuster adjuster(tex.get(), image->bounds(), pinnedUniqueID, + as_IB(image)->onImageInfo().colorSpace()); this->drawProducerNine(draw, &adjuster, center, dst, paint); } else { SkBitmap bm; diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp index 9febeaa96e..b8c89645b2 100644 --- a/src/image/SkImage.cpp +++ b/src/image/SkImage.cpp @@ -511,3 +511,17 @@ sk_sp SkImageDeserializer::makeFromMemory(const void* data, size_t leng const SkIRect* subset) { return SkImage::MakeFromEncoded(SkData::MakeWithCopy(data, length), subset); } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void SkImage_pinAsTexture(const SkImage* image, GrContext* ctx) { + SkASSERT(image); + SkASSERT(ctx); + as_IB(image)->onPinAsTexture(ctx); +} + +void SkImage_unpinAsTexture(const SkImage* image, GrContext* ctx) { + SkASSERT(image); + SkASSERT(ctx); + as_IB(image)->onUnpinAsTexture(ctx); +} diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h index 1cfb7daad6..09971c1198 100644 --- a/src/image/SkImage_Base.h +++ b/src/image/SkImage_Base.h @@ -8,6 +8,7 @@ #ifndef SkImage_Base_DEFINED #define SkImage_Base_DEFINED +#include "GrTexture.h" #include "SkAtomics.h" #include "SkImage.h" #include "SkSurface.h" @@ -40,6 +41,7 @@ public: int srcX, int srcY, CachingHint) const; virtual GrTexture* peekTexture() const { return nullptr; } + virtual sk_sp refPinnedTexture(uint32_t* uniqueID) const { return nullptr; } virtual SkImageCacherator* peekCacherator() const { return nullptr; } // return a read-only copy of the pixels. We promise to not modify them, @@ -69,6 +71,9 @@ public: fAddedToCache.store(true); } + virtual void onPinAsTexture(GrContext*) const {} + virtual void onUnpinAsTexture(GrContext*) const {} + private: // Set true by caches when they cache content that's derived from the current pixels. mutable SkAtomic fAddedToCache; diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp index 44bb71c088..76f19bc31e 100644 --- a/src/image/SkImage_Gpu.cpp +++ b/src/image/SkImage_Gpu.cpp @@ -83,8 +83,9 @@ bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const { GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& params, SkSourceGammaTreatment gammaTreatment) const { - return GrImageTextureAdjuster(as_IB(this)).refTextureSafeForParams(params, gammaTreatment, - nullptr); + GrTextureAdjuster adjuster(this->peekTexture(), this->bounds(), this->uniqueID(), + this->onImageInfo().colorSpace()); + return adjuster.refTextureSafeForParams(params, gammaTreatment, nullptr); } bool SkImage_Gpu::isOpaque() const { diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h index 5faaa7526b..44949a13ac 100644 --- a/src/image/SkImage_Gpu.h +++ b/src/image/SkImage_Gpu.h @@ -43,6 +43,10 @@ public: sk_sp onMakeSubset(const SkIRect&) const override; GrTexture* peekTexture() const override { return fTexture; } + sk_sp refPinnedTexture(uint32_t* uniqueID) const override { + *uniqueID = this->uniqueID(); + return sk_ref_sp(fTexture.get()); + } bool isOpaque() const override; bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint) const override; diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp index 67d521e345..abdecb9794 100644 --- a/src/image/SkImage_Raster.cpp +++ b/src/image/SkImage_Raster.cpp @@ -115,9 +115,21 @@ public: return fBitmap.pixelRef() && fBitmap.pixelRef()->isLazyGenerated(); } +#if SK_SUPPORT_GPU + sk_sp refPinnedTexture(uint32_t* uniqueID) const override; + void onPinAsTexture(GrContext*) const override; + void onUnpinAsTexture(GrContext*) const override; +#endif + private: SkBitmap fBitmap; +#if SK_SUPPORT_GPU + mutable sk_sp fPinnedTexture; + mutable int32_t fPinnedCount = 0; + mutable uint32_t fPinnedUniqueID = 0; +#endif + typedef SkImage_Base INHERITED; }; @@ -149,7 +161,11 @@ SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, const SkIPoint& SkASSERT(fBitmap.isImmutable()); } -SkImage_Raster::~SkImage_Raster() {} +SkImage_Raster::~SkImage_Raster() { +#if SK_SUPPORT_GPU + SkASSERT(nullptr == fPinnedTexture.get()); // want the caller to have manually unpinned +#endif +} bool SkImage_Raster::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint) const { @@ -178,6 +194,8 @@ bool SkImage_Raster::getROPixels(SkBitmap* dst, CachingHint) const { return true; } +#include "GrImageIDTextureAdjuster.h" + GrTexture* SkImage_Raster::asTextureRef(GrContext* ctx, const GrTextureParams& params, SkSourceGammaTreatment gammaTreatment) const { #if SK_SUPPORT_GPU @@ -185,12 +203,64 @@ GrTexture* SkImage_Raster::asTextureRef(GrContext* ctx, const GrTextureParams& p return nullptr; } + uint32_t uniqueID; + sk_sp tex = this->refPinnedTexture(&uniqueID); + if (tex) { + GrTextureAdjuster adjuster(fPinnedTexture.get(), fBitmap.bounds(), + fPinnedUniqueID, fBitmap.colorSpace()); + return adjuster.refTextureSafeForParams(params, gammaTreatment, nullptr); + } + return GrRefCachedBitmapTexture(ctx, fBitmap, params, gammaTreatment); #endif return nullptr; } +#if SK_SUPPORT_GPU + +sk_sp SkImage_Raster::refPinnedTexture(uint32_t* uniqueID) const { + if (fPinnedTexture) { + SkASSERT(fPinnedCount > 0); + SkASSERT(fPinnedUniqueID != 0); + *uniqueID = fPinnedUniqueID; + return fPinnedTexture; + } + return nullptr; +} + +void SkImage_Raster::onPinAsTexture(GrContext* ctx) const { + if (fPinnedTexture) { + SkASSERT(fPinnedCount > 0); + SkASSERT(fPinnedUniqueID != 0); + SkASSERT(fPinnedTexture->getContext() == ctx); + } else { + SkASSERT(fPinnedCount == 0); + SkASSERT(fPinnedUniqueID == 0); + fPinnedTexture.reset(GrRefCachedBitmapTexture(ctx, fBitmap, + GrTextureParams::ClampNoFilter(), + SkSourceGammaTreatment::kRespect)); + fPinnedUniqueID = fBitmap.getGenerationID(); + } + // Note: we always increment, even if we failed to create the pinned texture + ++fPinnedCount; +} + +void SkImage_Raster::onUnpinAsTexture(GrContext* ctx) const { + // Note: we always decrement, even if fPinnedTexture is null + SkASSERT(fPinnedCount > 0); + SkASSERT(fPinnedUniqueID != 0); + if (fPinnedTexture) { + SkASSERT(fPinnedTexture->getContext() == ctx); + } + + if (0 == --fPinnedCount) { + fPinnedTexture.reset(nullptr); + fPinnedUniqueID = 0; + } +} +#endif + sk_sp SkImage_Raster::onMakeSubset(const SkIRect& subset) const { // TODO : could consider heurist of sharing pixels, if subset is pretty close to complete -- cgit v1.2.3