Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(298)

Side by Side Diff: src/record/SkRecordOpts.cpp

Issue 245853002: Refactor SkRecord opts, converting playback optimizations where possible. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: apply Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/record/SkRecordOpts.h ('k') | src/record/SkRecorder.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "SkRecords.h" 10 #include "SkRecords.h"
11 #include "SkTDArray.h" 11 #include "SkTDArray.h"
12 12
13 void SkRecordOptimize(SkRecord* record) { 13 void SkRecordOptimize(SkRecord* record) {
14 // TODO(mtklein): fuse independent optimizations to reduce number of passes?
15 SkRecordNoopSaveRestores(record);
14 SkRecordAnnotateCullingPairs(record); 16 SkRecordAnnotateCullingPairs(record);
15 } 17 SkRecordReduceDrawPosTextStrength(record); // Helpful to run this before Bo undDrawPosTextH.
18 SkRecordBoundDrawPosTextH(record);
19 }
20
21 // Streamline replacing one command with another.
22 #define REPLACE(record, index, T, ...) \
23 SkNEW_PLACEMENT_ARGS(record->replace<SkRecords::T>(index), SkRecords::T, (__ VA_ARGS__))
16 24
17 namespace { 25 namespace {
18 26
19 struct Annotator { 27 // Convenience base class to share some common implementation code.
20 unsigned index; 28 class Common : SkNoncopyable {
21 SkTDArray<SkRecords::PushCull*> pushStack; 29 public:
22 30 explicit Common(SkRecord* record) : fRecord(record), fIndex(0) {}
23 // Do nothing to most record types. 31
24 template <typename T> void operator()(T*) {} 32 unsigned index() const { return fIndex; }
25 }; 33 void next() { ++fIndex; }
26 34
27 template <> void Annotator::operator()(SkRecords::PushCull* push) { 35 protected:
28 // Store the push's index for now. We'll calculate the offset using this in the paired pop. 36 SkRecord* fRecord;
29 push->popOffset = index; 37 unsigned fIndex;
30 pushStack.push(push); 38 };
31 } 39
32 40 // Turns logical no-op Save-[non-drawing command]*-Restore patterns into actual no-ops.
33 template <> void Annotator::operator()(SkRecords::PopCull* pop) { 41 // TODO(mtklein): state machine diagram
34 SkRecords::PushCull* push = pushStack.top(); 42 class SaveRestoreNooper : public Common {
35 pushStack.pop(); 43 public:
36 44 explicit SaveRestoreNooper(SkRecord* record)
37 SkASSERT(index > push->popOffset); // push->popOffset holds the ind ex of the push. 45 : Common(record), fSave(kInactive), fChanged(false) {}
38 push->popOffset = index - push->popOffset; // Now it's the offset between p ush and pop. 46
47 // Most drawing commands reset to inactive state without nooping anything.
48 template <typename T>
49 void operator()(T*) { fSave = kInactive; }
50
51 bool changed() const { return fChanged; }
52
53 private:
54 static const unsigned kInactive = ~0;
55 unsigned fSave;
56 bool fChanged;
57 };
58
59 // If the command doesn't draw anything, that doesn't reset the state back to in active.
60 // TODO(mtklein): do this with some sort of template-based trait mechanism inste ad of macros
61 #define IGNORE(T) template <> void SaveRestoreNooper::operator()(SkRecords::T*) {}
62 IGNORE(NoOp)
63 IGNORE(Concat)
64 IGNORE(SetMatrix)
65 IGNORE(ClipRect)
66 IGNORE(ClipRRect)
67 IGNORE(ClipPath)
68 IGNORE(ClipRegion)
69 IGNORE(PairedPushCull)
70 IGNORE(PushCull)
71 IGNORE(PopCull)
72 #undef CLIP
73
74 template <>
75 void SaveRestoreNooper::operator()(SkRecords::Save* r) {
76 fSave = SkCanvas::kMatrixClip_SaveFlag == r->flags ? this->index() : kInacti ve;
77 }
78
79 template <>
80 void SaveRestoreNooper::operator()(SkRecords::Restore* r) {
81 if (fSave != kInactive) {
82 // Remove everything between the save and restore, inclusive on both sid es.
83 fChanged = true;
84 SkRecord::Destroyer destroyer;
85 for (unsigned i = fSave; i <= this->index(); i++) {
86 fRecord->mutate(i, destroyer);
87 REPLACE(fRecord, i, NoOp);
88 }
89 fSave = kInactive;
90 }
91 }
92
93
94 // Tries to replace PushCull with PairedPushCull, which lets us skip to the pair ed PopCull
95 // when the canvas can quickReject the cull rect.
96 class CullAnnotator : public Common {
97 public:
98 explicit CullAnnotator(SkRecord* record) : Common(record) {}
99
100 // Do nothing to most ops.
101 template <typename T>
102 void operator()(T*) {}
103
104 private:
105 struct Pair {
106 unsigned index;
107 SkRecords::PushCull* command;
108 };
109
110 SkTDArray<Pair> fPushStack;
111 };
112
113 template <>
114 void CullAnnotator::operator()(SkRecords::PushCull* push) {
115 Pair pair = { this->index(), push };
116 fPushStack.push(pair);
117 }
118
119 template <>
120 void CullAnnotator::operator()(SkRecords::PopCull* pop) {
121 Pair push = fPushStack.top();
122 fPushStack.pop();
123
124 SkASSERT(this->index() > push.index);
125 unsigned skip = this->index() - push.index;
126
127 // PairedPushCull adopts push.command.
128 REPLACE(fRecord, push.index, PairedPushCull, push.command, skip);
129 }
130
131 // Replaces DrawPosText with DrawPosTextH when all Y coordinates are equal.
132 class StrengthReducer : public Common {
133 public:
134 explicit StrengthReducer(SkRecord* record) : Common(record) {}
135
136 // Do nothing to most ops.
137 template <typename T>
138 void operator()(T*) {}
139 };
140
141 template <>
142 void StrengthReducer::operator()(SkRecords::DrawPosText* r) {
143 const unsigned points = r->paint.countText(r->text, r->byteLength);
144 if (points == 0) {
145 // No point (ha!).
146 return;
147 }
148
149 const SkScalar firstY = r->pos[0].fY;
150 for (unsigned i = 1; i < points; i++) {
151 if (r->pos[i].fY != firstY) {
152 // Needs the full strength of DrawPosText.
153 return;
154 }
155 }
156 // All ys are the same. We can replace DrawPosText with DrawPosTextH.
157
158 // r->pos is points SkPoints, [(x,y),(x,y),(x,y),(x,y), ... ].
159 // We're going to squint and look at that as 2*points SkScalars, [x,y,x,y,x, y,x,y, ...].
160 // Then we'll rearrange things so all the xs are in order up front, clobberi ng the ys.
161 SK_COMPILE_ASSERT(sizeof(SkPoint) == 2 * sizeof(SkScalar), SquintingIsNotSaf e);
162 SkScalar* scalars = &r->pos[0].fX;
163 for (unsigned i = 0; i < 2*points; i += 2) {
164 scalars[i/2] = scalars[i];
165 }
166
167 SkRecord::Destroyer destroyer;
168 fRecord->mutate(this->index(), destroyer);
169 REPLACE(fRecord, this->index(),
170 DrawPosTextH, (char*)r->text, r->byteLength, scalars, firstY, r->pai nt);
171 }
172
173
174 // Tries to replace DrawPosTextH with BoundedDrawPosTextH, which knows conservat ive upper and lower
175 // bounds to use with SkCanvas::quickRejectY.
176 class TextBounder : public Common {
177 public:
178 explicit TextBounder(SkRecord* record) : Common(record) {}
179
180 // Do nothing to most ops.
181 template <typename T>
182 void operator()(T*) {}
183 };
184
185 template <>
186 void TextBounder::operator()(SkRecords::DrawPosTextH* r) {
187 // If we're drawing vertical text, none of the checks we're about to do make any sense.
188 // We'll need to call SkPaint::computeFastBounds() later, so bail if that's not possible.
189 if (r->paint.isVerticalText() || !r->paint.canComputeFastBounds()) {
190 return;
191 }
192
193 // Rather than checking the top and bottom font metrics, we guess. Actually looking up the
194 // top and bottom metrics is slow, and this overapproximation should be good enough.
195 const SkScalar buffer = r->paint.getTextSize() * 1.5f;
196 SkDEBUGCODE(SkPaint::FontMetrics metrics;)
197 SkDEBUGCODE(r->paint.getFontMetrics(&metrics);)
198 SkASSERT(-buffer <= metrics.fTop);
199 SkASSERT(+buffer >= metrics.fBottom);
200
201 // Let the paint adjust the text bounds. We don't care about left and right here, so we use
202 // 0 and 1 respectively just so the bounds rectangle isn't empty.
203 SkRect bounds;
204 bounds.set(0, r->y - buffer, SK_Scalar1, r->y + buffer);
205 SkRect adjusted = r->paint.computeFastBounds(bounds, &bounds);
206
207 // BoundedDrawPosTextH adopts r.
208 REPLACE(fRecord, this->index(), BoundedDrawPosTextH, r, adjusted.fTop, adjus ted.fBottom);
209 }
210
211 template <typename Pass>
212 static void run_pass(Pass& pass, SkRecord* record) {
213 for (; pass.index() < record->count(); pass.next()) {
214 record->mutate(pass.index(), pass);
215 }
39 } 216 }
40 217
41 } // namespace 218 } // namespace
42 219
220
221 void SkRecordNoopSaveRestores(SkRecord* record) {
222 // Run SaveRestoreNooper until it doesn't make any more changes.
223 bool changed;
224 do {
225 SaveRestoreNooper nooper(record);
226 run_pass(nooper, record);
227 changed = nooper.changed();
228 } while (changed);
229 }
230
43 void SkRecordAnnotateCullingPairs(SkRecord* record) { 231 void SkRecordAnnotateCullingPairs(SkRecord* record) {
44 Annotator annotator; 232 CullAnnotator annotator(record);
45 233 run_pass(annotator, record);
46 for (annotator.index = 0; annotator.index < record->count(); annotator.index ++) { 234 }
47 record->mutate(annotator.index, annotator); 235
48 } 236 void SkRecordReduceDrawPosTextStrength(SkRecord* record) {
49 } 237 StrengthReducer reducer(record);
238 run_pass(reducer, record);
239 }
240
241 void SkRecordBoundDrawPosTextH(SkRecord* record) {
242 TextBounder bounder(record);
243 run_pass(bounder, record);
244 }
245
246 #undef REPLACE
OLDNEW
« no previous file with comments | « src/record/SkRecordOpts.h ('k') | src/record/SkRecorder.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698