Flutter Engine
The Flutter Engine
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.
44
47
49
50 struct SaveInfo {
54
57 };
58
59 std::vector<SaveInfo> save_infos;
60};
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 };
231DEFINE_SET_CLEAR_DLATTR_OP(ImageFilter, ImageFilter, filter)
232DEFINE_SET_CLEAR_DLATTR_OP(MaskFilter, MaskFilter, filter)
233DEFINE_SET_CLEAR_DLATTR_OP(ColorSource, Shader, source)
234#undef DEFINE_SET_CLEAR_DLATTR_OP
235
236// 4 byte header + 80 bytes for the embedded DlImageColorSource
237// uses 84 total bytes (4 bytes unused)
239 static constexpr auto kType = DisplayListOpType::kSetImageColorSource;
240
242 : source(source->image(),
243 source->horizontal_tile_mode(),
244 source->vertical_tile_mode(),
245 source->sampling(),
246 source->matrix_ptr()) {}
247
249
250 void dispatch(DispatchContext& ctx) const {
252 }
253};
254
255// 56 bytes: 4 byte header, 4 byte padding, 8 for vtable, 8 * 2 for sk_sps, 24
256// for the std::vector.
258 static constexpr auto kType = DisplayListOpType::kSetRuntimeEffectColorSource;
259
262 : source(source->runtime_effect(),
263 source->samplers(),
264 source->uniform_data()) {}
265
267
268 void dispatch(DispatchContext& ctx) const {
270 }
271
273 return (source == other->source) ? DisplayListCompare::kEqual
275 }
276};
277
278#ifdef IMPELLER_ENABLE_3D
279struct SetSceneColorSourceOp : DLOp {
280 static constexpr auto kType = DisplayListOpType::kSetSceneColorSource;
281
282 explicit SetSceneColorSourceOp(const DlSceneColorSource* source)
283 : source(source->scene_node(), source->camera_matrix()) {}
284
285 const DlSceneColorSource source;
286
287 void dispatch(DispatchContext& ctx) const {
288 ctx.receiver.setColorSource(&source);
289 }
290
291 DisplayListCompare equals(const SetSceneColorSourceOp* other) const {
292 return (source == other->source) ? DisplayListCompare::kEqual
294 }
295};
296#endif // IMPELLER_ENABLE_3D
297
298// 4 byte header + 16 byte payload uses 24 total bytes (4 bytes unused)
300 static constexpr auto kType = DisplayListOpType::kSetSharedImageFilter;
301
303 : filter(filter->shared()) {}
304
305 const std::shared_ptr<DlImageFilter> filter;
306
307 void dispatch(DispatchContext& ctx) const {
308 ctx.receiver.setImageFilter(filter.get());
309 }
310
314 }
315};
316
317// The base struct for all save() and saveLayer() ops
318// 4 byte header + 12 byte payload packs exactly into 16 bytes
319struct SaveOpBase : DLOp {
320 static constexpr uint32_t kDepthInc = 0;
321 static constexpr uint32_t kRenderOpInc = 1;
322
324
327
328 // options parameter is only used by saveLayer operations, but since
329 // it packs neatly into the empty space created by laying out the rest
330 // of the data here, it can be stored for free and defaulted to 0 for
331 // 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 + 20 byte payload packs into 36 bytes
360
363};
364// 36 byte SaveLayerOpBase with no additional data packs into 40 bytes
365// of buffer storage with 4 bytes unused.
367 static constexpr auto kType = DisplayListOpType::kSaveLayer;
368
371
372 void dispatch(DispatchContext& ctx) const {
373 if (save_needed(ctx)) {
376 }
377 }
378};
379// 36 byte SaveLayerOpBase + 4 bytes for alignment + 16 byte payload packs
380// into minimum 56 bytes
382 static constexpr auto kType = DisplayListOpType::kSaveLayerBackdrop;
383
385 const SkRect& rect,
386 const DlImageFilter* backdrop)
387 : SaveLayerOpBase(options, rect), backdrop(backdrop->shared()) {}
388
389 const std::shared_ptr<DlImageFilter> backdrop;
390
391 void dispatch(DispatchContext& ctx) const {
392 if (save_needed(ctx)) {
394 backdrop.get());
395 }
396 }
397
399 return (options == other->options && rect == other->rect &&
400 Equals(backdrop, other->backdrop))
403 }
404};
405// 4 byte header + no payload uses minimum 8 bytes (4 bytes unused)
406struct RestoreOp final : DLOp {
407 static constexpr auto kType = DisplayListOpType::kRestore;
408 static constexpr uint32_t kDepthInc = 0;
409 static constexpr uint32_t kRenderOpInc = 1;
410
412
413 void dispatch(DispatchContext& ctx) const {
415 if (info.save_was_needed) {
416 ctx.receiver.restore();
417 }
418 ctx.next_restore_index = info.previous_restore_index;
419 ctx.save_infos.pop_back();
420 }
421};
422
424 static constexpr uint32_t kDepthInc = 0;
425 static constexpr uint32_t kRenderOpInc = 1;
426
427 inline bool op_needed(const DispatchContext& context) const {
428 return context.next_render_index <= context.next_restore_index;
429 }
430};
431// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
432// (4 bytes unused)
434 static constexpr auto kType = DisplayListOpType::kTranslate;
435
437
440
441 void dispatch(DispatchContext& ctx) const {
442 if (op_needed(ctx)) {
443 ctx.receiver.translate(tx, ty);
444 }
445 }
446};
447// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
448// (4 bytes unused)
450 static constexpr auto kType = DisplayListOpType::kScale;
451
453
456
457 void dispatch(DispatchContext& ctx) const {
458 if (op_needed(ctx)) {
459 ctx.receiver.scale(sx, sy);
460 }
461 }
462};
463// 4 byte header + 4 byte payload packs into minimum 8 bytes
465 static constexpr auto kType = DisplayListOpType::kRotate;
466
468
470
471 void dispatch(DispatchContext& ctx) const {
472 if (op_needed(ctx)) {
474 }
475 }
476};
477// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
478// (4 bytes unused)
480 static constexpr auto kType = DisplayListOpType::kSkew;
481
483
486
487 void dispatch(DispatchContext& ctx) const {
488 if (op_needed(ctx)) {
489 ctx.receiver.skew(sx, sy);
490 }
491 }
492};
493// 4 byte header + 24 byte payload uses 28 bytes but is rounded up to 32 bytes
494// (4 bytes unused)
496 static constexpr auto kType = DisplayListOpType::kTransform2DAffine;
497
498 // clang-format off
501 : mxx(mxx), mxy(mxy), mxt(mxt), myx(myx), myy(myy), myt(myt) {}
502 // clang-format on
503
506
507 void dispatch(DispatchContext& ctx) const {
508 if (op_needed(ctx)) {
510 myx, myy, myt);
511 }
512 }
513};
514// 4 byte header + 64 byte payload uses 68 bytes which is rounded up to 72 bytes
515// (4 bytes unused)
517 static constexpr auto kType = DisplayListOpType::kTransformFullPerspective;
518
519 // clang-format off
525 : mxx(mxx), mxy(mxy), mxz(mxz), mxt(mxt),
526 myx(myx), myy(myy), myz(myz), myt(myt),
527 mzx(mzx), mzy(mzy), mzz(mzz), mzt(mzt),
528 mwx(mwx), mwy(mwy), mwz(mwz), mwt(mwt) {}
529 // clang-format on
530
535
536 void dispatch(DispatchContext& ctx) const {
537 if (op_needed(ctx)) {
539 myx, myy, myz, myt, //
540 mzx, mzy, mzz, mzt, //
541 mwx, mwy, mwz, mwt);
542 }
543 }
544};
545
546// 4 byte header with no payload.
548 static constexpr auto kType = DisplayListOpType::kTransformReset;
549
550 TransformResetOp() = default;
551
552 void dispatch(DispatchContext& ctx) const {
553 if (op_needed(ctx)) {
555 }
556 }
557};
558
559// 4 byte header + 4 byte common payload packs into minimum 8 bytes
560// SkRect is 16 more bytes, which packs efficiently into 24 bytes total
561// SkRRect is 52 more bytes, which rounds up to 56 bytes (4 bytes unused)
562// which packs into 64 bytes total
563// CacheablePath is 128 more bytes, which packs efficiently into 136 bytes total
564//
565// We could pack the clip_op and the bool both into the free 4 bytes after
566// the header, but the Windows compiler keeps wanting to expand that
567// packing into more bytes than needed (even when they are declared as
568// packed bit fields!)
569#define DEFINE_CLIP_SHAPE_OP(shapetype, clipop) \
570 struct Clip##clipop##shapetype##Op final : TransformClipOpBase { \
571 static constexpr auto kType = DisplayListOpType::kClip##clipop##shapetype; \
572 \
573 Clip##clipop##shapetype##Op(Sk##shapetype shape, bool is_aa) \
574 : is_aa(is_aa), shape(shape) {} \
575 \
576 const bool is_aa; \
577 const Sk##shapetype shape; \
578 \
579 void dispatch(DispatchContext& ctx) const { \
580 if (op_needed(ctx)) { \
581 ctx.receiver.clip##shapetype(shape, DlCanvas::ClipOp::k##clipop, \
582 is_aa); \
583 } \
584 } \
585 };
586DEFINE_CLIP_SHAPE_OP(Rect, Intersect)
587DEFINE_CLIP_SHAPE_OP(RRect, Intersect)
588DEFINE_CLIP_SHAPE_OP(Rect, Difference)
589DEFINE_CLIP_SHAPE_OP(RRect, Difference)
590#undef DEFINE_CLIP_SHAPE_OP
591
592#define DEFINE_CLIP_PATH_OP(clipop) \
593 struct Clip##clipop##PathOp final : TransformClipOpBase { \
594 static constexpr auto kType = DisplayListOpType::kClip##clipop##Path; \
595 \
596 Clip##clipop##PathOp(const SkPath& path, bool is_aa) \
597 : is_aa(is_aa), cached_path(path) {} \
598 \
599 const bool is_aa; \
600 const DlOpReceiver::CacheablePath cached_path; \
601 \
602 void dispatch(DispatchContext& ctx) const { \
603 if (op_needed(ctx)) { \
604 if (ctx.receiver.PrefersImpellerPaths()) { \
605 ctx.receiver.clipPath(cached_path, DlCanvas::ClipOp::k##clipop, \
606 is_aa); \
607 } else { \
608 ctx.receiver.clipPath(cached_path.sk_path, \
609 DlCanvas::ClipOp::k##clipop, is_aa); \
610 } \
611 } \
612 } \
613 \
614 DisplayListCompare equals(const Clip##clipop##PathOp* other) const { \
615 return is_aa == other->is_aa && cached_path == other->cached_path \
616 ? DisplayListCompare::kEqual \
617 : DisplayListCompare::kNotEqual; \
618 } \
619 };
620DEFINE_CLIP_PATH_OP(Intersect)
621DEFINE_CLIP_PATH_OP(Difference)
622#undef DEFINE_CLIP_PATH_OP
623
624struct DrawOpBase : DLOp {
625 static constexpr uint32_t kDepthInc = 1;
626 static constexpr uint32_t kRenderOpInc = 1;
627
628 inline bool op_needed(const DispatchContext& ctx) const {
629 return ctx.cur_index >= ctx.next_render_index;
630 }
631};
632
633// 4 byte header + no payload uses minimum 8 bytes (4 bytes unused)
634struct DrawPaintOp final : DrawOpBase {
635 static constexpr auto kType = DisplayListOpType::kDrawPaint;
636
638
639 void dispatch(DispatchContext& ctx) const {
640 if (op_needed(ctx)) {
641 ctx.receiver.drawPaint();
642 }
643 }
644};
645// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
646// (4 bytes unused)
647struct DrawColorOp final : DrawOpBase {
648 static constexpr auto kType = DisplayListOpType::kDrawColor;
649
651
654
655 void dispatch(DispatchContext& ctx) const {
656 if (op_needed(ctx)) {
658 }
659 }
660};
661
662// The common data is a 4 byte header with an unused 4 bytes
663// SkRect is 16 more bytes, using 20 bytes which rounds up to 24 bytes total
664// (4 bytes unused)
665// SkOval is same as SkRect
666// SkRRect is 52 more bytes, which packs efficiently into 56 bytes total
667#define DEFINE_DRAW_1ARG_OP(op_name, arg_type, arg_name) \
668 struct Draw##op_name##Op final : DrawOpBase { \
669 static constexpr auto kType = DisplayListOpType::kDraw##op_name; \
670 \
671 explicit Draw##op_name##Op(arg_type arg_name) : arg_name(arg_name) {} \
672 \
673 const arg_type arg_name; \
674 \
675 void dispatch(DispatchContext& ctx) const { \
676 if (op_needed(ctx)) { \
677 ctx.receiver.draw##op_name(arg_name); \
678 } \
679 } \
680 };
684#undef DEFINE_DRAW_1ARG_OP
685
686// 4 byte header + 128 byte payload uses 132 bytes but is rounded
687// up to 136 bytes (4 bytes unused)
688struct DrawPathOp final : DrawOpBase {
689 static constexpr auto kType = DisplayListOpType::kDrawPath;
690
691 explicit DrawPathOp(const SkPath& path) : cached_path(path) {}
692
694
695 void dispatch(DispatchContext& ctx) const {
696 if (op_needed(ctx)) {
697 if (ctx.receiver.PrefersImpellerPaths()) {
699 } else {
701 }
702 }
703 }
704
708 }
709};
710
711// The common data is a 4 byte header with an unused 4 bytes
712// 2 x SkPoint is 16 more bytes, using 20 bytes rounding up to 24 bytes total
713// (4 bytes unused)
714// SkPoint + SkScalar is 12 more bytes, packing efficiently into 16 bytes total
715// 2 x SkRRect is 104 more bytes, using 108 and rounding up to 112 bytes total
716// (4 bytes unused)
717#define DEFINE_DRAW_2ARG_OP(op_name, type1, name1, type2, name2) \
718 struct Draw##op_name##Op final : DrawOpBase { \
719 static constexpr auto kType = DisplayListOpType::kDraw##op_name; \
720 \
721 Draw##op_name##Op(type1 name1, type2 name2) \
722 : name1(name1), name2(name2) {} \
723 \
724 const type1 name1; \
725 const type2 name2; \
726 \
727 void dispatch(DispatchContext& ctx) const { \
728 if (op_needed(ctx)) { \
729 ctx.receiver.draw##op_name(name1, name2); \
730 } \
731 } \
732 };
734DEFINE_DRAW_2ARG_OP(Circle, SkPoint, center, SkScalar, radius)
735DEFINE_DRAW_2ARG_OP(DRRect, SkRRect, outer, SkRRect, inner)
736#undef DEFINE_DRAW_2ARG_OP
737
738// 4 byte header + 24 byte payload packs into 32 bytes (4 bytes unused)
740 static constexpr auto kType = DisplayListOpType::kDrawDashedLine;
741
743 const DlPoint& p1,
747
748 const DlPoint p0;
749 const DlPoint p1;
752
753 void dispatch(DispatchContext& ctx) const {
754 if (op_needed(ctx)) {
756 }
757 }
758};
759
760// 4 byte header + 28 byte payload packs efficiently into 32 bytes
761struct DrawArcOp final : DrawOpBase {
762 static constexpr auto kType = DisplayListOpType::kDrawArc;
763
766
770 const bool center;
771
772 void dispatch(DispatchContext& ctx) const {
773 if (op_needed(ctx)) {
775 }
776 }
777};
778
779// 4 byte header + 4 byte fixed payload packs efficiently into 8 bytes
780// But then there is a list of points following the structure which
781// is guaranteed to be a multiple of 8 bytes (SkPoint is 8 bytes)
782// so this op will always pack efficiently
783// The point type is packed into 3 different OpTypes to avoid expanding
784// the fixed payload beyond the 8 bytes
785#define DEFINE_DRAW_POINTS_OP(name, mode) \
786 struct Draw##name##Op final : DrawOpBase { \
787 static constexpr auto kType = DisplayListOpType::kDraw##name; \
788 \
789 explicit Draw##name##Op(uint32_t count) : count(count) {} \
790 \
791 const uint32_t count; \
792 \
793 void dispatch(DispatchContext& ctx) const { \
794 if (op_needed(ctx)) { \
795 const SkPoint* pts = reinterpret_cast<const SkPoint*>(this + 1); \
796 ctx.receiver.drawPoints(DlCanvas::PointMode::mode, count, pts); \
797 } \
798 } \
799 };
800DEFINE_DRAW_POINTS_OP(Points, kPoints);
802DEFINE_DRAW_POINTS_OP(Polygon, kPolygon);
803#undef DEFINE_DRAW_POINTS_OP
804
805// 4 byte header + 4 byte payload packs efficiently into 8 bytes
806// The DlVertices object will be pod-allocated after this structure
807// and can take any number of bytes so the final efficiency will
808// depend on the size of the DlVertices.
809// Note that the DlVertices object ends with an array of 16-bit
810// indices so the alignment can be up to 6 bytes off leading to
811// up to 6 bytes of overhead
814
816
818
819 void dispatch(DispatchContext& ctx) const {
820 if (op_needed(ctx)) {
821 const DlVertices* vertices =
822 reinterpret_cast<const DlVertices*>(this + 1);
823 ctx.receiver.drawVertices(vertices, mode);
824 }
825 }
826};
827
828// 4 byte header + 40 byte payload uses 44 bytes but is rounded up to 48 bytes
829// (4 bytes unused)
830#define DEFINE_DRAW_IMAGE_OP(name, with_attributes) \
831 struct name##Op final : DrawOpBase { \
832 static constexpr auto kType = DisplayListOpType::k##name; \
833 \
834 name##Op(const sk_sp<DlImage>& image, \
835 const SkPoint& point, \
836 DlImageSampling sampling) \
837 : point(point), sampling(sampling), image(std::move(image)) {} \
838 \
839 const SkPoint point; \
840 const DlImageSampling sampling; \
841 const sk_sp<DlImage> image; \
842 \
843 void dispatch(DispatchContext& ctx) const { \
844 if (op_needed(ctx)) { \
845 ctx.receiver.drawImage(image, point, sampling, with_attributes); \
846 } \
847 } \
848 \
849 DisplayListCompare equals(const name##Op* other) const { \
850 return (point == other->point && sampling == other->sampling && \
851 image->Equals(other->image)) \
852 ? DisplayListCompare::kEqual \
853 : DisplayListCompare::kNotEqual; \
854 } \
855 };
857DEFINE_DRAW_IMAGE_OP(DrawImageWithAttr, true)
858#undef DEFINE_DRAW_IMAGE_OP
859
860// 4 byte header + 72 byte payload uses 76 bytes but is rounded up to 80 bytes
861// (4 bytes unused)
863 static constexpr auto kType = DisplayListOpType::kDrawImageRect;
864
866 const SkRect& src,
867 const SkRect& dst,
871 : src(src),
872 dst(dst),
876 image(image) {}
877
878 const SkRect src;
879 const SkRect dst;
884
885 void dispatch(DispatchContext& ctx) const {
886 if (op_needed(ctx)) {
889 }
890 }
891
893 return (src == other->src && dst == other->dst &&
894 sampling == other->sampling &&
896 constraint == other->constraint && image->Equals(other->image))
899 }
900};
901
902// 4 byte header + 44 byte payload packs efficiently into 48 bytes
903#define DEFINE_DRAW_IMAGE_NINE_OP(name, render_with_attributes) \
904 struct name##Op final : DrawOpBase { \
905 static constexpr auto kType = DisplayListOpType::k##name; \
906 \
907 name##Op(const sk_sp<DlImage>& image, \
908 const SkIRect& center, \
909 const SkRect& dst, \
910 DlFilterMode mode) \
911 : center(center), dst(dst), mode(mode), image(std::move(image)) {} \
912 \
913 const SkIRect center; \
914 const SkRect dst; \
915 const DlFilterMode mode; \
916 const sk_sp<DlImage> image; \
917 \
918 void dispatch(DispatchContext& ctx) const { \
919 if (op_needed(ctx)) { \
920 ctx.receiver.drawImageNine(image, center, dst, mode, \
921 render_with_attributes); \
922 } \
923 } \
924 \
925 DisplayListCompare equals(const name##Op* other) const { \
926 return (center == other->center && dst == other->dst && \
927 mode == other->mode && image->Equals(other->image)) \
928 ? DisplayListCompare::kEqual \
929 : DisplayListCompare::kNotEqual; \
930 } \
931 };
932DEFINE_DRAW_IMAGE_NINE_OP(DrawImageNine, false)
933DEFINE_DRAW_IMAGE_NINE_OP(DrawImageNineWithAttr, true)
934#undef DEFINE_DRAW_IMAGE_NINE_OP
935
936// 4 byte header + 40 byte payload uses 44 bytes but is rounded up to 48 bytes
937// (4 bytes unused)
938// Each of these is then followed by a number of lists.
939// SkRSXform list is a multiple of 16 bytes so it is always packed well
940// SkRect list is also a multiple of 16 bytes so it also packs well
941// DlColor list only packs well if the count is even, otherwise there
942// can be 4 unusued bytes at the end.
945 int count,
948 bool has_colors,
950 : count(count),
951 mode_index(static_cast<uint16_t>(mode)),
955 atlas(atlas) {}
956
957 const int count;
958 const uint16_t mode_index;
959 const uint8_t has_colors;
963
964 bool equals(const DrawAtlasBaseOp* other,
965 const void* pod_this,
966 const void* pod_other) const {
967 bool ret = (count == other->count && mode_index == other->mode_index &&
968 has_colors == other->has_colors &&
970 sampling == other->sampling && atlas->Equals(other->atlas));
971 if (ret) {
972 size_t bytes = count * (sizeof(SkRSXform) + sizeof(SkRect));
973 if (has_colors) {
974 bytes += count * sizeof(DlColor);
975 }
976 ret = (memcmp(pod_this, pod_other, bytes) == 0);
977 }
978 return ret;
979 }
980};
981
982// Packs into 48 bytes as per DrawAtlasBaseOp
983// with array data following the struct also as per DrawAtlasBaseOp
985 static constexpr auto kType = DisplayListOpType::kDrawAtlas;
986
988 int count,
991 bool has_colors,
994 count,
995 mode,
996 sampling,
999
1000 void dispatch(DispatchContext& ctx) const {
1001 if (op_needed(ctx)) {
1002 const SkRSXform* xform = reinterpret_cast<const SkRSXform*>(this + 1);
1003 const SkRect* tex = reinterpret_cast<const SkRect*>(xform + count);
1004 const DlColor* colors =
1005 has_colors ? reinterpret_cast<const DlColor*>(tex + count) : nullptr;
1006 const DlBlendMode mode = static_cast<DlBlendMode>(mode_index);
1007 ctx.receiver.drawAtlas(atlas, xform, tex, colors, count, mode, sampling,
1008 nullptr, render_with_attributes);
1009 }
1010 }
1011
1013 const void* pod_this = reinterpret_cast<const void*>(this + 1);
1014 const void* pod_other = reinterpret_cast<const void*>(other + 1);
1015 return (DrawAtlasBaseOp::equals(other, pod_this, pod_other))
1018 }
1019};
1020
1021// Packs into 48 bytes as per DrawAtlasBaseOp plus
1022// an additional 16 bytes for the cull rect resulting in a total
1023// of 56 bytes for the Culled drawAtlas.
1024// Also with array data following the struct as per DrawAtlasBaseOp
1026 static constexpr auto kType = DisplayListOpType::kDrawAtlasCulled;
1027
1029 int count,
1032 bool has_colors,
1033 const SkRect& cull_rect,
1036 count,
1037 mode,
1038 sampling,
1039 has_colors,
1042
1044
1045 void dispatch(DispatchContext& ctx) const {
1046 if (op_needed(ctx)) {
1047 const SkRSXform* xform = reinterpret_cast<const SkRSXform*>(this + 1);
1048 const SkRect* tex = reinterpret_cast<const SkRect*>(xform + count);
1049 const DlColor* colors =
1050 has_colors ? reinterpret_cast<const DlColor*>(tex + count) : nullptr;
1051 const DlBlendMode mode = static_cast<DlBlendMode>(mode_index);
1052 ctx.receiver.drawAtlas(atlas, xform, tex, colors, count, mode, sampling,
1054 }
1055 }
1056
1058 const void* pod_this = reinterpret_cast<const void*>(this + 1);
1059 const void* pod_other = reinterpret_cast<const void*>(other + 1);
1060 return (cull_rect == other->cull_rect &&
1061 DrawAtlasBaseOp::equals(other, pod_this, pod_other))
1064 }
1065};
1066
1067// 4 byte header + ptr aligned payload uses 12 bytes round up to 16
1068// (4 bytes unused)
1070 static constexpr auto kType = DisplayListOpType::kDrawDisplayList;
1071
1075
1078
1079 void dispatch(DispatchContext& ctx) const {
1080 if (op_needed(ctx)) {
1082 }
1083 }
1084
1086 return (opacity == other->opacity &&
1087 display_list->Equals(other->display_list))
1090 }
1091};
1092
1093// 4 byte header + 8 payload bytes + an aligned pointer take 24 bytes
1094// (4 unused to align the pointer)
1096 static constexpr auto kType = DisplayListOpType::kDrawTextBlob;
1097
1099 : x(x), y(y), blob(blob) {}
1100
1104
1105 void dispatch(DispatchContext& ctx) const {
1106 if (op_needed(ctx)) {
1107 ctx.receiver.drawTextBlob(blob, x, y);
1108 }
1109 }
1110};
1111
1113 static constexpr auto kType = DisplayListOpType::kDrawTextFrame;
1114
1115 DrawTextFrameOp(const std::shared_ptr<impeller::TextFrame>& text_frame,
1116 SkScalar x,
1117 SkScalar y)
1118 : x(x), y(y), text_frame(text_frame) {}
1119
1122 const std::shared_ptr<impeller::TextFrame> text_frame;
1123
1124 void dispatch(DispatchContext& ctx) const {
1125 if (op_needed(ctx)) {
1127 }
1128 }
1129};
1130
1131// 4 byte header + 140 byte payload packs evenly into 140 bytes
1132#define DEFINE_DRAW_SHADOW_OP(name, transparent_occluder) \
1133 struct Draw##name##Op final : DrawOpBase { \
1134 static constexpr auto kType = DisplayListOpType::kDraw##name; \
1135 \
1136 Draw##name##Op(const SkPath& path, \
1137 DlColor color, \
1138 SkScalar elevation, \
1139 SkScalar dpr) \
1140 : color(color), elevation(elevation), dpr(dpr), cached_path(path) {} \
1141 \
1142 const DlColor color; \
1143 const SkScalar elevation; \
1144 const SkScalar dpr; \
1145 const DlOpReceiver::CacheablePath cached_path; \
1146 \
1147 void dispatch(DispatchContext& ctx) const { \
1148 if (op_needed(ctx)) { \
1149 if (ctx.receiver.PrefersImpellerPaths()) { \
1150 ctx.receiver.drawShadow(cached_path, color, elevation, \
1151 transparent_occluder, dpr); \
1152 } else { \
1153 ctx.receiver.drawShadow(cached_path.sk_path, color, elevation, \
1154 transparent_occluder, dpr); \
1155 } \
1156 } \
1157 } \
1158 \
1159 DisplayListCompare equals(const Draw##name##Op* other) const { \
1160 return color == other->color && elevation == other->elevation && \
1161 dpr == other->dpr && cached_path == other->cached_path \
1162 ? DisplayListCompare::kEqual \
1163 : DisplayListCompare::kNotEqual; \
1164 } \
1165 };
1166DEFINE_DRAW_SHADOW_OP(Shadow, false)
1167DEFINE_DRAW_SHADOW_OP(ShadowTransparentOccluder, true)
1168#undef DEFINE_DRAW_SHADOW_OP
1169
1170#pragma pack(pop, DLOpPackLabel)
1171
1172} // namespace flutter
1173
1174#endif // FLUTTER_DISPLAY_LIST_DL_OP_RECORDS_H_
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
bool equals(SkDrawable *a, SkDrawable *b)
Definition: SkPath.h:59
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 drawDashedLine(const DlPoint &p0, const DlPoint &p1, DlScalar on_length, DlScalar off_length)=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_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)
SkBitmap source
Definition: examples.cpp:28
float SkScalar
Definition: extension.cpp:12
sk_sp< const SkImage > image
Definition: SkRecords.h:269
SkRRect rrect
Definition: SkRecords.h:232
SkRect oval
Definition: SkRecords.h:249
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
PODArray< SkColor > colors
Definition: SkRecords.h:276
SkSamplingOptions sampling
Definition: SkRecords.h:337
void DrawImage(SkCanvas *canvas, const SkImage *image, SkScalar x, SkScalar y, const SkSamplingOptions &sampling={}, const SkPaint *paint=nullptr, SkCanvas::SrcRectConstraint constraint=SkCanvas::kFast_SrcRectConstraint)
impeller::Scalar DlScalar
bool Equals(const T *a, const T *b)
Definition: dl_comparable.h:19
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
DEFINE_DRAW_POINTS_OP(Points, kPoints)
DlDrawStyle
Definition: dl_paint.h:19
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
DisplayListCompare
Definition: dl_op_records.h:72
Join
Definition: path.h:24
TRect< Scalar > Rect
Definition: rect.h:769
Cap
Definition: path.h:18
SK_API sk_sp< PrecompileShader > ColorFilter(SkSpan< const sk_sp< PrecompileShader > > shaders, SkSpan< const sk_sp< PrecompileColorFilter > > colorFilters)
flutter::DlColor DlColor
static constexpr uint32_t kRenderOpInc
DisplayListCompare equals(const DLOp *other) const
DisplayListOpType type
static constexpr uint32_t kDepthInc
Definition: dl_op_records.h:99
SaveInfo(int previous_restore_index, bool save_was_needed)
Definition: dl_op_records.h:51
DlOpReceiver & receiver
Definition: dl_op_records.h:43
std::vector< SaveInfo > save_infos
Definition: dl_op_records.h:59
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
const uint16_t mode_index
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 DlColor color
const DlBlendMode mode
static constexpr auto kType
void dispatch(DispatchContext &ctx) const
DrawDashedLineOp(const DlPoint &p0, const DlPoint &p1, DlScalar on_length, DlScalar off_length)
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 bool render_with_attributes
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)
uint32_t total_content_depth
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
const SkScalar ty
TranslateOp(SkScalar tx, SkScalar ty)
const SkScalar tx