Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
dl_op_records.h
Go to the documentation of this file.
1// Copyright 2013 The Flutter 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#ifndef FLUTTER_DISPLAY_LIST_DL_OP_RECORDS_H_
6#define FLUTTER_DISPLAY_LIST_DL_OP_RECORDS_H_
7
8#include "flutter/display_list/display_list.h"
9#include "flutter/display_list/dl_blend_mode.h"
10#include "flutter/display_list/dl_op_receiver.h"
11#include "flutter/display_list/dl_sampling_options.h"
12#include "flutter/display_list/effects/dl_color_source.h"
13#include "flutter/fml/macros.h"
14
15#include "flutter/impeller/geometry/path.h"
16#include "flutter/impeller/typographer/text_frame.h"
18
19namespace flutter {
20
21// Structure holding the information necessary to dispatch and
22// potentially cull the DLOps during playback.
23//
24// Generally drawing ops will execute as long as |cur_index|
25// is at or after |next_render_index|, so setting the latter
26// to 0 will render all primitives and setting it to MAX_INT
27// will skip all remaining rendering primitives.
28//
29// Save and saveLayer ops will execute as long as the next
30// rendering index is before their closing restore index.
31// They will also store their own restore index into the
32// |next_restore_index| field for use by clip and transform ops.
33//
34// Clip and transform ops will only execute if the next
35// render index is before the next restore index. Otherwise
36// their modified state will not be used before it gets
37// restored.
38//
39// Attribute ops always execute as they are too numerous and
40// cheap to deal with a complicated "lifetime" tracking to
41// determine if they will be used.
61
62// Most Ops can be bulk compared using memcmp because they contain
63// only numeric values or constructs that are constructed from numeric
64// values.
65//
66// Some contain sk_sp<> references which can also be bulk compared
67// to see if they are pointing to the same reference. (Note that
68// two sk_sp<> that refer to the same object are themselves ==.)
69//
70// Only a DLOp that wants to do a deep compare needs to override the
71// DLOp::equals() method and return a value of kEqual or kNotEqual.
73 // The Op is deferring comparisons to a bulk memcmp performed lazily
74 // across all bulk-comparable ops.
76
77 // The Op provided a specific equals method that spotted a difference
79
80 // The Op provided a specific equals method that saw no differences
81 kEqual,
82};
83
84// "DLOpPackLabel" is just a label for the pack pragma so it can be popped
85// later.
86#pragma pack(push, DLOpPackLabel, 8)
87
88// Assuming a 64-bit platform (most of our platforms at this time?)
89// the following comments are a "worst case" assessment of how well
90// these structures pack into memory. They may be packed more tightly
91// on some of the 32-bit platforms that we see in older phones.
92//
93// Struct allocation in the DL memory is aligned to a void* boundary
94// which means that the minimum (aligned) struct size will be 8 bytes.
95// The DLOp base uses 4 bytes so each Op-specific struct gets 4 bytes
96// of data for "free" and works best when it packs well into an 8-byte
97// aligned size.
98struct DLOp {
99 static constexpr uint32_t kDepthInc = 0;
100 static constexpr uint32_t kRenderOpInc = 0;
101
103 uint32_t size : 24;
104
105 DisplayListCompare equals(const DLOp* other) const {
107 }
108};
109
110// 4 byte header + 4 byte payload packs into minimum 8 bytes
111#define DEFINE_SET_BOOL_OP(name) \
112 struct Set##name##Op final : DLOp { \
113 static constexpr auto kType = DisplayListOpType::kSet##name; \
114 \
115 explicit Set##name##Op(bool value) : value(value) {} \
116 \
117 const bool value; \
118 \
119 void dispatch(DispatchContext& ctx) const { \
120 ctx.receiver.set##name(value); \
121 } \
122 };
123DEFINE_SET_BOOL_OP(AntiAlias)
124DEFINE_SET_BOOL_OP(InvertColors)
125#undef DEFINE_SET_BOOL_OP
126
127// 4 byte header + 4 byte payload packs into minimum 8 bytes
128#define DEFINE_SET_ENUM_OP(name) \
129 struct SetStroke##name##Op final : DLOp { \
130 static constexpr auto kType = DisplayListOpType::kSetStroke##name; \
131 \
132 explicit SetStroke##name##Op(DlStroke##name value) : value(value) {} \
133 \
134 const DlStroke##name value; \
135 \
136 void dispatch(DispatchContext& ctx) const { \
137 ctx.receiver.setStroke##name(value); \
138 } \
139 };
142#undef DEFINE_SET_ENUM_OP
143
144// 4 byte header + 4 byte payload packs into minimum 8 bytes
145struct SetStyleOp final : DLOp {
146 static constexpr auto kType = DisplayListOpType::kSetStyle;
147
149
151
152 void dispatch(DispatchContext& ctx) const {
154 }
155};
156// 4 byte header + 4 byte payload packs into minimum 8 bytes
157struct SetStrokeWidthOp final : DLOp {
158 static constexpr auto kType = DisplayListOpType::kSetStrokeWidth;
159
160 explicit SetStrokeWidthOp(float width) : width(width) {}
161
162 const float width;
163
164 void dispatch(DispatchContext& ctx) const {
166 }
167};
168// 4 byte header + 4 byte payload packs into minimum 8 bytes
169struct SetStrokeMiterOp final : DLOp {
170 static constexpr auto kType = DisplayListOpType::kSetStrokeMiter;
171
172 explicit SetStrokeMiterOp(float limit) : limit(limit) {}
173
174 const float limit;
175
176 void dispatch(DispatchContext& ctx) const {
178 }
179};
180
181// 4 byte header + 4 byte payload packs into minimum 8 bytes
182struct SetColorOp final : DLOp {
183 static constexpr auto kType = DisplayListOpType::kSetColor;
184
186
188
189 void dispatch(DispatchContext& ctx) const { ctx.receiver.setColor(color); }
190};
191// 4 byte header + 4 byte payload packs into minimum 8 bytes
192struct SetBlendModeOp final : DLOp {
193 static constexpr auto kType = DisplayListOpType::kSetBlendMode;
194
196
198
199 void dispatch(DispatchContext& ctx) const { //
201 }
202};
203
204// Clear: 4 byte header + unused 4 byte payload uses 8 bytes
205// (4 bytes unused)
206// Set: 4 byte header + unused 4 byte struct padding + Dl<name>
207// instance copied to the memory following the record
208// yields a size and efficiency that has somewhere between
209// 4 and 8 bytes unused
210#define DEFINE_SET_CLEAR_DLATTR_OP(name, sk_name, field) \
211 struct Clear##name##Op final : DLOp { \
212 static constexpr auto kType = DisplayListOpType::kClear##name; \
213 \
214 Clear##name##Op() {} \
215 \
216 void dispatch(DispatchContext& ctx) const { \
217 ctx.receiver.set##name(nullptr); \
218 } \
219 }; \
220 struct SetPod##name##Op final : DLOp { \
221 static constexpr auto kType = DisplayListOpType::kSetPod##name; \
222 \
223 SetPod##name##Op() {} \
224 \
225 void dispatch(DispatchContext& ctx) const { \
226 const Dl##name* filter = reinterpret_cast<const Dl##name*>(this + 1); \
227 ctx.receiver.set##name(filter); \
228 } \
229 };
230DEFINE_SET_CLEAR_DLATTR_OP(ColorFilter, ColorFilter, filter)
231DEFINE_SET_CLEAR_DLATTR_OP(ImageFilter, ImageFilter, filter)
232DEFINE_SET_CLEAR_DLATTR_OP(MaskFilter, MaskFilter, filter)
233DEFINE_SET_CLEAR_DLATTR_OP(ColorSource, Shader, source)
234DEFINE_SET_CLEAR_DLATTR_OP(PathEffect, PathEffect, effect)
235#undef DEFINE_SET_CLEAR_DLATTR_OP
236
237// 4 byte header + 80 bytes for the embedded DlImageColorSource
238// uses 84 total bytes (4 bytes unused)
240 static constexpr auto kType = DisplayListOpType::kSetImageColorSource;
241
243 : source(source->image(),
244 source->horizontal_tile_mode(),
245 source->vertical_tile_mode(),
246 source->sampling(),
247 source->matrix_ptr()) {}
248
250
251 void dispatch(DispatchContext& ctx) const {
253 }
254};
255
256// 56 bytes: 4 byte header, 4 byte padding, 8 for vtable, 8 * 2 for sk_sps, 24
257// for the std::vector.
259 static constexpr auto kType = DisplayListOpType::kSetRuntimeEffectColorSource;
260
263 : source(source->runtime_effect(),
264 source->samplers(),
265 source->uniform_data()) {}
266
268
269 void dispatch(DispatchContext& ctx) const {
271 }
272
277};
278
279#ifdef IMPELLER_ENABLE_3D
280struct SetSceneColorSourceOp : DLOp {
281 static constexpr auto kType = DisplayListOpType::kSetSceneColorSource;
282
283 explicit SetSceneColorSourceOp(const DlSceneColorSource* source)
284 : source(source->scene_node(), source->camera_matrix()) {}
285
286 const DlSceneColorSource source;
287
288 void dispatch(DispatchContext& ctx) const {
289 ctx.receiver.setColorSource(&source);
290 }
291
292 DisplayListCompare equals(const SetSceneColorSourceOp* other) const {
293 return (source == other->source) ? DisplayListCompare::kEqual
294 : DisplayListCompare::kNotEqual;
295 }
296};
297#endif // IMPELLER_ENABLE_3D
298
299// 4 byte header + 16 byte payload uses 24 total bytes (4 bytes unused)
301 static constexpr auto kType = DisplayListOpType::kSetSharedImageFilter;
302
304 : filter(filter->shared()) {}
305
306 const std::shared_ptr<DlImageFilter> filter;
307
308 void dispatch(DispatchContext& ctx) const {
309 ctx.receiver.setImageFilter(filter.get());
310 }
311
316};
317
318// The base struct for all save() and saveLayer() ops
319// 4 byte header + 8 byte payload packs into 16 bytes (4 bytes unused)
320struct SaveOpBase : DLOp {
321 static constexpr uint32_t kDepthInc = 0;
322 static constexpr uint32_t kRenderOpInc = 1;
323
325
328
329 // options parameter is only used by saveLayer operations, but since
330 // it packs neatly into the empty space created by laying out the 64-bit
331 // offsets, it can be stored for free and defaulted to 0 for save operations.
335
336 inline bool save_needed(DispatchContext& ctx) const {
337 bool needed = ctx.next_render_index <= restore_index;
338 ctx.save_infos.emplace_back(ctx.next_restore_index, needed);
340 return needed;
341 }
342};
343// 16 byte SaveOpBase with no additional data (options is unsed here)
344struct SaveOp final : SaveOpBase {
345 static constexpr auto kType = DisplayListOpType::kSave;
346
348
349 void dispatch(DispatchContext& ctx) const {
350 if (save_needed(ctx)) {
352 }
353 }
354};
355// The base struct for all saveLayer() ops
356// 16 byte SaveOpBase + 16 byte payload packs into 32 bytes (4 bytes unused)
363// 32 byte SaveLayerOpBase with no additional data
365 static constexpr auto kType = DisplayListOpType::kSaveLayer;
366
369
370 void dispatch(DispatchContext& ctx) const {
371 if (save_needed(ctx)) {
373 }
374 }
375};
376// 32 byte SaveLayerOpBase + 16 byte payload packs into minimum 48 bytes
378 static constexpr auto kType = DisplayListOpType::kSaveLayerBackdrop;
379
384
385 const std::shared_ptr<DlImageFilter> backdrop;
386
387 void dispatch(DispatchContext& ctx) const {
388 if (save_needed(ctx)) {
390 backdrop.get());
391 }
392 }
393
395 return (options == other->options && rect == other->rect &&
396 Equals(backdrop, other->backdrop))
399 }
400};
401// 4 byte header + no payload uses minimum 8 bytes (4 bytes unused)
402struct RestoreOp final : DLOp {
403 static constexpr auto kType = DisplayListOpType::kRestore;
404 static constexpr uint32_t kDepthInc = 0;
405 static constexpr uint32_t kRenderOpInc = 1;
406
408
409 void dispatch(DispatchContext& ctx) const {
411 if (info.save_was_needed) {
412 ctx.receiver.restore();
413 }
414 ctx.next_restore_index = info.previous_restore_index;
415 ctx.save_infos.pop_back();
416 }
417};
418
420 static constexpr uint32_t kDepthInc = 0;
421 static constexpr uint32_t kRenderOpInc = 1;
422
423 inline bool op_needed(const DispatchContext& context) const {
424 return context.next_render_index <= context.next_restore_index;
425 }
426};
427// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
428// (4 bytes unused)
430 static constexpr auto kType = DisplayListOpType::kTranslate;
431
433
436
437 void dispatch(DispatchContext& ctx) const {
438 if (op_needed(ctx)) {
439 ctx.receiver.translate(tx, ty);
440 }
441 }
442};
443// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
444// (4 bytes unused)
446 static constexpr auto kType = DisplayListOpType::kScale;
447
449
452
453 void dispatch(DispatchContext& ctx) const {
454 if (op_needed(ctx)) {
455 ctx.receiver.scale(sx, sy);
456 }
457 }
458};
459// 4 byte header + 4 byte payload packs into minimum 8 bytes
461 static constexpr auto kType = DisplayListOpType::kRotate;
462
464
466
467 void dispatch(DispatchContext& ctx) const {
468 if (op_needed(ctx)) {
470 }
471 }
472};
473// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
474// (4 bytes unused)
476 static constexpr auto kType = DisplayListOpType::kSkew;
477
479
482
483 void dispatch(DispatchContext& ctx) const {
484 if (op_needed(ctx)) {
485 ctx.receiver.skew(sx, sy);
486 }
487 }
488};
489// 4 byte header + 24 byte payload uses 28 bytes but is rounded up to 32 bytes
490// (4 bytes unused)
492 static constexpr auto kType = DisplayListOpType::kTransform2DAffine;
493
494 // clang-format off
498 // clang-format on
499
502
503 void dispatch(DispatchContext& ctx) const {
504 if (op_needed(ctx)) {
506 myx, myy, myt);
507 }
508 }
509};
510// 4 byte header + 64 byte payload uses 68 bytes which is rounded up to 72 bytes
511// (4 bytes unused)
513 static constexpr auto kType = DisplayListOpType::kTransformFullPerspective;
514
515 // clang-format off
525 // clang-format on
526
531
532 void dispatch(DispatchContext& ctx) const {
533 if (op_needed(ctx)) {
535 myx, myy, myz, myt, //
536 mzx, mzy, mzz, mzt, //
537 mwx, mwy, mwz, mwt);
538 }
539 }
540};
541
542// 4 byte header with no payload.
544 static constexpr auto kType = DisplayListOpType::kTransformReset;
545
546 TransformResetOp() = default;
547
548 void dispatch(DispatchContext& ctx) const {
549 if (op_needed(ctx)) {
551 }
552 }
553};
554
555// 4 byte header + 4 byte common payload packs into minimum 8 bytes
556// SkRect is 16 more bytes, which packs efficiently into 24 bytes total
557// SkRRect is 52 more bytes, which rounds up to 56 bytes (4 bytes unused)
558// which packs into 64 bytes total
559// CacheablePath is 128 more bytes, which packs efficiently into 136 bytes total
560//
561// We could pack the clip_op and the bool both into the free 4 bytes after
562// the header, but the Windows compiler keeps wanting to expand that
563// packing into more bytes than needed (even when they are declared as
564// packed bit fields!)
565#define DEFINE_CLIP_SHAPE_OP(shapetype, clipop) \
566 struct Clip##clipop##shapetype##Op final : TransformClipOpBase { \
567 static constexpr auto kType = DisplayListOpType::kClip##clipop##shapetype; \
568 \
569 Clip##clipop##shapetype##Op(Sk##shapetype shape, bool is_aa) \
570 : is_aa(is_aa), shape(shape) {} \
571 \
572 const bool is_aa; \
573 const Sk##shapetype shape; \
574 \
575 void dispatch(DispatchContext& ctx) const { \
576 if (op_needed(ctx)) { \
577 ctx.receiver.clip##shapetype(shape, DlCanvas::ClipOp::k##clipop, \
578 is_aa); \
579 } \
580 } \
581 };
582DEFINE_CLIP_SHAPE_OP(Rect, Intersect)
583DEFINE_CLIP_SHAPE_OP(RRect, Intersect)
584DEFINE_CLIP_SHAPE_OP(Rect, Difference)
585DEFINE_CLIP_SHAPE_OP(RRect, Difference)
586#undef DEFINE_CLIP_SHAPE_OP
587
588#define DEFINE_CLIP_PATH_OP(clipop) \
589 struct Clip##clipop##PathOp final : TransformClipOpBase { \
590 static constexpr auto kType = DisplayListOpType::kClip##clipop##Path; \
591 \
592 Clip##clipop##PathOp(const SkPath& path, bool is_aa) \
593 : is_aa(is_aa), cached_path(path) {} \
594 \
595 const bool is_aa; \
596 const DlOpReceiver::CacheablePath cached_path; \
597 \
598 void dispatch(DispatchContext& ctx) const { \
599 if (op_needed(ctx)) { \
600 if (ctx.receiver.PrefersImpellerPaths()) { \
601 ctx.receiver.clipPath(cached_path, DlCanvas::ClipOp::k##clipop, \
602 is_aa); \
603 } else { \
604 ctx.receiver.clipPath(cached_path.sk_path, \
605 DlCanvas::ClipOp::k##clipop, is_aa); \
606 } \
607 } \
608 } \
609 \
610 DisplayListCompare equals(const Clip##clipop##PathOp* other) const { \
611 return is_aa == other->is_aa && cached_path == other->cached_path \
612 ? DisplayListCompare::kEqual \
613 : DisplayListCompare::kNotEqual; \
614 } \
615 };
616DEFINE_CLIP_PATH_OP(Intersect)
617DEFINE_CLIP_PATH_OP(Difference)
618#undef DEFINE_CLIP_PATH_OP
619
620struct DrawOpBase : DLOp {
621 static constexpr uint32_t kDepthInc = 1;
622 static constexpr uint32_t kRenderOpInc = 1;
623
624 inline bool op_needed(const DispatchContext& ctx) const {
625 return ctx.cur_index >= ctx.next_render_index;
626 }
627};
628
629// 4 byte header + no payload uses minimum 8 bytes (4 bytes unused)
630struct DrawPaintOp final : DrawOpBase {
631 static constexpr auto kType = DisplayListOpType::kDrawPaint;
632
634
635 void dispatch(DispatchContext& ctx) const {
636 if (op_needed(ctx)) {
637 ctx.receiver.drawPaint();
638 }
639 }
640};
641// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
642// (4 bytes unused)
643struct DrawColorOp final : DrawOpBase {
644 static constexpr auto kType = DisplayListOpType::kDrawColor;
645
647
650
651 void dispatch(DispatchContext& ctx) const {
652 if (op_needed(ctx)) {
654 }
655 }
656};
657
658// The common data is a 4 byte header with an unused 4 bytes
659// SkRect is 16 more bytes, using 20 bytes which rounds up to 24 bytes total
660// (4 bytes unused)
661// SkOval is same as SkRect
662// SkRRect is 52 more bytes, which packs efficiently into 56 bytes total
663#define DEFINE_DRAW_1ARG_OP(op_name, arg_type, arg_name) \
664 struct Draw##op_name##Op final : DrawOpBase { \
665 static constexpr auto kType = DisplayListOpType::kDraw##op_name; \
666 \
667 explicit Draw##op_name##Op(arg_type arg_name) : arg_name(arg_name) {} \
668 \
669 const arg_type arg_name; \
670 \
671 void dispatch(DispatchContext& ctx) const { \
672 if (op_needed(ctx)) { \
673 ctx.receiver.draw##op_name(arg_name); \
674 } \
675 } \
676 };
677DEFINE_DRAW_1ARG_OP(Rect, SkRect, rect)
678DEFINE_DRAW_1ARG_OP(Oval, SkRect, oval)
679DEFINE_DRAW_1ARG_OP(RRect, SkRRect, rrect)
680#undef DEFINE_DRAW_1ARG_OP
681
682// 4 byte header + 128 byte payload uses 132 bytes but is rounded
683// up to 136 bytes (4 bytes unused)
684struct DrawPathOp final : DrawOpBase {
685 static constexpr auto kType = DisplayListOpType::kDrawPath;
686
687 explicit DrawPathOp(const SkPath& path) : cached_path(path) {}
688
690
691 void dispatch(DispatchContext& ctx) const {
692 if (op_needed(ctx)) {
693 if (ctx.receiver.PrefersImpellerPaths()) {
695 } else {
697 }
698 }
699 }
700
705};
706
707// The common data is a 4 byte header with an unused 4 bytes
708// 2 x SkPoint is 16 more bytes, using 20 bytes rounding up to 24 bytes total
709// (4 bytes unused)
710// SkPoint + SkScalar is 12 more bytes, packing efficiently into 16 bytes total
711// 2 x SkRRect is 104 more bytes, using 108 and rounding up to 112 bytes total
712// (4 bytes unused)
713#define DEFINE_DRAW_2ARG_OP(op_name, type1, name1, type2, name2) \
714 struct Draw##op_name##Op final : DrawOpBase { \
715 static constexpr auto kType = DisplayListOpType::kDraw##op_name; \
716 \
717 Draw##op_name##Op(type1 name1, type2 name2) \
718 : name1(name1), name2(name2) {} \
719 \
720 const type1 name1; \
721 const type2 name2; \
722 \
723 void dispatch(DispatchContext& ctx) const { \
724 if (op_needed(ctx)) { \
725 ctx.receiver.draw##op_name(name1, name2); \
726 } \
727 } \
728 };
731DEFINE_DRAW_2ARG_OP(DRRect, SkRRect, outer, SkRRect, inner)
732#undef DEFINE_DRAW_2ARG_OP
733
734// 4 byte header + 28 byte payload packs efficiently into 32 bytes
735struct DrawArcOp final : DrawOpBase {
736 static constexpr auto kType = DisplayListOpType::kDrawArc;
737
740
744 const bool center;
745
746 void dispatch(DispatchContext& ctx) const {
747 if (op_needed(ctx)) {
749 }
750 }
751};
752
753// 4 byte header + 4 byte fixed payload packs efficiently into 8 bytes
754// But then there is a list of points following the structure which
755// is guaranteed to be a multiple of 8 bytes (SkPoint is 8 bytes)
756// so this op will always pack efficiently
757// The point type is packed into 3 different OpTypes to avoid expanding
758// the fixed payload beyond the 8 bytes
759#define DEFINE_DRAW_POINTS_OP(name, mode) \
760 struct Draw##name##Op final : DrawOpBase { \
761 static constexpr auto kType = DisplayListOpType::kDraw##name; \
762 \
763 explicit Draw##name##Op(uint32_t count) : count(count) {} \
764 \
765 const uint32_t count; \
766 \
767 void dispatch(DispatchContext& ctx) const { \
768 if (op_needed(ctx)) { \
769 const SkPoint* pts = reinterpret_cast<const SkPoint*>(this + 1); \
770 ctx.receiver.drawPoints(DlCanvas::PointMode::mode, count, pts); \
771 } \
772 } \
773 };
777#undef DEFINE_DRAW_POINTS_OP
778
779// 4 byte header + 4 byte payload packs efficiently into 8 bytes
780// The DlVertices object will be pod-allocated after this structure
781// and can take any number of bytes so the final efficiency will
782// depend on the size of the DlVertices.
783// Note that the DlVertices object ends with an array of 16-bit
784// indices so the alignment can be up to 6 bytes off leading to
785// up to 6 bytes of overhead
787 static constexpr auto kType = DisplayListOpType::kDrawVertices;
788
790
792
793 void dispatch(DispatchContext& ctx) const {
794 if (op_needed(ctx)) {
795 const DlVertices* vertices =
796 reinterpret_cast<const DlVertices*>(this + 1);
797 ctx.receiver.drawVertices(vertices, mode);
798 }
799 }
800};
801
802// 4 byte header + 40 byte payload uses 44 bytes but is rounded up to 48 bytes
803// (4 bytes unused)
804#define DEFINE_DRAW_IMAGE_OP(name, with_attributes) \
805 struct name##Op final : DrawOpBase { \
806 static constexpr auto kType = DisplayListOpType::k##name; \
807 \
808 name##Op(const sk_sp<DlImage>& image, \
809 const SkPoint& point, \
810 DlImageSampling sampling) \
811 : point(point), sampling(sampling), image(std::move(image)) {} \
812 \
813 const SkPoint point; \
814 const DlImageSampling sampling; \
815 const sk_sp<DlImage> image; \
816 \
817 void dispatch(DispatchContext& ctx) const { \
818 if (op_needed(ctx)) { \
819 ctx.receiver.drawImage(image, point, sampling, with_attributes); \
820 } \
821 } \
822 \
823 DisplayListCompare equals(const name##Op* other) const { \
824 return (point == other->point && sampling == other->sampling && \
825 image->Equals(other->image)) \
826 ? DisplayListCompare::kEqual \
827 : DisplayListCompare::kNotEqual; \
828 } \
829 };
830DEFINE_DRAW_IMAGE_OP(DrawImage, false)
831DEFINE_DRAW_IMAGE_OP(DrawImageWithAttr, true)
832#undef DEFINE_DRAW_IMAGE_OP
833
834// 4 byte header + 72 byte payload uses 76 bytes but is rounded up to 80 bytes
835// (4 bytes unused)
837 static constexpr auto kType = DisplayListOpType::kDrawImageRect;
838
851
852 const SkRect src;
853 const SkRect dst;
858
859 void dispatch(DispatchContext& ctx) const {
860 if (op_needed(ctx)) {
863 }
864 }
865
867 return (src == other->src && dst == other->dst &&
868 sampling == other->sampling &&
870 constraint == other->constraint && image->Equals(other->image))
873 }
874};
875
876// 4 byte header + 44 byte payload packs efficiently into 48 bytes
877#define DEFINE_DRAW_IMAGE_NINE_OP(name, render_with_attributes) \
878 struct name##Op final : DrawOpBase { \
879 static constexpr auto kType = DisplayListOpType::k##name; \
880 \
881 name##Op(const sk_sp<DlImage>& image, \
882 const SkIRect& center, \
883 const SkRect& dst, \
884 DlFilterMode mode) \
885 : center(center), dst(dst), mode(mode), image(std::move(image)) {} \
886 \
887 const SkIRect center; \
888 const SkRect dst; \
889 const DlFilterMode mode; \
890 const sk_sp<DlImage> image; \
891 \
892 void dispatch(DispatchContext& ctx) const { \
893 if (op_needed(ctx)) { \
894 ctx.receiver.drawImageNine(image, center, dst, mode, \
895 render_with_attributes); \
896 } \
897 } \
898 \
899 DisplayListCompare equals(const name##Op* other) const { \
900 return (center == other->center && dst == other->dst && \
901 mode == other->mode && image->Equals(other->image)) \
902 ? DisplayListCompare::kEqual \
903 : DisplayListCompare::kNotEqual; \
904 } \
905 };
906DEFINE_DRAW_IMAGE_NINE_OP(DrawImageNine, false)
907DEFINE_DRAW_IMAGE_NINE_OP(DrawImageNineWithAttr, true)
908#undef DEFINE_DRAW_IMAGE_NINE_OP
909
910// 4 byte header + 40 byte payload uses 44 bytes but is rounded up to 48 bytes
911// (4 bytes unused)
912// Each of these is then followed by a number of lists.
913// SkRSXform list is a multiple of 16 bytes so it is always packed well
914// SkRect list is also a multiple of 16 bytes so it also packs well
915// DlColor list only packs well if the count is even, otherwise there
916// can be 4 unusued bytes at the end.
930
931 const int count;
932 const uint16_t mode_index;
933 const uint8_t has_colors;
937
938 bool equals(const DrawAtlasBaseOp* other,
939 const void* pod_this,
940 const void* pod_other) const {
941 bool ret = (count == other->count && mode_index == other->mode_index &&
942 has_colors == other->has_colors &&
944 sampling == other->sampling && atlas->Equals(other->atlas));
945 if (ret) {
946 size_t bytes = count * (sizeof(SkRSXform) + sizeof(SkRect));
947 if (has_colors) {
948 bytes += count * sizeof(DlColor);
949 }
950 ret = (memcmp(pod_this, pod_other, bytes) == 0);
951 }
952 return ret;
953 }
954};
955
956// Packs into 48 bytes as per DrawAtlasBaseOp
957// with array data following the struct also as per DrawAtlasBaseOp
959 static constexpr auto kType = DisplayListOpType::kDrawAtlas;
960
973
974 void dispatch(DispatchContext& ctx) const {
975 if (op_needed(ctx)) {
976 const SkRSXform* xform = reinterpret_cast<const SkRSXform*>(this + 1);
977 const SkRect* tex = reinterpret_cast<const SkRect*>(xform + count);
978 const DlColor* colors =
979 has_colors ? reinterpret_cast<const DlColor*>(tex + count) : nullptr;
980 const DlBlendMode mode = static_cast<DlBlendMode>(mode_index);
981 ctx.receiver.drawAtlas(atlas, xform, tex, colors, count, mode, sampling,
982 nullptr, render_with_attributes);
983 }
984 }
985
987 const void* pod_this = reinterpret_cast<const void*>(this + 1);
988 const void* pod_other = reinterpret_cast<const void*>(other + 1);
989 return (DrawAtlasBaseOp::equals(other, pod_this, pod_other))
992 }
993};
994
995// Packs into 48 bytes as per DrawAtlasBaseOp plus
996// an additional 16 bytes for the cull rect resulting in a total
997// of 56 bytes for the Culled drawAtlas.
998// Also with array data following the struct as per DrawAtlasBaseOp
1000 static constexpr auto kType = DisplayListOpType::kDrawAtlasCulled;
1001
1016
1018
1019 void dispatch(DispatchContext& ctx) const {
1020 if (op_needed(ctx)) {
1021 const SkRSXform* xform = reinterpret_cast<const SkRSXform*>(this + 1);
1022 const SkRect* tex = reinterpret_cast<const SkRect*>(xform + count);
1023 const DlColor* colors =
1024 has_colors ? reinterpret_cast<const DlColor*>(tex + count) : nullptr;
1025 const DlBlendMode mode = static_cast<DlBlendMode>(mode_index);
1026 ctx.receiver.drawAtlas(atlas, xform, tex, colors, count, mode, sampling,
1028 }
1029 }
1030
1032 const void* pod_this = reinterpret_cast<const void*>(this + 1);
1033 const void* pod_other = reinterpret_cast<const void*>(other + 1);
1034 return (cull_rect == other->cull_rect &&
1035 DrawAtlasBaseOp::equals(other, pod_this, pod_other))
1038 }
1039};
1040
1041// 4 byte header + ptr aligned payload uses 12 bytes round up to 16
1042// (4 bytes unused)
1044 static constexpr auto kType = DisplayListOpType::kDrawDisplayList;
1045
1049
1052
1053 void dispatch(DispatchContext& ctx) const {
1054 if (op_needed(ctx)) {
1056 }
1057 }
1058
1060 return (opacity == other->opacity &&
1061 display_list->Equals(other->display_list))
1064 }
1065};
1066
1067// 4 byte header + 8 payload bytes + an aligned pointer take 24 bytes
1068// (4 unused to align the pointer)
1070 static constexpr auto kType = DisplayListOpType::kDrawTextBlob;
1071
1074
1078
1079 void dispatch(DispatchContext& ctx) const {
1080 if (op_needed(ctx)) {
1081 ctx.receiver.drawTextBlob(blob, x, y);
1082 }
1083 }
1084};
1085
1087 static constexpr auto kType = DisplayListOpType::kDrawTextFrame;
1088
1089 DrawTextFrameOp(const std::shared_ptr<impeller::TextFrame>& text_frame,
1090 SkScalar x,
1091 SkScalar y)
1092 : x(x), y(y), text_frame(text_frame) {}
1093
1096 const std::shared_ptr<impeller::TextFrame> text_frame;
1097
1098 void dispatch(DispatchContext& ctx) const {
1099 if (op_needed(ctx)) {
1101 }
1102 }
1103};
1104
1105// 4 byte header + 140 byte payload packs evenly into 140 bytes
1106#define DEFINE_DRAW_SHADOW_OP(name, transparent_occluder) \
1107 struct Draw##name##Op final : DrawOpBase { \
1108 static constexpr auto kType = DisplayListOpType::kDraw##name; \
1109 \
1110 Draw##name##Op(const SkPath& path, \
1111 DlColor color, \
1112 SkScalar elevation, \
1113 SkScalar dpr) \
1114 : color(color), elevation(elevation), dpr(dpr), cached_path(path) {} \
1115 \
1116 const DlColor color; \
1117 const SkScalar elevation; \
1118 const SkScalar dpr; \
1119 const DlOpReceiver::CacheablePath cached_path; \
1120 \
1121 void dispatch(DispatchContext& ctx) const { \
1122 if (op_needed(ctx)) { \
1123 if (ctx.receiver.PrefersImpellerPaths()) { \
1124 ctx.receiver.drawShadow(cached_path, color, elevation, \
1125 transparent_occluder, dpr); \
1126 } else { \
1127 ctx.receiver.drawShadow(cached_path.sk_path, color, elevation, \
1128 transparent_occluder, dpr); \
1129 } \
1130 } \
1131 } \
1132 \
1133 DisplayListCompare equals(const Draw##name##Op* other) const { \
1134 return color == other->color && elevation == other->elevation && \
1135 dpr == other->dpr && cached_path == other->cached_path \
1136 ? DisplayListCompare::kEqual \
1137 : DisplayListCompare::kNotEqual; \
1138 } \
1139 };
1140DEFINE_DRAW_SHADOW_OP(Shadow, false)
1141DEFINE_DRAW_SHADOW_OP(ShadowTransparentOccluder, true)
1142#undef DEFINE_DRAW_SHADOW_OP
1143
1144#pragma pack(pop, DLOpPackLabel)
1145
1146} // namespace flutter
1147
1148#endif // FLUTTER_DISPLAY_LIST_DL_OP_RECORDS_H_
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
static bool equals(T *a, T *b)
static SkScalar center(float pos0, float pos1)
Internal API for rendering recorded display lists to backends.
virtual void drawImageRect(const sk_sp< DlImage > image, const SkRect &src, const SkRect &dst, DlImageSampling sampling, bool render_with_attributes, SrcRectConstraint constraint=SrcRectConstraint::kFast)=0
virtual void save()=0
virtual void drawArc(const SkRect &oval_bounds, SkScalar start_degrees, SkScalar sweep_degrees, bool use_center)=0
virtual void saveLayer(const SkRect &bounds, const SaveLayerOptions options, const DlImageFilter *backdrop=nullptr)=0
virtual void setStrokeMiter(float limit)=0
virtual void transformReset()=0
virtual void drawVertices(const DlVertices *vertices, DlBlendMode mode)=0
virtual void restore()=0
virtual void drawPath(const CacheablePath &cache)
virtual void skew(SkScalar sx, SkScalar sy)=0
virtual void drawDisplayList(const sk_sp< DisplayList > display_list, SkScalar opacity=SK_Scalar1)=0
virtual void setStrokeWidth(float width)=0
virtual void drawTextFrame(const std::shared_ptr< impeller::TextFrame > &text_frame, SkScalar x, SkScalar y)=0
virtual void drawColor(DlColor color, DlBlendMode mode)=0
virtual void drawAtlas(const sk_sp< DlImage > atlas, const SkRSXform xform[], const SkRect tex[], const DlColor colors[], int count, DlBlendMode mode, DlImageSampling sampling, const SkRect *cull_rect, bool render_with_attributes)=0
virtual void transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt, SkScalar myx, SkScalar myy, SkScalar myt)=0
virtual void translate(SkScalar tx, SkScalar ty)=0
virtual void scale(SkScalar sx, SkScalar sy)=0
virtual void setImageFilter(const DlImageFilter *filter)=0
virtual void setColorSource(const DlColorSource *source)=0
virtual void rotate(SkScalar degrees)=0
virtual void drawPaint()=0
virtual bool PrefersImpellerPaths() const
virtual void setDrawStyle(DlDrawStyle style)=0
virtual void drawTextBlob(const sk_sp< SkTextBlob > blob, SkScalar x, SkScalar y)=0
virtual void setBlendMode(DlBlendMode mode)=0
virtual void transformFullPerspective(SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt, SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt, SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt, SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt)=0
virtual void setColor(DlColor color)=0
Holds all of the data (both required and optional) for a DisplayList drawVertices call.
Definition dl_vertices.h:71
#define DEFINE_DRAW_IMAGE_NINE_OP(name, render_with_attributes)
#define DEFINE_SET_BOOL_OP(name)
#define DEFINE_DRAW_IMAGE_OP(name, with_attributes)
#define DEFINE_DRAW_SHADOW_OP(name, transparent_occluder)
#define DEFINE_DRAW_2ARG_OP(op_name, type1, name1, type2, name2)
#define DEFINE_DRAW_POINTS_OP(name, mode)
#define DEFINE_CLIP_SHAPE_OP(shapetype, clipop)
#define DEFINE_CLIP_PATH_OP(clipop)
#define DEFINE_SET_CLEAR_DLATTR_OP(name, sk_name, field)
#define DEFINE_DRAW_1ARG_OP(op_name, arg_type, arg_name)
#define DEFINE_SET_ENUM_OP(name)
sk_sp< SkImage > image
Definition examples.cpp:29
SkBitmap source
Definition examples.cpp:28
float SkScalar
Definition extension.cpp:12
static const SkPoint kPoints[kNumLabels]
Definition flippity.cpp:53
bool Equals(const T *a, const T *b)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57
DlDrawStyle
Definition dl_paint.h:20
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition switches.h:228
static constexpr uint32_t kRenderOpInc
DisplayListCompare equals(const DLOp *other) const
DisplayListOpType type
static constexpr uint32_t kDepthInc
SaveInfo(int previous_restore_index, bool save_was_needed)
std::vector< SaveInfo > save_infos
DrawArcOp(SkRect bounds, SkScalar start, SkScalar sweep, bool center)
const SkRect bounds
static constexpr auto kType
const SkScalar start
const SkScalar sweep
void dispatch(DispatchContext &ctx) const
const sk_sp< DlImage > atlas
DrawAtlasBaseOp(const sk_sp< DlImage > &atlas, int count, DlBlendMode mode, DlImageSampling sampling, bool has_colors, bool render_with_attributes)
bool equals(const DrawAtlasBaseOp *other, const void *pod_this, const void *pod_other) const
const uint8_t render_with_attributes
const DlImageSampling sampling
DisplayListCompare equals(const DrawAtlasCulledOp *other) const
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
DrawAtlasCulledOp(const sk_sp< DlImage > &atlas, int count, DlBlendMode mode, DlImageSampling sampling, bool has_colors, const SkRect &cull_rect, bool render_with_attributes)
void dispatch(DispatchContext &ctx) const
static constexpr auto kType
DisplayListCompare equals(const DrawAtlasOp *other) const
DrawAtlasOp(const sk_sp< DlImage > &atlas, int count, DlBlendMode mode, DlImageSampling sampling, bool has_colors, bool render_with_attributes)
DrawColorOp(DlColor color, DlBlendMode mode)
const DlBlendMode mode
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
DisplayListCompare equals(const DrawDisplayListOp *other) const
static constexpr auto kType
const sk_sp< DisplayList > display_list
DrawDisplayListOp(const sk_sp< DisplayList > &display_list, SkScalar opacity)
void dispatch(DispatchContext &ctx) const
const sk_sp< DlImage > image
static constexpr auto kType
const DlImageSampling sampling
DrawImageRectOp(const sk_sp< DlImage > &image, const SkRect &src, const SkRect &dst, DlImageSampling sampling, bool render_with_attributes, DlCanvas::SrcRectConstraint constraint)
const DlCanvas::SrcRectConstraint constraint
void dispatch(DispatchContext &ctx) const
DisplayListCompare equals(const DrawImageRectOp *other) const
static constexpr uint32_t kRenderOpInc
bool op_needed(const DispatchContext &ctx) const
static constexpr uint32_t kDepthInc
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
DisplayListCompare equals(const DrawPathOp *other) const
DrawPathOp(const SkPath &path)
static constexpr auto kType
const DlOpReceiver::CacheablePath cached_path
void dispatch(DispatchContext &ctx) const
void dispatch(DispatchContext &ctx) const
static constexpr auto kType
DrawTextBlobOp(const sk_sp< SkTextBlob > &blob, SkScalar x, SkScalar y)
const sk_sp< SkTextBlob > blob
const std::shared_ptr< impeller::TextFrame > text_frame
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
DrawTextFrameOp(const std::shared_ptr< impeller::TextFrame > &text_frame, SkScalar x, SkScalar y)
static constexpr auto kType
const DlBlendMode mode
DrawVerticesOp(DlBlendMode mode)
void dispatch(DispatchContext &ctx) const
void dispatch(DispatchContext &ctx) const
static constexpr auto kType
static constexpr uint32_t kRenderOpInc
static constexpr uint32_t kDepthInc
void dispatch(DispatchContext &ctx) const
RotateOp(SkScalar degrees)
static constexpr auto kType
const SkScalar degrees
DisplayListCompare equals(const SaveLayerBackdropOp *other) const
static constexpr auto kType
const std::shared_ptr< DlImageFilter > backdrop
SaveLayerBackdropOp(const SaveLayerOptions &options, const SkRect &rect, const DlImageFilter *backdrop)
void dispatch(DispatchContext &ctx) const
SaveLayerOpBase(const SaveLayerOptions &options, const SkRect &rect)
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
SaveLayerOp(const SaveLayerOptions &options, const SkRect &rect)
static constexpr uint32_t kRenderOpInc
bool save_needed(DispatchContext &ctx) const
static constexpr uint32_t kDepthInc
SaveOpBase(const SaveLayerOptions &options)
SaveLayerOptions options
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
static constexpr auto kType
const SkScalar sy
const SkScalar sx
ScaleOp(SkScalar sx, SkScalar sy)
void dispatch(DispatchContext &ctx) const
const DlBlendMode mode
static constexpr auto kType
SetBlendModeOp(DlBlendMode mode)
void dispatch(DispatchContext &ctx) const
const DlColor color
static constexpr auto kType
SetColorOp(DlColor color)
void dispatch(DispatchContext &ctx) const
SetImageColorSourceOp(const DlImageColorSource *source)
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
const DlImageColorSource source
SetRuntimeEffectColorSourceOp(const DlRuntimeEffectColorSource *source)
void dispatch(DispatchContext &ctx) const
const DlRuntimeEffectColorSource source
DisplayListCompare equals(const SetRuntimeEffectColorSourceOp *other) const
SetSharedImageFilterOp(const DlImageFilter *filter)
DisplayListCompare equals(const SetSharedImageFilterOp *other) const
const std::shared_ptr< DlImageFilter > filter
void dispatch(DispatchContext &ctx) const
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
static constexpr auto kType
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
const DlDrawStyle style
void dispatch(DispatchContext &ctx) const
static constexpr auto kType
SetStyleOp(DlDrawStyle style)
SkewOp(SkScalar sx, SkScalar sy)
static constexpr auto kType
const SkScalar sy
void dispatch(DispatchContext &ctx) const
const SkScalar sx
void dispatch(DispatchContext &ctx) const
Transform2DAffineOp(SkScalar mxx, SkScalar mxy, SkScalar mxt, SkScalar myx, SkScalar myy, SkScalar myt)
static constexpr auto kType
bool op_needed(const DispatchContext &context) const
static constexpr uint32_t kDepthInc
static constexpr uint32_t kRenderOpInc
void dispatch(DispatchContext &ctx) const
TransformFullPerspectiveOp(SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt, SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt, SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt, SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt)
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
TranslateOp(SkScalar tx, SkScalar ty)