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

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

Issue 258693006: Start using type traits in src/record instead of macros. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: ben Created 6 years, 7 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/SkRecordDraw.cpp ('k') | src/record/SkRecordTraits.h » ('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 "SkRecordTraits.h"
10 #include "SkRecords.h" 11 #include "SkRecords.h"
11 #include "SkTDArray.h" 12 #include "SkTDArray.h"
12 13
13 void SkRecordOptimize(SkRecord* record) { 14 void SkRecordOptimize(SkRecord* record) {
14 // TODO(mtklein): fuse independent optimizations to reduce number of passes? 15 // TODO(mtklein): fuse independent optimizations to reduce number of passes?
15 SkRecordNoopSaveRestores(record); 16 SkRecordNoopSaveRestores(record);
16 SkRecordAnnotateCullingPairs(record); 17 SkRecordAnnotateCullingPairs(record);
17 SkRecordReduceDrawPosTextStrength(record); // Helpful to run this before Bo undDrawPosTextH. 18 SkRecordReduceDrawPosTextStrength(record); // Helpful to run this before Bo undDrawPosTextH.
18 SkRecordBoundDrawPosTextH(record); 19 SkRecordBoundDrawPosTextH(record);
19 } 20 }
(...skipping 13 matching lines...) Expand all
33 unsigned fIndex; 34 unsigned fIndex;
34 }; 35 };
35 36
36 // Turns logical no-op Save-[non-drawing command]*-Restore patterns into actual no-ops. 37 // Turns logical no-op Save-[non-drawing command]*-Restore patterns into actual no-ops.
37 // TODO(mtklein): state machine diagram 38 // TODO(mtklein): state machine diagram
38 class SaveRestoreNooper : public Common { 39 class SaveRestoreNooper : public Common {
39 public: 40 public:
40 explicit SaveRestoreNooper(SkRecord* record) 41 explicit SaveRestoreNooper(SkRecord* record)
41 : Common(record), fSave(kInactive), fChanged(false) {} 42 : Common(record), fSave(kInactive), fChanged(false) {}
42 43
43 // Most drawing commands reset to inactive state without nooping anything. 44 // Drawing commands reset state to inactive without nooping.
44 template <typename T> 45 template <typename T>
45 void operator()(T*) { fSave = kInactive; } 46 SK_WHEN(SkRecords::IsDraw<T>, void) operator()(T*) { fSave = kInactive; }
47
48 // Most non-drawing commands can be ignored.
49 template <typename T>
50 SK_WHEN(!SkRecords::IsDraw<T>, void) operator()(T*) {}
51
52 void operator()(SkRecords::Save* r) {
53 fSave = SkCanvas::kMatrixClip_SaveFlag == r->flags ? this->index() : kIn active;
54 }
55
56 void operator()(SkRecords::Restore* r) {
57 if (fSave != kInactive) {
58 // Remove everything between the save and restore, inclusive on both sides.
59 fChanged = true;
60 for (unsigned i = fSave; i <= this->index(); i++) {
61 fRecord->replace<SkRecords::NoOp>(i);
62 }
63 fSave = kInactive;
64 }
65 }
46 66
47 bool changed() const { return fChanged; } 67 bool changed() const { return fChanged; }
48 68
49 private: 69 private:
50 static const unsigned kInactive = ~0; 70 static const unsigned kInactive = ~0;
51 unsigned fSave; 71 unsigned fSave;
52 bool fChanged; 72 bool fChanged;
53 }; 73 };
54 74
55 // If the command doesn't draw anything, that doesn't reset the state back to in active.
56 // TODO(mtklein): do this with some sort of template-based trait mechanism inste ad of macros
57 #define DOESNT_DRAW(T) template <> void SaveRestoreNooper::operator()(SkRecords: :T*) {}
58 DOESNT_DRAW(NoOp)
59 DOESNT_DRAW(Concat)
60 DOESNT_DRAW(SetMatrix)
61 DOESNT_DRAW(ClipRect)
62 DOESNT_DRAW(ClipRRect)
63 DOESNT_DRAW(ClipPath)
64 DOESNT_DRAW(ClipRegion)
65 DOESNT_DRAW(PairedPushCull)
66 DOESNT_DRAW(PushCull)
67 DOESNT_DRAW(PopCull)
68 #undef DOESNT_DRAW
69
70 template <>
71 void SaveRestoreNooper::operator()(SkRecords::Save* r) {
72 fSave = SkCanvas::kMatrixClip_SaveFlag == r->flags ? this->index() : kInacti ve;
73 }
74
75 template <>
76 void SaveRestoreNooper::operator()(SkRecords::Restore* r) {
77 if (fSave != kInactive) {
78 // Remove everything between the save and restore, inclusive on both sid es.
79 fChanged = true;
80 for (unsigned i = fSave; i <= this->index(); i++) {
81 fRecord->replace<SkRecords::NoOp>(i);
82 }
83 fSave = kInactive;
84 }
85 }
86
87
88 // Tries to replace PushCull with PairedPushCull, which lets us skip to the pair ed PopCull 75 // Tries to replace PushCull with PairedPushCull, which lets us skip to the pair ed PopCull
89 // when the canvas can quickReject the cull rect. 76 // when the canvas can quickReject the cull rect.
90 class CullAnnotator : public Common { 77 class CullAnnotator : public Common {
91 public: 78 public:
92 explicit CullAnnotator(SkRecord* record) : Common(record) {} 79 explicit CullAnnotator(SkRecord* record) : Common(record) {}
93 80
94 // Do nothing to most ops. 81 // Do nothing to most ops.
95 template <typename T> 82 template <typename T> void operator()(T*) {}
96 void operator()(T*) {} 83
84 void operator()(SkRecords::PushCull* push) {
85 Pair pair = { this->index(), push };
86 fPushStack.push(pair);
87 }
88
89 void operator()(SkRecords::PopCull* pop) {
90 Pair push = fPushStack.top();
91 fPushStack.pop();
92
93 SkASSERT(this->index() > push.index);
94 unsigned skip = this->index() - push.index;
95
96 SkRecords::Adopted<SkRecords::PushCull> adopted(push.command);
97 SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::PairedPushCull>(push.in dex, adopted),
98 SkRecords::PairedPushCull, (&adopted, skip));
99 }
97 100
98 private: 101 private:
99 struct Pair { 102 struct Pair {
100 unsigned index; 103 unsigned index;
101 SkRecords::PushCull* command; 104 SkRecords::PushCull* command;
102 }; 105 };
103 106
104 SkTDArray<Pair> fPushStack; 107 SkTDArray<Pair> fPushStack;
105 }; 108 };
106 109
107 template <>
108 void CullAnnotator::operator()(SkRecords::PushCull* push) {
109 Pair pair = { this->index(), push };
110 fPushStack.push(pair);
111 }
112
113 template <>
114 void CullAnnotator::operator()(SkRecords::PopCull* pop) {
115 Pair push = fPushStack.top();
116 fPushStack.pop();
117
118 SkASSERT(this->index() > push.index);
119 unsigned skip = this->index() - push.index;
120
121 SkRecords::Adopted<SkRecords::PushCull> adopted(push.command);
122 SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::PairedPushCull>(push.index, adopted),
123 SkRecords::PairedPushCull, (&adopted, skip));
124 }
125
126 // Replaces DrawPosText with DrawPosTextH when all Y coordinates are equal. 110 // Replaces DrawPosText with DrawPosTextH when all Y coordinates are equal.
127 class StrengthReducer : public Common { 111 class StrengthReducer : public Common {
128 public: 112 public:
129 explicit StrengthReducer(SkRecord* record) : Common(record) {} 113 explicit StrengthReducer(SkRecord* record) : Common(record) {}
130 114
131 // Do nothing to most ops. 115 // Do nothing to most ops.
132 template <typename T> 116 template <typename T> void operator()(T*) {}
133 void operator()(T*) {}
134 };
135 117
136 template <> 118 void operator()(SkRecords::DrawPosText* r) {
137 void StrengthReducer::operator()(SkRecords::DrawPosText* r) { 119 const unsigned points = r->paint.countText(r->text, r->byteLength);
138 const unsigned points = r->paint.countText(r->text, r->byteLength); 120 if (points == 0) {
139 if (points == 0) { 121 // No point (ha!).
140 // No point (ha!).
141 return;
142 }
143
144 const SkScalar firstY = r->pos[0].fY;
145 for (unsigned i = 1; i < points; i++) {
146 if (r->pos[i].fY != firstY) {
147 // Needs the full strength of DrawPosText.
148 return; 122 return;
149 } 123 }
124
125 const SkScalar firstY = r->pos[0].fY;
126 for (unsigned i = 1; i < points; i++) {
127 if (r->pos[i].fY != firstY) {
128 // Needs the full strength of DrawPosText.
129 return;
130 }
131 }
132 // All ys are the same. We can replace DrawPosText with DrawPosTextH.
133
134 // r->pos is points SkPoints, [(x,y),(x,y),(x,y),(x,y), ... ].
135 // We're going to squint and look at that as 2*points SkScalars, [x,y,x, y,x,y,x,y, ...].
136 // Then we'll rearrange things so all the xs are in order up front, clob bering the ys.
137 SK_COMPILE_ASSERT(sizeof(SkPoint) == 2 * sizeof(SkScalar), SquintingIsNo tSafe);
138 SkScalar* scalars = &r->pos[0].fX;
139 for (unsigned i = 0; i < 2*points; i += 2) {
140 scalars[i/2] = scalars[i];
141 }
142
143 // Extend lifetime of r to the end of the method so we can copy its part s.
144 SkRecords::Adopted<SkRecords::DrawPosText> adopted(r);
145 SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::DrawPosTextH>(this->ind ex(), adopted),
146 SkRecords::DrawPosTextH,
147 (r->text, r->byteLength, scalars, firstY, r->paint) );
150 } 148 }
151 // All ys are the same. We can replace DrawPosText with DrawPosTextH. 149 };
152
153 // r->pos is points SkPoints, [(x,y),(x,y),(x,y),(x,y), ... ].
154 // We're going to squint and look at that as 2*points SkScalars, [x,y,x,y,x, y,x,y, ...].
155 // Then we'll rearrange things so all the xs are in order up front, clobberi ng the ys.
156 SK_COMPILE_ASSERT(sizeof(SkPoint) == 2 * sizeof(SkScalar), SquintingIsNotSaf e);
157 SkScalar* scalars = &r->pos[0].fX;
158 for (unsigned i = 0; i < 2*points; i += 2) {
159 scalars[i/2] = scalars[i];
160 }
161
162 // Extend lifetime of r to the end of the method so we can copy its parts.
163 SkRecords::Adopted<SkRecords::DrawPosText> adopted(r);
164 SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::DrawPosTextH>(this->index() , adopted),
165 SkRecords::DrawPosTextH,
166 (r->text, r->byteLength, scalars, firstY, r->paint));
167 }
168
169 150
170 // Tries to replace DrawPosTextH with BoundedDrawPosTextH, which knows conservat ive upper and lower 151 // Tries to replace DrawPosTextH with BoundedDrawPosTextH, which knows conservat ive upper and lower
171 // bounds to use with SkCanvas::quickRejectY. 152 // bounds to use with SkCanvas::quickRejectY.
172 class TextBounder : public Common { 153 class TextBounder : public Common {
173 public: 154 public:
174 explicit TextBounder(SkRecord* record) : Common(record) {} 155 explicit TextBounder(SkRecord* record) : Common(record) {}
175 156
176 // Do nothing to most ops. 157 // Do nothing to most ops.
177 template <typename T> 158 template <typename T> void operator()(T*) {}
178 void operator()(T*) {} 159
160 void operator()(SkRecords::DrawPosTextH* r) {
161 // If we're drawing vertical text, none of the checks we're about to do make any sense.
162 // We'll need to call SkPaint::computeFastBounds() later, so bail if tha t's not possible.
163 if (r->paint.isVerticalText() || !r->paint.canComputeFastBounds()) {
164 return;
165 }
166
167 // Rather than checking the top and bottom font metrics, we guess. Actu ally looking up the
168 // top and bottom metrics is slow, and this overapproximation should be good enough.
169 const SkScalar buffer = r->paint.getTextSize() * 1.5f;
170 SkDEBUGCODE(SkPaint::FontMetrics metrics;)
171 SkDEBUGCODE(r->paint.getFontMetrics(&metrics);)
172 SkASSERT(-buffer <= metrics.fTop);
173 SkASSERT(+buffer >= metrics.fBottom);
174
175 // Let the paint adjust the text bounds. We don't care about left and r ight here, so we use
176 // 0 and 1 respectively just so the bounds rectangle isn't empty.
177 SkRect bounds;
178 bounds.set(0, r->y - buffer, SK_Scalar1, r->y + buffer);
179 SkRect adjusted = r->paint.computeFastBounds(bounds, &bounds);
180
181 SkRecords::Adopted<SkRecords::DrawPosTextH> adopted(r);
182 SkNEW_PLACEMENT_ARGS(
183 fRecord->replace<SkRecords::BoundedDrawPosTextH>(this->index(), adopted),
184 SkRecords::BoundedDrawPosTextH,
185 (&adopted, adjusted.fTop, adjusted.fBottom));
186 }
179 }; 187 };
180 188
181 template <>
182 void TextBounder::operator()(SkRecords::DrawPosTextH* r) {
183 // If we're drawing vertical text, none of the checks we're about to do make any sense.
184 // We'll need to call SkPaint::computeFastBounds() later, so bail if that's not possible.
185 if (r->paint.isVerticalText() || !r->paint.canComputeFastBounds()) {
186 return;
187 }
188
189 // Rather than checking the top and bottom font metrics, we guess. Actually looking up the
190 // top and bottom metrics is slow, and this overapproximation should be good enough.
191 const SkScalar buffer = r->paint.getTextSize() * 1.5f;
192 SkDEBUGCODE(SkPaint::FontMetrics metrics;)
193 SkDEBUGCODE(r->paint.getFontMetrics(&metrics);)
194 SkASSERT(-buffer <= metrics.fTop);
195 SkASSERT(+buffer >= metrics.fBottom);
196
197 // Let the paint adjust the text bounds. We don't care about left and right here, so we use
198 // 0 and 1 respectively just so the bounds rectangle isn't empty.
199 SkRect bounds;
200 bounds.set(0, r->y - buffer, SK_Scalar1, r->y + buffer);
201 SkRect adjusted = r->paint.computeFastBounds(bounds, &bounds);
202
203 SkRecords::Adopted<SkRecords::DrawPosTextH> adopted(r);
204 SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::BoundedDrawPosTextH>(this-> index(), adopted),
205 SkRecords::BoundedDrawPosTextH,
206 (&adopted, adjusted.fTop, adjusted.fBottom));
207 }
208 189
209 template <typename Pass> 190 template <typename Pass>
210 static void run_pass(Pass& pass, SkRecord* record) { 191 static void run_pass(Pass& pass, SkRecord* record) {
211 for (; pass.index() < record->count(); pass.next()) { 192 for (; pass.index() < record->count(); pass.next()) {
212 record->mutate(pass.index(), pass); 193 record->mutate(pass.index(), pass);
213 } 194 }
214 } 195 }
215 196
216 } // namespace 197 } // namespace
217 198
(...skipping 15 matching lines...) Expand all
233 214
234 void SkRecordReduceDrawPosTextStrength(SkRecord* record) { 215 void SkRecordReduceDrawPosTextStrength(SkRecord* record) {
235 StrengthReducer reducer(record); 216 StrengthReducer reducer(record);
236 run_pass(reducer, record); 217 run_pass(reducer, record);
237 } 218 }
238 219
239 void SkRecordBoundDrawPosTextH(SkRecord* record) { 220 void SkRecordBoundDrawPosTextH(SkRecord* record) {
240 TextBounder bounder(record); 221 TextBounder bounder(record);
241 run_pass(bounder, record); 222 run_pass(bounder, record);
242 } 223 }
OLDNEW
« no previous file with comments | « src/record/SkRecordDraw.cpp ('k') | src/record/SkRecordTraits.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698