diff options
author | 2015-07-16 07:40:45 -0700 | |
---|---|---|
committer | 2015-07-16 07:40:45 -0700 | |
commit | c83a29759a5c2966da5ab973e4fd90763e4c962b (patch) | |
tree | f47ed31d01e78faa7ef95a8962b3db7ec7243f4f /src/core | |
parent | 0df62e3d685f6b0b61ee514c68006e013109f5a1 (diff) |
have canvas send discard instead of retain if the draw would overwrite everything
Motivation:
- perf win for clients that overwrite the surface after a snapshot.
- may allow us to eliminate SkDeferredCanvas, as this was its primary advantage.
BUG=skia:
Review URL: https://codereview.chromium.org/1236023004
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkCanvas.cpp | 97 | ||||
-rw-r--r-- | src/core/SkPaintPriv.cpp | 19 | ||||
-rw-r--r-- | src/core/SkPaintPriv.h | 12 |
3 files changed, 105 insertions, 23 deletions
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 941d8688f1..570435869b 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -17,6 +17,7 @@ #include "SkImage.h" #include "SkMetaData.h" #include "SkNinePatchIter.h" +#include "SkPaintPriv.h" #include "SkPathOps.h" #include "SkPatchUtils.h" #include "SkPicture.h" @@ -36,6 +37,60 @@ #include "GrRenderTarget.h" #endif +/* + * Return true if the drawing this rect would hit every pixels in the canvas. + * + * Returns false if + * - rect does not contain the canvas' bounds + * - paint is not fill + * - paint would blur or otherwise change the coverage of the rect + */ +bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint, + ShaderOverrideOpacity overrideOpacity) const { + SK_COMPILE_ASSERT((int)SkPaintPriv::kNone_ShaderOverrideOpacity == + (int)kNone_ShaderOverrideOpacity, + need_matching_enums0); + SK_COMPILE_ASSERT((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity == + (int)kOpaque_ShaderOverrideOpacity, + need_matching_enums1); + SK_COMPILE_ASSERT((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity == + (int)kNotOpaque_ShaderOverrideOpacity, + need_matching_enums2); + + const SkISize size = this->getBaseLayerSize(); + const SkRect bounds = SkRect::MakeIWH(size.width(), size.height()); + if (!this->getClipStack()->quickContains(bounds)) { + return false; + } + + if (rect) { + if (!this->getTotalMatrix().rectStaysRect()) { + return false; // conservative + } + + SkRect devRect; + this->getTotalMatrix().mapRect(&devRect, *rect); + if (devRect.contains(bounds)) { + return false; + } + } + + if (paint) { + SkPaint::Style paintStyle = paint->getStyle(); + if (!(paintStyle == SkPaint::kFill_Style || + paintStyle == SkPaint::kStrokeAndFill_Style)) { + return false; + } + if (paint->getMaskFilter() || paint->getLooper() + || paint->getPathEffect() || paint->getImageFilter()) { + return false; // conservative + } + } + return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + static bool gIgnoreSaveLayerBounds; void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) { gIgnoreSaveLayerBounds = ignore; @@ -80,9 +135,28 @@ bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() { typedef SkTLazy<SkPaint> SkLazyPaint; -void SkCanvas::predrawNotify() { +void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) { if (fSurfaceBase) { - fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode); + fSurfaceBase->aboutToDraw(willOverwritesEntireSurface + ? SkSurface::kDiscard_ContentChangeMode + : SkSurface::kRetain_ContentChangeMode); + } +} + +void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint, + ShaderOverrideOpacity overrideOpacity) { + if (fSurfaceBase) { + SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode; + // Since willOverwriteAllPixels() may not be complete free to call, we only do so if + // there is an outstanding snapshot, since w/o that, there will be no copy-on-write + // and therefore we don't care which mode we're in. + // + if (fSurfaceBase->outstandingImageSnapshot()) { + if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) { + mode = SkSurface::kDiscard_ContentChangeMode; + } + } + fSurfaceBase->aboutToDraw(mode); } } @@ -497,6 +571,12 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { while (looper.next(type)) { \ SkDrawIter iter(this); +#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \ + this->predrawNotify(bounds, &paint, auxOpaque); \ + AutoDrawLooper looper(this, fProps, paint, false, bounds); \ + while (looper.next(type)) { \ + SkDrawIter iter(this); + #define LOOPER_END } //////////////////////////////////////////////////////////////////////////// @@ -815,7 +895,8 @@ bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel()); // Tell our owning surface to bump its generation ID - this->predrawNotify(); + const bool completeOverwrite = info.dimensions() == size; + this->predrawNotify(completeOverwrite); // The device can assert that the requested area is always contained in its bounds return device->writePixels(info, pixels, rowBytes, target.x(), target.y()); @@ -1866,7 +1947,7 @@ void SkCanvas::onDrawPaint(const SkPaint& paint) { } void SkCanvas::internalDrawPaint(const SkPaint& paint) { - LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL) + LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, NULL, false) while (iter.next()) { iter.fDevice->drawPaint(iter, looper.paint()); @@ -1924,7 +2005,7 @@ void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { } } - LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds) + LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false) while (iter.next()) { iter.fDevice->drawRect(iter, r, looper.paint()); @@ -2082,7 +2163,8 @@ void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const Sk paint = lazy.init(); } - LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) + LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, bounds, + image->isOpaque()) while (iter.next()) { iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint); @@ -2138,7 +2220,8 @@ void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, paint = lazy.init(); } - LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) + LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, bounds, + bitmap.isOpaque()) while (iter.next()) { iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), diff --git a/src/core/SkPaintPriv.cpp b/src/core/SkPaintPriv.cpp index a4a7327110..6725cb49be 100644 --- a/src/core/SkPaintPriv.cpp +++ b/src/core/SkPaintPriv.cpp @@ -5,26 +5,19 @@ * found in the LICENSE file. */ -#include "SkPaintPriv.h" - #include "SkBitmap.h" #include "SkColorFilter.h" +#include "SkPaintPriv.h" #include "SkImage.h" #include "SkPaint.h" #include "SkShader.h" -enum ShaderOverrideOpacity { - kNone_ShaderOverrideOpacity, //!< there is no overriding shader (bitmap or image) - kOpaque_ShaderOverrideOpacity, //!< the overriding shader is opaque - kNotOpaque_ShaderOverrideOpacity, //!< the overriding shader may not be opaque -}; - static bool changes_alpha(const SkPaint& paint) { SkColorFilter* cf = paint.getColorFilter(); return cf && !(cf->getFlags() & SkColorFilter::kAlphaUnchanged_Flag); } -static bool overwrites(const SkPaint* paint, ShaderOverrideOpacity overrideOpacity) { +bool SkPaintPriv::Overwrites(const SkPaint* paint, ShaderOverrideOpacity overrideOpacity) { if (!paint) { // No paint means we default to SRC_OVER, so we overwrite iff our shader-override // is opaque, or we don't have one. @@ -51,16 +44,12 @@ static bool overwrites(const SkPaint* paint, ShaderOverrideOpacity overrideOpaci return SkXfermode::IsOpaque(paint->getXfermode(), opacityType); } -bool SkPaintPriv::Overwrites(const SkPaint& paint) { - return overwrites(&paint, kNone_ShaderOverrideOpacity); -} - bool SkPaintPriv::Overwrites(const SkBitmap& bitmap, const SkPaint* paint) { - return overwrites(paint, bitmap.isOpaque() ? kOpaque_ShaderOverrideOpacity + return Overwrites(paint, bitmap.isOpaque() ? kOpaque_ShaderOverrideOpacity : kNotOpaque_ShaderOverrideOpacity); } bool SkPaintPriv::Overwrites(const SkImage* image, const SkPaint* paint) { - return overwrites(paint, image->isOpaque() ? kOpaque_ShaderOverrideOpacity + return Overwrites(paint, image->isOpaque() ? kOpaque_ShaderOverrideOpacity : kNotOpaque_ShaderOverrideOpacity); } diff --git a/src/core/SkPaintPriv.h b/src/core/SkPaintPriv.h index d859132391..708f861b70 100644 --- a/src/core/SkPaintPriv.h +++ b/src/core/SkPaintPriv.h @@ -16,13 +16,23 @@ class SkPaint; class SkPaintPriv { public: + enum ShaderOverrideOpacity { + kNone_ShaderOverrideOpacity, //!< there is no overriding shader (bitmap or image) + kOpaque_ShaderOverrideOpacity, //!< the overriding shader is opaque + kNotOpaque_ShaderOverrideOpacity, //!< the overriding shader may not be opaque + }; + /** * Returns true if drawing with this paint (or NULL) will ovewrite all affected pixels. * * Note: returns conservative true, meaning it may return false even though the paint might * in fact overwrite its pixels. */ - static bool Overwrites(const SkPaint& paint); + static bool Overwrites(const SkPaint* paint, ShaderOverrideOpacity); + + static bool Overwrites(const SkPaint& paint) { + return Overwrites(&paint, kNone_ShaderOverrideOpacity); + } /** * Returns true if drawing this bitmap with this paint (or NULL) will ovewrite all affected |