aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar mtklein <mtklein@chromium.org>2016-08-06 12:51:51 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-06 12:51:51 -0700
commit9c5052f16b249d2b7674ea86bd24ed0038ccc61f (patch)
treedb2e05f246b2e7d65c91275943e1ada80a4856f1
parentc6f411e72b1fea6608f540f64a57bcacbe3378cd (diff)
SkLite*
SkLiteRecorder, a new SkCanvas, fills out SkLiteDL, a new SkDrawable. This SkDrawable is a display list similar to SkRecord and SkBigPicture / SkRecordedDrawable, but with a few new design points inspired by Android and slimming paint: 1) SkLiteDL is structured as one big contiguous array rather than the two layer structure of SkRecord. This trades away flexibility and large-op-count performance for better data locality for small to medium size pictures. 2) We keep a global freelist of SkLiteDLs, both reusing the SkLiteDL struct itself and its contiguous byte array. This keeps the expected number of mallocs per display list allocation <1 (really, ~0) for cyclical use cases. These two together mean recording is faster. Measuring against the code we use at head, SkLiteRecorder trends about ~3x faster across various size pictures, matching speed at 0 draws and beating the special-case 1-draw pictures we have today. (I.e. we won't need those special case implementations anymore, because they're slower than this new generic code.) This new strategy records 10 drawRects() in about the same time the old strategy took for 2. This strategy stays the winner until at least 500 drawRect()s on my laptop, where I stopped checking. A simpler alternative to freelisting is also possible (but not implemented here), where we allow the client to manually reset() an SkLiteDL for reuse when its refcnt is 1. That's essentially what we're doing with the freelist, except tracking what's available for reuse globally instead of making the client do it. This code is not fully capable yet, but most of the key design points are there. The internal structure of SkLiteDL is the area I expect to be most volatile (anything involving Op), but its interface and the whole of SkLiteRecorder ought to be just about done. You can run nanobench --match picture_overhead as a demo. Everything it exercises is fully fleshed out, so what it tests is an apples-to-apples comparison as far as recording costs go. I have not yet compared playback performance. It should be simple to wrap this into an SkPicture subclass if we want. I won't start proposing we replace anything old with anything new quite yet until I have more ducks in a row, but this does look pretty promising (similar to the SkRecord over old SkPicture change a couple years ago) and I'd like to land, experiment, iterate, especially with an eye toward Android. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2213333002 Review-Url: https://codereview.chromium.org/2213333002
-rw-r--r--bench/PictureOverheadBench.cpp45
-rw-r--r--dm/DM.cpp1
-rw-r--r--dm/DMSrcSink.cpp22
-rw-r--r--dm/DMSrcSink.h6
-rw-r--r--gyp/core.gypi2
-rw-r--r--include/core/SkCanvas.h1
-rw-r--r--include/core/SkRefCnt.h7
-rw-r--r--src/core/SkLiteDL.cpp150
-rw-r--r--src/core/SkLiteDL.h86
-rw-r--r--src/core/SkLiteRecorder.cpp188
-rw-r--r--src/core/SkLiteRecorder.h85
-rw-r--r--tests/SkLiteDLTest.cpp64
12 files changed, 643 insertions, 14 deletions
diff --git a/bench/PictureOverheadBench.cpp b/bench/PictureOverheadBench.cpp
index fc72f8623a..3bd9fb0bd9 100644
--- a/bench/PictureOverheadBench.cpp
+++ b/bench/PictureOverheadBench.cpp
@@ -10,26 +10,53 @@
#include "Benchmark.h"
#include "SkCanvas.h"
+#include "SkLiteDL.h"
+#include "SkLiteRecorder.h"
#include "SkPictureRecorder.h"
-template <bool kDraw>
+template <int kDraws, bool kLite>
struct PictureOverheadBench : public Benchmark {
- const char* onGetName() override {
- return kDraw ? "picture_overhead_draw" : "picture_overhead_nodraw";
+ PictureOverheadBench() {
+ fName.appendf("picture_overhead_%d%s\n", kDraws, kLite ? "_lite" : "");
}
+ const char* onGetName() override { return fName.c_str(); }
bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
void onDraw(int loops, SkCanvas*) override {
+ SkLiteRecorder lite;
SkPictureRecorder rec;
for (int i = 0; i < loops; i++) {
- rec.beginRecording(SkRect::MakeWH(2000,3000));
- if (kDraw) {
- rec.getRecordingCanvas()->drawRect(SkRect::MakeXYWH(10, 10, 1000, 1000), SkPaint());
+ SkRect bounds{0,0, 2000,3000};
+
+ sk_sp<SkLiteDL> liteDL;
+ SkCanvas* canvas;
+ if (kLite) {
+ liteDL = SkLiteDL::New(bounds);
+ lite.reset(liteDL.get());
+ canvas = &lite;
+ } else {
+ rec.beginRecording(bounds);
+ canvas = rec.getRecordingCanvas();
+ }
+
+ for (int i = 0; i < kDraws; i++) {
+ canvas->drawRect({10,10, 1000, 1000}, SkPaint{});
+ }
+
+ if (!kLite) {
+ (void)rec.finishRecordingAsPicture();
}
- (void)rec.finishRecordingAsPicture();
}
}
+
+ SkString fName;
};
-DEF_BENCH(return (new PictureOverheadBench<false>);)
-DEF_BENCH(return (new PictureOverheadBench< true>);)
+DEF_BENCH(return (new PictureOverheadBench<0, false>);)
+DEF_BENCH(return (new PictureOverheadBench<1, false>);)
+DEF_BENCH(return (new PictureOverheadBench<2, false>);)
+DEF_BENCH(return (new PictureOverheadBench<10,false>);)
+DEF_BENCH(return (new PictureOverheadBench<0, true>);)
+DEF_BENCH(return (new PictureOverheadBench<1, true>);)
+DEF_BENCH(return (new PictureOverheadBench<2, true>);)
+DEF_BENCH(return (new PictureOverheadBench<10, true>);)
diff --git a/dm/DM.cpp b/dm/DM.cpp
index bf80c863ba..5dd8a6f63e 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -879,6 +879,7 @@ static Sink* create_sink(const SkCommandLineConfig* config) {
static Sink* create_via(const SkString& tag, Sink* wrapped) {
#define VIA(t, via, ...) if (tag.equals(t)) { return new via(__VA_ARGS__); }
+ VIA("lite", ViaLite, wrapped);
VIA("twice", ViaTwice, wrapped);
VIA("serialize", ViaSerialization, wrapped);
VIA("pic", ViaPicture, wrapped);
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 2e9e565c86..52e1dd9ef3 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -21,6 +21,8 @@
#include "SkImageGenerator.h"
#include "SkImageGeneratorCG.h"
#include "SkImageGeneratorWIC.h"
+#include "SkLiteDL.h"
+#include "SkLiteRecorder.h"
#include "SkMallocPixelRef.h"
#include "SkMultiPictureDraw.h"
#include "SkNullCanvas.h"
@@ -1609,4 +1611,24 @@ Error ViaSingletonPictures::draw(
});
}
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+Error ViaLite::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
+ auto size = src.size();
+ SkRect bounds = {0,0, (SkScalar)size.width(), (SkScalar)size.height()};
+ return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
+ sk_sp<SkLiteDL> dl = SkLiteDL::New(bounds);
+
+ SkLiteRecorder rec;
+ rec.reset(dl.get());
+
+ Error err = src.draw(&rec);
+ if (!err.isEmpty()) {
+ return err;
+ }
+ dl->draw(canvas);
+ return ""; //check_against_reference(bitmap, src, fSink);
+ });
+}
+
} // namespace DM
diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h
index a54ddb8d7f..086becb6f6 100644
--- a/dm/DMSrcSink.h
+++ b/dm/DMSrcSink.h
@@ -446,6 +446,12 @@ public:
Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
};
+class ViaLite : public Via {
+public:
+ explicit ViaLite(Sink* sink) : Via(sink) {}
+ Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
+};
+
} // namespace DM
#endif//DMSrcSink_DEFINED
diff --git a/gyp/core.gypi b/gyp/core.gypi
index 6b1d9f4eb5..306c90f5bc 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -161,6 +161,8 @@
'<(skia_src_path)/core/SkLinearBitmapPipeline_tile.h',
'<(skia_src_path)/core/SkLinearBitmapPipeline_sample.h',
'<(skia_src_path)/core/SkLineClipper.cpp',
+ '<(skia_src_path)/core/SkLiteDL.cpp',
+ '<(skia_src_path)/core/SkLiteRecorder.cpp',
'<(skia_src_path)/core/SkLocalMatrixImageFilter.cpp',
'<(skia_src_path)/core/SkLocalMatrixImageFilter.h',
'<(skia_src_path)/core/SkLocalMatrixShader.cpp',
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index c3f8599db4..26e3c8e3c5 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -1578,6 +1578,7 @@ private:
friend class SkDebugCanvas; // needs experimental fAllowSimplifyClip
friend class SkSurface_Raster; // needs getDevice()
friend class SkRecorder; // InitFlags
+ friend class SkLiteRecorder; // InitFlags
friend class SkNoSaveLayerCanvas; // InitFlags
friend class SkPictureImageFilter; // SkCanvas(SkBaseDevice*, SkSurfaceProps*, InitFlags)
friend class SkPictureRecord; // predrawNotify (why does it need it? <reed>)
diff --git a/include/core/SkRefCnt.h b/include/core/SkRefCnt.h
index 3227e68740..82a3c9e000 100644
--- a/include/core/SkRefCnt.h
+++ b/include/core/SkRefCnt.h
@@ -101,15 +101,12 @@ public:
protected:
/**
* Allow subclasses to call this if they've overridden internal_dispose
- * so they can reset fRefCnt before the destructor is called. Should only
- * be called right before calling through to inherited internal_dispose()
- * or before calling the destructor.
+ * so they can reset fRefCnt before the destructor is called or if they
+ * choose not to call the destructor (e.g. using a free list).
*/
void internal_dispose_restore_refcnt_to_1() const {
-#ifdef SK_DEBUG
SkASSERT(0 == getRefCnt());
fRefCnt.store(1, std::memory_order_relaxed);
-#endif
}
private:
diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp
new file mode 100644
index 0000000000..90f62c28f5
--- /dev/null
+++ b/src/core/SkLiteDL.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkLiteDL.h"
+#include "SkMutex.h"
+#include "SkSpinlock.h"
+
+namespace {
+ struct Op {
+ virtual ~Op() {}
+ virtual void draw(SkCanvas*) = 0;
+
+ size_t skip;
+ };
+
+ struct Save final : Op { void draw(SkCanvas* c) override { c-> save(); } };
+ struct Restore final : Op { void draw(SkCanvas* c) override { c->restore(); } };
+
+ struct Concat final : Op {
+ Concat(const SkMatrix& matrix) : matrix(matrix) {}
+ SkMatrix matrix;
+ void draw(SkCanvas* c) override { c->concat(matrix); }
+ };
+ struct SetMatrix final : Op {
+ SetMatrix(const SkMatrix& matrix) : matrix(matrix) {}
+ SkMatrix matrix;
+ void draw(SkCanvas* c) override { c->setMatrix(matrix); }
+ };
+
+ struct ClipRect final : Op {
+ ClipRect(const SkRect& rect, SkRegion::Op op, bool aa) : rect(rect), op(op), aa(aa) {}
+ SkRect rect;
+ SkRegion::Op op;
+ bool aa;
+ void draw(SkCanvas* c) override { c->clipRect(rect, op, aa); }
+ };
+
+ struct DrawRect final : Op {
+ DrawRect(const SkRect& rect, const SkPaint& paint) : rect(rect), paint(paint) {}
+ SkRect rect;
+ SkPaint paint;
+ void draw(SkCanvas* c) override { c->drawRect(rect, paint); }
+ };
+
+ struct DrawPath final : Op {
+ DrawPath(const SkPath& path, const SkPaint& paint) : path(path), paint(paint) {}
+ SkPath path;
+ SkPaint paint;
+ void draw(SkCanvas* c) override { c->drawPath(path, paint); }
+ };
+
+ template <typename T, typename... Args>
+ static void* push(SkTDArray<uint8_t>* bytes, size_t pod, Args&&... args) {
+ size_t skip = SkAlignPtr(sizeof(T) + pod);
+ auto op = (T*)bytes->append(skip);
+ new (op) T{ std::forward<Args>(args)... };
+ op->skip = skip;
+ return op+1;
+ }
+
+ template <typename Fn>
+ static void map(SkTDArray<uint8_t>* bytes, Fn&& fn) {
+ for (uint8_t* ptr = bytes->begin(); ptr < bytes->end(); ) {
+ auto op = (Op*)ptr;
+ fn(op);
+ ptr += op->skip;
+ }
+ }
+}
+
+void SkLiteDL:: save() { push <Save>(&fBytes, 0); }
+void SkLiteDL::restore() { push<Restore>(&fBytes, 0); }
+
+void SkLiteDL:: concat(const SkMatrix& matrix) { push <Concat>(&fBytes, 0, matrix); }
+void SkLiteDL::setMatrix(const SkMatrix& matrix) { push<SetMatrix>(&fBytes, 0, matrix); }
+
+void SkLiteDL::clipRect(const SkRect& rect, SkRegion::Op op, bool aa) {
+ push<ClipRect>(&fBytes, 0, rect, op, aa);
+}
+
+void SkLiteDL::drawRect(const SkRect& rect, const SkPaint& paint) {
+ push<DrawRect>(&fBytes, 0, rect, paint);
+}
+void SkLiteDL::drawPath(const SkPath& path, const SkPaint& paint) {
+ push<DrawPath>(&fBytes, 0, path, paint);
+}
+
+void SkLiteDL::onDraw(SkCanvas* canvas) {
+ map(&fBytes, [canvas](Op* op) { op->draw(canvas); });
+}
+
+SkRect SkLiteDL::onGetBounds() {
+ return fBounds;
+}
+
+SkLiteDL:: SkLiteDL() {}
+SkLiteDL::~SkLiteDL() {}
+
+static const int kFreeStackByteLimit = 128*1024;
+static const int kFreeStackCountLimit = 8;
+
+static SkSpinlock gFreeStackLock;
+static SkLiteDL* gFreeStack = nullptr;
+static int gFreeStackCount = 0;
+
+sk_sp<SkLiteDL> SkLiteDL::New(SkRect bounds) {
+ sk_sp<SkLiteDL> dl;
+ {
+ SkAutoMutexAcquire lock(gFreeStackLock);
+ if (gFreeStack) {
+ dl.reset(gFreeStack); // Adopts the ref the stack's been holding.
+ gFreeStack = gFreeStack->fNext;
+ gFreeStackCount--;
+ }
+ }
+
+ if (!dl) {
+ dl.reset(new SkLiteDL);
+ }
+
+ dl->fBounds = bounds;
+ return dl;
+}
+
+void SkLiteDL::internal_dispose() const {
+ // Whether we delete this or leave it on the free stack,
+ // we want its refcnt at 1.
+ this->internal_dispose_restore_refcnt_to_1();
+
+ auto self = const_cast<SkLiteDL*>(this);
+ map(&self->fBytes, [](Op* op) { op->~Op(); });
+
+ if (self->fBytes.reserved() < kFreeStackByteLimit) {
+ self->fBytes.rewind();
+ SkAutoMutexAcquire lock(gFreeStackLock);
+ if (gFreeStackCount < kFreeStackCountLimit) {
+ self->fNext = gFreeStack;
+ gFreeStack = self;
+ gFreeStackCount++;
+ return;
+ }
+ }
+
+ delete this;
+}
diff --git a/src/core/SkLiteDL.h b/src/core/SkLiteDL.h
new file mode 100644
index 0000000000..88c959f88d
--- /dev/null
+++ b/src/core/SkLiteDL.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkLiteDL_DEFINED
+#define SkLiteDL_DEFINED
+
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkDrawable.h"
+#include "SkRect.h"
+#include "SkTDArray.h"
+
+class SkLiteDL final : public SkDrawable {
+public:
+ static sk_sp<SkLiteDL> New(SkRect);
+
+ void save();
+ void saveLayer(const SkRect*, const SkPaint*, const SkImageFilter*, uint32_t) {/*TODO*/}
+ void restore();
+
+ void concat (const SkMatrix&);
+ void setMatrix (const SkMatrix&);
+ void translateZ(SkScalar) {/*TODO*/}
+
+ void clipPath (const SkPath&, SkRegion::Op, bool aa) {/*TODO*/}
+ void clipRRect (const SkRRect&, SkRegion::Op, bool aa) {/*TODO*/}
+ void clipRect (const SkRect&, SkRegion::Op, bool aa);
+ void clipRegion(const SkRegion&, SkRegion::Op) {/*TODO*/}
+
+
+ void drawPaint (const SkPaint&) {/*TODO*/}
+ void drawPath (const SkPath&, const SkPaint&);
+ void drawRect (const SkRect&, const SkPaint&);
+ void drawOval (const SkRect&, const SkPaint&) {/*TODO*/}
+ void drawRRect (const SkRRect&, const SkPaint&) {/*TODO*/}
+ void drawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) {/*TODO*/}
+
+ void drawAnnotation (const SkRect&, const char*, SkData*) {/*TODO*/}
+ void drawDrawable (SkDrawable*, const SkMatrix*) {/*TODO*/}
+ void drawPicture (const SkPicture*, const SkMatrix*, const SkPaint*) {/*TODO*/}
+ void drawShadowedPicture(const SkPicture*, const SkMatrix*, const SkPaint*) {/*TODO*/}
+
+ void drawText (const void*, size_t, SkScalar, SkScalar, const SkPaint&) {/*TODO*/}
+ void drawPosText (const void*, size_t, const SkPoint[], const SkPaint&) {/*TODO*/}
+ void drawPosTextH (const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) {/*TODO*/}
+ void drawTextOnPath (const void*, size_t, const SkPath&, const SkMatrix*, const SkPaint&) {/*TODO*/}
+ void drawTextRSXForm(const void*, size_t, const SkRSXform[], const SkRect*, const SkPaint&) {/*TODO*/}
+ void drawTextBlob (const SkTextBlob*, SkScalar,SkScalar, const SkPaint&) {/*TODO*/}
+
+ void drawBitmap (const SkBitmap&, SkScalar,SkScalar, const SkPaint*) {/*TODO*/}
+ void drawBitmapNine(const SkBitmap&, SkIRect, const SkRect&, const SkPaint*) {/*TODO*/}
+ void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, bool) {/*TODO*/}
+
+ void drawImage (const SkImage*, SkScalar,SkScalar, const SkPaint*) {/*TODO*/}
+ void drawImageNine (const SkImage*, SkIRect, const SkRect&, const SkPaint*) {/*TODO*/}
+ void drawImageRect (const SkImage*, const SkRect*, const SkRect&, const SkPaint*, bool) {/*TODO*/}
+ void drawImageLattice(const SkImage*, SkCanvas::Lattice, const SkRect&, const SkPaint*) {/*TODO*/}
+
+ void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4],
+ SkXfermode*, const SkPaint&) {/*TODO*/}
+ void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) {/*TODO*/}
+ void drawVertices(SkCanvas::VertexMode, int, const SkPoint[], const SkPoint[], const SkColor[],
+ SkXfermode*, const uint16_t[], int, const SkPaint&) {/*TODO*/}
+ void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
+ SkXfermode::Mode, const SkRect*, const SkPaint*) {/*TODO*/}
+
+private:
+ SkLiteDL();
+ ~SkLiteDL();
+
+ void internal_dispose() const override;
+
+ SkRect onGetBounds() override;
+ void onDraw(SkCanvas*) override;
+
+ SkLiteDL* fNext;
+ SkRect fBounds;
+ SkTDArray<uint8_t> fBytes;
+};
+
+#endif//SkLiteDL_DEFINED
diff --git a/src/core/SkLiteRecorder.cpp b/src/core/SkLiteRecorder.cpp
new file mode 100644
index 0000000000..00441fdf84
--- /dev/null
+++ b/src/core/SkLiteRecorder.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkLiteDL.h"
+#include "SkLiteRecorder.h"
+#include "SkSurface.h"
+
+SkLiteRecorder::SkLiteRecorder()
+ : SkCanvas({0,0,1,1}, SkCanvas::kConservativeRasterClip_InitFlag)
+ , fDL(nullptr) {}
+
+void SkLiteRecorder::reset(SkLiteDL* dl) {
+ this->resetForNextPicture(dl->getBounds().roundOut());
+ fDL = dl;
+}
+
+sk_sp<SkSurface> SkLiteRecorder::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
+ return nullptr;
+}
+
+void SkLiteRecorder::willSave() { fDL->save(); }
+SkCanvas::SaveLayerStrategy SkLiteRecorder::getSaveLayerStrategy(const SaveLayerRec& rec) {
+ fDL->saveLayer(rec.fBounds, rec.fPaint, rec.fBackdrop, rec.fSaveLayerFlags);
+ return SkCanvas::kNoLayer_SaveLayerStrategy;
+}
+void SkLiteRecorder::willRestore() { fDL->restore(); }
+
+void SkLiteRecorder::didConcat (const SkMatrix& matrix) { fDL-> concat(matrix); }
+void SkLiteRecorder::didSetMatrix(const SkMatrix& matrix) { fDL->setMatrix(matrix); }
+
+void SkLiteRecorder::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle style) {
+ fDL->clipRect(rect, op, style==kSoft_ClipEdgeStyle);
+ SkCanvas::onClipRect(rect, op, style);
+}
+void SkLiteRecorder::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle style) {
+ fDL->clipRRect(rrect, op, style==kSoft_ClipEdgeStyle);
+ SkCanvas::onClipRRect(rrect, op, style);
+}
+void SkLiteRecorder::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle style) {
+ fDL->clipPath(path, op, style==kSoft_ClipEdgeStyle);
+ SkCanvas::onClipPath(path, op, style);
+}
+void SkLiteRecorder::onClipRegion(const SkRegion& region, SkRegion::Op op) {
+ fDL->clipRegion(region, op);
+ SkCanvas::onClipRegion(region, op);
+}
+
+void SkLiteRecorder::onDrawPaint(const SkPaint& paint) {
+ fDL->drawPaint(paint);
+}
+void SkLiteRecorder::onDrawPath(const SkPath& path, const SkPaint& paint) {
+ fDL->drawPath(path, paint);
+}
+void SkLiteRecorder::onDrawRect(const SkRect& rect, const SkPaint& paint) {
+ fDL->drawRect(rect, paint);
+}
+void SkLiteRecorder::onDrawOval(const SkRect& oval, const SkPaint& paint) {
+ fDL->drawOval(oval, paint);
+}
+void SkLiteRecorder::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
+ fDL->drawRRect(rrect, paint);
+}
+void SkLiteRecorder::onDrawDRRect(const SkRRect& out, const SkRRect& in, const SkPaint& paint) {
+ fDL->drawDRRect(out, in, paint);
+}
+
+void SkLiteRecorder::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
+ fDL->drawDrawable(drawable, matrix);
+}
+void SkLiteRecorder::onDrawPicture(const SkPicture* picture,
+ const SkMatrix* matrix,
+ const SkPaint* paint) {
+ fDL->drawPicture(picture, matrix, paint);
+}
+void SkLiteRecorder::onDrawAnnotation(const SkRect& rect, const char key[], SkData* val) {
+ fDL->drawAnnotation(rect, key, val);
+}
+
+void SkLiteRecorder::onDrawText(const void* text, size_t bytes,
+ SkScalar x, SkScalar y,
+ const SkPaint& paint) {
+ fDL->drawText(text, bytes, x, y, paint);
+}
+void SkLiteRecorder::onDrawPosText(const void* text, size_t bytes,
+ const SkPoint pos[],
+ const SkPaint& paint) {
+ fDL->drawPosText(text, bytes, pos, paint);
+}
+void SkLiteRecorder::onDrawPosTextH(const void* text, size_t bytes,
+ const SkScalar xs[], SkScalar y,
+ const SkPaint& paint) {
+ fDL->drawPosTextH(text, bytes, xs, y, paint);
+}
+void SkLiteRecorder::onDrawTextOnPath(const void* text, size_t bytes,
+ const SkPath& path, const SkMatrix* matrix,
+ const SkPaint& paint) {
+ fDL->drawTextOnPath(text, bytes, path, matrix, paint);
+}
+void SkLiteRecorder::onDrawTextRSXform(const void* text, size_t bytes,
+ const SkRSXform xform[], const SkRect* cull,
+ const SkPaint& paint) {
+ fDL->drawTextRSXForm(text, bytes, xform, cull, paint);
+}
+void SkLiteRecorder::onDrawTextBlob(const SkTextBlob* blob,
+ SkScalar x, SkScalar y,
+ const SkPaint& paint) {
+ fDL->drawTextBlob(blob, x,y, paint);
+}
+
+void SkLiteRecorder::onDrawBitmap(const SkBitmap& bm,
+ SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ fDL->drawBitmap(bm, x,y, paint);
+}
+void SkLiteRecorder::onDrawBitmapNine(const SkBitmap& bm,
+ const SkIRect& center, const SkRect& dst,
+ const SkPaint* paint) {
+ fDL->drawBitmapNine(bm, center, dst, paint);
+}
+void SkLiteRecorder::onDrawBitmapRect(const SkBitmap& bm,
+ const SkRect* src, const SkRect& dst,
+ const SkPaint* paint, SrcRectConstraint constraint) {
+ fDL->drawBitmapRect(bm, src, dst, paint, constraint == kStrict_SrcRectConstraint);
+}
+
+void SkLiteRecorder::onDrawImage(const SkImage* img,
+ SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ fDL->drawImage(img, x,y, paint);
+}
+void SkLiteRecorder::onDrawImageNine(const SkImage* img,
+ const SkIRect& center, const SkRect& dst,
+ const SkPaint* paint) {
+ fDL->drawImageNine(img, center, dst, paint);
+}
+void SkLiteRecorder::onDrawImageRect(const SkImage* img,
+ const SkRect* src, const SkRect& dst,
+ const SkPaint* paint, SrcRectConstraint constraint) {
+ fDL->drawImageRect(img, src, dst, paint, constraint == kStrict_SrcRectConstraint);
+}
+void SkLiteRecorder::onDrawImageLattice(const SkImage* img,
+ const SkCanvas::Lattice& lattice, const SkRect& dst,
+ const SkPaint* paint) {
+ fDL->drawImageLattice(img, lattice, dst, paint);
+}
+
+
+void SkLiteRecorder::onDrawPatch(const SkPoint cubics[12],
+ const SkColor colors[4], const SkPoint texCoords[4],
+ SkXfermode* xfermode, const SkPaint& paint) {
+ fDL->drawPatch(cubics, colors, texCoords, xfermode, paint);
+}
+void SkLiteRecorder::onDrawPoints(SkCanvas::PointMode mode,
+ size_t count, const SkPoint pts[],
+ const SkPaint& paint) {
+ fDL->drawPoints(mode, count, pts, paint);
+}
+void SkLiteRecorder::onDrawVertices(SkCanvas::VertexMode mode,
+ int count, const SkPoint vertices[],
+ const SkPoint texs[], const SkColor colors[],
+ SkXfermode* xfermode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint& paint) {
+ fDL->drawVertices(mode, count, vertices, texs, colors, xfermode, indices, indexCount, paint);
+}
+void SkLiteRecorder::onDrawAtlas(const SkImage* atlas,
+ const SkRSXform xforms[],
+ const SkRect texs[],
+ const SkColor colors[],
+ int count,
+ SkXfermode::Mode xfermode,
+ const SkRect* cull,
+ const SkPaint* paint) {
+ fDL->drawAtlas(atlas, xforms, texs, colors, count, xfermode, cull, paint);
+}
+
+void SkLiteRecorder::didTranslateZ(SkScalar dz) {
+ fDL->translateZ(dz);
+}
+void SkLiteRecorder::onDrawShadowedPicture(const SkPicture* picture,
+ const SkMatrix* matrix,
+ const SkPaint* paint) {
+ fDL->drawShadowedPicture(picture, matrix, paint);
+}
diff --git a/src/core/SkLiteRecorder.h b/src/core/SkLiteRecorder.h
new file mode 100644
index 0000000000..1a38c02fb0
--- /dev/null
+++ b/src/core/SkLiteRecorder.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkLiteRecorder_DEFINED
+#define SkLiteRecorder_DEFINED
+
+#include "SkCanvas.h"
+
+class SkLiteDL;
+
+class SkLiteRecorder final : public SkCanvas {
+public:
+ SkLiteRecorder();
+ void reset(SkLiteDL*);
+
+ sk_sp<SkSurface> onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override;
+
+ void willSave() override;
+ SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
+ void willRestore() override;
+
+ void didConcat(const SkMatrix&) override;
+ void didSetMatrix(const SkMatrix&) 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 onDrawPaint (const SkPaint&) override;
+ void onDrawPath (const SkPath&, 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 onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
+
+ void onDrawDrawable(SkDrawable*, const SkMatrix*) override;
+ void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
+ void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
+
+ void onDrawText (const void*, size_t, SkScalar x, SkScalar y, const SkPaint&) override;
+ void onDrawPosText (const void*, size_t, const SkPoint[], const SkPaint&) override;
+ void onDrawPosTextH (const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override;
+ void onDrawTextOnPath(const void*, size_t,
+ const SkPath&, const SkMatrix*, const SkPaint&) override;
+ void onDrawTextRSXform(const void*, size_t,
+ const SkRSXform[], const SkRect*, const SkPaint&) override;
+ void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override;
+
+ void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override;
+ void onDrawBitmapNine(const SkBitmap&, const SkIRect&, const SkRect&, const SkPaint*) override;
+ void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*,
+ SrcRectConstraint) override;
+
+ void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override;
+ void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override;
+ void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override;
+ void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
+ SrcRectConstraint) override;
+
+ void onDrawPatch(const SkPoint[12], const SkColor[4],
+ const SkPoint[4], SkXfermode*, const SkPaint&) override;
+ void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
+ void onDrawVertices(VertexMode, int, const SkPoint[], const SkPoint[], const SkColor[],
+ SkXfermode*, const uint16_t[], int, const SkPaint&) override;
+ void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
+ int, SkXfermode::Mode, const SkRect*, const SkPaint*) override;
+
+#ifdef SK_EXPERIMENTAL_SHADOWING
+ void didTranslateZ(SkScalar) override;
+ void onDrawShadowedPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
+#else
+ void didTranslateZ(SkScalar);
+ void onDrawShadowedPicture(const SkPicture*, const SkMatrix*, const SkPaint*);
+#endif
+
+private:
+ SkLiteDL* fDL;
+};
+
+#endif//SkLiteRecorder_DEFINED
diff --git a/tests/SkLiteDLTest.cpp b/tests/SkLiteDLTest.cpp
new file mode 100644
index 0000000000..cb6ba98708
--- /dev/null
+++ b/tests/SkLiteDLTest.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkLiteDL.h"
+#include "SkLiteRecorder.h"
+
+#if 0 // This test doesn't make sense when run in a threaded environment. It tests global state.
+DEF_TEST(SkLiteDL_freelisting, r) {
+ // TODO: byte and count limit tests
+ sk_sp<SkLiteDL> sp1 = SkLiteDL::New({1,1,10,10}),
+ sp2 = SkLiteDL::New({2,2,20,20});
+
+ SkLiteDL* p1 = sp1.get();
+ SkLiteDL* p2 = sp2.get();
+ REPORTER_ASSERT(r, p1 != p2);
+ REPORTER_ASSERT(r, p1->getBounds().left() == 1);
+ REPORTER_ASSERT(r, p2->getBounds().left() == 2);
+
+ sp2.reset();
+
+ sk_sp<SkLiteDL> sp3 = SkLiteDL::New({3,3,30,30});
+ SkLiteDL* p3 = sp3.get();
+ REPORTER_ASSERT(r, p1 != p3);
+ REPORTER_ASSERT(r, p2 == p3);
+ REPORTER_ASSERT(r, p1->getBounds().left() == 1);
+ REPORTER_ASSERT(r, p3->getBounds().left() == 3);
+
+ sp3.reset();
+ sp1.reset();
+
+ sk_sp<SkLiteDL> sp4 = SkLiteDL::New({4,4,40,40});
+ SkLiteDL* p4 = sp4.get();
+ REPORTER_ASSERT(r, p4 == p1); // Checks that we operate in stack order. Nice, not essential.
+ REPORTER_ASSERT(r, p4->getBounds().left() == 4);
+}
+#endif
+
+DEF_TEST(SkLiteDL_basics, r) {
+ sk_sp<SkLiteDL> p { SkLiteDL::New({2,2,3,3}) };
+
+ p->save();
+ p->clipRect(SkRect{2,3,4,5}, SkRegion::kIntersect_Op, true);
+ p->drawRect(SkRect{0,0,9,9}, SkPaint{});
+ p->restore();
+}
+
+DEF_TEST(SkLiteRecorder, r) {
+ sk_sp<SkLiteDL> p { SkLiteDL::New({2,2,3,3}) };
+
+ SkLiteRecorder rec;
+ SkCanvas* c = &rec;
+
+ rec.reset(p.get());
+
+ c->save();
+ c->clipRect(SkRect{2,3,4,5}, SkRegion::kIntersect_Op, true);
+ c->drawRect(SkRect{0,0,9,9}, SkPaint{});
+ c->restore();
+}