aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar reed <reed@google.com>2015-07-16 07:40:45 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-07-16 07:40:45 -0700
commitc83a29759a5c2966da5ab973e4fd90763e4c962b (patch)
treef47ed31d01e78faa7ef95a8962b3db7ec7243f4f /src/core
parent0df62e3d685f6b0b61ee514c68006e013109f5a1 (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.cpp97
-rw-r--r--src/core/SkPaintPriv.cpp19
-rw-r--r--src/core/SkPaintPriv.h12
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