use special-image for imagefilters and save/restore layer
add special virtuals to device, in preparation for using them instead of bitmap for imagefilters
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2155933002
patch from issue 2155933002 at patchset 20001 (http://crrev.com/2155933002#ps20001)
use specialimages instead of bitmaps for imagefiltering
Review-Url: https://codereview.chromium.org/2155063002
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index e3b4ffb..4d68a8e 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -1420,6 +1420,10 @@
static bool BoundsAffectsClip(SaveLayerFlags);
static SaveLayerFlags LegacySaveFlagsToSaveLayerFlags(uint32_t legacySaveFlags);
+ static void DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
+ SkBaseDevice* dst, const SkMatrix& ctm,
+ const SkClipStack* clipStack);
+
enum ShaderOverrideOpacity {
kNone_ShaderOverrideOpacity, //!< there is no overriding shader (bitmap or image)
kOpaque_ShaderOverrideOpacity, //!< the overriding shader is opaque
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 1999f31..050253f 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1146,40 +1146,29 @@
return this->getSaveCount() - 1;
}
-static void draw_filter_into_device(SkBaseDevice* src, const SkImageFilter* filter,
- SkBaseDevice* dst, const SkMatrix& ctm) {
-
- SkBitmap srcBM;
-
-#if SK_SUPPORT_GPU
- // TODO: remove this virtual usage of accessRenderTarget! It is preventing
- // removal of the virtual on SkBaseDevice.
- GrRenderTarget* srcRT = src->accessRenderTarget();
- if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) {
- // When both the src & the dst are on the gpu but the src doesn't have a texture,
- // we create a temporary texture for the draw.
- // TODO: we should actually only copy the portion of the source needed to apply the image
- // filter
- GrContext* context = srcRT->getContext();
- SkAutoTUnref<GrTexture> tex(context->textureProvider()->createTexture(srcRT->desc(),
- SkBudgeted::kYes));
-
- context->copySurface(tex, srcRT);
-
- GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM);
- } else
-#endif
- {
- srcBM = src->accessBitmap(false);
+void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
+ SkBaseDevice* dst, const SkMatrix& ctm,
+ const SkClipStack* clipStack) {
+ SkDraw draw;
+ SkRasterClip rc;
+ rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
+ if (!dst->accessPixels(&draw.fDst)) {
+ draw.fDst.reset(dst->imageInfo(), nullptr, 0);
}
-
- SkCanvas c(dst);
+ draw.fMatrix = &SkMatrix::I();
+ draw.fRC = &rc;
+ draw.fClipStack = clipStack;
+ draw.fDevice = dst;
SkPaint p;
p.setImageFilter(filter->makeWithLocalMatrix(ctm));
- const SkScalar x = SkIntToScalar(src->getOrigin().x());
- const SkScalar y = SkIntToScalar(src->getOrigin().y());
- c.drawBitmap(srcBM, x, y, &p);
+
+ int x = src->getOrigin().x() - dst->getOrigin().x();
+ int y = src->getOrigin().y() - dst->getOrigin().y();
+ auto special = src->snapSpecial();
+ if (special) {
+ dst->drawSpecial(draw, special.get(), x, y, p);
+ }
}
static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
@@ -1270,7 +1259,7 @@
}
SkBaseDevice* priorDevice = this->getTopDevice();
- if (!priorDevice) {
+ if (nullptr == priorDevice) {
SkDebugf("Unable to find device for layer.");
return;
}
@@ -1294,15 +1283,16 @@
}
newDevice->setOrigin(ir.fLeft, ir.fTop);
- if (rec.fBackdrop) {
- draw_filter_into_device(priorDevice, rec.fBackdrop, newDevice, fMCRec->fMatrix);
- }
-
DeviceCM* layer = new DeviceCM(newDevice, paint, this, fConservativeRasterClip, stashedMatrix);
layer->fNext = fMCRec->fTopLayer;
fMCRec->fLayer = layer;
fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
+
+ if (rec.fBackdrop) {
+ DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice,
+ fMCRec->fMatrix, this->getClipStack());
+ }
}
int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
@@ -1452,18 +1442,19 @@
}
LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
+
while (iter.next()) {
SkBaseDevice* dstDev = iter.fDevice;
paint = &looper.paint();
SkImageFilter* filter = paint->getImageFilter();
SkIPoint pos = { x - iter.getX(), y - iter.getY() };
if (filter) {
- const SkBitmap& srcBM = srcDev->accessBitmap(false);
- dstDev->drawSpriteWithFilter(iter, srcBM, pos.x(), pos.y(), *paint);
+ dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint);
} else {
dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
}
}
+
LOOPER_END
}
@@ -2311,17 +2302,13 @@
paint = lazy.init();
}
+ sk_sp<SkSpecialImage> special;
bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
*paint);
if (drawAsSprite && paint->getImageFilter()) {
- SkBitmap bitmap;
- if (!as_IB(image)->asBitmapForImageFilters(&bitmap)) {
+ special = this->getDevice()->makeSpecial(image);
+ if (!special) {
drawAsSprite = false;
- } else{
- // Until imagefilters are updated, they cannot handle any src type but N32...
- if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().gammaCloseToSRGB()) {
- drawAsSprite = false;
- }
}
}
@@ -2329,15 +2316,12 @@
while (iter.next()) {
const SkPaint& pnt = looper.paint();
- if (drawAsSprite && pnt.getImageFilter()) {
- SkBitmap bitmap;
- if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
- SkPoint pt;
- iter.fMatrix->mapXY(x, y, &pt);
- iter.fDevice->drawSpriteWithFilter(iter, bitmap,
- SkScalarRoundToInt(pt.fX),
- SkScalarRoundToInt(pt.fY), pnt);
- }
+ if (special) {
+ SkPoint pt;
+ iter.fMatrix->mapXY(x, y, &pt);
+ iter.fDevice->drawSpecial(iter, special.get(),
+ SkScalarRoundToInt(pt.fX),
+ SkScalarRoundToInt(pt.fY), pnt);
} else {
iter.fDevice->drawImage(iter, image, x, y, pnt);
}
@@ -2400,11 +2384,12 @@
bounds = &storage;
}
+ sk_sp<SkSpecialImage> special;
bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
*paint);
if (drawAsSprite && paint->getImageFilter()) {
- // Until imagefilters are updated, they cannot handle any src type but N32...
- if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().gammaCloseToSRGB()) {
+ special = this->getDevice()->makeSpecial(bitmap);
+ if (!special) {
drawAsSprite = false;
}
}
@@ -2413,17 +2398,17 @@
while (iter.next()) {
const SkPaint& pnt = looper.paint();
- if (drawAsSprite && pnt.getImageFilter()) {
+ if (special) {
SkPoint pt;
iter.fMatrix->mapXY(x, y, &pt);
- iter.fDevice->drawSpriteWithFilter(iter, bitmap,
- SkScalarRoundToInt(pt.fX),
- SkScalarRoundToInt(pt.fY), pnt);
+ iter.fDevice->drawSpecial(iter, special.get(),
+ SkScalarRoundToInt(pt.fX),
+ SkScalarRoundToInt(pt.fY), pnt);
} else {
iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
}
}
-
+
LOOPER_END
}
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp
index 8875d22..e3a14e5 100644
--- a/src/core/SkSpecialImage.cpp
+++ b/src/core/SkSpecialImage.cpp
@@ -18,6 +18,13 @@
#include "SkSpecialSurface.h"
#include "SkSurfacePriv.h"
+// Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
+// a given info is supported.
+static bool valid_for_imagefilters(const SkImageInfo& info) {
+ // no support for other swizzles/depths yet
+ return info.colorType() == kN32_SkColorType;
+}
+
///////////////////////////////////////////////////////////////////////////////
class SkSpecialImage_Base : public SkSpecialImage {
public:
@@ -315,7 +322,11 @@
const SkSurfaceProps* props) {
SkASSERT(rect_fits(subset, image->width(), image->height()));
- return sk_make_sp<SkSpecialImage_Image>(subset, image, props);
+ if (valid_for_imagefilters(as_IB(image.get())->onImageInfo())) {
+ return sk_make_sp<SkSpecialImage_Image>(subset, image, props);
+ } else {
+ return nullptr;
+ }
}
///////////////////////////////////////////////////////////////////////////////
@@ -412,7 +423,16 @@
SkASSERT(nullptr == bm.getTexture());
SkASSERT(rect_fits(subset, bm.width(), bm.height()));
- return sk_make_sp<SkSpecialImage_Raster>(subset, bm, props);
+ const SkBitmap* srcBM = &bm;
+ SkBitmap tmpStorage;
+ // ImageFilters only handle N32 at the moment, so force our src to be that
+ if (!valid_for_imagefilters(bm.info())) {
+ if (!bm.copyTo(&tmpStorage, kN32_SkColorType)) {
+ return nullptr;
+ }
+ srcBM = &tmpStorage;
+ }
+ return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
}
#if SK_SUPPORT_GPU
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index ff2806a..8501a03 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -2262,6 +2262,5 @@
}
sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() {
- SkASSERT(false);
return nullptr;
}