remove SkMiniPicture and co.

This was an optimization for Chromium that I believe is no longer
relevant in a world of PaintOpBuffers.

Change-Id: Ic7526715a0ef1c3cec387a44189b7d56d5107af5
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/213680
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
Mike Klein 2019-05-14 13:03:17 -05:00 committed by Skia Commit-Bot
parent 42dda0884f
commit 046ecb1b5e
11 changed files with 25 additions and 332 deletions

View File

@ -254,8 +254,6 @@ skia_core_sources = [
"$_src/core/SkMatrixUtils.h",
"$_src/core/SkMipMap.cpp",
"$_src/core/SkMipMap.h",
"$_src/core/SkMiniRecorder.cpp",
"$_src/core/SkMiniRecorder.h",
"$_src/core/SkModeColorFilter.cpp",
"$_src/core/SkNextID.h",
"$_src/core/SkLatticeIter.cpp",

View File

@ -219,7 +219,6 @@ private:
friend class SkBigPicture;
friend class SkEmptyPicture;
friend class SkPicturePriv;
template <typename> friend class SkMiniPicture;
void serialize(SkWStream*, const SkSerialProcs*, class SkRefCntSet* typefaces) const;
static sk_sp<SkPicture> MakeFromStream(SkStream*, const SkDeserialProcs*,
@ -241,8 +240,6 @@ private:
// Returns NULL if this is not an SkBigPicture.
virtual const class SkBigPicture* asSkBigPicture() const { return nullptr; }
friend struct SkPathCounter;
// V35: Store SkRect (rather then width & height) in header
// V36: Remove (obsolete) alphatype from SkColorTable
// V37: Added shadow only option to SkDropShadowImageFilter (last version to record CLEAR)

View File

@ -22,7 +22,6 @@ namespace android {
class GrContext;
class SkCanvas;
class SkDrawable;
class SkMiniRecorder;
class SkPictureRecord;
class SkRecord;
class SkRecorder;
@ -117,7 +116,6 @@ private:
sk_sp<SkBBoxHierarchy> fBBH;
std::unique_ptr<SkRecorder> fRecorder;
sk_sp<SkRecord> fRecord;
std::unique_ptr<SkMiniRecorder> fMiniRecorder;
typedef SkNoncopyable INHERITED;
};

View File

@ -1,137 +0,0 @@
/*
* 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 "include/core/SkCanvas.h"
#include "include/core/SkPicture.h"
#include "include/core/SkTextBlob.h"
#include "include/private/SkOnce.h"
#include "src/core/SkMiniRecorder.h"
#include "src/core/SkPictureCommon.h"
#include "src/core/SkRecordDraw.h"
#include "src/core/SkRectPriv.h"
#include "src/core/SkTLazy.h"
#include <new>
using namespace SkRecords;
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(); }
};
// Calculate conservative bounds for each type of draw op that can be its own mini picture.
// These are fairly easy because we know they can't be affected by any matrix or saveLayers.
static SkRect adjust_for_paint(SkRect bounds, const SkPaint& paint) {
return paint.canComputeFastBounds() ? paint.computeFastBounds(bounds, &bounds)
: SkRectPriv::MakeLargest();
}
static SkRect bounds(const DrawRect& op) {
return adjust_for_paint(op.rect, op.paint);
}
static SkRect bounds(const DrawPath& op) {
return op.path.isInverseFillType() ? SkRectPriv::MakeLargest()
: adjust_for_paint(op.path.getBounds(), op.paint);
}
static SkRect bounds(const DrawTextBlob& op) {
return adjust_for_paint(op.blob->bounds().makeOffset(op.x, op.y), op.paint);
}
template <typename T>
class SkMiniPicture final : public SkPicture {
public:
SkMiniPicture(const SkRect* cull, T* op) : fCull(cull ? *cull : bounds(*op)) {
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; }
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.
(void)this->detachAsPicture(nullptr);
}
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, sk_ref_sp(b), x, y);
}
#undef TRY_TO_STORE
sk_sp<SkPicture> SkMiniRecorder::detachAsPicture(const SkRect* cull) {
#define CASE(Type) \
case State::k##Type: \
fState = State::kEmpty; \
return sk_make_sp<SkMiniPicture<Type>>(cull, reinterpret_cast<Type*>(fBuffer.get()))
static SkOnce once;
static SkPicture* empty;
switch (fState) {
case State::kEmpty:
once([]{ empty = new SkEmptyPicture; });
return sk_ref_sp(empty);
CASE(DrawPath);
CASE(DrawRect);
CASE(DrawTextBlob);
}
SkASSERT(false);
return nullptr;
#undef CASE
}
void SkMiniRecorder::flushAndReset(SkCanvas* canvas) {
#define CASE(Type) \
case State::k##Type: { \
fState = State::kEmpty; \
Type* op = reinterpret_cast<Type*>(fBuffer.get()); \
SkRecords::Draw(canvas, nullptr, nullptr, 0, nullptr)(*op); \
op->~Type(); \
} return
switch (fState) {
case State::kEmpty: return;
CASE(DrawPath);
CASE(DrawRect);
CASE(DrawTextBlob);
}
SkASSERT(false);
#undef CASE
}

View File

@ -1,57 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkMiniRecorder_DEFINED
#define SkMiniRecorder_DEFINED
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "src/core/SkRecords.h"
class SkCanvas;
// Records small pictures, but only a limited subset of the canvas API, and may fail.
class SkMiniRecorder : SkNoncopyable {
public:
SkMiniRecorder();
~SkMiniRecorder();
// Try to record an op. Returns false on failure.
bool drawPath(const SkPath&, const SkPaint&);
bool drawRect(const SkRect&, const SkPaint&);
bool drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y, const SkPaint&);
// Detach anything we've recorded as a picture, resetting this SkMiniRecorder.
// If cull is nullptr we'll calculate it.
sk_sp<SkPicture> detachAsPicture(const SkRect* cull);
// Flush anything we've recorded to the canvas, resetting this SkMiniRecorder.
// This is logically the same as but rather more efficient than:
// sk_sp<SkPicture> pic(this->detachAsPicture(nullptr));
// pic->playback(canvas);
void flushAndReset(SkCanvas*);
private:
enum class State {
kEmpty,
kDrawPath,
kDrawRect,
kDrawTextBlob,
};
State fState;
template <size_t A, size_t B>
struct Max { static const size_t val = A > B ? A : B; };
static const size_t kInlineStorage =
Max<sizeof(SkRecords::DrawPath),
Max<sizeof(SkRecords::DrawRect),
sizeof(SkRecords::DrawTextBlob)>::val>::val;
SkAlignedSStorage<kInlineStorage> fBuffer;
};
#endif//SkMiniRecorder_DEFINED

View File

@ -8,84 +8,8 @@
#ifndef SkPictureCommon_DEFINED
#define SkPictureCommon_DEFINED
// Some shared code used by both SkBigPicture and SkMiniPicture.
// SkTextHunter -- SkRecord visitor that returns true when the op draws text.
// SkPathCounter -- SkRecord visitor that counts paths that draw slowly on the GPU.
#include "include/core/SkPathEffect.h"
#include "include/core/SkShader.h"
#include "include/private/SkTLogic.h"
#include "src/core/SkRecords.h"
// TODO: might be nicer to have operator() return an int (the number of slow paths) ?
struct SkPathCounter {
// Some ops have a paint, some have an optional paint. Either way, get back a pointer.
static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
SkPathCounter() : fNumSlowPathsAndDashEffects(0) {}
void checkPaint(const SkPaint* paint) {
if (paint && paint->getPathEffect()) {
// Initially assume it's slow.
fNumSlowPathsAndDashEffects++;
}
}
void operator()(const SkRecords::DrawPoints& op) {
this->checkPaint(&op.paint);
const SkPathEffect* effect = op.paint.getPathEffect();
if (effect) {
SkPathEffect::DashInfo info;
SkPathEffect::DashType dashType = effect->asADash(&info);
if (2 == op.count && SkPaint::kRound_Cap != op.paint.getStrokeCap() &&
SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
fNumSlowPathsAndDashEffects--;
}
}
}
void operator()(const SkRecords::DrawPath& op) {
this->checkPaint(&op.paint);
if (op.paint.isAntiAlias() && !op.path.isConvex()) {
SkPaint::Style paintStyle = op.paint.getStyle();
const SkRect& pathBounds = op.path.getBounds();
if (SkPaint::kStroke_Style == paintStyle &&
0 == op.paint.getStrokeWidth()) {
// AA hairline concave path is not slow.
} else if (SkPaint::kFill_Style == paintStyle && pathBounds.width() < 64.f &&
pathBounds.height() < 64.f && !op.path.isVolatile()) {
// AADF eligible concave path is not slow.
} else {
fNumSlowPathsAndDashEffects++;
}
}
}
void operator()(const SkRecords::ClipPath& op) {
// TODO: does the SkRegion op matter?
if (op.opAA.aa() && !op.path.isConvex()) {
fNumSlowPathsAndDashEffects++;
}
}
void operator()(const SkRecords::SaveLayer& op) {
this->checkPaint(AsPtr(op.paint));
}
template <typename T>
SK_WHEN(T::kTags & SkRecords::kHasPaint_Tag, void) operator()(const T& op) {
this->checkPaint(AsPtr(op.paint));
}
template <typename T>
SK_WHEN(!(T::kTags & SkRecords::kHasPaint_Tag), void)
operator()(const T& op) { /* do nothing */ }
int fNumSlowPathsAndDashEffects;
};
sk_sp<SkImage> ImageDeserializer_SkDeserialImageProc(const void*, size_t, void* imagedeserializer);
class SkStream;
struct SkPictInfo;
bool SkPicture_StreamIsSKP(SkStream*, SkPictInfo*);

