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
diff --git a/src/core/SkLiteDL.h b/src/core/SkLiteDL.h
new file mode 100644
index 0000000..88c959f
--- /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