aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkMiniRecorder.cpp
diff options
context:
space:
mode:
authorGravatar mtklein <mtklein@chromium.org>2015-05-19 11:11:26 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-05-19 11:11:26 -0700
commit9db912c2ac2ab53bc24f2d50a3e5a80162051dcc (patch)
tree053a0e9ec711d0ccb95625219dd83022e7b6ece2 /src/core/SkMiniRecorder.cpp
parent612f70d5fa2d4bf7a393c791966bbce933407017 (diff)
Sketch splitting SkPicture into an interface and SkBigPicture.
Adds small pictures for drawRect(), drawTextBlob(), and drawPath(). These cover about 89% of draw calls from Blink SKPs, and about 25% of draw calls from our GMs. SkPicture handles: - serialization and deserialization - unique IDs Everything else is left to the subclasses: - playback(), cullRect() - hasBitmap(), hasText(), suitableForGPU(), etc. - LayerInfo / AccelData if applicable. The time to record a 1-op picture improves a good chunk (2 mallocs to 1), and the time to record a 0-op picture greatly improves (2 mallocs to none): picture_overhead_draw: 450ns -> 350ns picture_overhead_nodraw: 300ns -> 90ns BUG=skia: Committed: https://skia.googlesource.com/skia/+/c92c129ff85b05a714bd1bf921c02d5e14651f8b Latest blink_linux_rel: http://build.chromium.org/p/tryserver.blink/builders/linux_blink_rel/builds/61248 Committed: https://skia.googlesource.com/skia/+/15877b6eae33a9282458bdb904a6d00440eca0ec http://build.chromium.org/p/tryserver.blink/builders/linux_blink_rel/builds/62015 Review URL: https://codereview.chromium.org/1112523006
Diffstat (limited to 'src/core/SkMiniRecorder.cpp')
-rw-r--r--src/core/SkMiniRecorder.cpp104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/core/SkMiniRecorder.cpp b/src/core/SkMiniRecorder.cpp
new file mode 100644
index 0000000000..f851e1cac0
--- /dev/null
+++ b/src/core/SkMiniRecorder.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2015 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 "SkMiniRecorder.h"
+#include "SkPicture.h"
+#include "SkPictureCommon.h"
+#include "SkRecordDraw.h"
+#include "SkTextBlob.h"
+
+using namespace SkRecords;
+
+// SkEmptyPicture could logically be a singleton, but that plays badly with Blink's
+// Debug-only adopted() / requireAdoption() tracking in sk_ref_cnt_ext_debug.h.
+// TODO(mtklein): modify sk_ref_cnt_ext_debug.h to play better with non-new'd objects.
+class SkEmptyPicture final : public SkPicture {
+public:
+ void playback(SkCanvas*, AbortCallback*) const override { }
+
+ size_t approximateBytesUsed() const override { return sizeof(*this); }
+ int approximateOpCount() const override { return 0; }
+ SkRect cullRect() const override { return SkRect::MakeEmpty(); }
+ bool hasText() const override { return false; }
+ int numSlowPaths() const override { return 0; }
+ bool willPlayBackBitmaps() const override { return false; }
+};
+
+template <typename T>
+class SkMiniPicture final : public SkPicture {
+public:
+ SkMiniPicture(SkRect cull, T* op) : fCull(cull) {
+ memcpy(&fOp, op, sizeof(fOp)); // We take ownership of op's guts.
+ }
+
+ void playback(SkCanvas* c, AbortCallback*) const override {
+ SkRecords::Draw(c, nullptr, nullptr, 0, nullptr)(fOp);
+ }
+
+ size_t approximateBytesUsed() const override { return sizeof(*this); }
+ int approximateOpCount() const override { return 1; }
+ SkRect cullRect() const override { return fCull; }
+ bool hasText() const override { return SkTextHunter()(fOp); }
+ bool willPlayBackBitmaps() const override { return SkBitmapHunter()(fOp); }
+ int numSlowPaths() const override {
+ SkPathCounter counter;
+ counter(fOp);
+ return counter.fNumSlowPathsAndDashEffects;
+ }
+
+private:
+ SkRect fCull;
+ T fOp;
+};
+
+
+SkMiniRecorder::SkMiniRecorder() : fState(State::kEmpty) {}
+SkMiniRecorder::~SkMiniRecorder() {
+ if (fState != State::kEmpty) {
+ // We have internal state pending.
+ // Detaching then deleting a picture is an easy way to clean up.
+ SkDELETE(this->detachAsPicture(SkRect::MakeEmpty()));
+ }
+ SkASSERT(fState == State::kEmpty);
+}
+
+#define TRY_TO_STORE(Type, ...) \
+ if (fState != State::kEmpty) { return false; } \
+ fState = State::k##Type; \
+ new (fBuffer.get()) Type(__VA_ARGS__); \
+ return true
+
+bool SkMiniRecorder::drawRect(const SkRect& rect, const SkPaint& paint) {
+ TRY_TO_STORE(DrawRect, paint, rect);
+}
+
+bool SkMiniRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
+ TRY_TO_STORE(DrawPath, paint, path);
+}
+
+bool SkMiniRecorder::drawTextBlob(const SkTextBlob* b, SkScalar x, SkScalar y, const SkPaint& p) {
+ TRY_TO_STORE(DrawTextBlob, p, b, x, y);
+}
+#undef TRY_TO_STORE
+
+#define CASE(Type) \
+ case State::k##Type: \
+ fState = State::kEmpty; \
+ return SkNEW_ARGS(SkMiniPicture<Type>, (cull, reinterpret_cast<Type*>(fBuffer.get())))
+
+SkPicture* SkMiniRecorder::detachAsPicture(const SkRect& cull) {
+ switch (fState) {
+ case State::kEmpty: return SkNEW(SkEmptyPicture);
+ CASE(DrawPath);
+ CASE(DrawRect);
+ CASE(DrawTextBlob);
+ }
+ SkASSERT(false);
+ return NULL;
+}
+#undef CASE