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

Side by Side Diff: cc/paint/paint_op_buffer.cc

Issue 2768143002: Back PaintRecord with PaintOpBuffer instead of SkPicture (Closed)
Patch Set: Rebase, move slow path counting Created 3 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
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cc/paint/paint_op_buffer.h"
6
7 #include "base/template_util.h"
8 #include "cc/paint/display_item_list.h"
9 #include "cc/paint/paint_record.h"
10
11 namespace cc {
12
13 #define TYPES(M) \
14 M(ClipPathOp) \
15 M(ClipRectOp) \
16 M(ClipRRectOp) \
17 M(ConcatOp) \
18 M(DrawArcOp) \
19 M(DrawCircleOp) \
20 M(DrawColorOp) \
21 M(DrawDisplayItemListOp) \
22 M(DrawDRRectOp) \
23 M(DrawImageOp) \
24 M(DrawImageRectOp) \
25 M(DrawIRectOp) \
26 M(DrawLineOp) \
27 M(DrawOvalOp) \
28 M(DrawPathOp) \
29 M(DrawPosTextOp) \
30 M(DrawRecordOp) \
31 M(DrawRectOp) \
32 M(DrawRRectOp) \
33 M(DrawTextOp) \
34 M(DrawTextBlobOp) \
35 M(NoopOp) \
36 M(RestoreOp) \
37 M(RotateOp) \
38 M(SaveOp) \
39 M(SaveLayerOp) \
40 M(SaveLayerAlphaOp) \
41 M(ScaleOp) \
42 M(SetMatrixOp) \
43 M(TranslateOp)
44
45 // Helper template to share common code for RasterWithAlpha when paint ops
46 // have or don't have PaintFlags.
47 template <typename T, bool HasFlags>
48 struct Rasterizer {
49 static void Raster(const T* op, SkCanvas* canvas) {
50 // Paint ops with kHasPaintFlags need to declare RasterWithPaintFlags
51 // otherwise, the paint op needs its own Raster function. Without its
52 // own, this becomes an infinite loop as PaintOp::Raster calls itself.
53 static_assert(
54 !std::is_same<decltype(&PaintOp::Raster), decltype(&T::Raster)>::value,
55 "No Raster function");
56
57 op->Raster(canvas);
58 }
59 static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) {
60 DCHECK(T::kIsDrawOp);
61 // TODO(enne): is it ok to just drop the bounds here?
62 canvas->saveLayerAlpha(nullptr, alpha);
63 op->Raster(canvas);
64 canvas->restore();
65 }
66 };
67
68 template <typename T>
69 struct Rasterizer<T, true> {
70 static void Raster(const T* op, SkCanvas* canvas) {
71 op->RasterWithFlags(canvas, op->flags);
72 }
73 static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) {
74 DCHECK(T::kIsDrawOp);
75 if (alpha == 255) {
76 Raster(op, canvas);
77 } else if (op->flags.SupportsFoldingAlpha()) {
78 PaintFlags flags = op->flags;
79 flags.setAlpha(SkMulDiv255Round(flags.getAlpha(), alpha));
80 op->RasterWithFlags(canvas, flags);
81 } else {
82 canvas->saveLayerAlpha(nullptr, alpha);
83 op->RasterWithFlags(canvas, op->flags);
84 canvas->restore();
85 }
86 }
87 };
88
89 // TODO(enne): partially specialize RasterWithAlpha for draw color?
90
91 static constexpr size_t kNumOpTypes =
92 static_cast<size_t>(PaintOpType::LastPaintOpType) + 1;
93
94 // Verify that every op is in the TYPES macro.
95 #define M(T) 1 +
96 static_assert(kNumOpTypes == TYPES(M) 0, "Missing op in list");
97 #undef M
98
99 typedef void (*RasterFunction)(const PaintOp* op, SkCanvas* canvas);
100 #define M(T) \
101 [](const PaintOp* op, SkCanvas* canvas) { \
102 Rasterizer<T, T::kHasPaintFlags>::Raster(static_cast<const T*>(op), \
103 canvas); \
104 },
105 static const RasterFunction g_raster_functions[kNumOpTypes] = {TYPES(M)};
106 #undef M
107
108 typedef void (*RasterAlphaFunction)(const PaintOp* op,
109 SkCanvas* canvas,
110 uint8_t alpha);
111 #define M(T) \
112 T::kIsDrawOp ? \
113 [](const PaintOp* op, SkCanvas* canvas, uint8_t alpha) { \
114 Rasterizer<T, T::kHasPaintFlags>::RasterWithAlpha( \
115 static_cast<const T*>(op), canvas, alpha); \
116 } : nullptr ,
117 static const RasterAlphaFunction g_raster_alpha_functions[kNumOpTypes] = {
118 TYPES(M)};
119 #undef M
120
121 // Most state ops (matrix, clip, save, restore) have a trivial destructor.
122 typedef void (*VoidFunction)(PaintOp* op);
123 #define M(T) \
124 !base::is_trivially_destructible<T>::value \
125 ? [](PaintOp* op) { static_cast<T*>(op)->~T(); } \
126 : nullptr,
127 static const VoidFunction g_destructor_functions[kNumOpTypes] = {TYPES(M)};
128 #undef M
129
130 #define M(T) T::kIsDrawOp,
131 static bool g_is_draw_op[kNumOpTypes] = {TYPES(M)};
132 #undef M
133
134 #define M(T) \
135 static_assert(sizeof(T) <= sizeof(LargestPaintOp), \
136 #T " must be no bigger than LargestPaintOp");
137 TYPES(M);
138 #undef M
139
140 #undef TYPES
141
142 SkRect PaintOp::kUnsetRect = {SK_ScalarInfinity, 0, 0, 0};
143
144 void ClipPathOp::Raster(SkCanvas* canvas) const {
145 canvas->clipPath(path, op, antialias);
146 }
147
148 void ClipRectOp::Raster(SkCanvas* canvas) const {
149 canvas->clipRect(rect, op, antialias);
150 }
151
152 void ClipRRectOp::Raster(SkCanvas* canvas) const {
153 canvas->clipRRect(rrect, op, antialias);
154 }
155
156 void ConcatOp::Raster(SkCanvas* canvas) const {
157 canvas->concat(matrix);
158 }
159
160 void DrawArcOp::RasterWithFlags(SkCanvas* canvas,
161 const PaintFlags& flags) const {
162 canvas->drawArc(oval, start_angle, sweep_angle, use_center, ToSkPaint(flags));
163 }
164
165 void DrawCircleOp::RasterWithFlags(SkCanvas* canvas,
166 const PaintFlags& flags) const {
167 canvas->drawCircle(cx, cy, radius, ToSkPaint(flags));
168 }
169
170 void DrawColorOp::Raster(SkCanvas* canvas) const {
171 canvas->drawColor(color, mode);
172 }
173
174 void DrawDisplayItemListOp::Raster(SkCanvas* canvas) const {
175 list->Raster(canvas, nullptr);
176 }
177
178 void DrawDRRectOp::RasterWithFlags(SkCanvas* canvas,
179 const PaintFlags& flags) const {
180 canvas->drawDRRect(outer, inner, ToSkPaint(flags));
181 }
182
183 void DrawImageOp::RasterWithFlags(SkCanvas* canvas,
184 const PaintFlags& flags) const {
185 canvas->drawImage(image.get(), left, top, ToSkPaint(&flags));
186 }
187
188 void DrawImageRectOp::RasterWithFlags(SkCanvas* canvas,
189 const PaintFlags& flags) const {
190 // TODO(enne): Probably PaintCanvas should just use the skia enum directly.
191 SkCanvas::SrcRectConstraint skconstraint =
192 static_cast<SkCanvas::SrcRectConstraint>(constraint);
193 canvas->drawImageRect(image.get(), src, dst, ToSkPaint(&flags), skconstraint);
194 }
195
196 void DrawIRectOp::RasterWithFlags(SkCanvas* canvas,
197 const PaintFlags& flags) const {
198 canvas->drawIRect(rect, ToSkPaint(flags));
199 }
200
201 void DrawLineOp::RasterWithFlags(SkCanvas* canvas,
202 const PaintFlags& flags) const {
203 canvas->drawLine(x0, y0, x1, y1, ToSkPaint(flags));
204 }
205
206 void DrawOvalOp::RasterWithFlags(SkCanvas* canvas,
207 const PaintFlags& flags) const {
208 canvas->drawOval(oval, ToSkPaint(flags));
209 }
210
211 void DrawPathOp::RasterWithFlags(SkCanvas* canvas,
212 const PaintFlags& flags) const {
213 canvas->drawPath(path, ToSkPaint(flags));
214 }
215
216 void DrawPosTextOp::RasterWithFlags(SkCanvas* canvas,
217 const PaintFlags& flags) const {
218 canvas->drawPosText(paint_op_data(this), bytes, paint_op_array<SkPoint>(this),
219 ToSkPaint(flags));
220 }
221
222 void DrawRecordOp::Raster(SkCanvas* canvas) const {
223 record->playback(canvas);
224 }
225
226 void DrawRectOp::RasterWithFlags(SkCanvas* canvas,
227 const PaintFlags& flags) const {
228 canvas->drawRect(rect, ToSkPaint(flags));
229 }
230
231 void DrawRRectOp::RasterWithFlags(SkCanvas* canvas,
232 const PaintFlags& flags) const {
233 canvas->drawRRect(rrect, ToSkPaint(flags));
234 }
235
236 void DrawTextOp::RasterWithFlags(SkCanvas* canvas,
237 const PaintFlags& flags) const {
238 canvas->drawText(paint_op_data(this), bytes, x, y, ToSkPaint(flags));
239 }
240
241 void DrawTextBlobOp::RasterWithFlags(SkCanvas* canvas,
242 const PaintFlags& flags) const {
243 canvas->drawTextBlob(blob.get(), x, y, ToSkPaint(flags));
244 }
245
246 void RestoreOp::Raster(SkCanvas* canvas) const {
247 canvas->restore();
248 }
249
250 void RotateOp::Raster(SkCanvas* canvas) const {
251 canvas->rotate(degrees);
252 }
253
254 void SaveOp::Raster(SkCanvas* canvas) const {
255 canvas->save();
256 }
257
258 void SaveLayerOp::RasterWithFlags(SkCanvas* canvas,
259 const PaintFlags& flags) const {
260 // See PaintOp::kUnsetRect
261 bool unset = bounds.left() == SK_ScalarInfinity;
262
263 canvas->saveLayer(unset ? nullptr : &bounds, ToSkPaint(&flags));
264 }
265
266 void SaveLayerAlphaOp::Raster(SkCanvas* canvas) const {
267 // See PaintOp::kUnsetRect
268 bool unset = bounds.left() == SK_ScalarInfinity;
269 canvas->saveLayerAlpha(unset ? nullptr : &bounds, alpha);
270 }
271
272 void ScaleOp::Raster(SkCanvas* canvas) const {
273 canvas->scale(sx, sy);
274 }
275
276 void SetMatrixOp::Raster(SkCanvas* canvas) const {
277 canvas->setMatrix(matrix);
278 }
279
280 void TranslateOp::Raster(SkCanvas* canvas) const {
281 canvas->translate(dx, dy);
282 }
283
284 bool PaintOp::IsDrawOp() const {
285 return g_is_draw_op[type];
286 }
287
288 void PaintOp::Raster(SkCanvas* canvas) const {
289 g_raster_functions[type](this, canvas);
290 }
291
292 void PaintOp::RasterWithAlpha(SkCanvas* canvas, uint8_t alpha) const {
293 g_raster_alpha_functions[type](this, canvas, alpha);
294 }
295
296 DrawDisplayItemListOp::DrawDisplayItemListOp(
297 scoped_refptr<DisplayItemList> list)
298 : list(list) {}
299
300 int ClipPathOp::CountSlowPaths() const {
301 return antialias && !path.isConvex() ? 1 : 0;
302 }
303
304 int DrawLineOp::CountSlowPaths() const {
305 if (const SkPathEffect* effect = flags.getPathEffect()) {
306 SkPathEffect::DashInfo info;
307 SkPathEffect::DashType dashType = effect->asADash(&info);
308 if (flags.getStrokeCap() != PaintFlags::kRound_Cap &&
309 dashType == SkPathEffect::kDash_DashType && info.fCount == 2) {
310 // The PaintFlags will count this as 1, so uncount that here as
311 // this kind of line is special cased and not slow.
312 return -1;
313 }
314 }
315 return 0;
316 }
317
318 int DrawPathOp::CountSlowPaths() const {
319 // TODO(enne): It's not the best to have these Skia details exposed here,
320 // but hopefully the veto is shortlived and this can go away.
321 if (flags.isAntiAlias() && !path.isConvex()) {
322 PaintFlags::Style paintStyle = flags.getStyle();
323 const SkRect& pathBounds = path.getBounds();
324 if (paintStyle == PaintFlags::kStroke_Style &&
325 flags.getStrokeWidth() == 0) {
326 // AA hairline concave path is not slow.
327 } else if (paintStyle == PaintFlags::kFill_Style &&
328 pathBounds.width() < 64.f && pathBounds.height() < 64.f &&
329 !path.isVolatile()) {
330 // AADF eligible concave path is not slow.
331 } else {
332 return 1;
333 }
334 }
335 return 0;
336 }
337
338 DrawDisplayItemListOp::~DrawDisplayItemListOp() = default;
339
340 DrawImageOp::DrawImageOp(sk_sp<const SkImage> image,
341 SkScalar left,
342 SkScalar top,
343 const PaintFlags* flags)
344 : image(std::move(image)), left(left), top(top) {
345 if (flags)
346 this->flags = *flags;
347 }
348
349 DrawImageOp::~DrawImageOp() = default;
350
351 DrawImageRectOp::DrawImageRectOp(sk_sp<const SkImage> image,
352 const SkRect& src,
353 const SkRect& dst,
354 const PaintFlags* flags,
355 PaintCanvas::SrcRectConstraint constraint)
356 : image(image), src(src), dst(dst), constraint(constraint) {
357 if (flags)
358 this->flags = *flags;
359 }
360
361 DrawImageRectOp::~DrawImageRectOp() = default;
362
363 DrawPosTextOp::DrawPosTextOp(size_t bytes,
364 size_t count,
365 const PaintFlags& flags)
366 : PaintOpWithDataArray(bytes, count), flags(flags) {}
367
368 DrawPosTextOp::~DrawPosTextOp() = default;
369
370 DrawRecordOp::DrawRecordOp(sk_sp<const PaintRecord> record) : record(record) {}
371
372 DrawRecordOp::~DrawRecordOp() = default;
373
374 DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
375 SkScalar x,
376 SkScalar y,
377 const PaintFlags& flags)
378 : blob(blob), x(x), y(y), flags(flags) {}
379
380 DrawTextBlobOp::~DrawTextBlobOp() = default;
381
382 PaintOpBuffer::PaintOpBuffer() : cull_rect_(SkRect::MakeEmpty()) {}
383
384 PaintOpBuffer::PaintOpBuffer(const SkRect& cull_rect) : cull_rect_(cull_rect) {}
385
386 PaintOpBuffer::~PaintOpBuffer() {
387 Reset();
388 }
389
390 void PaintOpBuffer::Reset() {
391 for (auto* op : Iterator(this)) {
392 auto func = g_destructor_functions[op->type];
393 if (func)
394 func(op);
395 }
396
397 // Leave data_ allocated, reserved_ unchanged.
398 used_ = 0;
399 op_count_ = 0;
400 num_slow_paths_ = 0;
401 }
402
403 void PaintOpBuffer::playback(SkCanvas* canvas) const {
404 for (Iterator iter(this); iter; ++iter) {
405 // Optimize out save/restores or save/draw/restore that can be a single
406 // draw. See also: similar code in SkRecordOpts and cc's DisplayItemList.
407 // TODO(enne): consider making this recursive?
408 const PaintOp* op = *iter;
409 DCHECK(op);
410 if (op->GetType() == PaintOpType::SaveLayerAlpha) {
411 const PaintOp* second = iter.peek1();
412 if (second) {
413 if (second->GetType() == PaintOpType::Restore) {
414 ++iter;
415 continue;
416 }
417 if (second->IsDrawOp()) {
418 const PaintOp* third = iter.peek2();
419 if (third && third->GetType() == PaintOpType::Restore) {
420 const SaveLayerAlphaOp* save_op =
421 static_cast<const SaveLayerAlphaOp*>(op);
422 second->RasterWithAlpha(canvas, save_op->alpha);
423 ++iter;
424 ++iter;
425 continue;
426 }
427 }
428 }
429 } else if (op->GetType() == PaintOpType::SaveLayer) {
430 const PaintOp* second = iter.peek1();
431 if (second && second->GetType() == PaintOpType::Restore) {
432 ++iter;
433 continue;
434 }
435 }
436
437 op->Raster(canvas);
438 }
439 }
440
441 void PaintOpBuffer::playback(SkCanvas* canvas,
442 SkPicture::AbortCallback* callback) const {
443 // The abort callback is only used for analysis, in general, so
444 // this playback code can be more straightforward and not do the
445 // optimizations in the other function.
446 if (!callback) {
447 playback(canvas);
448 return;
449 }
450
451 // TODO(enne): ideally callers would just iterate themselves and we
452 // can remove the entire notion of an abort callback.
453 for (auto* op : Iterator(this)) {
454 op->Raster(canvas);
455 if (callback && callback->abort())
456 return;
457 }
458 }
459
460 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698