Update SkSpecialImage to be able to create tight SkImages and SkSurfaces
This calved off of: https://codereview.chromium.org/1810693003/ (Switch SkTileImageFilter over to new onFilterImage interface) since the TileImageFilter needs a tight bitmap/texture/image to perform its draw.
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1816223002
Review URL: https://codereview.chromium.org/1816223002
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp
index 426a44e..03223a2 100644
--- a/src/core/SkSpecialImage.cpp
+++ b/src/core/SkSpecialImage.cpp
@@ -35,9 +35,13 @@
// Delete this entry point ASAP (see skbug.com/4965)
virtual bool getBitmapDeprecated(SkBitmap* result) const = 0;
+ virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
+
virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageInfo& info) const = 0;
- virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
+ virtual sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const = 0;
+
+ virtual SkSurface* onMakeTightSurface(const SkImageInfo& info) const = 0;
private:
typedef SkSpecialImage INHERITED;
@@ -100,10 +104,19 @@
return as_SIB(this)->onMakeSurface(info);
}
+sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageInfo& info) const {
+ sk_sp<SkSurface> tmp(SkRef(as_SIB(this)->onMakeTightSurface(info)));
+ return tmp;
+}
+
sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
return as_SIB(this)->onMakeSubset(subset);
}
+sk_sp<SkImage> SkSpecialImage::makeTightSubset(const SkIRect& subset) const {
+ return as_SIB(this)->onMakeTightSubset(subset);
+}
+
#if SK_SUPPORT_GPU
#include "SkGr.h"
#include "SkGrPixelRef.h"
@@ -227,6 +240,20 @@
subsetImg);
}
+ sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
+ return fImage->makeSubset(subset);
+ }
+
+ SkSurface* onMakeTightSurface(const SkImageInfo& info) const override {
+#if SK_SUPPORT_GPU
+ GrTexture* texture = as_IB(fImage.get())->peekTexture();
+ if (texture) {
+ return SkSurface::NewRenderTarget(texture->getContext(), SkBudgeted::kYes, info, 0);
+ }
+#endif
+ return SkSurface::NewRaster(info, nullptr);
+ }
+
private:
sk_sp<SkImage> fImage;
@@ -332,6 +359,20 @@
subsetBM);
}
+ sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
+ SkBitmap subsetBM;
+
+ if (!fBitmap.extractSubset(&subsetBM, subset)) {
+ return nullptr;
+ }
+
+ return SkImage::MakeFromBitmap(subsetBM);
+ }
+
+ SkSurface* onMakeTightSurface(const SkImageInfo& info) const override {
+ return SkSurface::NewRaster(info);
+ }
+
private:
SkBitmap fBitmap;
@@ -363,6 +404,7 @@
#if SK_SUPPORT_GPU
///////////////////////////////////////////////////////////////////////////////
#include "GrTexture.h"
+#include "SkImage_Gpu.h"
class SkSpecialImage_Gpu : public SkSpecialImage_Base {
public:
@@ -445,6 +487,34 @@
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, SkBudgeted::kYes);
+ }
+
+ GrContext* ctx = fTexture->getContext();
+ GrSurfaceDesc desc = fTexture->desc();
+ desc.fWidth = subset.width();
+ desc.fHeight = subset.height();
+
+ GrTexture* subTx = ctx->textureProvider()->createTexture(desc, SkBudgeted::kYes);
+ if (!subTx) {
+ return nullptr;
+ }
+ ctx->copySurface(subTx, fTexture, subset, SkIPoint::Make(0, 0));
+ return sk_make_sp<SkImage_Gpu>(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID,
+ fAlphaType, subTx, SkBudgeted::kYes);
+ }
+
+ SkSurface* onMakeTightSurface(const SkImageInfo& info) const override {
+ return SkSurface::NewRenderTarget(fTexture->getContext(), SkBudgeted::kYes, info);
+ }
+
private:
SkAutoTUnref<GrTexture> fTexture;
const SkAlphaType fAlphaType;
diff --git a/src/core/SkSpecialImage.h b/src/core/SkSpecialImage.h
index 47ad6cc..778bf53 100644
--- a/src/core/SkSpecialImage.h
+++ b/src/core/SkSpecialImage.h
@@ -25,6 +25,7 @@
class SkPaint;
class SkPixmap;
class SkSpecialSurface;
+class SkSurface;
enum {
kNeedNewImageUniqueID_SpecialImage = 0
@@ -84,16 +85,29 @@
ReleaseContext);
/**
- * Create a new surface with a backend that is compatible with this image.
+ * Create a new special surface with a backend that is compatible with this special image.
*/
sk_sp<SkSpecialSurface> makeSurface(const SkImageInfo&) const;
/**
+ * Create a new surface with a backend that is compatible with this special image.
+ * TODO: switch this to makeSurface once we resolved the naming issue
+ */
+ sk_sp<SkSurface> makeTightSurface(const SkImageInfo&) const;
+
+ /**
* Extract a subset of this special image and return it as a special image.
* It may or may not point to the same backing memory.
*/
sk_sp<SkSpecialImage> makeSubset(const SkIRect& subset) const;
+ /**
+ * Extract a subset of this special image and return it as an SkImage.
+ * It may or may not point to the same backing memory.
+ * TODO: switch this to makeSurface once we resolved the naming issue
+ */
+ sk_sp<SkImage> makeTightSubset(const SkIRect& subset) const;
+
// These three internal methods will go away (see skbug.com/4965)
bool internal_getBM(SkBitmap* result);
static sk_sp<SkSpecialImage> internal_fromBM(SkImageFilter::Proxy*, const SkBitmap&);
diff --git a/tests/SpecialImageTest.cpp b/tests/SpecialImageTest.cpp
index 3240fbd..432adc8 100644
--- a/tests/SpecialImageTest.cpp
+++ b/tests/SpecialImageTest.cpp
@@ -12,6 +12,7 @@
#include "SkPixmap.h"
#include "SkSpecialImage.h"
#include "SkSpecialSurface.h"
+#include "SkSurface.h"
#include "Test.h"
#include "TestingSpecialImageAccess.h"
@@ -59,10 +60,12 @@
REPORTER_ASSERT(reporter, kSmallerSize == subset.height());
//--------------
+ // Test that peekTexture reports the correct backing type
REPORTER_ASSERT(reporter, peekTextureSucceeds ==
!!TestingSpecialImageAccess::PeekTexture(img.get()));
//--------------
+ // Test that peekPixels reports the correct backing type
SkPixmap pixmap;
REPORTER_ASSERT(reporter, peekPixelsSucceeds ==
!!TestingSpecialImageAccess::PeekPixels(img.get(), &pixmap));
@@ -72,6 +75,7 @@
}
//--------------
+ // Test that draw restricts itself to the subset
SkImageInfo info = SkImageInfo::MakeN32(kFullSize, kFullSize, kOpaque_SkAlphaType);
sk_sp<SkSpecialSurface> surf(img->makeSurface(info));
@@ -94,6 +98,32 @@
kSmallerSize+kPad-1));
REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad,
kSmallerSize+kPad));
+
+ //--------------
+ // Test that makeTightSubset & makeTightSurface return appropriately sized objects
+ // of the correct backing type
+ SkIRect newSubset = SkIRect::MakeWH(subset.width(), subset.height());
+ {
+ sk_sp<SkImage> tightImg(img->makeTightSubset(newSubset));
+
+ REPORTER_ASSERT(reporter, tightImg->width() == subset.width());
+ REPORTER_ASSERT(reporter, tightImg->height() == subset.height());
+ REPORTER_ASSERT(reporter, peekTextureSucceeds == !!tightImg->getTexture());
+ SkPixmap tmpPixmap;
+ REPORTER_ASSERT(reporter, peekPixelsSucceeds == !!tightImg->peekPixels(&tmpPixmap));
+ }
+ {
+ SkImageInfo info = SkImageInfo::MakeN32(subset.width(), subset.height(),
+ kPremul_SkAlphaType);
+ sk_sp<SkSurface> tightSurf(img->makeTightSurface(info));
+
+ REPORTER_ASSERT(reporter, tightSurf->width() == subset.width());
+ REPORTER_ASSERT(reporter, tightSurf->height() == subset.height());
+ REPORTER_ASSERT(reporter, peekTextureSucceeds ==
+ !!tightSurf->getTextureHandle(SkSurface::kDiscardWrite_BackendHandleAccess));
+ SkPixmap tmpPixmap;
+ REPORTER_ASSERT(reporter, peekPixelsSucceeds == !!tightSurf->peekPixels(&tmpPixmap));
+ }
}
DEF_TEST(SpecialImage_Raster, reporter) {