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
This commit is contained in:
parent
c6f411e72b
commit
9c5052f16b
@ -10,26 +10,53 @@
|
|||||||
|
|
||||||
#include "Benchmark.h"
|
#include "Benchmark.h"
|
||||||
#include "SkCanvas.h"
|
#include "SkCanvas.h"
|
||||||
|
#include "SkLiteDL.h"
|
||||||
|
#include "SkLiteRecorder.h"
|
||||||
#include "SkPictureRecorder.h"
|
#include "SkPictureRecorder.h"
|
||||||
|
|
||||||
template <bool kDraw>
|
template <int kDraws, bool kLite>
|
||||||
struct PictureOverheadBench : public Benchmark {
|
struct PictureOverheadBench : public Benchmark {
|
||||||
const char* onGetName() override {
|
PictureOverheadBench() {
|
||||||
return kDraw ? "picture_overhead_draw" : "picture_overhead_nodraw";
|
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; }
|
bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
|
||||||
|
|
||||||
void onDraw(int loops, SkCanvas*) override {
|
void onDraw(int loops, SkCanvas*) override {
|
||||||
|
SkLiteRecorder lite;
|
||||||
SkPictureRecorder rec;
|
SkPictureRecorder rec;
|
||||||
for (int i = 0; i < loops; i++) {
|
for (int i = 0; i < loops; i++) {
|
||||||
rec.beginRecording(SkRect::MakeWH(2000,3000));
|
SkRect bounds{0,0, 2000,3000};
|
||||||
if (kDraw) {
|
|
||||||
rec.getRecordingCanvas()->drawRect(SkRect::MakeXYWH(10, 10, 1000, 1000), SkPaint());
|
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<0, false>);)
|
||||||
DEF_BENCH(return (new PictureOverheadBench< true>);)
|
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>);)
|
||||||
|
@ -879,6 +879,7 @@ static Sink* create_sink(const SkCommandLineConfig* config) {
|
|||||||
|
|
||||||
static Sink* create_via(const SkString& tag, Sink* wrapped) {
|
static Sink* create_via(const SkString& tag, Sink* wrapped) {
|
||||||
#define VIA(t, via, ...) if (tag.equals(t)) { return new via(__VA_ARGS__); }
|
#define VIA(t, via, ...) if (tag.equals(t)) { return new via(__VA_ARGS__); }
|
||||||
|
VIA("lite", ViaLite, wrapped);
|
||||||
VIA("twice", ViaTwice, wrapped);
|
VIA("twice", ViaTwice, wrapped);
|
||||||
VIA("serialize", ViaSerialization, wrapped);
|
VIA("serialize", ViaSerialization, wrapped);
|
||||||
VIA("pic", ViaPicture, wrapped);
|
VIA("pic", ViaPicture, wrapped);
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include "SkImageGenerator.h"
|
#include "SkImageGenerator.h"
|
||||||
#include "SkImageGeneratorCG.h"
|
#include "SkImageGeneratorCG.h"
|
||||||
#include "SkImageGeneratorWIC.h"
|
#include "SkImageGeneratorWIC.h"
|
||||||
|
#include "SkLiteDL.h"
|
||||||
|
#include "SkLiteRecorder.h"
|
||||||
#include "SkMallocPixelRef.h"
|
#include "SkMallocPixelRef.h"
|
||||||
#include "SkMultiPictureDraw.h"
|
#include "SkMultiPictureDraw.h"
|
||||||
#include "SkNullCanvas.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
|
} // namespace DM
|
||||||
|
@ -446,6 +446,12 @@ public:
|
|||||||
Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
|
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
|
} // namespace DM
|
||||||
|
|
||||||
#endif//DMSrcSink_DEFINED
|
#endif//DMSrcSink_DEFINED
|
||||||
|
@ -161,6 +161,8 @@
|
|||||||
'<(skia_src_path)/core/SkLinearBitmapPipeline_tile.h',
|
'<(skia_src_path)/core/SkLinearBitmapPipeline_tile.h',
|
||||||
'<(skia_src_path)/core/SkLinearBitmapPipeline_sample.h',
|
'<(skia_src_path)/core/SkLinearBitmapPipeline_sample.h',
|
||||||
'<(skia_src_path)/core/SkLineClipper.cpp',
|
'<(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.cpp',
|
||||||
'<(skia_src_path)/core/SkLocalMatrixImageFilter.h',
|
'<(skia_src_path)/core/SkLocalMatrixImageFilter.h',
|
||||||
'<(skia_src_path)/core/SkLocalMatrixShader.cpp',
|
'<(skia_src_path)/core/SkLocalMatrixShader.cpp',
|
||||||
|
@ -1578,6 +1578,7 @@ private:
|
|||||||
friend class SkDebugCanvas; // needs experimental fAllowSimplifyClip
|
friend class SkDebugCanvas; // needs experimental fAllowSimplifyClip
|
||||||
friend class SkSurface_Raster; // needs getDevice()
|
friend class SkSurface_Raster; // needs getDevice()
|
||||||
friend class SkRecorder; // InitFlags
|
friend class SkRecorder; // InitFlags
|
||||||
|
friend class SkLiteRecorder; // InitFlags
|
||||||
friend class SkNoSaveLayerCanvas; // InitFlags
|
friend class SkNoSaveLayerCanvas; // InitFlags
|
||||||
friend class SkPictureImageFilter; // SkCanvas(SkBaseDevice*, SkSurfaceProps*, InitFlags)
|
friend class SkPictureImageFilter; // SkCanvas(SkBaseDevice*, SkSurfaceProps*, InitFlags)
|
||||||
friend class SkPictureRecord; // predrawNotify (why does it need it? <reed>)
|
friend class SkPictureRecord; // predrawNotify (why does it need it? <reed>)
|
||||||
|
@ -101,15 +101,12 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Allow subclasses to call this if they've overridden internal_dispose
|
* Allow subclasses to call this if they've overridden internal_dispose
|
||||||
* so they can reset fRefCnt before the destructor is called. Should only
|
* so they can reset fRefCnt before the destructor is called or if they
|
||||||
* be called right before calling through to inherited internal_dispose()
|
* choose not to call the destructor (e.g. using a free list).
|
||||||
* or before calling the destructor.
|
|
||||||
*/
|
*/
|
||||||
void internal_dispose_restore_refcnt_to_1() const {
|
void internal_dispose_restore_refcnt_to_1() const {
|
||||||
#ifdef SK_DEBUG
|
|
||||||
SkASSERT(0 == getRefCnt());
|
SkASSERT(0 == getRefCnt());
|
||||||
fRefCnt.store(1, std::memory_order_relaxed);
|
fRefCnt.store(1, std::memory_order_relaxed);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
150
src/core/SkLiteDL.cpp
Normal file
150
src/core/SkLiteDL.cpp
Normal file
@ -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;
|
||||||
|
}
|
86
src/core/SkLiteDL.h
Normal file
86
src/core/SkLiteDL.h
Normal file
@ -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
|
188
src/core/SkLiteRecorder.cpp
Normal file
188
src/core/SkLiteRecorder.cpp
Normal file
@ -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);
|
||||||
|
}
|
85
src/core/SkLiteRecorder.h
Normal file
85
src/core/SkLiteRecorder.h
Normal file
@ -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
|
64
tests/SkLiteDLTest.cpp
Normal file
64
tests/SkLiteDLTest.cpp
Normal file
@ -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();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user