| Index: src/core/SkRecordAnalysis.cpp
|
| diff --git a/src/core/SkRecordAnalysis.cpp b/src/core/SkRecordAnalysis.cpp
|
| index 0bfbaef9a65febd570b649bd16b01bdb85d1c17a..2d6d8fdaccf550485655fddda9d60991316df36a 100644
|
| --- a/src/core/SkRecordAnalysis.cpp
|
| +++ b/src/core/SkRecordAnalysis.cpp
|
| @@ -1,8 +1,12 @@
|
| #include "SkRecordAnalysis.h"
|
|
|
| +#include "SkPathEffect.h"
|
| #include "SkShader.h"
|
| #include "SkTLogic.h"
|
|
|
| +
|
| +namespace {
|
| +
|
| /** 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.
|
| @@ -55,7 +59,7 @@ struct BitmapTester {
|
| static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; }
|
| };
|
|
|
| -bool SkRecordWillPlaybackBitmaps(const SkRecord& record) {
|
| +bool SkWillPlaybackBitmaps(const SkRecord& record) {
|
| BitmapTester tester;
|
| for (unsigned i = 0; i < record.count(); i++) {
|
| if (record.visit<bool>(i, tester)) {
|
| @@ -64,3 +68,127 @@ bool SkRecordWillPlaybackBitmaps(const SkRecord& record) {
|
| }
|
| return false;
|
| }
|
| +
|
| +struct PathCounter {
|
| + SK_CREATE_MEMBER_DETECTOR(paint);
|
| + SK_CREATE_TYPE_DETECTOR(DrawPoints);
|
| + SK_CREATE_TYPE_DETECTOR(DrawPath);
|
| +
|
| + // 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; }
|
| +
|
| + PathCounter()
|
| + : numPaintWithPathEffectUses (0)
|
| + , numFastPathDashEffects (0)
|
| + , numAAConcavePaths (0)
|
| + , numAAHairlineConcavePaths (0) {
|
| + }
|
| +
|
| + // Must have a return type to make the SkRecord vistor templates happy.
|
| + template <typename T>
|
| + bool operator()(const T& r) {
|
| + CheckPaint(r);
|
| + CheckDrawPoints(r);
|
| + CheckDrawPath(r);
|
| + return true;
|
| + }
|
| +
|
| + template <typename T>
|
| + SK_WHEN(HasMember_paint<T>, void) CheckPaint(const T& r) {
|
| + const SkPaint* paint = AsPtr(r.paint);
|
| + if (paint && paint->getPathEffect()) {
|
| + numPaintWithPathEffectUses++;
|
| + }
|
| + }
|
| +
|
| + template <typename T>
|
| + SK_WHEN(!HasMember_paint<T>, void) CheckPaint(const T& r) { /* do nothing */ }
|
| +
|
| + template <typename T>
|
| + SK_WHEN(HasType_DrawPoints<T>, void) CheckDrawPoints(const T& r) {
|
| + const SkPathEffect* effect = r.paint.getPathEffect();
|
| + if (effect) {
|
| + SkPathEffect::DashInfo info;
|
| + SkPathEffect::DashType dashType = effect->asADash(&info);
|
| + if (2 == r.count && SkPaint::kRound_Cap != r.paint.getStrokeCap() &&
|
| + SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
|
| + numFastPathDashEffects++;
|
| + }
|
| + }
|
| + }
|
| +
|
| + template <typename T>
|
| + SK_WHEN(!HasType_DrawPoints<T>, void) CheckDrawPoints(const T& r) { /* do nothing */ }
|
| +
|
| + template <typename T>
|
| + SK_WHEN(HasType_DrawPath<T>, void) CheckDrawPath(const T& r) {
|
| + if (r.paint.isAntiAlias() && !r.path.isConvex()) {
|
| + numAAConcavePaths++;
|
| +
|
| + if (SkPaint::kStroke_Style == r.paint.getStyle() &&
|
| + 0 == r.paint.getStrokeWidth()) {
|
| + numAAHairlineConcavePaths++;
|
| + }
|
| + }
|
| + }
|
| +
|
| + template <typename T>
|
| + SK_WHEN(!HasType_DrawPath<T>, void) CheckDrawPath(const T& r) { /* do nothing */ }
|
| +
|
| +
|
| + int numPaintWithPathEffectUses;
|
| + int numFastPathDashEffects;
|
| + int numAAConcavePaths;
|
| + int numAAHairlineConcavePaths;
|
| +};
|
| +
|
| +bool SkRecordSuitableForGpuRasterization(const SkRecord& record,
|
| + const char** reason = NULL,
|
| + int sampleCount = 0) {
|
| + PathCounter counter;
|
| + for (unsigned i = 0; i < record.count(); i++) {
|
| + record.visit<bool>(i, counter);
|
| + }
|
| +
|
| + // TODO: the heuristic used here needs to be refined
|
| + static const int kNumPaintWithPathEffectsUsesTol = 1;
|
| + static const int kNumAAConcavePathsTol = 5;
|
| +
|
| + int numNonDashedPathEffects = counter.numPaintWithPathEffectUses -
|
| + counter.numFastPathDashEffects;
|
| + bool suitableForDash = (0 == counter.numPaintWithPathEffectUses) ||
|
| + (numNonDashedPathEffects < kNumPaintWithPathEffectsUsesTol
|
| + && 0 == sampleCount);
|
| +
|
| + bool ret = suitableForDash &&
|
| + (counter.numAAConcavePaths - counter.numAAHairlineConcavePaths)
|
| + < 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 ((counter.numAAConcavePaths - counter.numAAHairlineConcavePaths)
|
| + >= kNumAAConcavePathsTol)
|
| + *reason = "Too many anti-aliased concave paths.";
|
| + else
|
| + *reason = "Unknown reason for GPU unsuitability.";
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +SkRecordAnalysis AnalyzeSkRecord(const SkRecord& record) {
|
| + SkRecordAnalysis results;
|
| +
|
| + results.fWillPlaybackBitmaps = SkWillPlaybackBitmaps(record);
|
| + results.fSuitableForGpuRasterization = SkRecordSuitableForGpuRasterization(record);
|
| +
|
| + return results;
|
| +}
|
| +
|
|
|