Index: src/core/SkSpecialImage.cpp |
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp |
index fc6cffec383fa8d24d37f4dfbe58f784dcf5195e..f18e6a7c7c109bf33552bbca2917c4bdc20bcb58 100644 |
--- a/src/core/SkSpecialImage.cpp |
+++ b/src/core/SkSpecialImage.cpp |
@@ -218,18 +218,7 @@ |
} |
bool onGetROPixels(SkBitmap* bm) const override { |
- SkBitmap tmp; |
- |
- if (!as_IB(fImage)->getROPixels(&tmp)) { |
- return false; |
- } |
- |
- if (this->subset().contains(tmp.bounds())) { |
- *bm = tmp; |
- return true; |
- } |
- |
- return tmp.extractSubset(bm, this->subset()); |
+ return as_IB(fImage)->getROPixels(bm); |
} |
GrTexture* onPeekTexture() const override { return as_IB(fImage)->peekTexture(); } |
@@ -273,7 +262,14 @@ |
} |
sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override { |
- return SkSpecialImage::MakeFromImage(subset, fImage, &this->props()); |
+ sk_sp<SkImage> subsetImg(fImage->makeSubset(subset)); |
+ if (!subsetImg) { |
+ return nullptr; |
+ } |
+ |
+ return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(subset.width(), subset.height()), |
+ subsetImg, |
+ &this->props()); |
} |
sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override { |
@@ -442,8 +438,145 @@ |
#if SK_SUPPORT_GPU |
/////////////////////////////////////////////////////////////////////////////// |
- |
+#include "GrTexture.h" |
#include "SkImage_Gpu.h" |
+ |
+class SkSpecialImage_Gpu : public SkSpecialImage_Base { |
+public: |
+ SkSpecialImage_Gpu(const SkIRect& subset, |
+ uint32_t uniqueID, sk_sp<GrTexture> tex, SkAlphaType at, |
+ const SkSurfaceProps* props) |
+ : INHERITED(subset, uniqueID, props) |
+ , fTexture(std::move(tex)) |
+ , fAlphaType(at) |
+ , fAddedRasterVersionToCache(false) { |
+ } |
+ |
+ ~SkSpecialImage_Gpu() override { |
+ if (fAddedRasterVersionToCache.load()) { |
+ SkNotifyBitmapGenIDIsStale(this->uniqueID()); |
+ } |
+ } |
+ |
+ bool isOpaque() const override { |
+ return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType; |
+ } |
+ |
+ size_t getSize() const override { return fTexture->gpuMemorySize(); } |
+ |
+ void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override { |
+ SkRect dst = SkRect::MakeXYWH(x, y, |
+ this->subset().width(), this->subset().height()); |
+ |
+ SkBitmap bm; |
+ |
+ GrWrapTextureInBitmap(fTexture.get(), |
+ fTexture->width(), fTexture->height(), this->isOpaque(), &bm); |
+ |
+ canvas->drawBitmapRect(bm, this->subset(), |
+ dst, paint, SkCanvas::kStrict_SrcRectConstraint); |
+ } |
+ |
+ GrTexture* onPeekTexture() const override { return fTexture.get(); } |
+ |
+ sk_sp<GrTexture> onAsTextureRef(GrContext*) const override { return fTexture; } |
+ |
+ bool onGetROPixels(SkBitmap* dst) const override { |
+ if (SkBitmapCache::Find(this->uniqueID(), dst)) { |
+ SkASSERT(dst->getGenerationID() == this->uniqueID()); |
+ SkASSERT(dst->isImmutable()); |
+ SkASSERT(dst->getPixels()); |
+ return true; |
+ } |
+ |
+ SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(), |
+ this->isOpaque() ? kOpaque_SkAlphaType |
+ : kPremul_SkAlphaType); |
+ |
+ if (!dst->tryAllocPixels(info)) { |
+ return false; |
+ } |
+ |
+ if (!fTexture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig, |
+ dst->getPixels(), dst->rowBytes())) { |
+ return false; |
+ } |
+ |
+ dst->pixelRef()->setImmutableWithID(this->uniqueID()); |
+ SkBitmapCache::Add(this->uniqueID(), *dst); |
+ fAddedRasterVersionToCache.store(true); |
+ return true; |
+ } |
+ |
+ bool getBitmapDeprecated(SkBitmap* result) const override { |
+ const SkImageInfo info = GrMakeInfoFromTexture(fTexture.get(), |
+ this->width(), this->height(), |
+ this->isOpaque()); |
+ if (!result->setInfo(info)) { |
+ return false; |
+ } |
+ |
+ const SkImageInfo prInfo = info.makeWH(fTexture->width(), fTexture->height()); |
+ |
+ SkAutoTUnref<SkGrPixelRef> pixelRef(new SkGrPixelRef(prInfo, fTexture.get())); |
+ result->setPixelRef(pixelRef, this->subset().fLeft, this->subset().fTop); |
+ return true; |
+ } |
+ |
+ sk_sp<SkSpecialSurface> onMakeSurface(const SkImageInfo& info) const override { |
+ if (!fTexture->getContext()) { |
+ return nullptr; |
+ } |
+ |
+ GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(info, *fTexture->getContext()->caps()); |
+ desc.fFlags = kRenderTarget_GrSurfaceFlag; |
+ |
+ return SkSpecialSurface::MakeRenderTarget(fTexture->getContext(), desc); |
+ } |
+ |
+ sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override { |
+ return SkSpecialImage::MakeFromGpu(subset, |
+ this->uniqueID(), |
+ fTexture, |
+ &this->props(), |
+ fAlphaType); |
+ } |
+ |
+ sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override { |
+ if (0 == subset.fLeft && 0 == subset.fTop && |
+ fTexture->width() == subset.width() && |
+ fTexture->height() == subset.height()) { |
+ // The existing GrTexture is already tight so reuse it in the SkImage |
+ return sk_make_sp<SkImage_Gpu>(fTexture->width(), fTexture->height(), |
+ kNeedNewImageUniqueID, |
+ fAlphaType, fTexture.get(), SkBudgeted::kYes); |
+ } |
+ |
+ GrContext* ctx = fTexture->getContext(); |
+ GrSurfaceDesc desc = fTexture->desc(); |
+ desc.fWidth = subset.width(); |
+ desc.fHeight = subset.height(); |
+ |
+ sk_sp<GrTexture> subTx(ctx->textureProvider()->createTexture(desc, SkBudgeted::kYes)); |
+ if (!subTx) { |
+ return nullptr; |
+ } |
+ ctx->copySurface(subTx.get(), fTexture.get(), subset, SkIPoint::Make(0, 0)); |
+ return sk_make_sp<SkImage_Gpu>(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID, |
+ fAlphaType, subTx.get(), SkBudgeted::kYes); |
+ } |
+ |
+ sk_sp<SkSurface> onMakeTightSurface(const SkImageInfo& info) const override { |
+ return SkSurface::MakeRenderTarget(fTexture->getContext(), SkBudgeted::kYes, info); |
+ } |
+ |
+private: |
+ sk_sp<GrTexture> fTexture; |
+ const SkAlphaType fAlphaType; |
+ mutable SkAtomic<bool> fAddedRasterVersionToCache; |
+ |
+ typedef SkSpecialImage_Base INHERITED; |
+}; |
sk_sp<SkSpecialImage> SkSpecialImage::MakeFromGpu(const SkIRect& subset, |
uint32_t uniqueID, |
@@ -451,11 +584,7 @@ |
const SkSurfaceProps* props, |
SkAlphaType at) { |
SkASSERT(rect_fits(subset, tex->width(), tex->height())); |
- |
- sk_sp<SkImage> image(new SkImage_Gpu(tex->width(), tex->height(), |
- uniqueID, at, |
- tex.get(), SkBudgeted::kYes)); |
- return sk_make_sp<SkSpecialImage_Image>(subset, std::move(image), props); |
-} |
- |
-#endif |
+ return sk_make_sp<SkSpecialImage_Gpu>(subset, uniqueID, std::move(tex), at, props); |
+} |
+ |
+#endif |