diff options
author | tomhudson <tomhudson@chromium.org> | 2014-08-20 05:29:41 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-20 05:29:41 -0700 |
commit | 3a0f27916712bb3226874aeaa268e30f565880de (patch) | |
tree | ebfd03a22ebe5a22a709ee5cc09ff4c8a74d3e07 /src | |
parent | 5dfe779c2e684e3e1aacfa24aa7be9c9da1598f9 (diff) |
Move the code over using the same template type approach previously used for willPlayBackBitmaps in http://skbug.com/2702.
Also unifies that flag and this one into a struct so they and others can be computed together. The struct is stored const to enforce lifetime expectations. Adds a few new cases to the unit test.
BUG=skia:2700
R=mtklein@google.com, reed@google.com, robertphillips@google.com, tomhudson@google.com
Committed: https://skia.googlesource.com/skia/+/60c2a79cfa8ceebcbafc243407564dc71f5e3b4f
Author: tomhudson@chromium.org
Review URL: https://codereview.chromium.org/364823009
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkPicture.cpp | 196 | ||||
-rw-r--r-- | src/core/SkRecordAnalysis.cpp | 66 | ||||
-rw-r--r-- | src/core/SkRecordAnalysis.h | 8 |
3 files changed, 187 insertions, 83 deletions
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index 8825123336..1396406540 100644 --- a/src/core/SkPicture.cpp +++ b/src/core/SkPicture.cpp @@ -19,11 +19,13 @@ #include "SkChunkAlloc.h" #include "SkDrawPictureCallback.h" #include "SkPaintPriv.h" +#include "SkPathEffect.h" #include "SkPicture.h" -#include "SkRecordAnalysis.h" #include "SkRegion.h" +#include "SkShader.h" #include "SkStream.h" #include "SkTDArray.h" +#include "SkTLogic.h" #include "SkTSearch.h" #include "SkTime.h" @@ -46,12 +48,184 @@ template <typename T> int SafeCount(const T* obj) { /////////////////////////////////////////////////////////////////////////////// +namespace { + +// Some commands 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; } + +/** SkRecords visitor to determine whether an instance may require an + "external" bitmap to rasterize. May return false positives. + Does not return true for bitmap text. + + Expected use is to determine whether images need to be decoded before + rasterizing a particular SkRecord. + */ +struct BitmapTester { + // Helpers. These create HasMember_bitmap and HasMember_paint. + SK_CREATE_MEMBER_DETECTOR(bitmap); + SK_CREATE_MEMBER_DETECTOR(paint); + + + // Main entry for visitor: + // If the command has a bitmap directly, return true. + // If the command has a paint and the paint has a bitmap, return true. + // Otherwise, return false. + template <typename T> + bool operator()(const T& r) { return CheckBitmap(r); } + + + // If the command 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 = AsPtr(r.paint); + if (paint) { + const SkShader* shader = paint->getShader(); + if (shader && + shader->asABitmap(NULL, NULL, NULL) == 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; } +}; + +bool WillPlaybackBitmaps(const SkRecord& record) { + BitmapTester tester; + for (unsigned i = 0; i < record.count(); i++) { + if (record.visit<bool>(i, tester)) { + return true; + } + } + return false; +} + +/** SkRecords visitor to determine heuristically whether or not a SkPicture + will be performant when rasterized on the GPU. + */ +struct PathCounter { + SK_CREATE_MEMBER_DETECTOR(paint); + + PathCounter() + : numPaintWithPathEffectUses (0) + , numFastPathDashEffects (0) + , numAAConcavePaths (0) + , numAAHairlineConcavePaths (0) { + } + + void checkPaint(const SkPaint* paint) { + if (paint && paint->getPathEffect()) { + numPaintWithPathEffectUses++; + } + } + + 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) { + numFastPathDashEffects++; + } + } + } + + void operator()(const SkRecords::DrawPath& op) { + this->checkPaint(&op.paint); + if (op.paint.isAntiAlias() && !op.path.isConvex()) { + numAAConcavePaths++; + + if (SkPaint::kStroke_Style == op.paint.getStyle() && + 0 == op.paint.getStrokeWidth()) { + numAAHairlineConcavePaths++; + } + } + } + + template <typename T> + SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) { + this->checkPaint(AsPtr(op.paint)); + } + + template <typename T> + SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing */ } + + + int numPaintWithPathEffectUses; + int numFastPathDashEffects; + int numAAConcavePaths; + int numAAHairlineConcavePaths; +}; + +} // namespace + +void SkPicture::Analysis::init(const SkRecord& record) { + + fWillPlaybackBitmaps = WillPlaybackBitmaps(record); + + PathCounter counter; + for (unsigned i = 0; i < record.count(); i++) { + record.visit<void>(i, counter); + } + fNumPaintWithPathEffectUses = counter.numPaintWithPathEffectUses; + fNumFastPathDashEffects = counter.numFastPathDashEffects; + fNumAAConcavePaths = counter.numAAConcavePaths; + fNumAAHairlineConcavePaths = counter.numAAHairlineConcavePaths; +} + +bool SkPicture::Analysis::suitableForGpuRasterization(const char** reason, + int sampleCount) const { + // TODO: the heuristic used here needs to be refined + static const int kNumPaintWithPathEffectsUsesTol = 1; + static const int kNumAAConcavePathsTol = 5; + + int numNonDashedPathEffects = fNumPaintWithPathEffectUses - + fNumFastPathDashEffects; + bool suitableForDash = (0 == fNumPaintWithPathEffectUses) || + (numNonDashedPathEffects < kNumPaintWithPathEffectsUsesTol + && 0 == sampleCount); + + bool ret = suitableForDash && + (fNumAAConcavePaths - fNumAAHairlineConcavePaths) + < kNumAAConcavePathsTol; + + if (!ret && NULL != reason) { + if (!suitableForDash) { + if (0 != sampleCount) { + *reason = "Can't use multisample on dash effect."; + } else { + *reason = "Too many non dashed path effects."; + } + } else if ((fNumAAConcavePaths - fNumAAHairlineConcavePaths) + >= kNumAAConcavePathsTol) + *reason = "Too many anti-aliased concave paths."; + else + *reason = "Unknown reason for GPU unsuitability."; + } + return ret; +} + +/////////////////////////////////////////////////////////////////////////////// + #ifdef SK_SUPPORT_LEGACY_DEFAULT_PICTURE_CTOR // fRecord OK SkPicture::SkPicture() : fWidth(0) - , fHeight(0) - , fRecordWillPlayBackBitmaps(false) { + , fHeight(0) { this->needsNewGenID(); } #endif @@ -62,7 +236,7 @@ SkPicture::SkPicture(int width, int height, bool deepCopyOps) : fWidth(width) , fHeight(height) - , fRecordWillPlayBackBitmaps(false) { + , fAnalysis() { this->needsNewGenID(); SkPictInfo info; @@ -137,7 +311,6 @@ SkPicture* SkPicture::clone() const { } SkPicture* clone = SkNEW_ARGS(SkPicture, (newData.detach(), fWidth, fHeight)); - clone->fRecordWillPlayBackBitmaps = fRecordWillPlayBackBitmaps; clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0 return clone; @@ -271,7 +444,7 @@ SkPicture::SkPicture(SkPictureData* data, int width, int height) : fData(data) , fWidth(width) , fHeight(height) - , fRecordWillPlayBackBitmaps(false) { + , fAnalysis() { this->needsNewGenID(); } @@ -386,8 +559,11 @@ void SkPicture::flatten(SkWriteBuffer& buffer) const { } #if SK_SUPPORT_GPU -// fRecord TODO +// fRecord OK bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const { + if (fRecord.get()) { + return fAnalysis.suitableForGpuRasterization(reason, 0); + } if (NULL == fData.get()) { if (NULL != reason) { *reason = "Missing internal data."; @@ -407,7 +583,7 @@ bool SkPicture::hasText() const { // fRecord OK bool SkPicture::willPlayBackBitmaps() const { if (fRecord.get()) { - return fRecordWillPlayBackBitmaps; + return fAnalysis.fWillPlaybackBitmaps; } if (!fData.get()) { return false; @@ -441,8 +617,10 @@ SkPicture::SkPicture(int width, int height, SkRecord* record, SkBBoxHierarchy* b , fHeight(height) , fRecord(record) , fBBH(SkSafeRef(bbh)) - , fRecordWillPlayBackBitmaps(SkRecordWillPlaybackBitmaps(*record)) { + , fAnalysis() { // TODO: delay as much of this work until just before first playback? + + const_cast<Analysis*>(&fAnalysis)->init(*record); if (fBBH.get()) { SkRecordFillBounds(*record, fBBH.get()); } diff --git a/src/core/SkRecordAnalysis.cpp b/src/core/SkRecordAnalysis.cpp deleted file mode 100644 index 0bfbaef9a6..0000000000 --- a/src/core/SkRecordAnalysis.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "SkRecordAnalysis.h" - -#include "SkShader.h" -#include "SkTLogic.h" - -/** SkRecords visitor to determine whether an instance may require an - "external" bitmap to rasterize. May return false positives. - Does not return true for bitmap text. - - Expected use is to determine whether images need to be decoded before - rasterizing a particular SkRecord. - */ -struct BitmapTester { - // Helpers. These create HasMember_bitmap and HasMember_paint. - SK_CREATE_MEMBER_DETECTOR(bitmap); - SK_CREATE_MEMBER_DETECTOR(paint); - - // Some commands 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; } - - - // Main entry for visitor: - // If the command has a bitmap directly, return true. - // If the command has a paint and the paint has a bitmap, return true. - // Otherwise, return false. - template <typename T> - bool operator()(const T& r) { return CheckBitmap(r); } - - - // If the command 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 = AsPtr(r.paint); - if (paint) { - const SkShader* shader = paint->getShader(); - if (shader && - shader->asABitmap(NULL, NULL, NULL) == 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; } -}; - -bool SkRecordWillPlaybackBitmaps(const SkRecord& record) { - BitmapTester tester; - for (unsigned i = 0; i < record.count(); i++) { - if (record.visit<bool>(i, tester)) { - return true; - } - } - return false; -} diff --git a/src/core/SkRecordAnalysis.h b/src/core/SkRecordAnalysis.h deleted file mode 100644 index 6bdd5bc311..0000000000 --- a/src/core/SkRecordAnalysis.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef SkRecordAnalysis_DEFINED -#define SkRecordAnalysis_DEFINED - -#include "SkRecord.h" - -bool SkRecordWillPlaybackBitmaps(const SkRecord& record); - -#endif // SkRecordAnalysis_DEFINED |