View File

@ -12,6 +12,7 @@
#include "include/core/SkCanvasVirtualEnforcer.h"
#include "include/core/SkFlattenable.h"
#include "include/core/SkPicture.h"
#include "include/core/SkTextBlob.h"
#include "include/core/SkVertices.h"
#include "include/private/SkTArray.h"
#include "include/private/SkTDArray.h"

View File

@ -10,7 +10,6 @@
#include "include/core/SkPictureRecorder.h"
#include "include/core/SkTypes.h"
#include "src/core/SkBigPicture.h"
#include "src/core/SkMiniRecorder.h"
#include "src/core/SkRecord.h"
#include "src/core/SkRecordDraw.h"
#include "src/core/SkRecordOpts.h"
@ -19,8 +18,7 @@
SkPictureRecorder::SkPictureRecorder() {
fActivelyRecording = false;
fMiniRecorder.reset(new SkMiniRecorder);
fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeEmpty(), fMiniRecorder.get()));
fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeEmpty()));
}
SkPictureRecorder::~SkPictureRecorder() {}
@ -44,7 +42,7 @@ SkCanvas* SkPictureRecorder::beginRecording(const SkRect& userCullRect,
SkRecorder::DrawPictureMode dpm = (recordFlags & kPlaybackDrawPicture_RecordFlag)
? SkRecorder::Playback_DrawPictureMode
: SkRecorder::Record_DrawPictureMode;
fRecorder->reset(fRecord.get(), cullRect, dpm, fMiniRecorder.get());
fRecorder->reset(fRecord.get(), cullRect, dpm);
fActivelyRecording = true;
return this->getRecordingCanvas();
}
@ -53,14 +51,21 @@ SkCanvas* SkPictureRecorder::getRecordingCanvas() {
return fActivelyRecording ? fRecorder.get() : nullptr;
}
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(); }
};
sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture(uint32_t finishFlags) {
fActivelyRecording = false;
fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
if (fRecord->count() == 0) {
auto pic = fMiniRecorder->detachAsPicture(fBBH ? nullptr : &fCullRect);
fBBH.reset(nullptr);
return pic;
return sk_make_sp<SkEmptyPicture>();
}
// TODO: delay as much of this work until just before first playback?
@ -115,7 +120,6 @@ void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
sk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable(uint32_t finishFlags) {
fActivelyRecording = false;
fRecorder->flushMiniRecorder();
fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
SkRecordOptimize(fRecord.get());

View File

@ -39,28 +39,25 @@ void SkDrawableList::append(SkDrawable* drawable) {
///////////////////////////////////////////////////////////////////////////////////////////////
SkRecorder::SkRecorder(SkRecord* record, int width, int height, SkMiniRecorder* mr)
SkRecorder::SkRecorder(SkRecord* record, int width, int height)
: SkCanvasVirtualEnforcer<SkNoDrawCanvas>(width, height)
, fDrawPictureMode(Record_DrawPictureMode)
, fApproxBytesUsedBySubPictures(0)
, fRecord(record)
, fMiniRecorder(mr) {}
, fRecord(record) {}
SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds, SkMiniRecorder* mr)
SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds)
: SkCanvasVirtualEnforcer<SkNoDrawCanvas>(bounds.roundOut())
, fDrawPictureMode(Record_DrawPictureMode)
, fApproxBytesUsedBySubPictures(0)
, fRecord(record)
, fMiniRecorder(mr) {}
, fRecord(record) {}
void SkRecorder::reset(SkRecord* record, const SkRect& bounds,
DrawPictureMode dpm, SkMiniRecorder* mr) {
DrawPictureMode dpm) {
this->forgetRecord();
fDrawPictureMode = dpm;
fRecord = record;
SkIRect rounded = bounds.roundOut();
this->resetCanvas(rounded.right(), rounded.bottom());
fMiniRecorder = mr;
}
void SkRecorder::forgetRecord() {
@ -72,15 +69,9 @@ void SkRecorder::forgetRecord() {
// To make appending to fRecord a little less verbose.
template<typename T, typename... Args>
void SkRecorder::append(Args&&... args) {
if (fMiniRecorder) {
this->flushMiniRecorder();
}
new (fRecord->append<T>()) T{std::forward<Args>(args)...};
}
#define TRY_MINIRECORDER(method, ...) \
if (fMiniRecorder && fMiniRecorder->method(__VA_ARGS__)) return
// For methods which must call back into SkNoDrawCanvas.
#define INHERITED(method, ...) this->SkNoDrawCanvas::method(__VA_ARGS__)
@ -127,14 +118,6 @@ char* SkRecorder::copy(const char* src) {
return this->copy(src, strlen(src)+1);
}
void SkRecorder::flushMiniRecorder() {
if (fMiniRecorder) {
SkMiniRecorder* mr = fMiniRecorder;
fMiniRecorder = nullptr; // Needs to happen before flushAndReset() or we recurse forever.
mr->flushAndReset(this);
}
}
void SkRecorder::onDrawPaint(const SkPaint& paint) {
this->append<SkRecords::DrawPaint>(paint);
}
@ -151,7 +134,6 @@ void SkRecorder::onDrawPoints(PointMode mode,
}
void SkRecorder::onDrawRect(const SkRect& rect, const SkPaint& paint) {
TRY_MINIRECORDER(drawRect, rect, paint);
this->append<SkRecords::DrawRect>(paint, rect);
}
@ -190,7 +172,6 @@ void SkRecorder::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
}
void SkRecorder::onDrawPath(const SkPath& path, const SkPaint& paint) {
TRY_MINIRECORDER(drawPath, path, paint);
this->append<SkRecords::DrawPath>(paint, path);
}
@ -259,7 +240,6 @@ void SkRecorder::onDrawImageLattice(const SkImage* image, const Lattice& lattice
void SkRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) {
TRY_MINIRECORDER(drawTextBlob, blob, x, y, paint);
this->append<SkRecords::DrawTextBlob>(paint, sk_ref_sp(blob), x, y);
}

View File

@ -12,7 +12,6 @@
#include "include/private/SkTDArray.h"
#include "include/utils/SkNoDrawCanvas.h"
#include "src/core/SkBigPicture.h"
#include "src/core/SkMiniRecorder.h"
#include "src/core/SkRecord.h"
#include "src/core/SkRecords.h"
@ -40,11 +39,11 @@ private:
class SkRecorder final : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> {
public:
// Does not take ownership of the SkRecord.
SkRecorder(SkRecord*, int width, int height, SkMiniRecorder* = nullptr); // legacy version
SkRecorder(SkRecord*, const SkRect& bounds, SkMiniRecorder* = nullptr);
SkRecorder(SkRecord*, int width, int height); // legacy version
SkRecorder(SkRecord*, const SkRect& bounds);
enum DrawPictureMode { Record_DrawPictureMode, Playback_DrawPictureMode };
void reset(SkRecord*, const SkRect& bounds, DrawPictureMode, SkMiniRecorder* = nullptr);
void reset(SkRecord*, const SkRect& bounds, DrawPictureMode);
size_t approxBytesUsedBySubPictures() const { return fApproxBytesUsedBySubPictures; }
@ -121,8 +120,6 @@ public:
sk_sp<SkSurface> onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override;
void flushMiniRecorder();
private:
template <typename T>
T* copy(const T*);
@ -137,8 +134,6 @@ private:
size_t fApproxBytesUsedBySubPictures;
SkRecord* fRecord;
std::unique_ptr<SkDrawableList> fDrawableList;
SkMiniRecorder* fMiniRecorder;
};
#endif//SkRecorder_DEFINED

View File

@ -11,6 +11,7 @@
#include "include/core/SkClipOp.h"
#include "include/core/SkColor.h"
#include "include/core/SkData.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkMatrix.h"
@ -29,7 +30,6 @@
#include "src/core/SkBBoxHierarchy.h"
#include "src/core/SkBigPicture.h"
#include "src/core/SkClipOpPriv.h"
#include "src/core/SkMiniRecorder.h"
#include "src/core/SkPicturePriv.h"
#include "src/core/SkRectPriv.h"
#include "tests/Test.h"
@ -758,16 +758,6 @@ DEF_TEST(Picture_getRecordingCanvas, r) {
}
}
DEF_TEST(MiniRecorderLeftHanging, r) {
// Any shader or other ref-counted effect will do just fine here.
SkPaint paint;
paint.setShader(SkShaders::Color(SK_ColorRED));
SkMiniRecorder rec;
REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint));
// Don't call rec.detachPicture(). Test succeeds by not asserting or leaking the shader.
}
DEF_TEST(Picture_preserveCullRect, r) {
SkPictureRecorder recorder;
@ -793,7 +783,7 @@ DEF_TEST(Picture_preserveCullRect, r) {
// bounds of those ops, we should trim down the picture cull to the ops' bounds.
// If we're not using an SkBBH, we shouldn't change it.
DEF_TEST(Picture_UpdatedCull_1, r) {
// Testing 1 draw exercises SkMiniPicture.
// Testing 1 draw exercised SkMiniPicture, which no longer exists, but still a fine test.
SkRTreeFactory factory;
SkPictureRecorder recorder;