OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkRecordOpts.h" | 8 #include "SkRecordOpts.h" |
9 | 9 |
10 #include "SkRecordPattern.h" | 10 #include "SkRecordPattern.h" |
11 #include "SkRecords.h" | 11 #include "SkRecords.h" |
12 #include "SkTDArray.h" | 12 #include "SkTDArray.h" |
13 | 13 |
14 using namespace SkRecords; | 14 using namespace SkRecords; |
15 | 15 |
16 void SkRecordOptimize(SkRecord* record) { | 16 void SkRecordOptimize(SkRecord* record) { |
17 // TODO(mtklein): fuse independent optimizations to reduce number of passes? | 17 // TODO(mtklein): fuse independent optimizations to reduce number of passes? |
18 SkRecordNoopCulls(record); | |
19 SkRecordNoopSaveRestores(record); | 18 SkRecordNoopSaveRestores(record); |
20 // TODO(mtklein): figure out why we draw differently and reenable | 19 // TODO(mtklein): figure out why we draw differently and reenable |
21 //SkRecordNoopSaveLayerDrawRestores(record); | 20 //SkRecordNoopSaveLayerDrawRestores(record); |
22 | 21 |
23 SkRecordAnnotateCullingPairs(record); | |
24 SkRecordReduceDrawPosTextStrength(record); // Helpful to run this before Bo
undDrawPosTextH. | 22 SkRecordReduceDrawPosTextStrength(record); // Helpful to run this before Bo
undDrawPosTextH. |
25 SkRecordBoundDrawPosTextH(record); | |
26 } | 23 } |
27 | 24 |
28 // Most of the optimizations in this file are pattern-based. These are all defi
ned as structs with: | 25 // Most of the optimizations in this file are pattern-based. These are all defi
ned as structs with: |
29 // - a Pattern typedef | 26 // - a Pattern typedef |
30 // - a bool onMatch(SkRceord*, Pattern*, unsigned begin, unsigned end) method, | 27 // - a bool onMatch(SkRceord*, Pattern*, unsigned begin, unsigned end) method, |
31 // which returns true if it made changes and false if not. | 28 // which returns true if it made changes and false if not. |
32 | 29 |
33 // Run a pattern-based optimization once across the SkRecord, returning true if
it made any changes. | 30 // Run a pattern-based optimization once across the SkRecord, returning true if
it made any changes. |
34 // It looks for spans which match Pass::Pattern, and when found calls onMatch()
with the pattern, | 31 // It looks for spans which match Pass::Pattern, and when found calls onMatch()
with the pattern, |
35 // record, and [begin,end) span of the commands that matched. | 32 // record, and [begin,end) span of the commands that matched. |
36 template <typename Pass> | 33 template <typename Pass> |
37 static bool apply(Pass* pass, SkRecord* record) { | 34 static bool apply(Pass* pass, SkRecord* record) { |
38 typename Pass::Pattern pattern; | 35 typename Pass::Pattern pattern; |
39 bool changed = false; | 36 bool changed = false; |
40 unsigned begin, end = 0; | 37 unsigned begin, end = 0; |
41 | 38 |
42 while (pattern.search(record, &begin, &end)) { | 39 while (pattern.search(record, &begin, &end)) { |
43 changed |= pass->onMatch(record, &pattern, begin, end); | 40 changed |= pass->onMatch(record, &pattern, begin, end); |
44 } | 41 } |
45 return changed; | 42 return changed; |
46 } | 43 } |
47 | 44 |
48 struct CullNooper { | |
49 typedef Pattern3<Is<PushCull>, Star<Is<NoOp> >, Is<PopCull> > Pattern; | |
50 | |
51 bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned en
d) { | |
52 record->replace<NoOp>(begin); // PushCull | |
53 record->replace<NoOp>(end-1); // PopCull | |
54 return true; | |
55 } | |
56 }; | |
57 | |
58 void SkRecordNoopCulls(SkRecord* record) { | |
59 CullNooper pass; | |
60 while (apply(&pass, record)); | |
61 } | |
62 | |
63 // Turns the logical NoOp Save and Restore in Save-Draw*-Restore patterns into a
ctual NoOps. | 45 // Turns the logical NoOp Save and Restore in Save-Draw*-Restore patterns into a
ctual NoOps. |
64 struct SaveOnlyDrawsRestoreNooper { | 46 struct SaveOnlyDrawsRestoreNooper { |
65 typedef Pattern3<Is<Save>, | 47 typedef Pattern3<Is<Save>, |
66 Star<Or<Is<NoOp>, IsDraw> >, | 48 Star<Or<Is<NoOp>, IsDraw> >, |
67 Is<Restore> > | 49 Is<Restore> > |
68 Pattern; | 50 Pattern; |
69 | 51 |
70 bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned en
d) { | 52 bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned en
d) { |
71 record->replace<NoOp>(begin); // Save | 53 record->replace<NoOp>(begin); // Save |
72 record->replace<NoOp>(end-1); // Restore | 54 record->replace<NoOp>(end-1); // Restore |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 DrawPosTextH, | 185 DrawPosTextH, |
204 (draw->paint, draw->text, draw->byteLength, scalars
, firstY)); | 186 (draw->paint, draw->text, draw->byteLength, scalars
, firstY)); |
205 return true; | 187 return true; |
206 } | 188 } |
207 }; | 189 }; |
208 void SkRecordReduceDrawPosTextStrength(SkRecord* record) { | 190 void SkRecordReduceDrawPosTextStrength(SkRecord* record) { |
209 StrengthReducer pass; | 191 StrengthReducer pass; |
210 apply(&pass, record); | 192 apply(&pass, record); |
211 } | 193 } |
212 | 194 |
213 // Tries to replace DrawPosTextH with BoundedDrawPosTextH, which knows conservat
ive upper and lower | |
214 // bounds to use with SkCanvas::quickRejectY. | |
215 struct TextBounder { | |
216 typedef Pattern1<Is<DrawPosTextH> > Pattern; | |
217 | |
218 bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned en
d) { | |
219 SkASSERT(end == begin + 1); | |
220 DrawPosTextH* draw = pattern->first<DrawPosTextH>(); | |
221 | |
222 // If we're drawing vertical text, none of the checks we're about to do
make any sense. | |
223 // We'll need to call SkPaint::computeFastBounds() later, so bail if tha
t's not possible. | |
224 if (draw->paint.isVerticalText() || !draw->paint.canComputeFastBounds())
{ | |
225 return false; | |
226 } | |
227 | |
228 // Rather than checking the top and bottom font metrics, we guess. Actu
ally looking up the | |
229 // top and bottom metrics is slow, and this overapproximation should be
good enough. | |
230 const SkScalar buffer = draw->paint.getTextSize() * 1.5f; | |
231 SkDEBUGCODE(SkPaint::FontMetrics metrics;) | |
232 SkDEBUGCODE(draw->paint.getFontMetrics(&metrics);) | |
233 SkASSERT(-buffer <= metrics.fTop); | |
234 SkASSERT(+buffer >= metrics.fBottom); | |
235 | |
236 // Let the paint adjust the text bounds. We don't care about left and r
ight here, so we use | |
237 // 0 and 1 respectively just so the bounds rectangle isn't empty. | |
238 SkRect bounds; | |
239 bounds.set(0, draw->y - buffer, SK_Scalar1, draw->y + buffer); | |
240 SkRect adjusted = draw->paint.computeFastBounds(bounds, &bounds); | |
241 | |
242 Adopted<DrawPosTextH> adopted(draw); | |
243 SkNEW_PLACEMENT_ARGS(record->replace<BoundedDrawPosTextH>(begin, adopted
), | |
244 BoundedDrawPosTextH, | |
245 (&adopted, adjusted.fTop, adjusted.fBottom)); | |
246 return true; | |
247 } | |
248 }; | |
249 void SkRecordBoundDrawPosTextH(SkRecord* record) { | |
250 TextBounder pass; | |
251 apply(&pass, record); | |
252 } | |
253 | |
254 // Replaces PushCull with PairedPushCull, which lets us skip to the paired PopCu
ll when the canvas | |
255 // can quickReject the cull rect. | |
256 // There's no efficient way (yet?) to express this one as a pattern, so we write
a custom pass. | |
257 class CullAnnotator { | |
258 public: | |
259 // Do nothing to most ops. | |
260 template <typename T> void operator()(T*) {} | |
261 | |
262 void operator()(PushCull* push) { | |
263 Pair pair = { fIndex, push }; | |
264 fPushStack.push(pair); | |
265 } | |
266 | |
267 void operator()(PopCull* pop) { | |
268 Pair push = fPushStack.top(); | |
269 fPushStack.pop(); | |
270 | |
271 SkASSERT(fIndex > push.index); | |
272 unsigned skip = fIndex - push.index; | |
273 | |
274 Adopted<PushCull> adopted(push.command); | |
275 SkNEW_PLACEMENT_ARGS(fRecord->replace<PairedPushCull>(push.index, adopte
d), | |
276 PairedPushCull, (&adopted, skip)); | |
277 } | |
278 | |
279 void apply(SkRecord* record) { | |
280 for (fRecord = record, fIndex = 0; fIndex < record->count(); fIndex++) { | |
281 fRecord->mutate<void>(fIndex, *this); | |
282 } | |
283 } | |
284 | |
285 private: | |
286 struct Pair { | |
287 unsigned index; | |
288 PushCull* command; | |
289 }; | |
290 | |
291 SkTDArray<Pair> fPushStack; | |
292 SkRecord* fRecord; | |
293 unsigned fIndex; | |
294 }; | |
295 void SkRecordAnnotateCullingPairs(SkRecord* record) { | |
296 CullAnnotator pass; | |
297 pass.apply(record); | |
298 } | |
OLD | NEW |