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

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

Issue 2768143002: Back PaintRecord with PaintOpBuffer instead of SkPicture (Closed)
Patch Set: more const casting Created 3 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 | « cc/paint/paint_op_buffer.h ('k') | cc/paint/paint_op_buffer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "cc/paint/display_item_list.h"
8 #include "cc/paint/paint_record.h"
9 #include "third_party/skia/include/core/SkAnnotation.h"
10
11 namespace cc {
12
13 #define TYPES(M) \
14 M(AnnotateOp) \
15 M(ClipPathOp) \
16 M(ClipRectOp) \
17 M(ClipRRectOp) \
18 M(ConcatOp) \
19 M(DrawArcOp) \
20 M(DrawCircleOp) \
21 M(DrawColorOp) \
22 M(DrawDisplayItemListOp) \
23 M(DrawDRRectOp) \
24 M(DrawImageOp) \
25 M(DrawImageRectOp) \
26 M(DrawIRectOp) \
27 M(DrawLineOp) \
28 M(DrawOvalOp) \
29 M(DrawPathOp) \
30 M(DrawPosTextOp) \
31 M(DrawRecordOp) \
32 M(DrawRectOp) \
33 M(DrawRRectOp) \
34 M(DrawTextOp) \
35 M(DrawTextBlobOp) \
36 M(NoopOp) \
37 M(RestoreOp) \
38 M(RotateOp) \
39 M(SaveOp) \
40 M(SaveLayerOp) \
41 M(SaveLayerAlphaOp) \
42 M(ScaleOp) \
43 M(SetMatrixOp) \
44 M(TranslateOp)
45
46 // Helper template to share common code for RasterWithAlpha when paint ops
47 // have or don't have PaintFlags.
48 template <typename T, bool HasFlags>
49 struct Rasterizer {
50 static void Raster(const T* op,
51 SkCanvas* canvas,
52 const SkMatrix& original_ctm) {
53 // Paint ops with kHasPaintFlags need to declare RasterWithPaintFlags
54 // otherwise, the paint op needs its own Raster function. Without its
55 // own, this becomes an infinite loop as PaintOp::Raster calls itself.
56 static_assert(
57 !std::is_same<decltype(&PaintOp::Raster), decltype(&T::Raster)>::value,
58 "No Raster function");
59
60 op->Raster(canvas);
61 }
62 static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) {
63 DCHECK(T::kIsDrawOp);
64 // TODO(enne): is it ok to just drop the bounds here?
65 canvas->saveLayerAlpha(nullptr, alpha);
66 op->Raster(canvas);
67 canvas->restore();
68 }
69 };
70
71 template <typename T>
72 struct Rasterizer<T, true> {
73 static void Raster(const T* op,
74 SkCanvas* canvas,
75 const SkMatrix& original_ctm) {
76 op->RasterWithFlags(canvas, op->flags);
77 }
78 static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) {
79 DCHECK(T::kIsDrawOp);
80 SkMatrix unused_matrix;
81 if (alpha == 255) {
82 Raster(op, canvas, unused_matrix);
83 } else if (op->flags.SupportsFoldingAlpha()) {
84 PaintFlags flags = op->flags;
85 flags.setAlpha(SkMulDiv255Round(flags.getAlpha(), alpha));
86 op->RasterWithFlags(canvas, flags);
87 } else {
88 canvas->saveLayerAlpha(nullptr, alpha);
89 op->RasterWithFlags(canvas, op->flags);
90 canvas->restore();
91 }
92 }
93 };
94
95 template <>
96 struct Rasterizer<SetMatrixOp, false> {
97 static void Raster(const SetMatrixOp* op,
98 SkCanvas* canvas,
99 const SkMatrix& original_ctm) {
100 op->Raster(canvas, original_ctm);
101 }
102 static void RasterWithAlpha(const SetMatrixOp* op,
103 SkCanvas* canvas,
104 uint8_t alpha) {
105 NOTREACHED();
106 }
107 };
108
109 template <>
110 struct Rasterizer<DrawRecordOp, false> {
111 static void Raster(const DrawRecordOp* op,
112 SkCanvas* canvas,
113 const SkMatrix& original_ctm) {
114 op->Raster(canvas);
115 }
116 static void RasterWithAlpha(const DrawRecordOp* op,
117 SkCanvas* canvas,
118 uint8_t alpha) {
119 // This "looking into records" optimization is done here instead of
120 // in the PaintOpBuffer::Raster function as DisplayItemList calls
121 // into RasterWithAlpha directly.
122 if (op->record->approximateOpCount() == 1) {
123 PaintOp* single_op = op->record->GetFirstOp();
124 // RasterWithAlpha only supported for draw ops.
125 if (single_op->IsDrawOp()) {
126 single_op->RasterWithAlpha(canvas, alpha);
127 return;
128 }
129 }
130
131 canvas->saveLayerAlpha(nullptr, alpha);
132 op->Raster(canvas);
133 canvas->restore();
134 }
135 };
136
137 // TODO(enne): partially specialize RasterWithAlpha for draw color?
138
139 static constexpr size_t kNumOpTypes =
140 static_cast<size_t>(PaintOpType::LastPaintOpType) + 1;
141
142 // Verify that every op is in the TYPES macro.
143 #define M(T) +1
144 static_assert(kNumOpTypes == TYPES(M), "Missing op in list");
145 #undef M
146
147 using RasterFunction = void (*)(const PaintOp* op,
148 SkCanvas* canvas,
149 const SkMatrix& original_ctm);
150 #define M(T) \
151 [](const PaintOp* op, SkCanvas* canvas, const SkMatrix& original_ctm) { \
152 Rasterizer<T, T::kHasPaintFlags>::Raster(static_cast<const T*>(op), \
153 canvas, original_ctm); \
154 },
155 static const RasterFunction g_raster_functions[kNumOpTypes] = {TYPES(M)};
156 #undef M
157
158 using RasterAlphaFunction = void (*)(const PaintOp* op,
159 SkCanvas* canvas,
160 uint8_t alpha);
161 #define M(T) \
162 T::kIsDrawOp ? \
163 [](const PaintOp* op, SkCanvas* canvas, uint8_t alpha) { \
164 Rasterizer<T, T::kHasPaintFlags>::RasterWithAlpha( \
165 static_cast<const T*>(op), canvas, alpha); \
166 } : static_cast<RasterAlphaFunction>(nullptr),
167 static const RasterAlphaFunction g_raster_alpha_functions[kNumOpTypes] = {
168 TYPES(M)};
169 #undef M
170
171 // Most state ops (matrix, clip, save, restore) have a trivial destructor.
172 // TODO(enne): evaluate if we need the nullptr optimization or if
173 // we even need to differentiate trivial destructors here.
174 using VoidFunction = void (*)(PaintOp* op);
175 #define M(T) \
176 !std::is_trivially_destructible<T>::value \
177 ? [](PaintOp* op) { static_cast<T*>(op)->~T(); } \
178 : static_cast<VoidFunction>(nullptr),
179 static const VoidFunction g_destructor_functions[kNumOpTypes] = {TYPES(M)};
180 #undef M
181
182 #define M(T) T::kIsDrawOp,
183 static bool g_is_draw_op[kNumOpTypes] = {TYPES(M)};
184 #undef M
185
186 #define M(T) \
187 static_assert(sizeof(T) <= sizeof(LargestPaintOp), \
188 #T " must be no bigger than LargestPaintOp");
189 TYPES(M);
190 #undef M
191
192 #define M(T) \
193 static_assert(ALIGNOF(T) <= PaintOpBuffer::PaintOpAlign, \
194 #T " must have alignment no bigger than PaintOpAlign");
195 TYPES(M);
196 #undef M
197
198 #undef TYPES
199
200 SkRect PaintOp::kUnsetRect = {SK_ScalarInfinity, 0, 0, 0};
201
202 void AnnotateOp::Raster(SkCanvas* canvas) const {
203 switch (annotation_type) {
204 case PaintCanvas::AnnotationType::URL:
205 SkAnnotateRectWithURL(canvas, rect, data.get());
206 break;
207 case PaintCanvas::AnnotationType::LINK_TO_DESTINATION:
208 SkAnnotateLinkToDestination(canvas, rect, data.get());
209 break;
210 case PaintCanvas::AnnotationType::NAMED_DESTINATION: {
211 SkPoint point = SkPoint::Make(rect.x(), rect.y());
212 SkAnnotateNamedDestination(canvas, point, data.get());
213 break;
214 }
215 }
216 }
217
218 void ClipPathOp::Raster(SkCanvas* canvas) const {
219 canvas->clipPath(path, op, antialias);
220 }
221
222 void ClipRectOp::Raster(SkCanvas* canvas) const {
223 canvas->clipRect(rect, op, antialias);
224 }
225
226 void ClipRRectOp::Raster(SkCanvas* canvas) const {
227 canvas->clipRRect(rrect, op, antialias);
228 }
229
230 void ConcatOp::Raster(SkCanvas* canvas) const {
231 canvas->concat(matrix);
232 }
233
234 void DrawArcOp::RasterWithFlags(SkCanvas* canvas,
235 const PaintFlags& flags) const {
236 canvas->drawArc(oval, start_angle, sweep_angle, use_center, ToSkPaint(flags));
237 }
238
239 void DrawCircleOp::RasterWithFlags(SkCanvas* canvas,
240 const PaintFlags& flags) const {
241 canvas->drawCircle(cx, cy, radius, ToSkPaint(flags));
242 }
243
244 void DrawColorOp::Raster(SkCanvas* canvas) const {
245 canvas->drawColor(color, mode);
246 }
247
248 void DrawDisplayItemListOp::Raster(SkCanvas* canvas) const {
249 list->Raster(canvas, nullptr);
250 }
251
252 void DrawDRRectOp::RasterWithFlags(SkCanvas* canvas,
253 const PaintFlags& flags) const {
254 canvas->drawDRRect(outer, inner, ToSkPaint(flags));
255 }
256
257 void DrawImageOp::RasterWithFlags(SkCanvas* canvas,
258 const PaintFlags& flags) const {
259 canvas->drawImage(image.sk_image().get(), left, top, ToSkPaint(&flags));
260 }
261
262 void DrawImageRectOp::RasterWithFlags(SkCanvas* canvas,
263 const PaintFlags& flags) const {
264 // TODO(enne): Probably PaintCanvas should just use the skia enum directly.
265 SkCanvas::SrcRectConstraint skconstraint =
266 static_cast<SkCanvas::SrcRectConstraint>(constraint);
267 canvas->drawImageRect(image.sk_image().get(), src, dst, ToSkPaint(&flags),
268 skconstraint);
269 }
270
271 void DrawIRectOp::RasterWithFlags(SkCanvas* canvas,
272 const PaintFlags& flags) const {
273 canvas->drawIRect(rect, ToSkPaint(flags));
274 }
275
276 void DrawLineOp::RasterWithFlags(SkCanvas* canvas,
277 const PaintFlags& flags) const {
278 canvas->drawLine(x0, y0, x1, y1, ToSkPaint(flags));
279 }
280
281 void DrawOvalOp::RasterWithFlags(SkCanvas* canvas,
282 const PaintFlags& flags) const {
283 canvas->drawOval(oval, ToSkPaint(flags));
284 }
285
286 void DrawPathOp::RasterWithFlags(SkCanvas* canvas,
287 const PaintFlags& flags) const {
288 canvas->drawPath(path, ToSkPaint(flags));
289 }
290
291 void DrawPosTextOp::RasterWithFlags(SkCanvas* canvas,
292 const PaintFlags& flags) const {
293 canvas->drawPosText(GetData(), bytes, GetArray(), ToSkPaint(flags));
294 }
295
296 void DrawRecordOp::Raster(SkCanvas* canvas) const {
297 record->playback(canvas);
298 }
299
300 void DrawRectOp::RasterWithFlags(SkCanvas* canvas,
301 const PaintFlags& flags) const {
302 canvas->drawRect(rect, ToSkPaint(flags));
303 }
304
305 void DrawRRectOp::RasterWithFlags(SkCanvas* canvas,
306 const PaintFlags& flags) const {
307 canvas->drawRRect(rrect, ToSkPaint(flags));
308 }
309
310 void DrawTextOp::RasterWithFlags(SkCanvas* canvas,
311 const PaintFlags& flags) const {
312 canvas->drawText(GetData(), bytes, x, y, ToSkPaint(flags));
313 }
314
315 void DrawTextBlobOp::RasterWithFlags(SkCanvas* canvas,
316 const PaintFlags& flags) const {
317 canvas->drawTextBlob(blob.get(), x, y, ToSkPaint(flags));
318 }
319
320 void RestoreOp::Raster(SkCanvas* canvas) const {
321 canvas->restore();
322 }
323
324 void RotateOp::Raster(SkCanvas* canvas) const {
325 canvas->rotate(degrees);
326 }
327
328 void SaveOp::Raster(SkCanvas* canvas) const {
329 canvas->save();
330 }
331
332 void SaveLayerOp::RasterWithFlags(SkCanvas* canvas,
333 const PaintFlags& flags) const {
334 // See PaintOp::kUnsetRect
335 bool unset = bounds.left() == SK_ScalarInfinity;
336
337 canvas->saveLayer(unset ? nullptr : &bounds, ToSkPaint(&flags));
338 }
339
340 void SaveLayerAlphaOp::Raster(SkCanvas* canvas) const {
341 // See PaintOp::kUnsetRect
342 bool unset = bounds.left() == SK_ScalarInfinity;
343 canvas->saveLayerAlpha(unset ? nullptr : &bounds, alpha);
344 }
345
346 void ScaleOp::Raster(SkCanvas* canvas) const {
347 canvas->scale(sx, sy);
348 }
349
350 void SetMatrixOp::Raster(SkCanvas* canvas, const SkMatrix& original_ctm) const {
351 canvas->setMatrix(SkMatrix::Concat(original_ctm, matrix));
352 }
353
354 void TranslateOp::Raster(SkCanvas* canvas) const {
355 canvas->translate(dx, dy);
356 }
357
358 bool PaintOp::IsDrawOp() const {
359 return g_is_draw_op[type];
360 }
361
362 void PaintOp::Raster(SkCanvas* canvas, const SkMatrix& original_ctm) const {
363 g_raster_functions[type](this, canvas, original_ctm);
364 }
365
366 void PaintOp::RasterWithAlpha(SkCanvas* canvas, uint8_t alpha) const {
367 g_raster_alpha_functions[type](this, canvas, alpha);
368 }
369
370 int ClipPathOp::CountSlowPaths() const {
371 return antialias && !path.isConvex() ? 1 : 0;
372 }
373
374 int DrawLineOp::CountSlowPaths() const {
375 if (const SkPathEffect* effect = flags.getPathEffect()) {
376 SkPathEffect::DashInfo info;
377 SkPathEffect::DashType dashType = effect->asADash(&info);
378 if (flags.getStrokeCap() != PaintFlags::kRound_Cap &&
379 dashType == SkPathEffect::kDash_DashType && info.fCount == 2) {
380 // The PaintFlags will count this as 1, so uncount that here as
381 // this kind of line is special cased and not slow.
382 return -1;
383 }
384 }
385 return 0;
386 }
387
388 int DrawPathOp::CountSlowPaths() const {
389 // This logic is copied from SkPathCounter instead of attempting to expose
390 // that from Skia.
391 if (!flags.isAntiAlias() || path.isConvex())
392 return 0;
393
394 PaintFlags::Style paintStyle = flags.getStyle();
395 const SkRect& pathBounds = path.getBounds();
396 if (paintStyle == PaintFlags::kStroke_Style && flags.getStrokeWidth() == 0) {
397 // AA hairline concave path is not slow.
398 return 0;
399 } else if (paintStyle == PaintFlags::kFill_Style &&
400 pathBounds.width() < 64.f && pathBounds.height() < 64.f &&
401 !path.isVolatile()) {
402 // AADF eligible concave path is not slow.
403 return 0;
404 } else {
405 return 1;
406 }
407 }
408
409 AnnotateOp::AnnotateOp(PaintCanvas::AnnotationType annotation_type,
410 const SkRect& rect,
411 sk_sp<SkData> data)
412 : annotation_type(annotation_type), rect(rect), data(std::move(data)) {}
413
414 AnnotateOp::~AnnotateOp() = default;
415
416 DrawDisplayItemListOp::DrawDisplayItemListOp(
417 scoped_refptr<DisplayItemList> list)
418 : list(list) {}
419
420 size_t DrawDisplayItemListOp::AdditionalBytesUsed() const {
421 return list->ApproximateMemoryUsage();
422 }
423
424 DrawDisplayItemListOp::DrawDisplayItemListOp(const DrawDisplayItemListOp& op) =
425 default;
426
427 DrawDisplayItemListOp& DrawDisplayItemListOp::operator=(
428 const DrawDisplayItemListOp& op) = default;
429
430 DrawDisplayItemListOp::~DrawDisplayItemListOp() = default;
431
432 DrawImageOp::DrawImageOp(const PaintImage& image,
433 SkScalar left,
434 SkScalar top,
435 const PaintFlags* flags)
436 : image(image),
437 left(left),
438 top(top),
439 flags(flags ? *flags : PaintFlags()) {}
440
441 DrawImageOp::~DrawImageOp() = default;
442
443 DrawImageRectOp::DrawImageRectOp(const PaintImage& image,
444 const SkRect& src,
445 const SkRect& dst,
446 const PaintFlags* flags,
447 PaintCanvas::SrcRectConstraint constraint)
448 : image(image),
449 flags(flags ? *flags : PaintFlags()),
450 src(src),
451 dst(dst),
452 constraint(constraint) {}
453
454 DrawImageRectOp::~DrawImageRectOp() = default;
455
456 DrawPosTextOp::DrawPosTextOp(size_t bytes,
457 size_t count,
458 const PaintFlags& flags)
459 : PaintOpWithArray(bytes, count), flags(flags) {}
460
461 DrawPosTextOp::~DrawPosTextOp() = default;
462
463 DrawRecordOp::DrawRecordOp(sk_sp<const PaintRecord> record)
464 : record(std::move(record)) {}
465
466 DrawRecordOp::~DrawRecordOp() = default;
467
468 size_t DrawRecordOp::AdditionalBytesUsed() const {
469 return record->approximateBytesUsed();
470 }
471
472 DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
473 SkScalar x,
474 SkScalar y,
475 const PaintFlags& flags)
476 : blob(std::move(blob)), x(x), y(y), flags(flags) {}
477
478 DrawTextBlobOp::~DrawTextBlobOp() = default;
479
480 PaintOpBuffer::PaintOpBuffer() : cull_rect_(SkRect::MakeEmpty()) {}
481
482 PaintOpBuffer::PaintOpBuffer(const SkRect& cull_rect) : cull_rect_(cull_rect) {}
483
484 PaintOpBuffer::~PaintOpBuffer() {
485 Reset();
486 }
487
488 void PaintOpBuffer::Reset() {
489 for (auto* op : Iterator(this)) {
490 auto func = g_destructor_functions[op->type];
491 if (func)
492 func(op);
493 }
494
495 // Leave data_ allocated, reserved_ unchanged.
496 used_ = 0;
497 op_count_ = 0;
498 num_slow_paths_ = 0;
499 }
500
501 void PaintOpBuffer::playback(SkCanvas* canvas) const {
502 // TODO(enne): a PaintRecord that contains a SetMatrix assumes that the
503 // SetMatrix is local to that PaintRecord itself. Said differently, if you
504 // translate(x, y), then draw a paint record with a SetMatrix(identity),
505 // the translation should be preserved instead of clobbering the top level
506 // transform. This could probably be done more efficiently.
507 SkMatrix original = canvas->getTotalMatrix();
508
509 for (Iterator iter(this); iter; ++iter) {
510 // Optimize out save/restores or save/draw/restore that can be a single
511 // draw. See also: similar code in SkRecordOpts and cc's DisplayItemList.
512 // TODO(enne): consider making this recursive?
513 const PaintOp* op = *iter;
514 if (op->GetType() == PaintOpType::SaveLayerAlpha) {
515 const PaintOp* second = iter.peek1();
516 if (second) {
517 if (second->GetType() == PaintOpType::Restore) {
518 ++iter;
519 continue;
520 }
521 if (second->IsDrawOp()) {
522 const PaintOp* third = iter.peek2();
523 if (third && third->GetType() == PaintOpType::Restore) {
524 const SaveLayerAlphaOp* save_op =
525 static_cast<const SaveLayerAlphaOp*>(op);
526 second->RasterWithAlpha(canvas, save_op->alpha);
527 ++iter;
528 ++iter;
529 continue;
530 }
531 }
532 }
533 }
534 // TODO(enne): skip SaveLayer followed by restore with nothing in
535 // between, however SaveLayer with image filters on it (or maybe
536 // other PaintFlags options) are not a noop. Figure out what these
537 // are so we can skip them correctly.
538
539 op->Raster(canvas, original);
540 }
541 }
542
543 void PaintOpBuffer::playback(SkCanvas* canvas,
544 SkPicture::AbortCallback* callback) const {
545 // The abort callback is only used for analysis, in general, so
546 // this playback code can be more straightforward and not do the
547 // optimizations in the other function.
548 if (!callback) {
549 playback(canvas);
550 return;
551 }
552
553 SkMatrix original = canvas->getTotalMatrix();
554
555 // TODO(enne): ideally callers would just iterate themselves and we
556 // can remove the entire notion of an abort callback.
557 for (auto* op : Iterator(this)) {
558 op->Raster(canvas, original);
559 if (callback && callback->abort())
560 return;
561 }
562 }
563
564 void PaintOpBuffer::ReallocBuffer(size_t new_size) {
565 DCHECK_GE(new_size, used_);
566 std::unique_ptr<char, base::AlignedFreeDeleter> new_data(
567 static_cast<char*>(base::AlignedAlloc(new_size, PaintOpAlign)));
568 memcpy(new_data.get(), data_.get(), used_);
569 data_ = std::move(new_data);
570 reserved_ = new_size;
571 }
572
573 void PaintOpBuffer::ShrinkToFit() {
574 if (!used_ || used_ == reserved_)
575 return;
576 ReallocBuffer(used_);
577 }
578
579 } // namespace cc
OLDNEW
« no previous file with comments | « cc/paint/paint_op_buffer.h ('k') | cc/paint/paint_op_buffer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698