Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
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
15#include "flutter/fml/macros.h"
16
17// NOLINTBEGIN(clang-analyzer-core.CallAndMessage)
18
19namespace flutter {
20
21// Most Ops can be bulk compared using memcmp because they contain
22// only numeric values or constructs that are constructed from numeric
23// values.
24//
25// Some contain sk_sp<> references which can also be bulk compared
26// to see if they are pointing to the same reference. (Note that
27// two sk_sp<> that refer to the same object are themselves ==.)
28//
29// Only a DLOp that wants to do a deep compare needs to override the
30// DLOp::equals() method and return a value of kEqual or kNotEqual.
32 // The Op is deferring comparisons to a bulk memcmp performed lazily
33 // across all bulk-comparable ops.
35
36 // The Op provided a specific equals method that spotted a difference
38
39 // The Op provided a specific equals method that saw no differences
40 kEqual,
41};
42
43// "DLOpPackLabel" is just a label for the pack pragma so it can be popped
44// later.
45#pragma pack(push, DLOpPackLabel, 8)
46
47// Assuming a 64-bit platform (most of our platforms at this time?)
48// the following comments are a "worst case" assessment of how well
49// these structures pack into memory. They may be packed more tightly
50// on some of the 32-bit platforms that we see in older phones.
51//
52// Struct allocation in the DL memory is aligned to a void* boundary
53// which means that the minimum (aligned) struct size will be 8 bytes.
54// The DLOp base uses 4 bytes so each Op-specific struct gets 4 bytes
55// of data for "free" and works best when it packs well into an 8-byte
56// aligned size.
57struct DLOp {
58 static constexpr uint32_t kDepthInc = 0;
59 static constexpr uint32_t kRenderOpInc = 0;
60
62
64
68};
69
70// 4 byte header + 4 byte payload packs into minimum 8 bytes
71#define DEFINE_SET_BOOL_OP(name) \
72 struct Set##name##Op final : DLOp { \
73 static constexpr auto kType = DisplayListOpType::kSet##name; \
74 \
75 explicit Set##name##Op(bool value) : DLOp(kType), value(value) {} \
76 \
77 const bool value; \
78 \
79 void dispatch(DlOpReceiver& receiver) const { receiver.set##name(value); } \
80 };
81DEFINE_SET_BOOL_OP(AntiAlias)
82DEFINE_SET_BOOL_OP(InvertColors)
83#undef DEFINE_SET_BOOL_OP
84
85// 4 byte header + 4 byte payload packs into minimum 8 bytes
86#define DEFINE_SET_ENUM_OP(name) \
87 struct SetStroke##name##Op final : DLOp { \
88 static constexpr auto kType = DisplayListOpType::kSetStroke##name; \
89 \
90 explicit SetStroke##name##Op(DlStroke##name value) \
91 : DLOp(kType), value(value) {} \
92 \
93 const DlStroke##name value; \
94 \
95 void dispatch(DlOpReceiver& receiver) const { \
96 receiver.setStroke##name(value); \
97 } \
98 };
101#undef DEFINE_SET_ENUM_OP
102
103// 4 byte header + 4 byte payload packs into minimum 8 bytes
104struct SetStyleOp final : DLOp {
105 static constexpr auto kType = DisplayListOpType::kSetStyle;
106
108
110
111 void dispatch(DlOpReceiver& receiver) const { //
112 receiver.setDrawStyle(style);
113 }
114};
115// 4 byte header + 4 byte payload packs into minimum 8 bytes
116struct SetStrokeWidthOp final : DLOp {
117 static constexpr auto kType = DisplayListOpType::kSetStrokeWidth;
118
119 explicit SetStrokeWidthOp(float width) : DLOp(kType), width(width) {}
120
121 const float width;
122
123 void dispatch(DlOpReceiver& receiver) const {
124 receiver.setStrokeWidth(width);
125 }
126};
127// 4 byte header + 4 byte payload packs into minimum 8 bytes
128struct SetStrokeMiterOp final : DLOp {
129 static constexpr auto kType = DisplayListOpType::kSetStrokeMiter;
130
131 explicit SetStrokeMiterOp(float limit) : DLOp(kType), limit(limit) {}
132
133 const float limit;
134
135 void dispatch(DlOpReceiver& receiver) const {
136 receiver.setStrokeMiter(limit);
137 }
138};
139
140// 4 byte header + 20 byte payload packs into minimum 24 bytes
141struct SetColorOp final : DLOp {
142 static constexpr auto kType = DisplayListOpType::kSetColor;
143
145
147
148 void dispatch(DlOpReceiver& receiver) const { receiver.setColor(color); }
149};
150// 4 byte header + 4 byte payload packs into minimum 8 bytes
151struct SetBlendModeOp final : DLOp {
152 static constexpr auto kType = DisplayListOpType::kSetBlendMode;
153
155
157
158 void dispatch(DlOpReceiver& receiver) const { //
159 receiver.setBlendMode(mode);
160 }
161};
162
163// Clear: 4 byte header + unused 4 byte payload uses 8 bytes
164// (4 bytes unused)
165// Set: 4 byte header + unused 4 byte struct padding + Dl<name>
166// instance copied to the memory following the record
167// yields a size and efficiency that has somewhere between
168// 4 and 8 bytes unused
169#define DEFINE_SET_CLEAR_DLATTR_OP(name, field) \
170 struct Clear##name##Op final : DLOp { \
171 static constexpr auto kType = DisplayListOpType::kClear##name; \
172 \
173 Clear##name##Op() : DLOp(kType) {} \
174 \
175 void dispatch(DlOpReceiver& receiver) const { \
176 receiver.set##name(nullptr); \
177 } \
178 }; \
179 struct SetPod##name##Op final : DLOp { \
180 static constexpr auto kType = DisplayListOpType::kSetPod##name; \
181 \
182 SetPod##name##Op() : DLOp(kType) {} \
183 \
184 void dispatch(DlOpReceiver& receiver) const { \
185 const Dl##name* filter = reinterpret_cast<const Dl##name*>(this + 1); \
186 receiver.set##name(filter); \
187 } \
188 };
189DEFINE_SET_CLEAR_DLATTR_OP(ColorFilter, filter)
190DEFINE_SET_CLEAR_DLATTR_OP(ImageFilter, filter)
191DEFINE_SET_CLEAR_DLATTR_OP(MaskFilter, filter)
192DEFINE_SET_CLEAR_DLATTR_OP(ColorSource, source)
193#undef DEFINE_SET_CLEAR_DLATTR_OP
194
195// 4 byte header + 96 bytes for the embedded DlImageColorSource
196// uses 104 total bytes (4 bytes unused)
198 static constexpr auto kType = DisplayListOpType::kSetImageColorSource;
199
201 : DLOp(kType),
203 source->horizontal_tile_mode(),
204 source->vertical_tile_mode(),
205 source->sampling(),
206 source->matrix_ptr()) {}
207
209
210 void dispatch(DlOpReceiver& receiver) const {
211 receiver.setColorSource(&source);
212 }
213};
214
215// 56 bytes: 4 byte header, 4 byte padding, 8 for vtable, 8 * 2 for sk_sps, 24
216// for the std::vector.
218 static constexpr auto kType = DisplayListOpType::kSetRuntimeEffectColorSource;
219
222 : DLOp(kType),
223 source(source->runtime_effect(),
224 source->samplers(),
225 source->uniform_data()) {}
226
228
229 void dispatch(DlOpReceiver& receiver) const {
230 receiver.setColorSource(&source);
231 }
232
237};
238
239// 4 byte header + 16 byte payload uses 24 total bytes (4 bytes unused)
241 static constexpr auto kType = DisplayListOpType::kSetSharedImageFilter;
242
244 : DLOp(kType), filter(filter->shared()) {}
245
246 const std::shared_ptr<DlImageFilter> filter;
247
248 void dispatch(DlOpReceiver& receiver) const {
249 receiver.setImageFilter(filter.get());
250 }
251
256};
257
258// The base struct for all save() and saveLayer() ops
259// 4 byte header + 12 byte payload packs exactly into 16 bytes
260struct SaveOpBase : DLOp {
261 static constexpr uint32_t kDepthInc = 0;
262 static constexpr uint32_t kRenderOpInc = 1;
263
266
272
273 // options parameter is only used by saveLayer operations, but since
274 // it packs neatly into the empty space created by laying out the rest
275 // of the data here, it can be stored for free and defaulted to 0 for
276 // save operations.
280};
281// 16 byte SaveOpBase with no additional data (options is unsed here)
282struct SaveOp final : SaveOpBase {
283 static constexpr auto kType = DisplayListOpType::kSave;
284
286
287 void dispatch(DlOpReceiver& receiver) const {
288 receiver.save(total_content_depth);
289 }
290};
291// The base struct for all saveLayer() ops
292// 16 byte SaveOpBase + 20 byte payload packs into 36 bytes
302// 36 byte SaveLayerOpBase with no additional data packs into 40 bytes
303// of buffer storage with 4 bytes unused.
305 static constexpr auto kType = DisplayListOpType::kSaveLayer;
306
309
310 void dispatch(DlOpReceiver& receiver) const {
312 }
313};
314// 36 byte SaveLayerOpBase + 4 bytes for alignment + 16 byte payload packs
315// into minimum 56 bytes
317 static constexpr auto kType = DisplayListOpType::kSaveLayerBackdrop;
318
320 const DlRect& rect,
321 const DlImageFilter* backdrop,
322 std::optional<int64_t> backdrop_id)
324 backdrop(backdrop->shared()),
325 backdrop_id_(backdrop_id) {}
326
327 const std::shared_ptr<DlImageFilter> backdrop;
328 std::optional<int64_t> backdrop_id_;
329
330 void dispatch(DlOpReceiver& receiver) const {
332 backdrop.get(), backdrop_id_);
333 }
334
336 return (options == other->options && rect == other->rect &&
337 Equals(backdrop, other->backdrop) &&
338 backdrop_id_ == other->backdrop_id_)
341 }
342};
343// 4 byte header + no payload uses minimum 8 bytes (4 bytes unused)
344struct RestoreOp final : DLOp {
345 static constexpr auto kType = DisplayListOpType::kRestore;
346 static constexpr uint32_t kDepthInc = 0;
347 static constexpr uint32_t kRenderOpInc = 1;
348
350
351 void dispatch(DlOpReceiver& receiver) const { //
352 receiver.restore();
353 }
354};
355
357 static constexpr uint32_t kDepthInc = 0;
358 static constexpr uint32_t kRenderOpInc = 1;
359
361};
362// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
363// (4 bytes unused)
365 static constexpr auto kType = DisplayListOpType::kTranslate;
366
369
372
373 void dispatch(DlOpReceiver& receiver) const { //
374 receiver.translate(tx, ty);
375 }
376};
377// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
378// (4 bytes unused)
380 static constexpr auto kType = DisplayListOpType::kScale;
381
384
387
388 void dispatch(DlOpReceiver& receiver) const { //
389 receiver.scale(sx, sy);
390 }
391};
392// 4 byte header + 4 byte payload packs into minimum 8 bytes
394 static constexpr auto kType = DisplayListOpType::kRotate;
395
398
400
401 void dispatch(DlOpReceiver& receiver) const { //
402 receiver.rotate(degrees);
403 }
404};
405// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
406// (4 bytes unused)
408 static constexpr auto kType = DisplayListOpType::kSkew;
409
412
415
416 void dispatch(DlOpReceiver& receiver) const { //
417 receiver.skew(sx, sy);
418 }
419};
420// 4 byte header + 24 byte payload uses 28 bytes but is rounded up to 32 bytes
421// (4 bytes unused)
423 static constexpr auto kType = DisplayListOpType::kTransform2DAffine;
424
425 // clang-format off
431 // clang-format on
432
435
436 void dispatch(DlOpReceiver& receiver) const {
437 receiver.transform2DAffine(mxx, mxy, mxt, //
438 myx, myy, myt);
439 }
440};
441// 4 byte header + 64 byte payload uses 68 bytes which is rounded up to 72 bytes
442// (4 bytes unused)
444 static constexpr auto kType = DisplayListOpType::kTransformFullPerspective;
445
446 // clang-format off
457 // clang-format on
458
463
464 void dispatch(DlOpReceiver& receiver) const {
465 receiver.transformFullPerspective(mxx, mxy, mxz, mxt, //
466 myx, myy, myz, myt, //
467 mzx, mzy, mzz, mzt, //
468 mwx, mwy, mwz, mwt);
469 }
470};
471
472// 4 byte header with no payload.
474 static constexpr auto kType = DisplayListOpType::kTransformReset;
475
477
478 void dispatch(DlOpReceiver& receiver) const { //
479 receiver.transformReset();
480 }
481};
482
483// 4 byte header + 4 byte common payload packs into minimum 8 bytes
484// DlRect is 16 more bytes, which packs efficiently into 24 bytes total
485// DlRoundRect is 48 more bytes, which rounds up to 48 bytes
486// which packs into 56 bytes total
487// DlRoundSuperellipse is the same as DlRoundRect
488//
489// We could pack the clip_op and the bool both into the free 4 bytes after
490// the header, but the Windows compiler keeps wanting to expand that
491// packing into more bytes than needed (even when they are declared as
492// packed bit fields!)
493#define DEFINE_CLIP_SHAPE_OP(shapename, shapetype, clipop) \
494 struct Clip##clipop##shapename##Op final : TransformClipOpBase { \
495 static constexpr auto kType = DisplayListOpType::kClip##clipop##shapename; \
496 \
497 Clip##clipop##shapename##Op(shapetype shape, bool is_aa) \
498 : TransformClipOpBase(kType), is_aa(is_aa), shape(shape) {} \
499 \
500 const bool is_aa; \
501 const shapetype shape; \
502 \
503 void dispatch(DlOpReceiver& receiver) const { \
504 receiver.clip##shapename(shape, DlClipOp::k##clipop, is_aa); \
505 } \
506 };
507DEFINE_CLIP_SHAPE_OP(Rect, DlRect, Intersect)
508DEFINE_CLIP_SHAPE_OP(Oval, DlRect, Intersect)
509DEFINE_CLIP_SHAPE_OP(RoundRect, DlRoundRect, Intersect)
510DEFINE_CLIP_SHAPE_OP(RoundSuperellipse, DlRoundSuperellipse, Intersect)
511DEFINE_CLIP_SHAPE_OP(Rect, DlRect, Difference)
512DEFINE_CLIP_SHAPE_OP(Oval, DlRect, Difference)
513DEFINE_CLIP_SHAPE_OP(RoundRect, DlRoundRect, Difference)
514DEFINE_CLIP_SHAPE_OP(RoundSuperellipse, DlRoundSuperellipse, Difference)
515#undef DEFINE_CLIP_SHAPE_OP
516
517// 4 byte header + 28 byte payload packs evenly into 32 bytes
518#define DEFINE_CLIP_PATH_OP(clipop) \
519 struct Clip##clipop##PathOp final : TransformClipOpBase { \
520 static constexpr auto kType = DisplayListOpType::kClip##clipop##Path; \
521 \
522 Clip##clipop##PathOp(const DlPath& path, bool is_aa) \
523 : TransformClipOpBase(kType), is_aa(is_aa), path(path) {} \
524 \
525 const bool is_aa; \
526 const DlPath path; \
527 \
528 void dispatch(DlOpReceiver& receiver) const { \
529 receiver.clipPath(path, DlClipOp::k##clipop, is_aa); \
530 } \
531 \
532 DisplayListCompare equals(const Clip##clipop##PathOp* other) const { \
533 return is_aa == other->is_aa && path == other->path \
534 ? DisplayListCompare::kEqual \
535 : DisplayListCompare::kNotEqual; \
536 } \
537 };
538DEFINE_CLIP_PATH_OP(Intersect)
539DEFINE_CLIP_PATH_OP(Difference)
540#undef DEFINE_CLIP_PATH_OP
541
542struct DrawOpBase : DLOp {
543 static constexpr uint32_t kDepthInc = 1;
544 static constexpr uint32_t kRenderOpInc = 1;
545
547};
548
549// 4 byte header + no payload uses minimum 8 bytes (4 bytes unused)
550struct DrawPaintOp final : DrawOpBase {
551 static constexpr auto kType = DisplayListOpType::kDrawPaint;
552
554
555 void dispatch(DlOpReceiver& receiver) const { //
556 receiver.drawPaint();
557 }
558};
559// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
560// (4 bytes unused)
561struct DrawColorOp final : DrawOpBase {
562 static constexpr auto kType = DisplayListOpType::kDrawColor;
563
566
569
570 void dispatch(DlOpReceiver& receiver) const {
571 receiver.drawColor(color, mode);
572 }
573};
574
575// The common data is a 4 byte header with an unused 4 bytes
576// DlRect is 16 more bytes, using 20 bytes which rounds up to 24 bytes total
577// (4 bytes unused)
578// SkOval is same as DlRect
579// DlRoundRect is 48 more bytes, using 52 bytes which rounds up to 56 bytes
580// total (4 bytes unused)
581// DlRoundSuperellipse is the same as DlRoundRect
582#define DEFINE_DRAW_1ARG_OP(op_name, arg_type, arg_name) \
583 struct Draw##op_name##Op final : DrawOpBase { \
584 static constexpr auto kType = DisplayListOpType::kDraw##op_name; \
585 \
586 explicit Draw##op_name##Op(arg_type arg_name) \
587 : DrawOpBase(kType), arg_name(arg_name) {} \
588 \
589 const arg_type arg_name; \
590 \
591 void dispatch(DlOpReceiver& receiver) const { \
592 receiver.draw##op_name(arg_name); \
593 } \
594 };
595DEFINE_DRAW_1ARG_OP(Rect, DlRect, rect)
596DEFINE_DRAW_1ARG_OP(Oval, DlRect, oval)
597DEFINE_DRAW_1ARG_OP(RoundRect, DlRoundRect, rrect)
598DEFINE_DRAW_1ARG_OP(RoundSuperellipse, DlRoundSuperellipse, rse)
599#undef DEFINE_DRAW_1ARG_OP
600
601// 4 byte header + 24 byte payload uses 28 bytes but is rounded
602// up to 32 bytes (4 bytes unused)
603struct DrawPathOp final : DrawOpBase {
604 static constexpr auto kType = DisplayListOpType::kDrawPath;
605
606 explicit DrawPathOp(const DlPath& path) : DrawOpBase(kType), path(path) {}
607
609
610 void dispatch(DlOpReceiver& receiver) const { //
611 receiver.drawPath(path);
612 }
613
618};
619
620// The common data is a 4 byte header with an unused 4 bytes
621// 2 x DlPoint is 16 more bytes, using 20 bytes rounding up to 24 bytes total
622// (4 bytes unused)
623// DlPoint + DlScalar is 12 more bytes, packing efficiently into 16 bytes total
624// 2 x DlRoundRect is 96 more bytes, using 100 and rounding up to 104 bytes
625// total (4 bytes unused)
626#define DEFINE_DRAW_2ARG_OP(op_name, type1, name1, type2, name2) \
627 struct Draw##op_name##Op final : DrawOpBase { \
628 static constexpr auto kType = DisplayListOpType::kDraw##op_name; \
629 \
630 Draw##op_name##Op(type1 name1, type2 name2) \
631 : DrawOpBase(kType), name1(name1), name2(name2) {} \
632 \
633 const type1 name1; \
634 const type2 name2; \
635 \
636 void dispatch(DlOpReceiver& receiver) const { \
637 receiver.draw##op_name(name1, name2); \
638 } \
639 };
641DEFINE_DRAW_2ARG_OP(Circle, DlPoint, center, DlScalar, radius)
642DEFINE_DRAW_2ARG_OP(DiffRoundRect, DlRoundRect, outer, DlRoundRect, inner)
643#undef DEFINE_DRAW_2ARG_OP
644
645// 4 byte header + 24 byte payload packs into 32 bytes (4 bytes unused)
647 static constexpr auto kType = DisplayListOpType::kDrawDashedLine;
648
658
659 const DlPoint p0;
660 const DlPoint p1;
663
664 void dispatch(DlOpReceiver& receiver) const {
666 }
667};
668
669// 4 byte header + 28 byte payload packs efficiently into 32 bytes
670struct DrawArcOp final : DrawOpBase {
671 static constexpr auto kType = DisplayListOpType::kDrawArc;
672
679
683 const bool center;
684
685 void dispatch(DlOpReceiver& receiver) const {
686 receiver.drawArc(bounds, start, sweep, center);
687 }
688};
689
690// 4 byte header + 4 byte fixed payload packs efficiently into 8 bytes
691// But then there is a list of points following the structure which
692// is guaranteed to be a multiple of 8 bytes (DlPoint is 8 bytes)
693// so this op will always pack efficiently
694// The point type is packed into 3 different OpTypes to avoid expanding
695// the fixed payload beyond the 8 bytes
696#define DEFINE_DRAW_POINTS_OP(name, mode) \
697 struct Draw##name##Op final : DrawOpBase { \
698 static constexpr auto kType = DisplayListOpType::kDraw##name; \
699 \
700 explicit Draw##name##Op(uint32_t count) \
701 : DrawOpBase(kType), count(count) {} \
702 \
703 const uint32_t count; \
704 \
705 void dispatch(DlOpReceiver& receiver) const { \
706 const DlPoint* pts = reinterpret_cast<const DlPoint*>(this + 1); \
707 receiver.drawPoints(DlPointMode::mode, count, pts); \
708 } \
709 };
713#undef DEFINE_DRAW_POINTS_OP
714
715// 4 byte header + 20 byte payload packs efficiently into 24 bytes
717 static constexpr auto kType = DisplayListOpType::kDrawVertices;
718
719 explicit DrawVerticesOp(const std::shared_ptr<DlVertices>& vertices,
722
724 const std::shared_ptr<DlVertices> vertices;
725
726 void dispatch(DlOpReceiver& receiver) const {
727 receiver.drawVertices(vertices, mode);
728 }
729};
730
731// 4 byte header + 40 byte payload uses 44 bytes but is rounded up to 48 bytes
732// (4 bytes unused)
733#define DEFINE_DRAW_IMAGE_OP(name, with_attributes) \
734 struct name##Op final : DrawOpBase { \
735 static constexpr auto kType = DisplayListOpType::k##name; \
736 \
737 name##Op(const sk_sp<DlImage>& image, \
738 const DlPoint& point, \
739 DlImageSampling sampling) \
740 : DrawOpBase(kType), \
741 point(point), \
742 sampling(sampling), \
743 image(std::move(image)) {} \
744 \
745 const DlPoint point; \
746 const DlImageSampling sampling; \
747 const sk_sp<DlImage> image; \
748 \
749 void dispatch(DlOpReceiver& receiver) const { \
750 receiver.drawImage(image, point, sampling, with_attributes); \
751 } \
752 \
753 DisplayListCompare equals(const name##Op* other) const { \
754 return (point == other->point && sampling == other->sampling && \
755 image->Equals(other->image)) \
756 ? DisplayListCompare::kEqual \
757 : DisplayListCompare::kNotEqual; \
758 } \
759 };
760DEFINE_DRAW_IMAGE_OP(DrawImage, false)
761DEFINE_DRAW_IMAGE_OP(DrawImageWithAttr, true)
762#undef DEFINE_DRAW_IMAGE_OP
763
764// 4 byte header + 72 byte payload uses 76 bytes but is rounded up to 80 bytes
765// (4 bytes unused)
767 static constexpr auto kType = DisplayListOpType::kDrawImageRect;
768
782
783 const DlRect src;
784 const DlRect dst;
788 const sk_sp<DlImage> image;
789
790 void dispatch(DlOpReceiver& receiver) const {
792 constraint);
793 }
794
796 return (src == other->src && dst == other->dst &&
797 sampling == other->sampling &&
799 constraint == other->constraint && image->Equals(other->image))
802 }
803};
804
805// 4 byte header + 44 byte payload packs efficiently into 48 bytes
806#define DEFINE_DRAW_IMAGE_NINE_OP(name, render_with_attributes) \
807 struct name##Op final : DrawOpBase { \
808 static constexpr auto kType = DisplayListOpType::k##name; \
809 static constexpr uint32_t kDepthInc = 9; \
810 \
811 name##Op(const sk_sp<DlImage>& image, \
812 const DlIRect& center, \
813 const DlRect& dst, \
814 DlFilterMode mode) \
815 : DrawOpBase(kType), \
816 center(center), \
817 dst(dst), \
818 mode(mode), \
819 image(std::move(image)) {} \
820 \
821 const DlIRect center; \
822 const DlRect dst; \
823 const DlFilterMode mode; \
824 const sk_sp<DlImage> image; \
825 \
826 void dispatch(DlOpReceiver& receiver) const { \
827 receiver.drawImageNine(image, center, dst, mode, \
828 render_with_attributes); \
829 } \
830 \
831 DisplayListCompare equals(const name##Op* other) const { \
832 return (center == other->center && dst == other->dst && \
833 mode == other->mode && image->Equals(other->image)) \
834 ? DisplayListCompare::kEqual \
835 : DisplayListCompare::kNotEqual; \
836 } \
837 };
838DEFINE_DRAW_IMAGE_NINE_OP(DrawImageNine, false)
839DEFINE_DRAW_IMAGE_NINE_OP(DrawImageNineWithAttr, true)
840#undef DEFINE_DRAW_IMAGE_NINE_OP
841
842// 4 byte header + 40 byte payload uses 44 bytes but is rounded up to 48 bytes
843// (4 bytes unused)
844// Each of these is then followed by a number of lists.
845// DlRSTransform list is a multiple of 16 bytes so it is always packed well
846// DlRect list is also a multiple of 16 bytes so it also packs well
847// DlColor list only packs well if the count is even, otherwise there
848// can be 4 unusued bytes at the end.
851 const sk_sp<DlImage>& atlas,
852 int count,
853 DlBlendMode mode,
855 bool has_colors,
857 : DrawOpBase(type),
858 count(count),
859 mode_index(static_cast<uint16_t>(mode)),
863 atlas(atlas) {}
864
865 const int count;
866 const uint16_t mode_index;
867 const uint8_t has_colors;
870 const sk_sp<DlImage> atlas;
871
872 bool equals(const DrawAtlasBaseOp* other,
873 const void* pod_this,
874 const void* pod_other) const {
875 bool ret = (count == other->count && mode_index == other->mode_index &&
876 has_colors == other->has_colors &&
878 sampling == other->sampling && atlas->Equals(other->atlas));
879 if (ret) {
880 size_t bytes = count * (sizeof(DlRSTransform) + sizeof(DlRect));
881 if (has_colors) {
882 bytes += count * sizeof(DlColor);
883 }
884 ret = (memcmp(pod_this, pod_other, bytes) == 0);
885 }
886 return ret;
887 }
888};
889
890// Packs into 48 bytes as per DrawAtlasBaseOp
891// with array data following the struct also as per DrawAtlasBaseOp
893 static constexpr auto kType = DisplayListOpType::kDrawAtlas;
894
895 DrawAtlasOp(const sk_sp<DlImage>& atlas,
896 int count,
897 DlBlendMode mode,
899 bool has_colors,
902 atlas,
903 count,
904 mode,
905 sampling,
908
909 void dispatch(DlOpReceiver& receiver) const {
910 const DlRSTransform* xform =
911 reinterpret_cast<const DlRSTransform*>(this + 1);
912 const DlRect* tex = reinterpret_cast<const DlRect*>(xform + count);
913 const DlColor* colors =
914 has_colors ? reinterpret_cast<const DlColor*>(tex + count) : nullptr;
915 const DlBlendMode mode = static_cast<DlBlendMode>(mode_index);
916 receiver.drawAtlas(atlas, xform, tex, colors, count, mode, sampling,
917 nullptr, render_with_attributes);
918 }
919
921 const void* pod_this = reinterpret_cast<const void*>(this + 1);
922 const void* pod_other = reinterpret_cast<const void*>(other + 1);
923 return (DrawAtlasBaseOp::equals(other, pod_this, pod_other))
926 }
927};
928
929// Packs into 48 bytes as per DrawAtlasBaseOp plus
930// an additional 16 bytes for the cull rect resulting in a total
931// of 56 bytes for the Culled drawAtlas.
932// Also with array data following the struct as per DrawAtlasBaseOp
934 static constexpr auto kType = DisplayListOpType::kDrawAtlasCulled;
935
936 DrawAtlasCulledOp(const sk_sp<DlImage>& atlas,
937 int count,
938 DlBlendMode mode,
940 bool has_colors,
941 const DlRect& cull_rect,
944 atlas,
945 count,
946 mode,
947 sampling,
951
953
954 void dispatch(DlOpReceiver& receiver) const {
955 const DlRSTransform* xform =
956 reinterpret_cast<const DlRSTransform*>(this + 1);
957 const DlRect* tex = reinterpret_cast<const DlRect*>(xform + count);
958 const DlColor* colors =
959 has_colors ? reinterpret_cast<const DlColor*>(tex + count) : nullptr;
960 const DlBlendMode mode = static_cast<DlBlendMode>(mode_index);
961 receiver.drawAtlas(atlas, xform, tex, colors, count, mode, sampling,
963 }
964
966 const void* pod_this = reinterpret_cast<const void*>(this + 1);
967 const void* pod_other = reinterpret_cast<const void*>(other + 1);
968 return (cull_rect == other->cull_rect &&
969 DrawAtlasBaseOp::equals(other, pod_this, pod_other))
972 }
973};
974
975// 4 byte header + ptr aligned payload uses 12 bytes round up to 16
976// (4 bytes unused)
978 static constexpr auto kType = DisplayListOpType::kDrawDisplayList;
979
983
985 const sk_sp<DisplayList> display_list;
986
987 void dispatch(DlOpReceiver& receiver) const {
989 }
990
992 return (opacity == other->opacity &&
993 display_list->Equals(other->display_list))
996 }
997};
998
999// 4 byte header + 8 payload bytes + an aligned pointer take 24 bytes
1000// (4 unused to align the pointer)
1001struct DrawTextOp final : DrawOpBase {
1002 static constexpr auto kType = DisplayListOpType::kDrawText;
1003
1004 DrawTextOp(const std::shared_ptr<DlText>& text, DlScalar x, DlScalar y)
1005 : DrawOpBase(kType), x(x), y(y), text(text) {}
1006
1009 const std::shared_ptr<DlText> text;
1010
1011 void dispatch(DlOpReceiver& receiver) const { receiver.drawText(text, x, y); }
1012
1014 return Equals(text, other->text) && x == other->x && y == other->y
1017 }
1018};
1019
1020// 4 byte header + 52 byte payload packs evenly into 56 bytes
1021#define DEFINE_DRAW_SHADOW_OP(name, transparent_occluder) \
1022 struct Draw##name##Op final : DrawOpBase { \
1023 static constexpr auto kType = DisplayListOpType::kDraw##name; \
1024 \
1025 Draw##name##Op(const DlPath& path, \
1026 DlColor color, \
1027 DlScalar elevation, \
1028 DlScalar dpr) \
1029 : DrawOpBase(kType), \
1030 color(color), \
1031 elevation(elevation), \
1032 dpr(dpr), \
1033 path(path) {} \
1034 \
1035 const DlColor color; \
1036 const DlScalar elevation; \
1037 const DlScalar dpr; \
1038 const DlPath path; \
1039 \
1040 void dispatch(DlOpReceiver& receiver) const { \
1041 receiver.drawShadow(path, color, elevation, transparent_occluder, dpr); \
1042 } \
1043 \
1044 DisplayListCompare equals(const Draw##name##Op* other) const { \
1045 return color == other->color && elevation == other->elevation && \
1046 dpr == other->dpr && path == other->path \
1047 ? DisplayListCompare::kEqual \
1048 : DisplayListCompare::kNotEqual; \
1049 } \
1050 };
1051DEFINE_DRAW_SHADOW_OP(Shadow, false)
1052DEFINE_DRAW_SHADOW_OP(ShadowTransparentOccluder, true)
1053#undef DEFINE_DRAW_SHADOW_OP
1054
1055#pragma pack(pop, DLOpPackLabel)
1056
1057} // namespace flutter
1058
1059// NOLINTEND(clang-analyzer-core.CallAndMessage)
1060
1061#endif // FLUTTER_DISPLAY_LIST_DL_OP_RECORDS_H_
Internal API for rendering recorded display lists to backends.
virtual void drawText(const std::shared_ptr< DlText > &text, DlScalar x, DlScalar y)=0
virtual void save()=0
virtual void setStrokeMiter(float limit)=0
virtual void transformReset()=0
virtual void drawPath(const DlPath &path)=0
virtual void restore()=0
virtual void drawImageRect(const sk_sp< DlImage > image, const DlRect &src, const DlRect &dst, DlImageSampling sampling, bool render_with_attributes, DlSrcRectConstraint constraint=DlSrcRectConstraint::kFast)=0
virtual void drawArc(const DlRect &oval_bounds, DlScalar start_degrees, DlScalar sweep_degrees, bool use_center)=0
virtual void translate(DlScalar tx, DlScalar ty)=0
virtual void scale(DlScalar sx, DlScalar sy)=0
virtual void setStrokeWidth(float width)=0
virtual void rotate(DlScalar degrees)=0
virtual void drawVertices(const std::shared_ptr< DlVertices > &vertices, DlBlendMode mode)=0
virtual void drawDisplayList(const sk_sp< DisplayList > display_list, DlScalar opacity=SK_Scalar1)=0
virtual void transform2DAffine(DlScalar mxx, DlScalar mxy, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myt)=0
virtual void transformFullPerspective(DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt, DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt, DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt)=0
virtual void skew(DlScalar sx, DlScalar sy)=0
virtual void drawColor(DlColor color, DlBlendMode mode)=0
virtual void drawAtlas(const sk_sp< DlImage > atlas, const DlRSTransform xform[], const DlRect tex[], const DlColor colors[], int count, DlBlendMode mode, DlImageSampling sampling, const DlRect *cull_rect, bool render_with_attributes)=0
virtual void drawDashedLine(const DlPoint &p0, const DlPoint &p1, DlScalar on_length, DlScalar off_length)=0
virtual void setImageFilter(const DlImageFilter *filter)=0
virtual void setColorSource(const DlColorSource *source)=0
virtual void drawPaint()=0
virtual void setDrawStyle(DlDrawStyle style)=0
virtual void setBlendMode(DlBlendMode mode)=0
virtual void setColor(DlColor color)=0
virtual void saveLayer(const DlRect &bounds, const SaveLayerOptions options, const DlImageFilter *backdrop=nullptr, std::optional< int64_t > backdrop_id=std::nullopt)=0
#define DEFINE_DRAW_IMAGE_NINE_OP(name, render_with_attributes)
#define DEFINE_SET_BOOL_OP(name)
#define DEFINE_CLIP_SHAPE_OP(shapename, shapetype, clipop)
#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_PATH_OP(clipop)
#define DEFINE_SET_CLEAR_DLATTR_OP(name, field)
#define DEFINE_DRAW_1ARG_OP(op_name, arg_type, arg_name)
#define DEFINE_SET_ENUM_OP(name)
FlutterVulkanImage * image
impeller::Scalar DlScalar
uint32_t DlIndex
impeller::RoundRect DlRoundRect
impeller::RSTransform DlRSTransform
impeller::Rect DlRect
impeller::RoundSuperellipse DlRoundSuperellipse
@ kLines
draw each separate pair of points as a line segment
@ kPolygon
draw each pair of overlapping points as a line segment
@ kPoints
draw each point separately
bool Equals(const T *a, const U *b)
DlDrawStyle
Definition dl_paint.h:19
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all 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
impeller::Point DlPoint
DlSrcRectConstraint
Definition dl_types.h:21
Join
An enum that describes ways to join two segments of a path.
Cap
An enum that describes ways to decorate the end of a path contour.
BlendMode
Definition color.h:58
static constexpr uint32_t kRenderOpInc
DisplayListCompare equals(const DLOp *other) const
DLOp(DisplayListOpType type)
const DisplayListOpType type
static constexpr uint32_t kDepthInc
const DlScalar sweep
DrawArcOp(DlRect bounds, DlScalar start, DlScalar sweep, bool center)
void dispatch(DlOpReceiver &receiver) const
static constexpr auto kType
const DlScalar start
const DlRect bounds
DrawAtlasBaseOp(DisplayListOpType type, const sk_sp< DlImage > &atlas, int count, DlBlendMode mode, DlImageSampling sampling, bool has_colors, bool render_with_attributes)
const sk_sp< DlImage > atlas
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
DrawAtlasCulledOp(const sk_sp< DlImage > &atlas, int count, DlBlendMode mode, DlImageSampling sampling, bool has_colors, const DlRect &cull_rect, bool render_with_attributes)
void dispatch(DlOpReceiver &receiver) const
void dispatch(DlOpReceiver &receiver) 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(DlOpReceiver &receiver) const
DrawDashedLineOp(const DlPoint &p0, const DlPoint &p1, DlScalar on_length, DlScalar off_length)
void dispatch(DlOpReceiver &receiver) const
static constexpr auto kType
DrawDisplayListOp(const sk_sp< DisplayList > &display_list, DlScalar opacity)
DisplayListCompare equals(const DrawDisplayListOp *other) const
static constexpr auto kType
const sk_sp< DisplayList > display_list
void dispatch(DlOpReceiver &receiver) const
const sk_sp< DlImage > image
static constexpr auto kType
const DlSrcRectConstraint constraint
const DlImageSampling sampling
DrawImageRectOp(const sk_sp< DlImage > &image, const DlRect &src, const DlRect &dst, DlImageSampling sampling, bool render_with_attributes, DlSrcRectConstraint constraint)
DisplayListCompare equals(const DrawImageRectOp *other) const
void dispatch(DlOpReceiver &receiver) const
static constexpr uint32_t kRenderOpInc
DrawOpBase(DisplayListOpType type)
static constexpr uint32_t kDepthInc
static constexpr auto kType
void dispatch(DlOpReceiver &receiver) const
DisplayListCompare equals(const DrawPathOp *other) const
static constexpr auto kType
DrawPathOp(const DlPath &path)
void dispatch(DlOpReceiver &receiver) const
static constexpr auto kType
DrawTextOp(const std::shared_ptr< DlText > &text, DlScalar x, DlScalar y)
DisplayListCompare equals(const DrawTextOp *other) const
const std::shared_ptr< DlText > text
void dispatch(DlOpReceiver &receiver) const
const std::shared_ptr< DlVertices > vertices
DrawVerticesOp(const std::shared_ptr< DlVertices > &vertices, DlBlendMode mode)
static constexpr auto kType
const DlBlendMode mode
void dispatch(DlOpReceiver &receiver) const
static constexpr auto kType
void dispatch(DlOpReceiver &receiver) const
static constexpr uint32_t kRenderOpInc
static constexpr uint32_t kDepthInc
RotateOp(DlScalar degrees)
static constexpr auto kType
const DlScalar degrees
void dispatch(DlOpReceiver &receiver) const
void dispatch(DlOpReceiver &receiver) const
SaveLayerBackdropOp(const SaveLayerOptions &options, const DlRect &rect, const DlImageFilter *backdrop, std::optional< int64_t > backdrop_id)
DisplayListCompare equals(const SaveLayerBackdropOp *other) const
static constexpr auto kType
const std::shared_ptr< DlImageFilter > backdrop
std::optional< int64_t > backdrop_id_
SaveLayerOpBase(DisplayListOpType type, const SaveLayerOptions &options, const DlRect &rect)
void dispatch(DlOpReceiver &receiver) const
static constexpr auto kType
SaveLayerOp(const SaveLayerOptions &options, const DlRect &rect)
SaveOpBase(DisplayListOpType type)
static constexpr uint32_t kRenderOpInc
SaveOpBase(DisplayListOpType type, const SaveLayerOptions &options)
static constexpr uint32_t kDepthInc
SaveLayerOptions options
static constexpr auto kType
void dispatch(DlOpReceiver &receiver) const
void dispatch(DlOpReceiver &receiver) const
static constexpr auto kType
const DlScalar sy
const DlScalar sx
ScaleOp(DlScalar sx, DlScalar sy)
const DlBlendMode mode
static constexpr auto kType
void dispatch(DlOpReceiver &receiver) const
SetBlendModeOp(DlBlendMode mode)
const DlColor color
static constexpr auto kType
SetColorOp(DlColor color)
void dispatch(DlOpReceiver &receiver) const
SetImageColorSourceOp(const DlImageColorSource *source)
static constexpr auto kType
void dispatch(DlOpReceiver &receiver) const
const DlImageColorSource source
SetRuntimeEffectColorSourceOp(const DlRuntimeEffectColorSource *source)
void dispatch(DlOpReceiver &receiver) 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(DlOpReceiver &receiver) const
static constexpr auto kType
void dispatch(DlOpReceiver &receiver) const
static constexpr auto kType
void dispatch(DlOpReceiver &receiver) const
static constexpr auto kType
const DlDrawStyle style
void dispatch(DlOpReceiver &receiver) const
static constexpr auto kType
SetStyleOp(DlDrawStyle style)
void dispatch(DlOpReceiver &receiver) const
const DlScalar sx
SkewOp(DlScalar sx, DlScalar sy)
static constexpr auto kType
const DlScalar sy
Transform2DAffineOp(DlScalar mxx, DlScalar mxy, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myt)
void dispatch(DlOpReceiver &receiver) const
static constexpr auto kType
TransformClipOpBase(DisplayListOpType type)
static constexpr uint32_t kDepthInc
static constexpr uint32_t kRenderOpInc
void dispatch(DlOpReceiver &receiver) const
TransformFullPerspectiveOp(DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt, DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt, DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt)
static constexpr auto kType
void dispatch(DlOpReceiver &receiver) const
static constexpr auto kType
TranslateOp(DlScalar tx, DlScalar ty)
void dispatch(DlOpReceiver &receiver) const