| Index: src/core/SkBigPicture.cpp
|
| diff --git a/src/core/SkBigPicture.cpp b/src/core/SkBigPicture.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..62bc9c03e2c394ee6e73eda50e7d221f5e5c6c8b
|
| --- /dev/null
|
| +++ b/src/core/SkBigPicture.cpp
|
| @@ -0,0 +1,220 @@
|
| +/*
|
| + * 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 "SkBBoxHierarchy.h"
|
| +#include "SkBigPicture.h"
|
| +#include "SkPathEffect.h"
|
| +#include "SkRecord.h"
|
| +#include "SkRecordDraw.h"
|
| +
|
| +SkBigPicture::SkBigPicture(const SkRect& cull,
|
| + SkRecord* record,
|
| + SnapshotArray* drawablePicts,
|
| + SkBBoxHierarchy* bbh,
|
| + AccelData* accelData,
|
| + size_t approxBytesUsedBySubPictures)
|
| + : fCullRect(cull)
|
| + , fAnalysis(*record)
|
| + , fApproxBytesUsedBySubPictures(approxBytesUsedBySubPictures)
|
| + , fRecord(record) // Take ownership of caller's ref.
|
| + , fDrawablePicts(drawablePicts) // Take ownership.
|
| + , fBBH(bbh) // Take ownership of caller's ref.
|
| + , fAccelData(accelData) // Take ownership of caller's ref.
|
| +{}
|
| +
|
| +void SkBigPicture::playback(SkCanvas* canvas, AbortCallback* callback) const {
|
| + SkASSERT(canvas);
|
| +
|
| + // If the query contains the whole picture, don't bother with the BBH.
|
| + SkRect clipBounds = { 0, 0, 0, 0 };
|
| + (void)canvas->getClipBounds(&clipBounds);
|
| + const bool useBBH = !clipBounds.contains(this->cullRect());
|
| +
|
| + SkRecordDraw(*fRecord,
|
| + canvas,
|
| + this->drawablePicts(),
|
| + nullptr,
|
| + this->drawableCount(),
|
| + useBBH ? fBBH : nullptr,
|
| + callback);
|
| +}
|
| +
|
| +void SkBigPicture::partialPlayback(SkCanvas* canvas,
|
| + unsigned start,
|
| + unsigned stop,
|
| + const SkMatrix& initialCTM) const {
|
| + SkASSERT(canvas);
|
| + SkRecordPartialDraw(*fRecord,
|
| + canvas,
|
| + this->drawablePicts(),
|
| + this->drawableCount(),
|
| + start,
|
| + stop,
|
| + initialCTM);
|
| +}
|
| +
|
| +SkRect SkBigPicture::cullRect() const { return fCullRect; }
|
| +bool SkBigPicture::hasText() const { return fAnalysis.fHasText; }
|
| +bool SkBigPicture::willPlayBackBitmaps() const { return fAnalysis.fWillPlaybackBitmaps; }
|
| +int SkBigPicture::numSlowPaths() const { return fAnalysis.fNumSlowPathsAndDashEffects; }
|
| +int SkBigPicture::approximateOpCount() const { return fRecord->count(); }
|
| +size_t SkBigPicture::approximateBytesUsed() const {
|
| + size_t bytes = sizeof(*this) + fRecord->bytesUsed() + fApproxBytesUsedBySubPictures;
|
| + if (fBBH) { bytes += fBBH->bytesUsed(); }
|
| + return bytes;
|
| +}
|
| +bool SkBigPicture::suitableForGpuRasterization(GrContext*, const char** reason) const {
|
| + return fAnalysis.suitableForGpuRasterization(reason);
|
| +}
|
| +
|
| +int SkBigPicture::drawableCount() const {
|
| + return fDrawablePicts ? fDrawablePicts->count() : 0;
|
| +}
|
| +SkPicture const* const* SkBigPicture::drawablePicts() const {
|
| + return fDrawablePicts ? fDrawablePicts->begin() : nullptr;
|
| +}
|
| +
|
| +
|
| +// Some ops have a paint, some have an optional paint. Either way, get back a pointer.
|
| +static const SkPaint* as_ptr(const SkPaint& p) { return &p; }
|
| +static const SkPaint* as_ptr(const SkRecords::Optional<SkPaint>& p) { return p; }
|
| +
|
| +struct TextHunter {
|
| + // Most ops never have text. Some always do. Subpictures know themeselves.
|
| + template <typename T> bool operator()(const T&) { return false; }
|
| + bool operator()(const SkRecords::DrawPosText&) { return true; }
|
| + bool operator()(const SkRecords::DrawPosTextH&) { return true; }
|
| + bool operator()(const SkRecords::DrawText&) { return true; }
|
| + bool operator()(const SkRecords::DrawTextBlob&) { return true; }
|
| + bool operator()(const SkRecords::DrawTextOnPath&) { return true; }
|
| + bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasText(); }
|
| +};
|
| +
|
| +struct BitmapHunter {
|
| + // Helpers. These create HasMember_bitmap and HasMember_paint.
|
| + SK_CREATE_MEMBER_DETECTOR(bitmap);
|
| + SK_CREATE_MEMBER_DETECTOR(paint);
|
| +
|
| + // Main entry for visitor:
|
| + // If the op is a DrawPicture, recurse.
|
| + // If the op has a bitmap directly, return true.
|
| + // If the op has a paint and the paint has a bitmap, return true.
|
| + // Otherwise, return false.
|
| + bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); }
|
| +
|
| + template <typename T>
|
| + bool operator()(const T& r) { return CheckBitmap(r); }
|
| +
|
| + // If the op has a bitmap, of course we're going to play back bitmaps.
|
| + template <typename T>
|
| + static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return true; }
|
| +
|
| + // If not, look for one in its paint (if it has a paint).
|
| + template <typename T>
|
| + static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return CheckPaint(r); }
|
| +
|
| + // If we have a paint, dig down into the effects looking for a bitmap.
|
| + template <typename T>
|
| + static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) {
|
| + const SkPaint* paint = as_ptr(r.paint);
|
| + if (paint) {
|
| + const SkShader* shader = paint->getShader();
|
| + if (shader &&
|
| + shader->asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefault_BitmapType) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + // If we don't have a paint, that non-paint has no bitmap.
|
| + template <typename T>
|
| + static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; }
|
| +};
|
| +
|
| +struct SkBigPicture::PathCounter {
|
| + SK_CREATE_MEMBER_DETECTOR(paint);
|
| +
|
| + PathCounter() : fNumSlowPathsAndDashEffects(0) {}
|
| +
|
| + // Recurse into nested pictures.
|
| + void operator()(const SkRecords::DrawPicture& op) {
|
| + fNumSlowPathsAndDashEffects += op.picture->numSlowPaths();
|
| + }
|
| +
|
| + 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++;
|
| + }
|
| + }
|
| + }
|
| +
|
| + template <typename T>
|
| + SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) {
|
| + this->checkPaint(as_ptr(op.paint));
|
| + }
|
| +
|
| + template <typename T>
|
| + SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing */ }
|
| +
|
| + int fNumSlowPathsAndDashEffects;
|
| +};
|
| +
|
| +SkBigPicture::Analysis::Analysis(const SkRecord& record) {
|
| + TextHunter text;
|
| + BitmapHunter bitmap;
|
| + PathCounter path;
|
| +
|
| + bool hasText = false, hasBitmap = false;
|
| + for (unsigned i = 0; i < record.count(); i++) {
|
| + hasText = hasText || record.visit<bool>(i, text);
|
| + hasBitmap = hasBitmap || record.visit<bool>(i, bitmap);
|
| + record.visit<void>(i, path);
|
| + }
|
| +
|
| + fHasText = hasText;
|
| + fWillPlaybackBitmaps = hasBitmap;
|
| + fNumSlowPathsAndDashEffects = SkTMin<int>(path.fNumSlowPathsAndDashEffects, 255);
|
| +}
|
| +
|
| +bool SkBigPicture::Analysis::suitableForGpuRasterization(const char** reason) const {
|
| + if (fNumSlowPathsAndDashEffects > 5) {
|
| + if (reason) { *reason = "Too many slow paths (either concave or dashed)."; }
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
|
|