OLD | NEW |
1 #include "SkRecordAnalysis.h" | 1 #include "SkRecordAnalysis.h" |
2 | 2 |
| 3 #include "SkPathEffect.h" |
3 #include "SkShader.h" | 4 #include "SkShader.h" |
4 #include "SkTLogic.h" | 5 #include "SkTLogic.h" |
5 | 6 |
| 7 |
| 8 namespace { |
| 9 |
6 /** SkRecords visitor to determine whether an instance may require an | 10 /** SkRecords visitor to determine whether an instance may require an |
7 "external" bitmap to rasterize. May return false positives. | 11 "external" bitmap to rasterize. May return false positives. |
8 Does not return true for bitmap text. | 12 Does not return true for bitmap text. |
9 | 13 |
10 Expected use is to determine whether images need to be decoded before | 14 Expected use is to determine whether images need to be decoded before |
11 rasterizing a particular SkRecord. | 15 rasterizing a particular SkRecord. |
12 */ | 16 */ |
13 struct BitmapTester { | 17 struct BitmapTester { |
14 // Helpers. These create HasMember_bitmap and HasMember_paint. | 18 // Helpers. These create HasMember_bitmap and HasMember_paint. |
15 SK_CREATE_MEMBER_DETECTOR(bitmap); | 19 SK_CREATE_MEMBER_DETECTOR(bitmap); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 } | 52 } |
49 } | 53 } |
50 return false; | 54 return false; |
51 } | 55 } |
52 | 56 |
53 // If we don't have a paint, that non-paint has no bitmap. | 57 // If we don't have a paint, that non-paint has no bitmap. |
54 template <typename T> | 58 template <typename T> |
55 static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return fals
e; } | 59 static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return fals
e; } |
56 }; | 60 }; |
57 | 61 |
58 bool SkRecordWillPlaybackBitmaps(const SkRecord& record) { | 62 bool SkWillPlaybackBitmaps(const SkRecord& record) { |
59 BitmapTester tester; | 63 BitmapTester tester; |
60 for (unsigned i = 0; i < record.count(); i++) { | 64 for (unsigned i = 0; i < record.count(); i++) { |
61 if (record.visit<bool>(i, tester)) { | 65 if (record.visit<bool>(i, tester)) { |
62 return true; | 66 return true; |
63 } | 67 } |
64 } | 68 } |
65 return false; | 69 return false; |
66 } | 70 } |
| 71 |
| 72 struct PathCounter { |
| 73 SK_CREATE_MEMBER_DETECTOR(paint); |
| 74 SK_CREATE_TYPE_DETECTOR(DrawPoints); |
| 75 SK_CREATE_TYPE_DETECTOR(DrawPath); |
| 76 |
| 77 // Some commands have a paint, some have an optional paint. Either way, get
back a pointer. |
| 78 static const SkPaint* AsPtr(const SkPaint& p) { return &p; } |
| 79 static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return
p; } |
| 80 |
| 81 PathCounter() |
| 82 : numPaintWithPathEffectUses (0) |
| 83 , numFastPathDashEffects (0) |
| 84 , numAAConcavePaths (0) |
| 85 , numAAHairlineConcavePaths (0) { |
| 86 } |
| 87 |
| 88 // Must have a return type to make the SkRecord vistor templates happy. |
| 89 template <typename T> |
| 90 bool operator()(const T& r) { |
| 91 CheckPaint(r); |
| 92 CheckDrawPoints(r); |
| 93 CheckDrawPath(r); |
| 94 return true; |
| 95 } |
| 96 |
| 97 template <typename T> |
| 98 SK_WHEN(HasMember_paint<T>, void) CheckPaint(const T& r) { |
| 99 const SkPaint* paint = AsPtr(r.paint); |
| 100 if (paint && paint->getPathEffect()) { |
| 101 numPaintWithPathEffectUses++; |
| 102 } |
| 103 } |
| 104 |
| 105 template <typename T> |
| 106 SK_WHEN(!HasMember_paint<T>, void) CheckPaint(const T& r) { /* do nothing */
} |
| 107 |
| 108 template <typename T> |
| 109 SK_WHEN(HasType_DrawPoints<T>, void) CheckDrawPoints(const T& r) { |
| 110 const SkPathEffect* effect = r.paint.getPathEffect(); |
| 111 if (effect) { |
| 112 SkPathEffect::DashInfo info; |
| 113 SkPathEffect::DashType dashType = effect->asADash(&info); |
| 114 if (2 == r.count && SkPaint::kRound_Cap != r.paint.getStrokeCap() && |
| 115 SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) { |
| 116 numFastPathDashEffects++; |
| 117 } |
| 118 } |
| 119 } |
| 120 |
| 121 template <typename T> |
| 122 SK_WHEN(!HasType_DrawPoints<T>, void) CheckDrawPoints(const T& r) { /* do no
thing */ } |
| 123 |
| 124 template <typename T> |
| 125 SK_WHEN(HasType_DrawPath<T>, void) CheckDrawPath(const T& r) { |
| 126 if (r.paint.isAntiAlias() && !r.path.isConvex()) { |
| 127 numAAConcavePaths++; |
| 128 |
| 129 if (SkPaint::kStroke_Style == r.paint.getStyle() && |
| 130 0 == r.paint.getStrokeWidth()) { |
| 131 numAAHairlineConcavePaths++; |
| 132 } |
| 133 } |
| 134 } |
| 135 |
| 136 template <typename T> |
| 137 SK_WHEN(!HasType_DrawPath<T>, void) CheckDrawPath(const T& r) { /* do nothin
g */ } |
| 138 |
| 139 |
| 140 int numPaintWithPathEffectUses; |
| 141 int numFastPathDashEffects; |
| 142 int numAAConcavePaths; |
| 143 int numAAHairlineConcavePaths; |
| 144 }; |
| 145 |
| 146 bool SkRecordSuitableForGpuRasterization(const SkRecord& record, |
| 147 const char** reason = NULL, |
| 148 int sampleCount = 0) { |
| 149 PathCounter counter; |
| 150 for (unsigned i = 0; i < record.count(); i++) { |
| 151 record.visit<bool>(i, counter); |
| 152 } |
| 153 |
| 154 // TODO: the heuristic used here needs to be refined |
| 155 static const int kNumPaintWithPathEffectsUsesTol = 1; |
| 156 static const int kNumAAConcavePathsTol = 5; |
| 157 |
| 158 int numNonDashedPathEffects = counter.numPaintWithPathEffectUses - |
| 159 counter.numFastPathDashEffects; |
| 160 bool suitableForDash = (0 == counter.numPaintWithPathEffectUses) || |
| 161 (numNonDashedPathEffects < kNumPaintWithPathEffectsUs
esTol |
| 162 && 0 == sampleCount); |
| 163 |
| 164 bool ret = suitableForDash && |
| 165 (counter.numAAConcavePaths - counter.numAAHairlineConcavePaths) |
| 166 < kNumAAConcavePathsTol; |
| 167 |
| 168 if (!ret && NULL != reason) { |
| 169 if (!suitableForDash) { |
| 170 if (0 != sampleCount) { |
| 171 *reason = "Can't use multisample on dash effect."; |
| 172 } else { |
| 173 *reason = "Too many non dashed path effects."; |
| 174 } |
| 175 } else if ((counter.numAAConcavePaths - counter.numAAHairlineConcavePath
s) |
| 176 >= kNumAAConcavePathsTol) |
| 177 *reason = "Too many anti-aliased concave paths."; |
| 178 else |
| 179 *reason = "Unknown reason for GPU unsuitability."; |
| 180 } |
| 181 return ret; |
| 182 } |
| 183 |
| 184 } // namespace |
| 185 |
| 186 SkRecordAnalysis AnalyzeSkRecord(const SkRecord& record) { |
| 187 SkRecordAnalysis results; |
| 188 |
| 189 results.fWillPlaybackBitmaps = SkWillPlaybackBitmaps(record); |
| 190 results.fSuitableForGpuRasterization = SkRecordSuitableForGpuRasterization(r
ecord); |
| 191 |
| 192 return results; |
| 193 } |
| 194 |
OLD | NEW |