aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed <reed@google.com>2015-08-19 08:18:04 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-08-19 08:18:04 -0700
commit451af5062e6bf9c665126d84516e0baafa27ecc4 (patch)
tree34a59d58a3d5667d2af2fa7dfbbba2f773d4bdea
parentda04e0e80a0113e1d838f7406cd8a8d545b8c02b (diff)
remove SkDeferredCanvas
Waiting a day or so to see if the blink-removal of SkDeferredCanvas sticks BUG=skia: Review URL: https://codereview.chromium.org/1269093002
-rw-r--r--bench/DeferredSurfaceCopyBench.cpp74
-rw-r--r--dm/DM.cpp1
-rw-r--r--dm/DMSrcSink.cpp27
-rw-r--r--gyp/utils.gypi2
-rw-r--r--include/core/SkCanvas.h1
-rw-r--r--include/core/SkDevice.h1
-rw-r--r--include/utils/SkDeferredCanvas.h261
-rw-r--r--samplecode/SampleApp.cpp20
-rw-r--r--samplecode/SampleApp.h4
-rw-r--r--src/core/SkPictureRecord.cpp3
-rw-r--r--src/utils/SkDeferredCanvas.cpp1027
-rw-r--r--tests/CanvasTest.cpp62
-rw-r--r--tests/DeferredCanvasTest.cpp949
13 files changed, 2 insertions, 2430 deletions
diff --git a/bench/DeferredSurfaceCopyBench.cpp b/bench/DeferredSurfaceCopyBench.cpp
deleted file mode 100644
index 3644627d31..0000000000
--- a/bench/DeferredSurfaceCopyBench.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Benchmark.h"
-#include "SkDeferredCanvas.h"
-#include "SkDevice.h"
-#include "SkImage.h"
-#include "SkSurface.h"
-#if SK_SUPPORT_GPU
-#include "GrRenderTarget.h"
-#endif
-
-class DeferredSurfaceCopyBench : public Benchmark {
- enum {
- kSurfaceWidth = 1000,
- kSurfaceHeight = 1000,
- };
-public:
- DeferredSurfaceCopyBench(bool discardableContents) {
- fDiscardableContents = discardableContents;
- }
-
-protected:
- const char* onGetName() override {
- return fDiscardableContents ? "DeferredSurfaceCopy_discardable" :
- "DeferredSurfaceCopy_nonDiscardable";
- }
-
- void onDraw(const int loops, SkCanvas* canvas) override {
- // The canvas is not actually used for this test except to provide
- // configuration information: gpu, multisampling, size, etc?
- SkImageInfo info = SkImageInfo::MakeN32Premul(kSurfaceWidth, kSurfaceHeight);
- const SkRect fullCanvasRect = SkRect::MakeWH(
- SkIntToScalar(kSurfaceWidth), SkIntToScalar(kSurfaceHeight));
- SkAutoTUnref<SkSurface> surface(canvas->newSurface(info));
-
- // newSurface() can return NULL for several reasons, so we need to check
- if (NULL == surface.get()) {
- SkDebugf("DeferredSurfaceCopyBench newSurface failed, bench results are meaningless\n");
- return; // should we signal the caller that we hit an error?
- }
-
- SkAutoTUnref<SkDeferredCanvas> drawingCanvas(SkDeferredCanvas::Create(surface));
-
- for (int iteration = 0; iteration < loops; iteration++) {
- drawingCanvas->clear(0);
- SkAutoTUnref<SkImage> image(drawingCanvas->newImageSnapshot());
- SkPaint paint;
- if (!fDiscardableContents) {
- // If paint is not opaque, prior canvas contents are
- // not discardable because they are needed for compositing.
- paint.setAlpha(127);
- }
- drawingCanvas->drawRect(fullCanvasRect, paint);
- // Trigger copy on write, which should be faster in the discardable case.
- drawingCanvas->flush();
- }
- }
-
-private:
- bool fDiscardableContents;
-
- typedef Benchmark INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_BENCH( return new DeferredSurfaceCopyBench(false); )
-DEF_BENCH( return new DeferredSurfaceCopyBench(true); )
diff --git a/dm/DM.cpp b/dm/DM.cpp
index 7067e7452e..c637edd9b9 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -418,7 +418,6 @@ static Sink* create_via(const char* tag, Sink* wrapped) {
VIA("twice", ViaTwice, wrapped);
VIA("pipe", ViaPipe, wrapped);
VIA("serialize", ViaSerialization, wrapped);
- VIA("deferred", ViaDeferred, wrapped);
VIA("2ndpic", ViaSecondPicture, wrapped);
VIA("sp", ViaSingletonPictures, wrapped);
VIA("tiles", ViaTiles, 256, 256, NULL, wrapped);
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index f766b49c79..5b2ccc8f57 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -10,7 +10,6 @@
#include "SkCodec.h"
#include "SkCommonFlags.h"
#include "SkData.h"
-#include "SkDeferredCanvas.h"
#include "SkDocument.h"
#include "SkError.h"
#include "SkFunction.h"
@@ -874,37 +873,13 @@ Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkStrin
return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
PipeController controller(canvas, &SkImageDecoder::DecodeMemory);
SkGPipeWriter pipe;
- const uint32_t kFlags = 0; // We mirror SkDeferredCanvas, which doesn't use any flags.
+ const uint32_t kFlags = 0;
return src.draw(pipe.startRecording(&controller, kFlags, size.width(), size.height()));
});
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-Error ViaDeferred::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
- // We draw via a deferred canvas into a surface that's compatible with the original canvas,
- // then snap that surface as an image and draw it into the original canvas.
- return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error {
- SkAutoTUnref<SkSurface> surface(canvas->newSurface(canvas->imageInfo()));
- if (!surface.get()) {
- return "can't make surface for deferred canvas";
- }
- SkAutoTDelete<SkDeferredCanvas> defcan(SkDeferredCanvas::Create(surface));
- Error err = src.draw(defcan);
- if (!err.isEmpty()) {
- return err;
- }
- SkAutoTUnref<SkImage> image(defcan->newImageSnapshot());
- if (!image) {
- return "failed to create deferred image snapshot";
- }
- canvas->drawImage(image, 0, 0, NULL);
- return "";
- });
-}
-
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
Error ViaSerialization::draw(
const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
// Record our Src into a picture.
diff --git a/gyp/utils.gypi b/gyp/utils.gypi
index e4033e9020..347cc24fef 100644
--- a/gyp/utils.gypi
+++ b/gyp/utils.gypi
@@ -18,7 +18,6 @@
'<(skia_include_path)/utils/SkCubicInterval.h',
'<(skia_include_path)/utils/SkCullPoints.h',
'<(skia_include_path)/utils/SkDebugUtils.h',
- '<(skia_include_path)/utils/SkDeferredCanvas.h',
'<(skia_include_path)/utils/SkDumpCanvas.h',
'<(skia_include_path)/utils/SkEventTracer.h',
'<(skia_include_path)/utils/SkInterpolator.h',
@@ -54,7 +53,6 @@
'<(skia_src_path)/utils/SkCullPoints.cpp',
'<(skia_src_path)/utils/SkDashPath.cpp',
'<(skia_src_path)/utils/SkDashPathPriv.h',
- '<(skia_src_path)/utils/SkDeferredCanvas.cpp',
'<(skia_src_path)/utils/SkDumpCanvas.cpp',
'<(skia_src_path)/utils/SkEventTracer.cpp',
'<(skia_src_path)/utils/SkFloatUtils.h',
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 6a88d68322..35c0fb75b5 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -1370,7 +1370,6 @@ private:
friend class AutoDrawLooper;
friend class SkLua; // needs top layer size and offset
friend class SkDebugCanvas; // needs experimental fAllowSimplifyClip
- friend class SkDeferredDevice; // needs getTopDevice()
friend class SkSurface_Raster; // needs getDevice()
friend class SkRecorder; // InitFlags
friend class SkNoSaveLayerCanvas; // InitFlags
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 3715b1d615..9e01e62649 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -373,7 +373,6 @@ private:
friend class SkDrawIter;
friend class SkDeviceFilteredPaint;
friend class SkImageFilter::Proxy;
- friend class SkDeferredDevice; // for newSurface
friend class SkNoPixelsBitmapDevice;
friend class SkSurface_Raster;
diff --git a/include/utils/SkDeferredCanvas.h b/include/utils/SkDeferredCanvas.h
deleted file mode 100644
index 9b50caf89b..0000000000
--- a/include/utils/SkDeferredCanvas.h
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkDeferredCanvas_DEFINED
-#define SkDeferredCanvas_DEFINED
-
-#include "SkCanvas.h"
-#include "SkPixelRef.h"
-
-class SkDeferredDevice;
-class SkImage;
-class SkSurface;
-
-/** \class SkDeferredCanvas
- Subclass of SkCanvas that encapsulates an SkPicture or SkGPipe for deferred
- drawing. The main difference between this class and SkPictureRecord (the
- canvas provided by SkPicture) is that this is a full drop-in replacement
- for SkCanvas, while SkPictureRecord only supports draw operations.
- SkDeferredCanvas will transparently trigger the flushing of deferred
- draw operations when an attempt is made to access the pixel data.
-*/
-class SK_API SkDeferredCanvas : public SkCanvas {
-public:
- class SK_API NotificationClient;
-
- /** Construct a canvas with the specified surface to draw into.
- This factory must be used for newImageSnapshot to work.
- @param surface Specifies a surface for the canvas to draw into.
- */
- static SkDeferredCanvas* Create(SkSurface* surface);
-
- virtual ~SkDeferredCanvas();
-
- /**
- * Specify the surface to be used by this canvas. Calling setSurface will
- * release the previously set surface or device. Takes a reference on the
- * surface.
- *
- * @param surface The surface that the canvas will raw into
- * @return The surface argument, for convenience.
- */
- SkSurface* setSurface(SkSurface* surface);
-
- /**
- * Specify a NotificationClient to be used by this canvas. Calling
- * setNotificationClient will release the previously set
- * NotificationClient, if any. SkDeferredCanvas does not take ownership
- * of the notification client. Therefore user code is resposible
- * for its destruction. The notification client must be unregistered
- * by calling setNotificationClient(NULL) if it is destroyed before
- * this canvas.
- * Note: Must be called after the device is set with setDevice.
- *
- * @param notificationClient interface for dispatching notifications
- * @return The notificationClient argument, for convenience.
- */
- NotificationClient* setNotificationClient(NotificationClient* notificationClient);
-
- /**
- * Enable or disable deferred drawing. When deferral is disabled,
- * pending draw operations are immediately flushed and from then on,
- * the SkDeferredCanvas behaves just like a regular SkCanvas.
- * This method must not be called while the save/restore stack is in use.
- * @param deferred true/false
- */
- void setDeferredDrawing(bool deferred);
-
- /**
- * Returns true if deferred drawing is currenlty enabled.
- */
- bool isDeferredDrawing() const;
-
- /**
- * Returns true if the canvas contains a fresh frame. A frame is
- * considered fresh when its content do not depend on the contents
- * of the previous frame. For example, if a canvas is cleared before
- * drawing each frame, the frames will all be considered fresh.
- * A frame is defined as the graphics image produced by as a result
- * of all the canvas draws operation executed between two successive
- * calls to isFreshFrame. The result of isFreshFrame is computed
- * conservatively, so it may report false negatives.
- */
- bool isFreshFrame() const;
-
- /**
- * Returns canvas's size.
- */
- SkISize getCanvasSize() const;
-
- /**
- * Returns true if the canvas has recorded draw commands that have
- * not yet been played back.
- */
- bool hasPendingCommands() const;
-
- /**
- * Flushes pending draw commands, if any, and returns an image of the
- * current state of the surface pixels up to this point. Subsequent
- * changes to the surface (by drawing into its canvas) will not be
- * reflected in this image. Will return NULL if the deferred canvas
- * was not constructed from an SkSurface.
- */
- SkImage* newImageSnapshot();
-
- /**
- * Specify the maximum number of bytes to be allocated for the purpose
- * of recording draw commands to this canvas. The default limit, is
- * 64MB.
- * @param maxStorage The maximum number of bytes to be allocated.
- */
- void setMaxRecordingStorage(size_t maxStorage);
-
- /**
- * Returns the number of bytes currently allocated for the purpose of
- * recording draw commands.
- */
- size_t storageAllocatedForRecording() const;
-
- /**
- * Attempt to reduce the storage allocated for recording by evicting
- * cache resources.
- * @param bytesToFree minimum number of bytes that should be attempted to
- * be freed.
- * @return number of bytes actually freed.
- */
- size_t freeMemoryIfPossible(size_t bytesToFree);
-
- /**
- * Specifies the maximum size (in bytes) allowed for a given image to be
- * rendered using the deferred canvas.
- */
- void setBitmapSizeThreshold(size_t sizeThreshold);
- size_t getBitmapSizeThreshold() const { return fBitmapSizeThreshold; }
-
- /**
- * Executes all pending commands without drawing
- */
- void silentFlush();
-
- SkDrawFilter* setDrawFilter(SkDrawFilter* filter) override;
-
-protected:
- void willSave() override;
- SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override;
- void willRestore() override;
-
- void didConcat(const SkMatrix&) override;
- void didSetMatrix(const SkMatrix&) override;
-
- void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
- virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
- const SkPaint&) override;
- virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
- const SkPaint&) override;
- virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
- SkScalar constY, const SkPaint&) override;
- virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
- const SkMatrix* matrix, const SkPaint&) override;
- virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
- const SkPaint& paint) override;
- virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
- const SkPoint texCoords[4], SkXfermode* xmode,
- const SkPaint& paint) override;
-
- void onDrawPaint(const SkPaint&) override;
- void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
- void onDrawRect(const SkRect&, const SkPaint&) override;
- void onDrawOval(const SkRect&, const SkPaint&) override;
- void onDrawRRect(const SkRRect&, const SkPaint&) override;
- void onDrawPath(const SkPath&, const SkPaint&) override;
- void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override;
- void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
- SrcRectConstraint) override;
- void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
- void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
- const SkPaint*, SrcRectConstraint) override;
- void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
- const SkPaint*) override;
- void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
- const SkPaint*) override;
- void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override;
- void onDrawVertices(VertexMode vmode, int vertexCount,
- const SkPoint vertices[], const SkPoint texs[],
- const SkColor colors[], SkXfermode* xmode,
- const uint16_t indices[], int indexCount,
- const SkPaint&) override;
- void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int count,
- SkXfermode::Mode, const SkRect* cullRect, const SkPaint*) override;
-
- void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
- void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
- void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
- void onClipRegion(const SkRegion&, SkRegion::Op) override;
-
- void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
-
-public:
- class NotificationClient {
- public:
- virtual ~NotificationClient() {}
-
- /**
- * Called before executing one or several draw commands, which means
- * once per flush when deferred rendering is enabled.
- */
- virtual void prepareForDraw() {}
-
- /**
- * Called after a recording a draw command if additional memory
- * had to be allocated for recording.
- * @param newAllocatedStorage same value as would be returned by
- * storageAllocatedForRecording(), for convenience.
- */
- virtual void storageAllocatedForRecordingChanged(size_t /*newAllocatedStorage*/) {}
-
- /**
- * Called after pending draw commands have been flushed
- */
- virtual void flushedDrawCommands() {}
-
- /**
- * Called after pending draw commands have been skipped, meaning
- * that they were optimized-out because the canvas is cleared
- * or completely overwritten by the command currently being recorded.
- */
- virtual void skippedPendingDrawCommands() {}
- };
-
-protected:
- SkCanvas* canvasForDrawIter() override;
- SkDeferredDevice* getDeferredDevice() const;
-
-private:
- SkDeferredCanvas(SkDeferredDevice*);
-
- void recordedDrawCommand();
- SkCanvas* drawingCanvas() const;
- SkCanvas* immediateCanvas() const;
- bool isFullFrame(const SkRect*, const SkPaint*) const;
- void validate() const;
- void init();
-
-
- int fSaveLevel;
- int fFirstSaveLayerIndex;
- size_t fBitmapSizeThreshold;
- bool fDeferredDrawing;
-
- mutable SkISize fCachedCanvasSize;
- mutable bool fCachedCanvasSizeDirty;
-
- friend class SkDeferredCanvasTester; // for unit testing
- typedef SkCanvas INHERITED;
-};
-
-
-#endif
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index ae9c88b7da..0a89b48e3c 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -15,7 +15,6 @@
#include "SkCanvas.h"
#include "SkCommandLineFlags.h"
#include "SkData.h"
-#include "SkDeferredCanvas.h"
#include "SkDevice.h"
#include "SkDocument.h"
#include "SkGPipe.h"
@@ -188,7 +187,6 @@ public:
switch (win->getDeviceType()) {
case kRaster_DeviceType: // fallthrough
case kPicture_DeviceType: // fallthrough
- case kDeferred_DeviceType: // fallthrough
case kGPU_DeviceType:
// all these guys use the native backend
fBackend = kNativeGL_BackEndType;
@@ -216,7 +214,6 @@ public:
switch (win->getDeviceType()) {
case kRaster_DeviceType: // fallthrough
case kPicture_DeviceType: // fallthrough
- case kDeferred_DeviceType: // fallthrough
case kGPU_DeviceType:
// all these guys use the native interface
glInterface.reset(GrGLCreateNativeInterface());
@@ -674,7 +671,6 @@ static inline SampleWindow::DeviceType cycle_devicetype(SampleWindow::DeviceType
SampleWindow::kANGLE_DeviceType,
#endif // SK_ANGLE
#endif // SK_SUPPORT_GPU
- SampleWindow::kDeferred_DeviceType,
SampleWindow::kRaster_DeviceType,
};
SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gCT) == SampleWindow::kDeviceTypeCnt, array_size_mismatch);
@@ -830,7 +826,7 @@ SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* dev
int itemID;
itemID =fAppMenu->appendList("Device Type", "Device Type", sinkID, 0,
- "Raster", "Picture", "OpenGL", "Deferred",
+ "Raster", "Picture", "OpenGL",
#if SK_ANGLE
"ANGLE",
#endif
@@ -1264,12 +1260,6 @@ SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
canvas = fPDFDocument->beginPage(this->width(), this->height());
} else if (kPicture_DeviceType == fDeviceType) {
canvas = fRecorder.beginRecording(9999, 9999, NULL, 0);
- } else if (kDeferred_DeviceType == fDeviceType) {
- fDeferredSurface.reset(canvas->newSurface(canvas->imageInfo()));
- if (fDeferredSurface.get()) {
- fDeferredCanvas.reset(SkDeferredCanvas::Create(fDeferredSurface));
- canvas = fDeferredCanvas;
- }
} else {
canvas = this->INHERITED::beforeChildren(canvas);
}
@@ -1376,13 +1366,6 @@ void SampleWindow::afterChildren(SkCanvas* orig) {
} else {
picture->playback(orig);
}
- } else if (kDeferred_DeviceType == fDeviceType) {
- SkAutoTUnref<SkImage> image(fDeferredCanvas->newImageSnapshot());
- if (image) {
- orig->drawImage(image, 0, 0, NULL);
- }
- fDeferredCanvas.reset(NULL);
- fDeferredSurface.reset(NULL);
}
// Do this after presentGL and other finishing, rather than in afterChild
@@ -1949,7 +1932,6 @@ static const char* gDeviceTypePrefix[] = {
"angle: ",
#endif // SK_ANGLE
#endif // SK_SUPPORT_GPU
- "deferred: ",
};
SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gDeviceTypePrefix) == SampleWindow::kDeviceTypeCnt,
array_size_mismatch);
diff --git a/samplecode/SampleApp.h b/samplecode/SampleApp.h
index c0f845d32c..1f8c33389a 100644
--- a/samplecode/SampleApp.h
+++ b/samplecode/SampleApp.h
@@ -23,7 +23,6 @@ class GrRenderTarget;
class SkCanvas;
class SkData;
-class SkDeferredCanvas;
class SkDocument;
class SkEvent;
class SkTypeface;
@@ -41,7 +40,6 @@ public:
kANGLE_DeviceType,
#endif // SK_ANGLE
#endif // SK_SUPPORT_GPU
- kDeferred_DeviceType,
kDeviceTypeCnt
};
@@ -162,8 +160,6 @@ private:
int fCurrIndex;
SkPictureRecorder fRecorder;
- SkAutoTDelete<SkSurface> fDeferredSurface;
- SkAutoTDelete<SkDeferredCanvas> fDeferredCanvas;
SkAutoTDelete<SkCanvas> fFlagsFilterCanvas;
SkPath fClipPath;
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 0383dda3d5..55262ad571 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -209,9 +209,6 @@ static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* si
#endif//SK_DEBUG
void SkPictureRecord::willRestore() {
- // FIXME: SkDeferredCanvas needs to be refactored to respect
- // save/restore balancing so that the following test can be
- // turned on permanently.
#if 0
SkASSERT(fRestoreOffsetStack.count() > 1);
#endif
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
deleted file mode 100644
index 6ccfb5e4b3..0000000000
--- a/src/utils/SkDeferredCanvas.cpp
+++ /dev/null
@@ -1,1027 +0,0 @@
-
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkDeferredCanvas.h"
-
-#include "SkChunkAlloc.h"
-#include "SkClipStack.h"
-#include "SkColorFilter.h"
-#include "SkDevice.h"
-#include "SkDrawFilter.h"
-#include "SkGPipe.h"
-#include "SkImage_Base.h"
-#include "SkPaint.h"
-#include "SkPaintPriv.h"
-#include "SkRRect.h"
-#include "SkShader.h"
-#include "SkSurface.h"
-
-enum {
- // Deferred canvas will auto-flush when recording reaches this limit
- kDefaultMaxRecordingStorageBytes = 64*1024*1024,
- kDeferredCanvasBitmapSizeThreshold = ~0U, // Disables this feature
-
- kNoSaveLayerIndex = -1,
-};
-
-enum PlaybackMode {
- kNormal_PlaybackMode,
- kSilent_PlaybackMode,
-};
-
-static uint64_t image_area(const SkImage* image) {
- return sk_64_mul(image->width(), image->height());
-}
-
-// HACK -- see crbug.com/485243
-//
-// Work around case where Blink gives us an image, but will "mutate" it (by changing its contents
-// directly using webgl). Until that is fixed at the call-site, we treat gpu-backed-images as
-// mutable for now (at least for the purposes of deferred canvas)
-//
-static bool should_draw_gpu_image_immediately(const SkImage* image) {
- return as_IB(image)->getTexture() != NULL;
-}
-
-static bool should_draw_immediately(const SkBitmap* bitmap, const SkImage* image,
- const SkPaint* paint, size_t bitmapSizeThreshold) {
- if (bitmap && ((bitmap->getTexture() && !bitmap->isImmutable()) ||
- (bitmap->getSize() > bitmapSizeThreshold))) {
- return true;
- }
- if (image) {
- if (should_draw_gpu_image_immediately(image) || image_area(image) > bitmapSizeThreshold) {
- return true;
- }
- }
- if (paint) {
- SkShader* shader = paint->getShader();
- // Here we detect the case where the shader is an SkBitmapProcShader
- // with a gpu texture attached. Checking this without RTTI
- // requires making the assumption that only gradient shaders
- // and SkBitmapProcShader implement asABitmap(). The following
- // code may need to be revised if that assumption is ever broken.
- if (shader && !shader->asAGradient(NULL)) {
- SkBitmap bm;
- if (shader->asABitmap(&bm, NULL, NULL) &&
- bm.getTexture()) {
- return true;
- }
- }
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// DeferredPipeController
-//-----------------------------------------------------------------------------
-
-class DeferredPipeController : public SkGPipeController {
-public:
- DeferredPipeController();
- void setPlaybackCanvas(SkCanvas*);
- virtual ~DeferredPipeController();
- void* requestBlock(size_t minRequest, size_t* actual) override;
- void notifyWritten(size_t bytes) override;
- void playback(bool silent);
- bool hasPendingCommands() const { return fAllocator.totalUsed() != 0; }
- size_t storageAllocatedForRecording() const { return fAllocator.totalCapacity(); }
-private:
- enum {
- kMinBlockSize = 4096
- };
- struct PipeBlock {
- PipeBlock(void* block, size_t size) { fBlock = block, fSize = size; }
- void* fBlock;
- size_t fSize;
- };
- void* fBlock;
- size_t fBytesWritten;
- SkChunkAlloc fAllocator;
- SkTDArray<PipeBlock> fBlockList;
- SkGPipeReader fReader;
-};
-
-DeferredPipeController::DeferredPipeController() :
- fAllocator(kMinBlockSize) {
- fBlock = NULL;
- fBytesWritten = 0;
-}
-
-DeferredPipeController::~DeferredPipeController() {
- fAllocator.reset();
-}
-
-void DeferredPipeController::setPlaybackCanvas(SkCanvas* canvas) {
- fReader.setCanvas(canvas);
-}
-
-void* DeferredPipeController::requestBlock(size_t minRequest, size_t *actual) {
- if (fBlock) {
- // Save the previous block for later
- PipeBlock previousBloc(fBlock, fBytesWritten);
- fBlockList.push(previousBloc);
- }
- size_t blockSize = SkTMax<size_t>(minRequest, kMinBlockSize);
- fBlock = fAllocator.allocThrow(blockSize);
- fBytesWritten = 0;
- *actual = blockSize;
- return fBlock;
-}
-
-void DeferredPipeController::notifyWritten(size_t bytes) {
- fBytesWritten += bytes;
-}
-
-void DeferredPipeController::playback(bool silent) {
- uint32_t flags = silent ? SkGPipeReader::kSilent_PlaybackFlag : 0;
- for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
- fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize,
- flags);
- }
- fBlockList.reset();
-
- if (fBlock) {
- fReader.playback(fBlock, fBytesWritten, flags);
- fBlock = NULL;
- }
-
- // Release all allocated blocks
- fAllocator.reset();
-
- this->purgeCaches();
-}
-
-//-----------------------------------------------------------------------------
-// SkDeferredDevice
-//-----------------------------------------------------------------------------
-class SkDeferredDevice : public SkBaseDevice {
-public:
- explicit SkDeferredDevice(SkSurface* surface);
- ~SkDeferredDevice();
-
- void setNotificationClient(SkDeferredCanvas::NotificationClient* notificationClient);
- SkCanvas* recordingCanvas();
- SkCanvas* immediateCanvas() const {return fImmediateCanvas;}
- SkBaseDevice* immediateDevice() const {return fImmediateCanvas->getTopDevice();}
- SkImage* newImageSnapshot();
- void setSurface(SkSurface* surface);
- bool isFreshFrame();
- bool hasPendingCommands();
- size_t storageAllocatedForRecording() const;
- size_t freeMemoryIfPossible(size_t bytesToFree);
- void flushPendingCommands(PlaybackMode);
- void skipPendingCommands();
- void setMaxRecordingStorage(size_t);
- void recordedDrawCommand();
- void setIsDrawingToLayer(bool value) {fIsDrawingToLayer = value;}
-
- SkImageInfo imageInfo() const override;
-
- GrRenderTarget* accessRenderTarget() override;
-
- SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
-
- SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override;
-
-protected:
- const SkBitmap& onAccessBitmap() override;
- bool onReadPixels(const SkImageInfo&, void*, size_t, int x, int y) override;
- bool onWritePixels(const SkImageInfo&, const void*, size_t, int x, int y) override;
-
- // None of the following drawing methods should ever get called on the
- // deferred device
- void drawPaint(const SkDraw&, const SkPaint& paint) override
- {SkASSERT(0);}
- void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
- size_t count, const SkPoint[],
- const SkPaint& paint) override
- {SkASSERT(0);}
- void drawRect(const SkDraw&, const SkRect& r,
- const SkPaint& paint) override
- {SkASSERT(0);}
- void drawOval(const SkDraw&, const SkRect&, const SkPaint&) override
- {SkASSERT(0);}
- void drawRRect(const SkDraw&, const SkRRect& rr,
- const SkPaint& paint) override
- {SkASSERT(0);}
- void drawPath(const SkDraw&, const SkPath& path,
- const SkPaint& paint,
- const SkMatrix* prePathMatrix = NULL,
- bool pathIsMutable = false) override
- {SkASSERT(0);}
- void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
- const SkMatrix& matrix, const SkPaint& paint) override
- {SkASSERT(0);}
- void drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect*,
- const SkRect&, const SkPaint&, SkCanvas::SrcRectConstraint) override
- {SkASSERT(0);}
- void drawSprite(const SkDraw&, const SkBitmap& bitmap,
- int x, int y, const SkPaint& paint) override
- {SkASSERT(0);}
- void drawImage(const SkDraw&, const SkImage*, SkScalar, SkScalar, const SkPaint&) override
- {SkASSERT(0);}
- void drawImageRect(const SkDraw&, const SkImage*, const SkRect*, const SkRect&,
- const SkPaint&, SkCanvas::SrcRectConstraint) override
- {SkASSERT(0);}
- void drawImageNine(const SkDraw&, const SkImage*, const SkIRect&, const SkRect&,
- const SkPaint&) override
- {SkASSERT(0);}
- void drawText(const SkDraw&, const void* text, size_t len,
- SkScalar x, SkScalar y, const SkPaint& paint) override
- {SkASSERT(0);}
- void drawPosText(const SkDraw&, const void* text, size_t len,
- const SkScalar pos[], int scalarsPerPos,
- const SkPoint& offset, const SkPaint& paint) override
- {SkASSERT(0);}
- void drawTextOnPath(const SkDraw&, const void* text,
- size_t len, const SkPath& path,
- const SkMatrix* matrix,
- const SkPaint& paint) override
- {SkASSERT(0);}
- void drawVertices(const SkDraw&, SkCanvas::VertexMode,
- int vertexCount, const SkPoint verts[],
- const SkPoint texs[], const SkColor colors[],
- SkXfermode* xmode, const uint16_t indices[],
- int indexCount, const SkPaint& paint) override
- {SkASSERT(0);}
- void drawPatch(const SkDraw&, const SkPoint cubics[12], const SkColor colors[4],
- const SkPoint texCoords[4], SkXfermode* xmode,
- const SkPaint& paint) override
- {SkASSERT(0);}
- void drawAtlas(const SkDraw&, const SkImage* atlas, const SkRSXform[], const SkRect[],
- const SkColor[], int count, SkXfermode::Mode, const SkPaint&) override
- {SkASSERT(0);}
-
- void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
- const SkPaint&) override
- {SkASSERT(0);}
-
- bool canHandleImageFilter(const SkImageFilter*) override {
- return false;
- }
- bool filterImage(const SkImageFilter*, const SkBitmap&,
- const SkImageFilter::Context&, SkBitmap*, SkIPoint*) override {
- return false;
- }
-
-private:
- void flush() override;
- void replaceBitmapBackendForRasterSurface(const SkBitmap&) override {}
-
- void beginRecording();
- void init();
- void aboutToDraw();
- void prepareForImmediatePixelWrite();
-
- DeferredPipeController fPipeController;
- SkGPipeWriter fPipeWriter;
- SkCanvas* fImmediateCanvas;
- SkCanvas* fRecordingCanvas;
- SkSurface* fSurface;
- SkDeferredCanvas::NotificationClient* fNotificationClient;
- bool fFreshFrame;
- bool fCanDiscardCanvasContents;
- bool fIsDrawingToLayer;
- size_t fMaxRecordingStorageBytes;
- size_t fPreviousStorageAllocated;
-
- typedef SkBaseDevice INHERITED;
-};
-
-SkDeferredDevice::SkDeferredDevice(SkSurface* surface)
- : INHERITED(surface->props()) {
- fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
- fNotificationClient = NULL;
- fImmediateCanvas = NULL;
- fSurface = NULL;
- this->setSurface(surface);
- this->init();
-}
-
-void SkDeferredDevice::setSurface(SkSurface* surface) {
- SkRefCnt_SafeAssign(fImmediateCanvas, surface->getCanvas());
- SkRefCnt_SafeAssign(fSurface, surface);
- fPipeController.setPlaybackCanvas(fImmediateCanvas);
-}
-
-void SkDeferredDevice::init() {
- fRecordingCanvas = NULL;
- fFreshFrame = true;
- fIsDrawingToLayer = false;
- fCanDiscardCanvasContents = false;
- fPreviousStorageAllocated = 0;
- fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
- fNotificationClient = NULL;
- this->beginRecording();
-}
-
-SkDeferredDevice::~SkDeferredDevice() {
- this->flushPendingCommands(kSilent_PlaybackMode);
- SkSafeUnref(fImmediateCanvas);
- SkSafeUnref(fSurface);
-}
-
-void SkDeferredDevice::setMaxRecordingStorage(size_t maxStorage) {
- fMaxRecordingStorageBytes = maxStorage;
- this->recordingCanvas(); // Accessing the recording canvas applies the new limit.
-}
-
-void SkDeferredDevice::beginRecording() {
- SkASSERT(NULL == fRecordingCanvas);
- fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0,
- immediateDevice()->width(), immediateDevice()->height());
-}
-
-void SkDeferredDevice::setNotificationClient(
- SkDeferredCanvas::NotificationClient* notificationClient) {
- fNotificationClient = notificationClient;
-}
-
-void SkDeferredDevice::skipPendingCommands() {
- if (!fIsDrawingToLayer) {
- fCanDiscardCanvasContents = true;
- if (fPipeController.hasPendingCommands()) {
- fFreshFrame = true;
- flushPendingCommands(kSilent_PlaybackMode);
- }
- }
-}
-
-bool SkDeferredDevice::isFreshFrame() {
- bool ret = fFreshFrame;
- fFreshFrame = false;
- return ret;
-}
-
-bool SkDeferredDevice::hasPendingCommands() {
- return fPipeController.hasPendingCommands();
-}
-
-void SkDeferredDevice::aboutToDraw() {
- if (fNotificationClient) {
- fNotificationClient->prepareForDraw();
- }
- if (fCanDiscardCanvasContents) {
- if (fSurface) {
- fSurface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
- }
- fCanDiscardCanvasContents = false;
- }
-}
-
-void SkDeferredDevice::flushPendingCommands(PlaybackMode playbackMode) {
- if (!fPipeController.hasPendingCommands()) {
- return;
- }
- if (playbackMode == kNormal_PlaybackMode) {
- aboutToDraw();
- }
- fPipeWriter.flushRecording(true);
- fPipeController.playback(kSilent_PlaybackMode == playbackMode);
- if (fNotificationClient) {
- if (playbackMode == kSilent_PlaybackMode) {
- fNotificationClient->skippedPendingDrawCommands();
- } else {
- fNotificationClient->flushedDrawCommands();
- }
- }
-
- fPreviousStorageAllocated = storageAllocatedForRecording();
-}
-
-void SkDeferredDevice::flush() {
- this->flushPendingCommands(kNormal_PlaybackMode);
- fImmediateCanvas->flush();
-}
-
-size_t SkDeferredDevice::freeMemoryIfPossible(size_t bytesToFree) {
- size_t val = fPipeWriter.freeMemoryIfPossible(bytesToFree);
- fPreviousStorageAllocated = storageAllocatedForRecording();
- return val;
-}
-
-size_t SkDeferredDevice::storageAllocatedForRecording() const {
- return (fPipeController.storageAllocatedForRecording()
- + fPipeWriter.storageAllocatedForRecording());
-}
-
-void SkDeferredDevice::recordedDrawCommand() {
- size_t storageAllocated = this->storageAllocatedForRecording();
-
- if (storageAllocated > fMaxRecordingStorageBytes) {
- // First, attempt to reduce cache without flushing
- size_t tryFree = storageAllocated - fMaxRecordingStorageBytes;
- if (this->freeMemoryIfPossible(tryFree) < tryFree) {
- // Flush is necessary to free more space.
- this->flushPendingCommands(kNormal_PlaybackMode);
- // Free as much as possible to avoid oscillating around fMaxRecordingStorageBytes
- // which could cause a high flushing frequency.
- this->freeMemoryIfPossible(~0U);
- }
- storageAllocated = this->storageAllocatedForRecording();
- }
-
- if (fNotificationClient &&
- storageAllocated != fPreviousStorageAllocated) {
- fPreviousStorageAllocated = storageAllocated;
- fNotificationClient->storageAllocatedForRecordingChanged(storageAllocated);
- }
-}
-
-SkCanvas* SkDeferredDevice::recordingCanvas() {
- return fRecordingCanvas;
-}
-
-SkImage* SkDeferredDevice::newImageSnapshot() {
- this->flush();
- return fSurface ? fSurface->newImageSnapshot() : NULL;
-}
-
-SkImageInfo SkDeferredDevice::imageInfo() const {
- return immediateDevice()->imageInfo();
-}
-
-GrRenderTarget* SkDeferredDevice::accessRenderTarget() {
- this->flushPendingCommands(kNormal_PlaybackMode);
- return immediateDevice()->accessRenderTarget();
-}
-
-void SkDeferredDevice::prepareForImmediatePixelWrite() {
- // The purpose of the following code is to make sure commands are flushed, that
- // aboutToDraw() is called and that notifyContentWillChange is called, without
- // calling anything redundantly.
- if (fPipeController.hasPendingCommands()) {
- this->flushPendingCommands(kNormal_PlaybackMode);
- } else {
- bool mustNotifyDirectly = !fCanDiscardCanvasContents;
- this->aboutToDraw();
- if (mustNotifyDirectly) {
- fSurface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
- }
- }
-
- fImmediateCanvas->flush();
-}
-
-bool SkDeferredDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
- int x, int y) {
- SkASSERT(x >= 0 && y >= 0);
- SkASSERT(x + info.width() <= width());
- SkASSERT(y + info.height() <= height());
-
- const SkImageInfo deviceInfo = this->imageInfo();
- if (info.width() == deviceInfo.width() && info.height() == deviceInfo.height()) {
- this->skipPendingCommands();
- } else {
- this->flushPendingCommands(kNormal_PlaybackMode);
- }
-
- this->prepareForImmediatePixelWrite();
- return immediateDevice()->onWritePixels(info, pixels, rowBytes, x, y);
-}
-
-const SkBitmap& SkDeferredDevice::onAccessBitmap() {
- this->flushPendingCommands(kNormal_PlaybackMode);
- return immediateDevice()->accessBitmap(false);
-}
-
-SkBaseDevice* SkDeferredDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint* layerPaint) {
- // Create a compatible non-deferred device.
- // We do not create a deferred device because we know the new device
- // will not be used with a deferred canvas (there is no API for that).
- // And connecting a SkDeferredDevice to non-deferred canvas can result
- // in unpredictable behavior.
- return this->immediateDevice()->onCreateDevice(cinfo, layerPaint);
-}
-
-SkSurface* SkDeferredDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
- return this->immediateDevice()->newSurface(info, props);
-}
-
-bool SkDeferredDevice::onReadPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
- int x, int y) {
- this->flushPendingCommands(kNormal_PlaybackMode);
- return fImmediateCanvas->readPixels(info, pixels, rowBytes, x, y);
-}
-
-class AutoImmediateDrawIfNeeded {
-public:
- AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap* bitmap,
- const SkPaint* paint) {
- this->init(canvas, bitmap, NULL, paint);
- }
- AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkImage* image,
- const SkPaint* paint) {
- this->init(canvas, NULL, image, paint);
- }
-
- AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkPaint* paint) {
- this->init(canvas, NULL, NULL, paint);
- }
-
- ~AutoImmediateDrawIfNeeded() {
- if (fCanvas) {
- fCanvas->setDeferredDrawing(true);
- }
- }
-private:
- void init(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkImage* image,
- const SkPaint* paint) {
- if (canvas.isDeferredDrawing() &&
- should_draw_immediately(bitmap, image, paint, canvas.getBitmapSizeThreshold())) {
- canvas.setDeferredDrawing(false);
- fCanvas = &canvas;
- } else {
- fCanvas = NULL;
- }
- }
-
- SkDeferredCanvas* fCanvas;
-};
-
-SkDeferredCanvas* SkDeferredCanvas::Create(SkSurface* surface) {
- if (!surface) {
- return NULL;
- }
-
- SkAutoTUnref<SkDeferredDevice> deferredDevice(SkNEW_ARGS(SkDeferredDevice, (surface)));
- return SkNEW_ARGS(SkDeferredCanvas, (deferredDevice));
-}
-
-SkDeferredCanvas::SkDeferredCanvas(SkDeferredDevice* device) : SkCanvas (device) {
- this->init();
-}
-
-void SkDeferredCanvas::init() {
- fBitmapSizeThreshold = kDeferredCanvasBitmapSizeThreshold;
- fDeferredDrawing = true; // On by default
- fCachedCanvasSize.setEmpty();
- fCachedCanvasSizeDirty = true;
- fSaveLevel = 0;
- fFirstSaveLayerIndex = kNoSaveLayerIndex;
-}
-
-void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) {
- this->validate();
- this->getDeferredDevice()->setMaxRecordingStorage(maxStorage);
-}
-
-size_t SkDeferredCanvas::storageAllocatedForRecording() const {
- return this->getDeferredDevice()->storageAllocatedForRecording();
-}
-
-size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) {
- return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree);
-}
-
-void SkDeferredCanvas::setBitmapSizeThreshold(size_t sizeThreshold) {
- fBitmapSizeThreshold = sizeThreshold;
-}
-
-void SkDeferredCanvas::recordedDrawCommand() {
- if (fDeferredDrawing) {
- this->getDeferredDevice()->recordedDrawCommand();
- }
-}
-
-void SkDeferredCanvas::validate() const {
- SkASSERT(this->getDevice());
-}
-
-SkCanvas* SkDeferredCanvas::drawingCanvas() const {
- this->validate();
- return fDeferredDrawing ? this->getDeferredDevice()->recordingCanvas() :
- this->getDeferredDevice()->immediateCanvas();
-}
-
-SkCanvas* SkDeferredCanvas::immediateCanvas() const {
- this->validate();
- return this->getDeferredDevice()->immediateCanvas();
-}
-
-SkDeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
- return static_cast<SkDeferredDevice*>(this->getDevice());
-}
-
-void SkDeferredCanvas::setDeferredDrawing(bool val) {
- this->validate(); // Must set device before calling this method
- if (val != fDeferredDrawing) {
- if (fDeferredDrawing) {
- // Going live.
- this->getDeferredDevice()->flushPendingCommands(kNormal_PlaybackMode);
- }
- fDeferredDrawing = val;
- }
-}
-
-bool SkDeferredCanvas::isDeferredDrawing() const {
- return fDeferredDrawing;
-}
-
-bool SkDeferredCanvas::isFreshFrame() const {
- return this->getDeferredDevice()->isFreshFrame();
-}
-
-SkISize SkDeferredCanvas::getCanvasSize() const {
- if (fCachedCanvasSizeDirty) {
- fCachedCanvasSize = this->getBaseLayerSize();
- fCachedCanvasSizeDirty = false;
- }
- return fCachedCanvasSize;
-}
-
-bool SkDeferredCanvas::hasPendingCommands() const {
- return this->getDeferredDevice()->hasPendingCommands();
-}
-
-void SkDeferredCanvas::silentFlush() {
- if (fDeferredDrawing) {
- this->getDeferredDevice()->flushPendingCommands(kSilent_PlaybackMode);
- }
-}
-
-SkDeferredCanvas::~SkDeferredCanvas() {
-}
-
-SkSurface* SkDeferredCanvas::setSurface(SkSurface* surface) {
- SkDeferredDevice* deferredDevice = this->getDeferredDevice();
- SkASSERT(deferredDevice);
- // By swapping the surface into the existing device, we preserve
- // all pending commands, which can help to seamlessly recover from
- // a lost accelerated graphics context.
- deferredDevice->setSurface(surface);
- fCachedCanvasSizeDirty = true;
- return surface;
-}
-
-SkDeferredCanvas::NotificationClient* SkDeferredCanvas::setNotificationClient(
- NotificationClient* notificationClient) {
-
- SkDeferredDevice* deferredDevice = this->getDeferredDevice();
- SkASSERT(deferredDevice);
- if (deferredDevice) {
- deferredDevice->setNotificationClient(notificationClient);
- }
- return notificationClient;
-}
-
-SkImage* SkDeferredCanvas::newImageSnapshot() {
- SkDeferredDevice* deferredDevice = this->getDeferredDevice();
- SkASSERT(deferredDevice);
- return deferredDevice ? deferredDevice->newImageSnapshot() : NULL;
-}
-
-bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
- const SkPaint* paint) const {
- SkCanvas* canvas = this->drawingCanvas();
- SkISize canvasSize = this->getCanvasSize();
- if (rect) {
- if (!canvas->getTotalMatrix().rectStaysRect()) {
- return false; // conservative
- }
-
- SkRect transformedRect;
- canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
-
- 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
- }
- }
-
- // The following test holds with AA enabled, and is conservative
- // by a 0.5 pixel margin with AA disabled
- if (transformedRect.fLeft > SkIntToScalar(0) ||
- transformedRect.fTop > SkIntToScalar(0) ||
- transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
- transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
- return false;
- }
- }
-
- return this->getClipStack()->quickContains(SkRect::MakeXYWH(0, 0,
- SkIntToScalar(canvasSize.fWidth), SkIntToScalar(canvasSize.fHeight)));
-}
-
-void SkDeferredCanvas::willSave() {
- fSaveLevel++;
- this->drawingCanvas()->save();
- this->recordedDrawCommand();
- this->INHERITED::willSave();
-}
-
-SkCanvas::SaveLayerStrategy SkDeferredCanvas::willSaveLayer(const SkRect* bounds,
- const SkPaint* paint, SaveFlags flags) {
- fSaveLevel++;
- if (fFirstSaveLayerIndex == kNoSaveLayerIndex) {
- fFirstSaveLayerIndex = fSaveLevel;
- this->getDeferredDevice()->setIsDrawingToLayer(true);
- }
- this->drawingCanvas()->saveLayer(bounds, paint, flags);
- this->recordedDrawCommand();
- this->INHERITED::willSaveLayer(bounds, paint, flags);
- // No need for a full layer.
- return kNoLayer_SaveLayerStrategy;
-}
-
-void SkDeferredCanvas::willRestore() {
- SkASSERT(fFirstSaveLayerIndex == kNoSaveLayerIndex || fFirstSaveLayerIndex <= fSaveLevel);
- if (fFirstSaveLayerIndex == fSaveLevel) {
- fFirstSaveLayerIndex = kNoSaveLayerIndex;
- this->getDeferredDevice()->setIsDrawingToLayer(false);
- }
- fSaveLevel--;
- this->drawingCanvas()->restore();
- this->recordedDrawCommand();
- this->INHERITED::willRestore();
-}
-
-void SkDeferredCanvas::didConcat(const SkMatrix& matrix) {
- this->drawingCanvas()->concat(matrix);
- this->recordedDrawCommand();
- this->INHERITED::didConcat(matrix);
-}
-
-void SkDeferredCanvas::didSetMatrix(const SkMatrix& matrix) {
- this->drawingCanvas()->setMatrix(matrix);
- this->recordedDrawCommand();
- this->INHERITED::didSetMatrix(matrix);
-}
-
-void SkDeferredCanvas::onClipRect(const SkRect& rect,
- SkRegion::Op op,
- ClipEdgeStyle edgeStyle) {
- this->drawingCanvas()->clipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
- this->INHERITED::onClipRect(rect, op, edgeStyle);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onClipRRect(const SkRRect& rrect,
- SkRegion::Op op,
- ClipEdgeStyle edgeStyle) {
- this->drawingCanvas()->clipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
- this->INHERITED::onClipRRect(rrect, op, edgeStyle);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onClipPath(const SkPath& path,
- SkRegion::Op op,
- ClipEdgeStyle edgeStyle) {
- this->drawingCanvas()->clipPath(path, op, kSoft_ClipEdgeStyle == edgeStyle);
- this->INHERITED::onClipPath(path, op, edgeStyle);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
- this->drawingCanvas()->clipRegion(deviceRgn, op);
- this->INHERITED::onClipRegion(deviceRgn, op);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawPaint(const SkPaint& paint) {
- if (fDeferredDrawing && this->isFullFrame(NULL, &paint) && SkPaintPriv::Overwrites(paint)) {
- this->getDeferredDevice()->skipPendingCommands();
- }
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawPaint(paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawPoints(PointMode mode, size_t count,
- const SkPoint pts[], const SkPaint& paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawPoints(mode, count, pts, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawOval(rect, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
- if (fDeferredDrawing && this->isFullFrame(&rect, &paint) && SkPaintPriv::Overwrites(paint)) {
- this->getDeferredDevice()->skipPendingCommands();
- }
-
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawRect(rect, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
- if (rrect.isRect()) {
- this->SkDeferredCanvas::drawRect(rrect.getBounds(), paint);
- } else if (rrect.isOval()) {
- this->SkDeferredCanvas::drawOval(rrect.getBounds(), paint);
- } else {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawRRect(rrect, paint);
- this->recordedDrawCommand();
- }
-}
-
-void SkDeferredCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
- const SkPaint& paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawDRRect(outer, inner, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawPath(path, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar left,
- SkScalar top, const SkPaint* paint) {
- SkRect bitmapRect = SkRect::MakeXYWH(left, top,
- SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
- if (fDeferredDrawing &&
- this->isFullFrame(&bitmapRect, paint) &&
- SkPaintPriv::Overwrites(bitmap, paint)) {
- this->getDeferredDevice()->skipPendingCommands();
- }
-
- AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
- this->drawingCanvas()->drawBitmap(bitmap, left, top, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
- const SkRect& dst, const SkPaint* paint,
- SrcRectConstraint constraint) {
- if (fDeferredDrawing &&
- this->isFullFrame(&dst, paint) &&
- SkPaintPriv::Overwrites(bitmap, paint)) {
- this->getDeferredDevice()->skipPendingCommands();
- }
-
- AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
- this->drawingCanvas()->legacy_drawBitmapRect(bitmap, src, dst, paint, (SrcRectConstraint)constraint);
- this->recordedDrawCommand();
-}
-
-
-void SkDeferredCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
- const SkPaint* paint) {
- SkRect bounds = SkRect::MakeXYWH(x, y,
- SkIntToScalar(image->width()), SkIntToScalar(image->height()));
- if (fDeferredDrawing &&
- this->isFullFrame(&bounds, paint) &&
- SkPaintPriv::Overwrites(image, paint)) {
- this->getDeferredDevice()->skipPendingCommands();
- }
-
- AutoImmediateDrawIfNeeded autoDraw(*this, image, paint);
- this->drawingCanvas()->drawImage(image, x, y, paint);
- this->recordedDrawCommand();
-}
-void SkDeferredCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint constraint) {
- if (fDeferredDrawing &&
- this->isFullFrame(&dst, paint) &&
- SkPaintPriv::Overwrites(image, paint)) {
- this->getDeferredDevice()->skipPendingCommands();
- }
-
- AutoImmediateDrawIfNeeded autoDraw(*this, image, paint);
- this->drawingCanvas()->legacy_drawImageRect(image, src, dst, paint, constraint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center,
- const SkRect& dst, const SkPaint* paint) {
- if (fDeferredDrawing &&
- this->isFullFrame(&dst, paint) &&
- SkPaintPriv::Overwrites(image, paint)) {
- this->getDeferredDevice()->skipPendingCommands();
- }
-
- AutoImmediateDrawIfNeeded autoDraw(*this, image, paint);
- this->drawingCanvas()->drawImageNine(image, center, dst, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawBitmapNine(const SkBitmap& bitmap,
- const SkIRect& center, const SkRect& dst,
- const SkPaint* paint) {
- // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
- // covers canvas entirely and dst covers canvas entirely
- AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
- this->drawingCanvas()->drawBitmapNine(bitmap, center, dst, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint) {
- SkRect bitmapRect = SkRect::MakeXYWH(
- SkIntToScalar(left),
- SkIntToScalar(top),
- SkIntToScalar(bitmap.width()),
- SkIntToScalar(bitmap.height()));
- if (fDeferredDrawing &&
- this->isFullFrame(&bitmapRect, paint) &&
- SkPaintPriv::Overwrites(bitmap, paint)) {
- this->getDeferredDevice()->skipPendingCommands();
- }
-
- AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
- this->drawingCanvas()->drawSprite(bitmap, left, top, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
- const SkPaint& paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawText(text, byteLength, x, y, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
- const SkPaint& paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawPosText(text, byteLength, pos, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
- SkScalar constY, const SkPaint& paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
- const SkMatrix* matrix, const SkPaint& paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
- const SkPaint& paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawTextBlob(blob, x, y, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
- const SkPaint* paint) {
- this->drawingCanvas()->drawPicture(picture, matrix, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
- const SkPoint vertices[],
- const SkPoint texs[],
- const SkColor colors[], SkXfermode* xmode,
- const uint16_t indices[], int indexCount,
- const SkPaint& paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
- indices, indexCount, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
- const SkPoint texCoords[4], SkXfermode* xmode,
- const SkPaint& paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawPatch(cubics, colors, texCoords, xmode, paint);
- this->recordedDrawCommand();
-}
-
-void SkDeferredCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[],
- const SkRect tex[], const SkColor colors[], int count,
- SkXfermode::Mode mode, const SkRect* cullRect,
- const SkPaint* paint) {
- AutoImmediateDrawIfNeeded autoDraw(*this, paint);
- this->drawingCanvas()->drawAtlas(atlas, xform, tex, colors, count, mode, cullRect, paint);
- this->recordedDrawCommand();
-}
-
-SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
- this->drawingCanvas()->setDrawFilter(filter);
- this->INHERITED::setDrawFilter(filter);
- this->recordedDrawCommand();
- return filter;
-}
-
-SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
- return this->drawingCanvas();
-}
diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp
index 5aa3d46628..c80e6bef95 100644
--- a/tests/CanvasTest.cpp
+++ b/tests/CanvasTest.cpp
@@ -46,7 +46,6 @@
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkClipStack.h"
-#include "SkDeferredCanvas.h"
#include "SkDevice.h"
#include "SkDocument.h"
#include "SkMatrix.h"
@@ -72,12 +71,6 @@ static void createBitmap(SkBitmap* bm, SkColor color) {
bm->eraseColor(color);
}
-static SkSurface* createSurface(SkColor color) {
- SkSurface* surface = SkSurface::NewRasterN32Premul(kWidth, kHeight);
- surface->getCanvas()->clear(color);
- return surface;
-}
-
///////////////////////////////////////////////////////////////////////////////
// Constants used by test steps
const SkPoint kTestPoints[] = {
@@ -239,16 +232,8 @@ static void test_clipstack(skiatest::Reporter* reporter) {
static const char* const kDefaultAssertMessageFormat = "%s";
static const char* const kCanvasDrawAssertMessageFormat =
"Drawing test step %s with SkCanvas";
-static const char* const kDeferredDrawAssertMessageFormat =
- "Drawing test step %s with SkDeferredCanvas";
static const char* const kNWayDrawAssertMessageFormat =
"Drawing test step %s with SkNWayCanvas";
-static const char* const kDeferredPreFlushAssertMessageFormat =
- "test step %s, SkDeferredCanvas state consistency before flush";
-static const char* const kDeferredPostFlushPlaybackAssertMessageFormat =
- "test step %s, SkDeferredCanvas playback canvas state consistency after flush";
-static const char* const kDeferredPostSilentFlushPlaybackAssertMessageFormat =
- "test step %s, SkDeferredCanvas playback canvas state consistency after silent flush";
static const char* const kNWayStateAssertMessageFormat =
"test step %s, SkNWayCanvas state consistency";
static const char* const kNWayIndirect1StateAssertMessageFormat =
@@ -586,49 +571,6 @@ static void TestPdfDevice(skiatest::Reporter* reporter,
REPORTER_ASSERT(reporter, doc->close());
}
-// The following class groups static functions that need to access
-// the privates members of SkDeferredCanvas
-class SkDeferredCanvasTester {
-public:
- static void TestDeferredCanvasStateConsistency(
- skiatest::Reporter* reporter,
- const TestData& d,
- CanvasTestStep* testStep,
- const SkCanvas& referenceCanvas, bool silent) {
-
- SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF));
- SkAutoTUnref<SkDeferredCanvas> deferredCanvas(SkDeferredCanvas::Create(surface.get()));
-
- testStep->setAssertMessageFormat(kDeferredDrawAssertMessageFormat);
- testStep->draw(deferredCanvas, d, reporter);
- testStep->setAssertMessageFormat(kDeferredPreFlushAssertMessageFormat);
- AssertCanvasStatesEqual(reporter, d, deferredCanvas, &referenceCanvas, testStep);
-
- if (silent) {
- deferredCanvas->silentFlush();
- } else {
- deferredCanvas->flush();
- }
-
- testStep->setAssertMessageFormat(
- silent ? kDeferredPostSilentFlushPlaybackAssertMessageFormat :
- kDeferredPostFlushPlaybackAssertMessageFormat);
- AssertCanvasStatesEqual(reporter, d, deferredCanvas->immediateCanvas(),
- &referenceCanvas, testStep);
-
- // Verified that deferred canvas state is not affected by flushing
- // pending draw operations
-
- // The following test code is commented out because it currently fails.
- // Issue: http://code.google.com/p/skia/issues/detail?id=496
- /*
- testStep->setAssertMessageFormat(kDeferredPostFlushAssertMessageFormat);
- AssertCanvasStatesEqual(reporter, &deferredCanvas, &referenceCanvas,
- testStep);
- */
- }
-};
-
// unused
static void TestNWayCanvasStateConsistency(
skiatest::Reporter* reporter,
@@ -675,10 +617,6 @@ static void TestOverrideStateConsistency(skiatest::Reporter* reporter, const Tes
testStep->setAssertMessageFormat(kCanvasDrawAssertMessageFormat);
testStep->draw(&referenceCanvas, d, reporter);
- SkDeferredCanvasTester::TestDeferredCanvasStateConsistency(reporter, d, testStep, referenceCanvas, false);
-
- SkDeferredCanvasTester::TestDeferredCanvasStateConsistency(reporter, d, testStep, referenceCanvas, true);
-
// The following test code is disabled because SkNWayCanvas does not
// report correct clipping and device bounds information
// Issue: http://code.google.com/p/skia/issues/detail?id=501
diff --git a/tests/DeferredCanvasTest.cpp b/tests/DeferredCanvasTest.cpp
deleted file mode 100644
index 600315ea2c..0000000000
--- a/tests/DeferredCanvasTest.cpp
+++ /dev/null
@@ -1,949 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "../src/image/SkImagePriv.h"
-#include "../src/image/SkSurface_Base.h"
-#include "SkBitmap.h"
-#include "SkBitmapProcShader.h"
-#include "SkDeferredCanvas.h"
-#include "SkGradientShader.h"
-#include "SkPath.h"
-#include "SkShader.h"
-#include "SkSurface.h"
-#include "Test.h"
-#include "sk_tool_utils.h"
-
-#if SK_SUPPORT_GPU
-#include "GrContextFactory.h"
-#else
-class GrContextFactory;
-#endif
-
-static const int gWidth = 2;
-static const int gHeight = 2;
-
-static void create(SkBitmap* bm, SkColor color) {
- bm->allocN32Pixels(gWidth, gHeight);
- bm->eraseColor(color);
-}
-
-static SkSurface* createSurface(SkColor color) {
- SkSurface* surface = SkSurface::NewRasterN32Premul(gWidth, gHeight);
- surface->getCanvas()->clear(color);
- return surface;
-}
-
-static SkPMColor read_pixel(SkSurface* surface, int x, int y) {
- SkPMColor pixel = 0;
- SkBitmap bitmap;
- bitmap.installPixels(SkImageInfo::MakeN32Premul(1, 1), &pixel, 4);
- SkCanvas canvas(bitmap);
-
- SkPaint paint;
- paint.setXfermodeMode(SkXfermode::kSrc_Mode);
- surface->draw(&canvas, -SkIntToScalar(x), -SkIntToScalar(y), &paint);
- return pixel;
-}
-
-class MockSurface : public SkSurface_Base {
-public:
- MockSurface(int width, int height) : SkSurface_Base(width, height, NULL) {
- clearCounts();
- fBitmap.allocN32Pixels(width, height);
- }
-
- SkCanvas* onNewCanvas() override {
- return SkNEW_ARGS(SkCanvas, (fBitmap));
- }
-
- SkSurface* onNewSurface(const SkImageInfo&) override {
- return NULL;
- }
-
- SkImage* onNewImageSnapshot(Budgeted) override {
- return SkNewImageFromRasterBitmap(fBitmap, &this->props());
- }
-
- void onCopyOnWrite(ContentChangeMode mode) override {
- if (mode == SkSurface::kDiscard_ContentChangeMode) {
- fCOWDiscardCount++;
- } else {
- fCOWRetainCount++;
- }
- }
-
- void onDiscard() override {
- fDiscardCount++;
- }
-
- void clearCounts() {
- fCOWDiscardCount = 0;
- fCOWRetainCount = 0;
- fDiscardCount = 0;
- }
-
- int fCOWDiscardCount;
- int fCOWRetainCount;
- int fDiscardCount;
- SkBitmap fBitmap;
-};
-
-static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter) {
- SkAutoTUnref<MockSurface> surface(SkNEW_ARGS(MockSurface, (10, 10)));
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
-
- SkBitmap srcBitmap;
- srcBitmap.allocPixels(SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType));
- srcBitmap.eraseColor(SK_ColorGREEN);
- // Tests below depend on this bitmap being recognized as opaque
-
- // Preliminary sanity check: no copy on write if no active snapshot
- // Discard notification happens on SkSurface::onDiscard, since no
- // active snapshot.
- surface->clearCounts();
- canvas->clear(SK_ColorWHITE);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->flush();
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
-
- // Case 1: Discard notification happens upon flushing
- // with an Image attached.
- surface->clearCounts();
- SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->clear(SK_ColorWHITE);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->flush();
- REPORTER_ASSERT(reporter, 1 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- // Case 2: Opaque writePixels
- surface->clearCounts();
- SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- // Case 3: writePixels that partially covers the canvas
- surface->clearCounts();
- SkAutoTUnref<SkImage> image3(canvas->newImageSnapshot());
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- // Case 4: unpremultiplied opaque writePixels that entirely
- // covers the canvas
- surface->clearCounts();
- SkAutoTUnref<SkImage> image4(canvas->newImageSnapshot());
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->writePixels(srcBitmap, 0, 0);
- REPORTER_ASSERT(reporter, 1 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->flush();
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- // Case 5: unpremultiplied opaque writePixels that partially
- // covers the canvas
- surface->clearCounts();
- SkAutoTUnref<SkImage> image5(canvas->newImageSnapshot());
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->writePixels(srcBitmap, 5, 0);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 1 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->flush();
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- // Case 6: unpremultiplied opaque writePixels that entirely
- // covers the canvas, preceded by clear
- surface->clearCounts();
- SkAutoTUnref<SkImage> image6(canvas->newImageSnapshot());
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->clear(SK_ColorWHITE);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->writePixels(srcBitmap, 0, 0);
- REPORTER_ASSERT(reporter, 1 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->flush();
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- // Case 7: unpremultiplied opaque writePixels that partially
- // covers the canvas, preceeded by a clear
- surface->clearCounts();
- SkAutoTUnref<SkImage> image7(canvas->newImageSnapshot());
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->clear(SK_ColorWHITE);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->writePixels(srcBitmap, 5, 0);
- REPORTER_ASSERT(reporter, 1 == surface->fCOWDiscardCount); // because of the clear
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->flush();
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- // Case 8: unpremultiplied opaque writePixels that partially
- // covers the canvas, preceeded by a drawREct that partially
- // covers the canvas
- surface->clearCounts();
- SkAutoTUnref<SkImage> image8(canvas->newImageSnapshot());
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- SkPaint paint;
- canvas->drawRect(SkRect::MakeLTRB(0, 0, 5, 5), paint);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->writePixels(srcBitmap, 5, 0);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 1 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-
- surface->clearCounts();
- canvas->flush();
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount);
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount);
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
-}
-
-static void TestDeferredCanvasFlush(skiatest::Reporter* reporter) {
- SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF));
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
-
- canvas->clear(0x00000000);
-
- // verify that clear was deferred
- REPORTER_ASSERT(reporter, 0xFFFFFFFF == read_pixel(surface, 0, 0));
-
- canvas->flush();
-
- // verify that clear was executed
- REPORTER_ASSERT(reporter, 0 == read_pixel(surface, 0, 0));
-}
-
-static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) {
- SkRect fullRect;
- fullRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth),
- SkIntToScalar(gHeight));
- SkRect partialRect;
- partialRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0),
- SkIntToScalar(1), SkIntToScalar(1));
-
- SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF));
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
-
- // verify that frame is intially fresh
- REPORTER_ASSERT(reporter, canvas->isFreshFrame());
- // no clearing op since last call to isFreshFrame -> not fresh
- REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
-
- // Verify that clear triggers a fresh frame
- canvas->clear(0x00000000);
- REPORTER_ASSERT(reporter, canvas->isFreshFrame());
-
- // Verify that clear with saved state triggers a fresh frame
- canvas->save();
- canvas->clear(0x00000000);
- canvas->restore();
- REPORTER_ASSERT(reporter, canvas->isFreshFrame());
-
- // Verify that clear within a layer does NOT trigger a fresh frame
- canvas->saveLayer(NULL, NULL);
- canvas->clear(0x00000000);
- canvas->restore();
- REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
-
- // Verify that full frame rects with different forms of opaque paint
- // trigger frames to be marked as fresh
- {
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setAlpha(255);
- canvas->drawRect(fullRect, paint);
- REPORTER_ASSERT(reporter, canvas->isFreshFrame());
- }
- {
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setAlpha(255);
- paint.setXfermodeMode(SkXfermode::kSrcIn_Mode);
- canvas->drawRect(fullRect, paint);
- REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
- }
- {
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- SkBitmap bmp;
- create(&bmp, 0xFFFFFFFF);
- bmp.setAlphaType(kOpaque_SkAlphaType);
- SkShader* shader = SkShader::CreateBitmapShader(bmp,
- SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
- paint.setShader(shader)->unref();
- canvas->drawRect(fullRect, paint);
- REPORTER_ASSERT(reporter, canvas->isFreshFrame());
- }
-
- // Verify that full frame rects with different forms of non-opaque paint
- // do not trigger frames to be marked as fresh
- {
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setAlpha(254);
- canvas->drawRect(fullRect, paint);
- REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
- }
- {
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- // Defining a cone that partially overlaps the canvas
- const SkPoint pt1 = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0));
- const SkScalar r1 = SkIntToScalar(1);
- const SkPoint pt2 = SkPoint::Make(SkIntToScalar(10), SkIntToScalar(0));
- const SkScalar r2 = SkIntToScalar(5);
- const SkColor colors[2] = {SK_ColorWHITE, SK_ColorWHITE};
- const SkScalar pos[2] = {0, SK_Scalar1};
- SkShader* shader = SkGradientShader::CreateTwoPointConical(
- pt1, r1, pt2, r2, colors, pos, 2, SkShader::kClamp_TileMode);
- paint.setShader(shader)->unref();
- canvas->drawRect(fullRect, paint);
- REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
- }
- {
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- SkBitmap bmp;
- create(&bmp, 0xFFFFFFFF);
- bmp.setAlphaType(kPremul_SkAlphaType);
- SkShader* shader = SkShader::CreateBitmapShader(bmp,
- SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
- paint.setShader(shader)->unref();
- canvas->drawRect(fullRect, paint);
- REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
- }
-
- // Verify that incomplete coverage does not trigger a fresh frame
- {
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setAlpha(255);
- canvas->drawRect(partialRect, paint);
- REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
- }
-
- // Verify that incomplete coverage due to clipping does not trigger a fresh
- // frame
- {
- canvas->save();
- canvas->clipRect(partialRect, SkRegion::kIntersect_Op, false);
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setAlpha(255);
- canvas->drawRect(fullRect, paint);
- canvas->restore();
- REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
- }
- {
- canvas->save();
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setAlpha(255);
- SkPath path;
- path.addCircle(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(2));
- canvas->clipPath(path, SkRegion::kIntersect_Op, false);
- canvas->drawRect(fullRect, paint);
- canvas->restore();
- REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
- }
-
- // Verify that stroked rect does not trigger a fresh frame
- {
- SkPaint paint;
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setAlpha(255);
- canvas->drawRect(fullRect, paint);
- REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
- }
-
- // Verify kSrcMode triggers a fresh frame even with transparent color
- {
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setAlpha(100);
- paint.setXfermodeMode(SkXfermode::kSrc_Mode);
- canvas->drawRect(fullRect, paint);
- REPORTER_ASSERT(reporter, canvas->isFreshFrame());
- }
-}
-
-class NotificationCounter : public SkDeferredCanvas::NotificationClient {
-public:
- NotificationCounter() {
- fPrepareForDrawCount = fStorageAllocatedChangedCount =
- fFlushedDrawCommandsCount = fSkippedPendingDrawCommandsCount = 0;
- }
-
- void prepareForDraw() override {
- fPrepareForDrawCount++;
- }
- void storageAllocatedForRecordingChanged(size_t) override {
- fStorageAllocatedChangedCount++;
- }
- void flushedDrawCommands() override {
- fFlushedDrawCommandsCount++;
- }
- void skippedPendingDrawCommands() override {
- fSkippedPendingDrawCommandsCount++;
- }
-
- int fPrepareForDrawCount;
- int fStorageAllocatedChangedCount;
- int fFlushedDrawCommandsCount;
- int fSkippedPendingDrawCommandsCount;
-
-private:
- typedef SkDeferredCanvas::NotificationClient INHERITED;
-};
-
-// Verifies that the deferred canvas triggers a flush when its memory
-// limit is exceeded
-static void TestDeferredCanvasMemoryLimit(skiatest::Reporter* reporter) {
- SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(100, 100));
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
-
- NotificationCounter notificationCounter;
- canvas->setNotificationClient(&notificationCounter);
-
- canvas->setMaxRecordingStorage(160000);
-
- SkBitmap sourceImage;
- // 100 by 100 image, takes 40,000 bytes in memory
- sourceImage.allocN32Pixels(100, 100);
- sourceImage.eraseColor(SK_ColorGREEN);
-
- for (int i = 0; i < 5; i++) {
- sourceImage.notifyPixelsChanged(); // to force re-serialization
- canvas->drawBitmap(sourceImage, 0, 0, NULL);
- }
-
- REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
-}
-
-static void TestDeferredCanvasSilentFlush(skiatest::Reporter* reporter) {
- SkAutoTUnref<SkSurface> surface(createSurface(0));
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
-
- NotificationCounter notificationCounter;
- canvas->setNotificationClient(&notificationCounter);
-
- canvas->silentFlush(); // will skip the initial clear that was recorded in createSurface
-
- REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
- REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
-}
-
-static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
- SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(100, 100));
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
-
- NotificationCounter notificationCounter;
- canvas->setNotificationClient(&notificationCounter);
-
- const int imageCount = 2;
- SkBitmap sourceImages[imageCount];
- for (int i = 0; i < imageCount; i++) {
- sourceImages[i].allocN32Pixels(100, 100);
- sourceImages[i].eraseColor(SK_ColorGREEN);
- }
-
- size_t bitmapSize = sourceImages[0].getSize();
-
- canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
- REPORTER_ASSERT(reporter, 1 == notificationCounter.fStorageAllocatedChangedCount);
- // stored bitmap + drawBitmap command
- REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > bitmapSize);
-
- // verify that nothing can be freed at this point
- REPORTER_ASSERT(reporter, 0 == canvas->freeMemoryIfPossible(~0U));
-
- // verify that flush leaves image in cache
- REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
- REPORTER_ASSERT(reporter, 0 == notificationCounter.fPrepareForDrawCount);
- canvas->flush();
- REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
- REPORTER_ASSERT(reporter, 1 == notificationCounter.fPrepareForDrawCount);
- REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() >= bitmapSize);
-
- // verify that after a flush, cached image can be freed
- REPORTER_ASSERT(reporter, canvas->freeMemoryIfPossible(~0U) >= bitmapSize);
-
- // Verify that caching works for avoiding multiple copies of the same bitmap
- canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
- REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
- canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
- REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
- REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
- REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < 2 * bitmapSize);
-
- // Verify partial eviction based on bytesToFree
- canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
- REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
- canvas->flush();
- REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
- REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2 * bitmapSize);
- size_t bytesFreed = canvas->freeMemoryIfPossible(1);
- REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
- REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
- REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
-
- // Verifiy that partial purge works, image zero is in cache but not reffed by
- // a pending draw, while image 1 is locked-in.
- canvas->freeMemoryIfPossible(~0U);
- REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
- canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
- canvas->flush();
- canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
- bytesFreed = canvas->freeMemoryIfPossible(~0U);
- // only one bitmap should have been freed.
- REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
- REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
- // Clear for next test
- canvas->flush();
- canvas->freeMemoryIfPossible(~0U);
- REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < bitmapSize);
-
- // Verify the image cache is sensitive to genID bumps
- canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
- sourceImages[1].notifyPixelsChanged();
- canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
- REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2*bitmapSize);
-
- // Verify that nothing in this test caused commands to be skipped
- REPORTER_ASSERT(reporter, 0 == notificationCounter.fSkippedPendingDrawCommandsCount);
-}
-
-static void TestDeferredCanvasSkip(skiatest::Reporter* reporter) {
- SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(100, 100));
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
-
- NotificationCounter notificationCounter;
- canvas->setNotificationClient(&notificationCounter);
- canvas->clear(0x0);
- REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
- REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
- canvas->flush();
- REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
- REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
-
-}
-
-static void TestDeferredCanvasBitmapShaderNoLeak(skiatest::Reporter* reporter) {
- // This is a regression test for crbug.com/155875
- // This test covers a code path that inserts bitmaps into the bitmap heap through the
- // flattening of SkBitmapProcShaders. The refcount in the bitmap heap is maintained through
- // the flattening and unflattening of the shader.
- SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(100, 100));
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
- // test will fail if nbIterations is not in sync with
- // BITMAPS_TO_KEEP in SkGPipeWrite.cpp
- const int nbIterations = 5;
- size_t bytesAllocated = 0;
- for(int pass = 0; pass < 2; ++pass) {
- for(int i = 0; i < nbIterations; ++i) {
- SkPaint paint;
- SkBitmap paintPattern;
- paintPattern.allocN32Pixels(10, 10);
- paintPattern.eraseColor(SK_ColorGREEN);
- paint.setShader(SkNEW_ARGS(SkBitmapProcShader,
- (paintPattern, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)))->unref();
- canvas->drawPaint(paint);
- canvas->flush();
-
- // In the first pass, memory allocation should be monotonically increasing as
- // the bitmap heap slots fill up. In the second pass memory allocation should be
- // stable as bitmap heap slots get recycled.
- size_t newBytesAllocated = canvas->storageAllocatedForRecording();
- if (pass == 0) {
- REPORTER_ASSERT(reporter, newBytesAllocated > bytesAllocated);
- bytesAllocated = newBytesAllocated;
- } else {
- REPORTER_ASSERT(reporter, newBytesAllocated == bytesAllocated);
- }
- }
- }
- // All cached resources should be evictable since last canvas call was flush()
- canvas->freeMemoryIfPossible(~0U);
- REPORTER_ASSERT(reporter, 0 == canvas->storageAllocatedForRecording());
-}
-
-static void TestDeferredCanvasBitmapSizeThreshold(skiatest::Reporter* reporter) {
- SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(100, 100));
-
- SkBitmap sourceImage;
- // 100 by 100 image, takes 40,000 bytes in memory
- sourceImage.allocN32Pixels(100, 100);
- sourceImage.eraseColor(SK_ColorGREEN);
-
- // 1 under : should not store the image
- {
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
- canvas->setBitmapSizeThreshold(39999);
- canvas->drawBitmap(sourceImage, 0, 0, NULL);
- size_t newBytesAllocated = canvas->storageAllocatedForRecording();
- REPORTER_ASSERT(reporter, newBytesAllocated == 0);
- }
-
- // exact value : should store the image
- {
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
- canvas->setBitmapSizeThreshold(40000);
- canvas->drawBitmap(sourceImage, 0, 0, NULL);
- size_t newBytesAllocated = canvas->storageAllocatedForRecording();
- REPORTER_ASSERT(reporter, newBytesAllocated > 0);
- }
-
- // 1 over : should still store the image
- {
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
- canvas->setBitmapSizeThreshold(40001);
- canvas->drawBitmap(sourceImage, 0, 0, NULL);
- size_t newBytesAllocated = canvas->storageAllocatedForRecording();
- REPORTER_ASSERT(reporter, newBytesAllocated > 0);
- }
-}
-
-static void TestDeferredCanvasImageFreeAfterFlush(skiatest::Reporter* reporter) {
- SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(100, 100));
- SkAutoTUnref<SkSurface> sourceSurface(SkSurface::NewRasterN32Premul(100, 100));
- SkAutoTUnref<SkImage> sourceImage(sourceSurface->newImageSnapshot());
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
-
- canvas->drawImage(sourceImage, 0, 0, NULL);
-
- size_t newBytesAllocated = canvas->storageAllocatedForRecording();
- REPORTER_ASSERT(reporter, newBytesAllocated > 0);
-
- canvas->flush();
-
- newBytesAllocated = canvas->storageAllocatedForRecording();
- REPORTER_ASSERT(reporter, newBytesAllocated == 0);
-}
-
-typedef const void* PixelPtr;
-// Returns an opaque pointer which, either points to a GrTexture or RAM pixel
-// buffer. Used to test pointer equality do determine whether a surface points
-// to the same pixel data storage as before.
-static PixelPtr get_surface_ptr(SkSurface* surface, bool useGpu) {
-#if SK_SUPPORT_GPU
- if (useGpu) {
- return surface->getCanvas()->internal_private_accessTopLayerRenderTarget()->asTexture();
- } else
-#endif
- {
- return surface->peekPixels(NULL, NULL);
- }
-}
-
-static void TestDeferredCanvasSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
- SkImageInfo imageSpec = SkImageInfo::MakeN32Premul(10, 10);
- bool useGpu = SkToBool(factory);
- int cnt;
-#if SK_SUPPORT_GPU
- if (useGpu) {
- cnt = GrContextFactory::kGLContextTypeCnt;
- } else {
- cnt = 1;
- }
-#else
- SkASSERT(!useGpu);
- cnt = 1;
-#endif
- for (int i = 0; i < cnt; ++i) {
- SkSurface* surface;
-#if SK_SUPPORT_GPU
- if (useGpu) {
- GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
- if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
- continue;
- }
- GrContext* context = factory->get(glCtxType);
- if (NULL == context) {
- return;
- }
-
- surface =
- SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, imageSpec, 0, NULL);
- } else
-#endif
- {
- surface = SkSurface::NewRaster(imageSpec);
- }
- SkASSERT(surface);
- SkAutoTUnref<SkSurface> aur(surface);
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface));
-
- SkImage* image1 = canvas->newImageSnapshot();
- SkAutoTUnref<SkImage> aur_i1(image1);
- PixelPtr pixels1 = get_surface_ptr(surface, useGpu);
- // The following clear would normally trigger a copy on write, but
- // it won't because rendering is deferred.
- canvas->clear(SK_ColorBLACK);
- // Obtaining a snapshot directly from the surface (as opposed to the
- // SkDeferredCanvas) will not trigger a flush of deferred draw operations
- // and will therefore return the same image as the previous snapshot.
- SkImage* image2 = surface->newImageSnapshot();
- SkAutoTUnref<SkImage> aur_i2(image2);
- // Images identical because of deferral
- REPORTER_ASSERT(reporter, image1->uniqueID() == image2->uniqueID());
- // Now we obtain a snpshot via the deferred canvas, which triggers a flush.
- // Because there is a pending clear, this will generate a different image.
- SkImage* image3 = canvas->newImageSnapshot();
- SkAutoTUnref<SkImage> aur_i3(image3);
- REPORTER_ASSERT(reporter, image1->uniqueID() != image3->uniqueID());
- // Verify that backing store is now a different buffer because of copy on
- // write
- PixelPtr pixels2 = get_surface_ptr(surface, useGpu);
- REPORTER_ASSERT(reporter, pixels1 != pixels2);
- // Verify copy-on write with a draw operation that gets deferred by
- // the in order draw buffer.
- SkPaint paint;
- canvas->drawPaint(paint);
- SkImage* image4 = canvas->newImageSnapshot(); // implicit flush
- SkAutoTUnref<SkImage> aur_i4(image4);
- REPORTER_ASSERT(reporter, image4->uniqueID() != image3->uniqueID());
- PixelPtr pixels3 = get_surface_ptr(surface, useGpu);
- REPORTER_ASSERT(reporter, pixels2 != pixels3);
- // Verify that a direct canvas flush with a pending draw does not trigger
- // a copy on write when the surface is not sharing its buffer with an
- // SkImage.
- canvas->clear(SK_ColorWHITE);
- canvas->flush();
- PixelPtr pixels4 = get_surface_ptr(surface, useGpu);
- canvas->drawPaint(paint);
- canvas->flush();
- PixelPtr pixels5 = get_surface_ptr(surface, useGpu);
- REPORTER_ASSERT(reporter, pixels4 == pixels5);
- }
-}
-
-static void TestDeferredCanvasSetSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
- SkImageInfo imageSpec = SkImageInfo::MakeN32Premul(10, 10);
- SkSurface* surface;
- SkSurface* alternateSurface;
- bool useGpu = SkToBool(factory);
- int cnt;
-#if SK_SUPPORT_GPU
- if (useGpu) {
- cnt = GrContextFactory::kGLContextTypeCnt;
- } else {
- cnt = 1;
- }
-#else
- SkASSERT(!useGpu);
- cnt = 1;
-#endif
-
- for (int i = 0; i < cnt; ++i) {
-#if SK_SUPPORT_GPU
- if (useGpu) {
- GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
- if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
- continue;
- }
- GrContext* context = factory->get(glCtxType);
- if (NULL == context) {
- continue;
- }
- surface =
- SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, imageSpec, 0, NULL);
- alternateSurface =
- SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, imageSpec, 0, NULL);
- } else
-#endif
- {
- surface = SkSurface::NewRaster(imageSpec);
- alternateSurface = SkSurface::NewRaster(imageSpec);
- }
- SkASSERT(surface);
- SkASSERT(alternateSurface);
- SkAutoTUnref<SkSurface> aur1(surface);
- SkAutoTUnref<SkSurface> aur2(alternateSurface);
- PixelPtr pixels1 = get_surface_ptr(surface, useGpu);
- PixelPtr pixels2 = get_surface_ptr(alternateSurface, useGpu);
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface));
- SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
- canvas->setSurface(alternateSurface);
- SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
- REPORTER_ASSERT(reporter, image1->uniqueID() != image2->uniqueID());
- // Verify that none of the above operations triggered a surface copy on write.
- REPORTER_ASSERT(reporter, get_surface_ptr(surface, useGpu) == pixels1);
- REPORTER_ASSERT(reporter, get_surface_ptr(alternateSurface, useGpu) == pixels2);
- // Verify that a flushed draw command will trigger a copy on write on alternateSurface.
- canvas->clear(SK_ColorWHITE);
- canvas->flush();
- REPORTER_ASSERT(reporter, get_surface_ptr(surface, useGpu) == pixels1);
- REPORTER_ASSERT(reporter, get_surface_ptr(alternateSurface, useGpu) != pixels2);
- }
-}
-
-static void TestDeferredCanvasCreateCompatibleDevice(skiatest::Reporter* reporter) {
- SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(100, 100));
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
-
- NotificationCounter notificationCounter;
- canvas->setNotificationClient(&notificationCounter);
-
- SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
- SkAutoTUnref<SkSurface> secondarySurface(canvas->newSurface(info));
-
- SkRect rect = SkRect::MakeWH(5, 5);
- SkPaint paint;
- // After spawning a compatible canvas:
- // 1) Verify that secondary canvas is usable and does not report to the notification client.
- surface->getCanvas()->drawRect(rect, paint);
- REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 0);
- // 2) Verify that original canvas is usable and still reports to the notification client.
- canvas->drawRect(rect, paint);
- REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 1);
-}
-
-static void TestDeferredCanvasGetCanvasSize(skiatest::Reporter* reporter) {
- SkRect rect;
- rect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth), SkIntToScalar(gHeight));
- SkRect clip;
- clip.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(1), SkIntToScalar(1));
-
- SkPaint paint;
- SkISize size = SkISize::Make(gWidth, gHeight);
-
- SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF));
- SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
- SkSurface* newSurface = SkSurface::NewRasterN32Premul(4, 4);
- SkAutoTUnref<SkSurface> aur(newSurface);
-
- for (int i = 0; i < 2; ++i) {
- if (i == 1) {
- canvas->setSurface(newSurface);
- size = SkISize::Make(4, 4);
- }
-
- // verify that canvas size is correctly initialized or set
- REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
-
- // Verify that clear, clip and draw the canvas will not change its size
- canvas->clear(0x00000000);
- canvas->clipRect(clip, SkRegion::kIntersect_Op, false);
- canvas->drawRect(rect, paint);
- REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
-
- // Verify that flush the canvas will not change its size
- canvas->flush();
- REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
-
- // Verify that clear canvas with saved state will not change its size
- canvas->save();
- canvas->clear(0xFFFFFFFF);
- REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
-
- // Verify that restore canvas state will not change its size
- canvas->restore();
- REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
-
- // Verify that clear within a layer will not change canvas size
- canvas->saveLayer(&clip, &paint);
- canvas->clear(0x00000000);
- REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
-
- // Verify that restore from a layer will not change canvas size
- canvas->restore();
- REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
- }
-}
-
-DEF_TEST(DeferredCanvas_CPU, reporter) {
- TestDeferredCanvasFlush(reporter);
- TestDeferredCanvasSilentFlush(reporter);
- TestDeferredCanvasFreshFrame(reporter);
- TestDeferredCanvasMemoryLimit(reporter);
- TestDeferredCanvasBitmapCaching(reporter);
- TestDeferredCanvasSkip(reporter);
- TestDeferredCanvasBitmapShaderNoLeak(reporter);
- TestDeferredCanvasBitmapSizeThreshold(reporter);
- TestDeferredCanvasImageFreeAfterFlush(reporter);
- TestDeferredCanvasCreateCompatibleDevice(reporter);
- TestDeferredCanvasWritePixelsToSurface(reporter);
- TestDeferredCanvasGetCanvasSize(reporter);
- TestDeferredCanvasSurface(reporter, NULL);
- TestDeferredCanvasSetSurface(reporter, NULL);
-}
-
-DEF_GPUTEST(DeferredCanvas_GPU, reporter, factory) {
- if (factory != NULL) {
- TestDeferredCanvasSurface(reporter, factory);
- TestDeferredCanvasSetSurface(reporter, factory);
- }
-}