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
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 { \
80 receiver.set##name(value); \
81 } \
82 };
83DEFINE_SET_BOOL_OP(AntiAlias)
84DEFINE_SET_BOOL_OP(InvertColors)
85#undef DEFINE_SET_BOOL_OP
86
87// 4 byte header + 4 byte payload packs into minimum 8 bytes
88#define DEFINE_SET_ENUM_OP(name) \
89 struct SetStroke##name##Op final : DLOp { \
90 static constexpr auto kType = DisplayListOpType::kSetStroke##name; \
91 \
92 explicit SetStroke##name##Op(DlStroke##name value) \
93 : DLOp(kType), value(value) {} \
94 \
95 const DlStroke##name value; \
96 \
97 void dispatch(DlOpReceiver& receiver) const { \
98 receiver.setStroke##name(value); \
99 } \
100 };
103#undef DEFINE_SET_ENUM_OP
104
105// 4 byte header + 4 byte payload packs into minimum 8 bytes
106struct SetStyleOp final : DLOp {
107 static constexpr auto kType = DisplayListOpType::kSetStyle;
108
110
112
113 void dispatch(DlOpReceiver& receiver) const { //
114 receiver.setDrawStyle(style);
115 }
116};
117// 4 byte header + 4 byte payload packs into minimum 8 bytes
118struct SetStrokeWidthOp final : DLOp {
119 static constexpr auto kType = DisplayListOpType::kSetStrokeWidth;
120
121 explicit SetStrokeWidthOp(float width) : DLOp(kType), width(width) {}
122
123 const float width;
124
125 void dispatch(DlOpReceiver& receiver) const {
126 receiver.setStrokeWidth(width);
127 }
128};
129// 4 byte header + 4 byte payload packs into minimum 8 bytes
130struct SetStrokeMiterOp final : DLOp {
131 static constexpr auto kType = DisplayListOpType::kSetStrokeMiter;
132
133 explicit SetStrokeMiterOp(float limit) : DLOp(kType), limit(limit) {}
134
135 const float limit;
136
137 void dispatch(DlOpReceiver& receiver) const {
138 receiver.setStrokeMiter(limit);
139 }
140};
141
142// 4 byte header + 20 byte payload packs into minimum 24 bytes
143struct SetColorOp final : DLOp {
144 static constexpr auto kType = DisplayListOpType::kSetColor;
145
147
149
150 void dispatch(DlOpReceiver& receiver) const { receiver.setColor(color); }
151};
152// 4 byte header + 4 byte payload packs into minimum 8 bytes
153struct SetBlendModeOp final : DLOp {
154 static constexpr auto kType = DisplayListOpType::kSetBlendMode;
155
157
159
160 void dispatch(DlOpReceiver& receiver) const { //
161 receiver.setBlendMode(mode);
162 }
163};
164
165// Clear: 4 byte header + unused 4 byte payload uses 8 bytes
166// (4 bytes unused)
167// Set: 4 byte header + unused 4 byte struct padding + Dl<name>
168// instance copied to the memory following the record
169// yields a size and efficiency that has somewhere between
170// 4 and 8 bytes unused
171#define DEFINE_SET_CLEAR_DLATTR_OP(name, field) \
172 struct Clear##name##Op final : DLOp { \
173 static constexpr auto kType = DisplayListOpType::kClear##name; \
174 \
175 Clear##name##Op() : DLOp(kType) {} \
176 \
177 void dispatch(DlOpReceiver& receiver) const { \
178 receiver.set##name(nullptr); \
179 } \
180 }; \
181 struct SetPod##name##Op final : DLOp { \
182 static constexpr auto kType = DisplayListOpType::kSetPod##name; \
183 \
184 SetPod##name##Op() : DLOp(kType) {} \
185 \
186 void dispatch(DlOpReceiver& receiver) const { \
187 const Dl##name* filter = reinterpret_cast<const Dl##name*>(this + 1); \
188 receiver.set##name(filter); \
189 } \
190 };
191DEFINE_SET_CLEAR_DLATTR_OP(ColorFilter, filter)
192DEFINE_SET_CLEAR_DLATTR_OP(ImageFilter, filter)
193DEFINE_SET_CLEAR_DLATTR_OP(MaskFilter, filter)
194DEFINE_SET_CLEAR_DLATTR_OP(ColorSource, source)
195#undef DEFINE_SET_CLEAR_DLATTR_OP
196
197// 4 byte header + 96 bytes for the embedded DlImageColorSource
198// uses 104 total bytes (4 bytes unused)
200 static constexpr auto kType = DisplayListOpType::kSetImageColorSource;
201
203 : DLOp(kType),
205 source->horizontal_tile_mode(),
206 source->vertical_tile_mode(),
207 source->sampling(),
208 source->matrix_ptr()) {}
209
211
212 void dispatch(DlOpReceiver& receiver) const {
213 receiver.setColorSource(&source);
214 }
215};
216
217// 56 bytes: 4 byte header, 4 byte padding, 8 for vtable, 8 * 2 for sk_sps, 24
218// for the std::vector.
220 static constexpr auto kType = DisplayListOpType::kSetRuntimeEffectColorSource;
221
224 : DLOp(kType),
225 source(source->runtime_effect(),
226 source->samplers(),
227 source->uniform_data()) {}
228
230
231 void dispatch(DlOpReceiver& receiver) const {
232 receiver.setColorSource(&source);
233 }
234
239};
240
241// 4 byte header + 16 byte payload uses 24 total bytes (4 bytes unused)
243 static constexpr auto kType = DisplayListOpType::kSetSharedImageFilter;
244
246 : DLOp(kType), filter(filter->shared()) {}
247
248 const std::shared_ptr<DlImageFilter> filter;
249
250 void dispatch(DlOpReceiver& receiver) const {
251 receiver.setImageFilter(filter.get());
252 }
253
258};
259
260// The base struct for all save() and saveLayer() ops
261// 4 byte header + 12 byte payload packs exactly into 16 bytes
262struct SaveOpBase : DLOp {
263 static constexpr uint32_t kDepthInc = 0;
264 static constexpr uint32_t kRenderOpInc = 1;
265
268
274
275 // options parameter is only used by saveLayer operations, but since
276 // it packs neatly into the empty space created by laying out the rest
277 // of the data here, it can be stored for free and defaulted to 0 for
278 // save operations.
282};
283// 16 byte SaveOpBase with no additional data (options is unsed here)
284struct SaveOp final : SaveOpBase {
285 static constexpr auto kType = DisplayListOpType::kSave;
286
288
289 void dispatch(DlOpReceiver& receiver) const {
290 receiver.save(total_content_depth);
291 }
292};
293// The base struct for all saveLayer() ops
294// 16 byte SaveOpBase + 20 byte payload packs into 36 bytes
304// 36 byte SaveLayerOpBase with no additional data packs into 40 bytes
305// of buffer storage with 4 bytes unused.
307 static constexpr auto kType = DisplayListOpType::kSaveLayer;
308
311
312 void dispatch(DlOpReceiver& receiver) const {
314 }
315};
316// 36 byte SaveLayerOpBase + 4 bytes for alignment + 16 byte payload packs
317// into minimum 56 bytes
319 static constexpr auto kType = DisplayListOpType::kSaveLayerBackdrop;
320
322 const DlRect& rect,
323 const DlImageFilter* backdrop,
324 std::optional<int64_t> backdrop_id)
326 backdrop(backdrop->shared()),
327 backdrop_id_(backdrop_id) {}
328
329 const std::shared_ptr<DlImageFilter> backdrop;
330 std::optional<int64_t> backdrop_id_;
331
332 void dispatch(DlOpReceiver& receiver) const {
334 backdrop.get(), backdrop_id_);
335 }
336
338 return (options == other->options && rect == other->rect &&
339 Equals(backdrop, other->backdrop) &&
340 backdrop_id_ == other->backdrop_id_)
343 }
344};
345// 4 byte header + no payload uses minimum 8 bytes (4 bytes unused)
346struct RestoreOp final : DLOp {
347 static constexpr auto kType = DisplayListOpType::kRestore;
348 static constexpr uint32_t kDepthInc = 0;
349 static constexpr uint32_t kRenderOpInc = 1;
350
352
353 void dispatch(DlOpReceiver& receiver) const { //
354 receiver.restore();
355 }
356};
357
359 static constexpr uint32_t kDepthInc = 0;
360 static constexpr uint32_t kRenderOpInc = 1;
361
363};
364// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
365// (4 bytes unused)
367 static constexpr auto kType = DisplayListOpType::kTranslate;
368
371
374
375 void dispatch(DlOpReceiver& receiver) const { //
376 receiver.translate(tx, ty);
377 }
378};
379// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
380// (4 bytes unused)
382 static constexpr auto kType = DisplayListOpType::kScale;
383
386
389
390 void dispatch(DlOpReceiver& receiver) const { //
391 receiver.scale(sx, sy);
392 }
393};
394// 4 byte header + 4 byte payload packs into minimum 8 bytes
396 static constexpr auto kType = DisplayListOpType::kRotate;
397
400
402
403 void dispatch(DlOpReceiver& receiver) const { //
404 receiver.rotate(degrees);
405 }
406};
407// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
408// (4 bytes unused)
410 static constexpr auto kType = DisplayListOpType::kSkew;
411
414
417
418 void dispatch(DlOpReceiver& receiver) const { //
419 receiver.skew(sx, sy);
420 }
421};
422// 4 byte header + 24 byte payload uses 28 bytes but is rounded up to 32 bytes
423// (4 bytes unused)
425 static constexpr auto kType = DisplayListOpType::kTransform2DAffine;
426
427 // clang-format off
433 // clang-format on
434
437
438 void dispatch(DlOpReceiver& receiver) const {
439 receiver.transform2DAffine(mxx, mxy, mxt, //
440 myx, myy, myt);
441 }
442};
443// 4 byte header + 64 byte payload uses 68 bytes which is rounded up to 72 bytes
444// (4 bytes unused)
446 static constexpr auto kType = DisplayListOpType::kTransformFullPerspective;
447
448 // clang-format off
459 // clang-format on
460
465
466 void dispatch(DlOpReceiver& receiver) const {
467 receiver.transformFullPerspective(mxx, mxy, mxz, mxt, //
468 myx, myy, myz, myt, //
469 mzx, mzy, mzz, mzt, //
470 mwx, mwy, mwz, mwt);
471 }
472};
473
474// 4 byte header with no payload.
476 static constexpr auto kType = DisplayListOpType::kTransformReset;
477
479
480 void dispatch(DlOpReceiver& receiver) const { //
481 receiver.transformReset();
482 }
483};
484
485// 4 byte header + 4 byte common payload packs into minimum 8 bytes
486// DlRect is 16 more bytes, which packs efficiently into 24 bytes total
487// DlRoundRect is 48 more bytes, which rounds up to 48 bytes
488// which packs into 56 bytes total
489// DlRoundSuperellipse is the same as DlRoundRect
490//
491// We could pack the clip_op and the bool both into the free 4 bytes after
492// the header, but the Windows compiler keeps wanting to expand that
493// packing into more bytes than needed (even when they are declared as
494// packed bit fields!)
495#define DEFINE_CLIP_SHAPE_OP(shapename, shapetype, clipop) \
496 struct Clip##clipop##shapename##Op final : TransformClipOpBase { \
497 static constexpr auto kType = DisplayListOpType::kClip##clipop##shapename; \
498 \
499 Clip##clipop##shapename##Op(shapetype shape, bool is_aa) \
500 : TransformClipOpBase(kType), is_aa(is_aa), shape(shape) {} \
501 \
502 const bool is_aa; \
503 const shapetype shape; \
504 \
505 void dispatch(DlOpReceiver& receiver) const { \
506 receiver.clip##shapename(shape, DlClipOp::k##clipop, is_aa); \
507 } \
508 };
509DEFINE_CLIP_SHAPE_OP(Rect, DlRect, Intersect)
510DEFINE_CLIP_SHAPE_OP(Oval, DlRect, Intersect)
511DEFINE_CLIP_SHAPE_OP(RoundRect, DlRoundRect, Intersect)
512DEFINE_CLIP_SHAPE_OP(RoundSuperellipse, DlRoundSuperellipse, Intersect)
513DEFINE_CLIP_SHAPE_OP(Rect, DlRect, Difference)
514DEFINE_CLIP_SHAPE_OP(Oval, DlRect, Difference)
515DEFINE_CLIP_SHAPE_OP(RoundRect, DlRoundRect, Difference)
516DEFINE_CLIP_SHAPE_OP(RoundSuperellipse, DlRoundSuperellipse, Difference)
517#undef DEFINE_CLIP_SHAPE_OP
518
519// 4 byte header + 28 byte payload packs evenly into 32 bytes
520#define DEFINE_CLIP_PATH_OP(clipop) \
521 struct Clip##clipop##PathOp final : TransformClipOpBase { \
522 static constexpr auto kType = DisplayListOpType::kClip##clipop##Path; \
523 \
524 Clip##clipop##PathOp(const DlPath& path, bool is_aa) \
525 : TransformClipOpBase(kType), is_aa(is_aa), path(path) {} \
526 \
527 const bool is_aa; \
528 const DlPath path; \
529 \
530 void dispatch(DlOpReceiver& receiver) const { \
531 receiver.clipPath(path, DlClipOp::k##clipop, is_aa); \
532 } \
533 \
534 DisplayListCompare equals(const Clip##clipop##PathOp* other) const { \
535 return is_aa == other->is_aa && path == other->path \
536 ? DisplayListCompare::kEqual \
537 : DisplayListCompare::kNotEqual; \
538 } \
539 };
540DEFINE_CLIP_PATH_OP(Intersect)
541DEFINE_CLIP_PATH_OP(Difference)
542#undef DEFINE_CLIP_PATH_OP
543
544struct DrawOpBase : DLOp {
545 static constexpr uint32_t kDepthInc = 1;
546 static constexpr uint32_t kRenderOpInc = 1;
547
549};
550
551// 4 byte header + no payload uses minimum 8 bytes (4 bytes unused)
552struct DrawPaintOp final : DrawOpBase {
553 static constexpr auto kType = DisplayListOpType::kDrawPaint;
554
556
557 void dispatch(DlOpReceiver& receiver) const { //
558 receiver.drawPaint();
559 }
560};
561// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
562// (4 bytes unused)
563struct DrawColorOp final : DrawOpBase {
564 static constexpr auto kType = DisplayListOpType::kDrawColor;
565
568
571
572 void dispatch(DlOpReceiver& receiver) const {
573 receiver.drawColor(color, mode);
574 }
575};
576
577// The common data is a 4 byte header with an unused 4 bytes
578// DlRect is 16 more bytes, using 20 bytes which rounds up to 24 bytes total
579// (4 bytes unused)
580// SkOval is same as DlRect
581// DlRoundRect is 48 more bytes, using 52 bytes which rounds up to 56 bytes
582// total (4 bytes unused)
583// DlRoundSuperellipse is the same as DlRoundRect
584#define DEFINE_DRAW_1ARG_OP(op_name, arg_type, arg_name) \
585 struct Draw##op_name##Op final : DrawOpBase { \
586 static constexpr auto kType = DisplayListOpType::kDraw##op_name; \
587 \
588 explicit Draw##op_name##Op(arg_type arg_name) \
589 : DrawOpBase(kType), arg_name(arg_name) {} \
590 \
591 const arg_type arg_name; \
592 \
593 void dispatch(DlOpReceiver& receiver) const { \
594 receiver.draw##op_name(arg_name); \
595 } \
596 };
597DEFINE_DRAW_1ARG_OP(Rect, DlRect, rect)
598DEFINE_DRAW_1ARG_OP(Oval, DlRect, oval)
599DEFINE_DRAW_1ARG_OP(RoundRect, DlRoundRect, rrect)
600DEFINE_DRAW_1ARG_OP(RoundSuperellipse, DlRoundSuperellipse, rse)
601#undef DEFINE_DRAW_1ARG_OP
602
603// 4 byte header + 24 byte payload uses 28 bytes but is rounded
604// up to 32 bytes (4 bytes unused)
605struct DrawPathOp final : DrawOpBase {
606 static constexpr auto kType = DisplayListOpType::kDrawPath;
607
608 explicit DrawPathOp(const DlPath& path) : DrawOpBase(kType), path(path) {}
609
611
612 void dispatch(DlOpReceiver& receiver) const { //
613 receiver.drawPath(path);
614 }
615
620};
621
622// The common data is a 4 byte header with an unused 4 bytes
623// 2 x DlPoint is 16 more bytes, using 20 bytes rounding up to 24 bytes total
624// (4 bytes unused)
625// DlPoint + DlScalar is 12 more bytes, packing efficiently into 16 bytes total
626// 2 x DlRoundRect is 96 more bytes, using 100 and rounding up to 104 bytes
627// total (4 bytes unused)
628#define DEFINE_DRAW_2ARG_OP(op_name, type1, name1, type2, name2) \
629 struct Draw##op_name##Op final : DrawOpBase { \
630 static constexpr auto kType = DisplayListOpType::kDraw##op_name; \
631 \
632 Draw##op_name##Op(type1 name1, type2 name2) \
633 : DrawOpBase(kType), name1(name1), name2(name2) {} \
634 \
635 const type1 name1; \
636 const type2 name2; \
637 \
638 void dispatch(DlOpReceiver& receiver) const { \
639 receiver.draw##op_name(name1, name2); \
640 } \
641 };
642DEFINE_DRAW_2ARG_OP(Line, DlPoint, p0, DlPoint, p1)
643DEFINE_DRAW_2ARG_OP(Circle, DlPoint, center, DlScalar, radius)
644DEFINE_DRAW_2ARG_OP(DiffRoundRect, DlRoundRect, outer, DlRoundRect, inner)
645#undef DEFINE_DRAW_2ARG_OP
646
647// 4 byte header + 24 byte payload packs into 32 bytes (4 bytes unused)
649 static constexpr auto kType = DisplayListOpType::kDrawDashedLine;
650
660
661 const DlPoint p0;
662 const DlPoint p1;
665
666 void dispatch(DlOpReceiver& receiver) const {
668 }
669};
670
671// 4 byte header + 28 byte payload packs efficiently into 32 bytes
672struct DrawArcOp final : DrawOpBase {
673 static constexpr auto kType = DisplayListOpType::kDrawArc;
674
681
685 const bool center;
686
687 void dispatch(DlOpReceiver& receiver) const {
688 receiver.drawArc(bounds, start, sweep, center);
689 }
690};
691
692// 4 byte header + 4 byte fixed payload packs efficiently into 8 bytes
693// But then there is a list of points following the structure which
694// is guaranteed to be a multiple of 8 bytes (DlPoint is 8 bytes)
695// so this op will always pack efficiently
696// The point type is packed into 3 different OpTypes to avoid expanding
697// the fixed payload beyond the 8 bytes
698#define DEFINE_DRAW_POINTS_OP(name, mode) \
699 struct Draw##name##Op final : DrawOpBase { \
700 static constexpr auto kType = DisplayListOpType::kDraw##name; \
701 \
702 explicit Draw##name##Op(uint32_t count) \
703 : DrawOpBase(kType), count(count) {} \
704 \
705 const uint32_t count; \
706 \
707 void dispatch(DlOpReceiver& receiver) const { \
708 const DlPoint* pts = reinterpret_cast<const DlPoint*>(this + 1); \
709 receiver.drawPoints(DlPointMode::mode, count, pts); \
710 } \
711 };
715#undef DEFINE_DRAW_POINTS_OP
716
717// 4 byte header + 20 byte payload packs efficiently into 24 bytes
719 static constexpr auto kType = DisplayListOpType::kDrawVertices;
720
721 explicit DrawVerticesOp(const std::shared_ptr<DlVertices>& vertices,
724
726 const std::shared_ptr<DlVertices> vertices;
727
728 void dispatch(DlOpReceiver& receiver) const {
729 receiver.drawVertices(vertices, mode);
730 }
731};
732
733// 4 byte header + 40 byte payload uses 44 bytes but is rounded up to 48 bytes
734// (4 bytes unused)
735#define DEFINE_DRAW_IMAGE_OP(name, with_attributes) \
736 struct name##Op final : DrawOpBase { \
737 static constexpr auto kType = DisplayListOpType::k##name; \
738 \
739 name##Op(const sk_sp<DlImage>& image, \
740 const DlPoint& point, \
741 DlImageSampling sampling) \
742 : DrawOpBase(kType), \
743 point(point), \
744 sampling(sampling), \
745 image(std::move(image)) {} \
746 \
747 const DlPoint point; \
748 const DlImageSampling sampling; \
749 const sk_sp<DlImage> image; \
750 \
751 void dispatch(DlOpReceiver& receiver) const { \
752 receiver.drawImage(image, point, sampling, with_attributes); \
753 } \
754 \
755 DisplayListCompare equals(const name##Op* other) const { \
756 return (point == other->point && sampling == other->sampling && \
757 image->Equals(other->image)) \
758 ? DisplayListCompare::kEqual \
759 : DisplayListCompare::kNotEqual; \
760 } \
761 };
762DEFINE_DRAW_IMAGE_OP(DrawImage, false)
763DEFINE_DRAW_IMAGE_OP(DrawImageWithAttr, true)
764#undef DEFINE_DRAW_IMAGE_OP
765
766// 4 byte header + 72 byte payload uses 76 bytes but is rounded up to 80 bytes
767// (4 bytes unused)
769 static constexpr auto kType = DisplayListOpType::kDrawImageRect;
770
784
785 const DlRect src;
786 const DlRect dst;
790 const sk_sp<DlImage> image;
791
792 void dispatch(DlOpReceiver& receiver) const {
794 constraint);
795 }
796
798 return (src == other->src && dst == other->dst &&
799 sampling == other->sampling &&
801 constraint == other->constraint && image->Equals(other->image))
804 }
805};
806
807// 4 byte header + 44 byte payload packs efficiently into 48 bytes
808#define DEFINE_DRAW_IMAGE_NINE_OP(name, render_with_attributes) \
809 struct name##Op final : DrawOpBase { \
810 static constexpr auto kType = DisplayListOpType::k##name; \
811 static constexpr uint32_t kDepthInc = 9; \
812 \
813 name##Op(const sk_sp<DlImage>& image, \
814 const DlIRect& center, \
815 const DlRect& dst, \
816 DlFilterMode mode) \
817 : DrawOpBase(kType), \
818 center(center), \
819 dst(dst), \
820 mode(mode), \
821 image(std::move(image)) {} \
822 \
823 const DlIRect center; \
824 const DlRect dst; \
825 const DlFilterMode mode; \
826 const sk_sp<DlImage> image; \
827 \
828 void dispatch(DlOpReceiver& receiver) const { \
829 receiver.drawImageNine(image, center, dst, mode, \
830 render_with_attributes); \
831 } \
832 \
833 DisplayListCompare equals(const name##Op* other) const { \
834 return (center == other->center && dst == other->dst && \
835 mode == other->mode && image->Equals(other->image)) \
836 ? DisplayListCompare::kEqual \
837 : DisplayListCompare::kNotEqual; \
838 } \
839 };
840DEFINE_DRAW_IMAGE_NINE_OP(DrawImageNine, false)
841DEFINE_DRAW_IMAGE_NINE_OP(DrawImageNineWithAttr, true)
842#undef DEFINE_DRAW_IMAGE_NINE_OP
843
844// 4 byte header + 40 byte payload uses 44 bytes but is rounded up to 48 bytes
845// (4 bytes unused)
846// Each of these is then followed by a number of lists.
847// DlRSTransform list is a multiple of 16 bytes so it is always packed well
848// DlRect list is also a multiple of 16 bytes so it also packs well
849// DlColor list only packs well if the count is even, otherwise there
850// can be 4 unusued bytes at the end.
853 const sk_sp<DlImage>& atlas,
854 int count,
855 DlBlendMode mode,
857 bool has_colors,
859 : DrawOpBase(type),
860 count(count),
861 mode_index(static_cast<uint16_t>(mode)),
865 atlas(atlas) {}
866
867 const int count;
868 const uint16_t mode_index;
869 const uint8_t has_colors;
872 const sk_sp<DlImage> atlas;
873
874 bool equals(const DrawAtlasBaseOp* other,
875 const void* pod_this,
876 const void* pod_other) const {
877 bool ret = (count == other->count && mode_index == other->mode_index &&
878 has_colors == other->has_colors &&
880 sampling == other->sampling && atlas->Equals(other->atlas));
881 if (ret) {
882 size_t bytes = count * (sizeof(DlRSTransform) + sizeof(DlRect));
883 if (has_colors) {
884 bytes += count * sizeof(DlColor);
885 }
886 ret = (memcmp(pod_this, pod_other, bytes) == 0);
887 }
888 return ret;
889 }
890};
891
892// Packs into 48 bytes as per DrawAtlasBaseOp
893// with array data following the struct also as per DrawAtlasBaseOp
895 static constexpr auto kType = DisplayListOpType::kDrawAtlas;
896
897 DrawAtlasOp(const sk_sp<DlImage>& atlas,
898 int count,
899 DlBlendMode mode,
901 bool has_colors,
904 atlas,
905 count,
906 mode,
907 sampling,
910
911 void dispatch(DlOpReceiver& receiver) const {
912 const DlRSTransform* xform =
913 reinterpret_cast<const DlRSTransform*>(this + 1);
914 const DlRect* tex = reinterpret_cast<const DlRect*>(xform + count);
915 const DlColor* colors =
916 has_colors ? reinterpret_cast<const DlColor*>(tex + count) : nullptr;
917 const DlBlendMode mode = static_cast<DlBlendMode>(mode_index);
918 receiver.drawAtlas(atlas, xform, tex, colors, count, mode, sampling,
919 nullptr, render_with_attributes);
920 }
921
923 const void* pod_this = reinterpret_cast<const void*>(this + 1);
924 const void* pod_other = reinterpret_cast<const void*>(other + 1);
925 return (DrawAtlasBaseOp::equals(other, pod_this, pod_other))
928 }
929};
930
931// Packs into 48 bytes as per DrawAtlasBaseOp plus
932// an additional 16 bytes for the cull rect resulting in a total
933// of 56 bytes for the Culled drawAtlas.
934// Also with array data following the struct as per DrawAtlasBaseOp
936 static constexpr auto kType = DisplayListOpType::kDrawAtlasCulled;
937
938 DrawAtlasCulledOp(const sk_sp<DlImage>& atlas,
939 int count,
940 DlBlendMode mode,
942 bool has_colors,
943 const DlRect& cull_rect,
946 atlas,
947 count,
948 mode,
949 sampling,
953
955
956 void dispatch(DlOpReceiver& receiver) const {
957 const DlRSTransform* xform =
958 reinterpret_cast<const DlRSTransform*>(this + 1);
959 const DlRect* tex = reinterpret_cast<const DlRect*>(xform + count);
960 const DlColor* colors =
961 has_colors ? reinterpret_cast<const DlColor*>(tex + count) : nullptr;
962 const DlBlendMode mode = static_cast<DlBlendMode>(mode_index);
963 receiver.drawAtlas(atlas, xform, tex, colors, count, mode, sampling,
965 }
966
968 const void* pod_this = reinterpret_cast<const void*>(this + 1);
969 const void* pod_other = reinterpret_cast<const void*>(other + 1);
970 return (cull_rect == other->cull_rect &&
971 DrawAtlasBaseOp::equals(other, pod_this, pod_other))
974 }
975};
976
977// 4 byte header + ptr aligned payload uses 12 bytes round up to 16
978// (4 bytes unused)
980 static constexpr auto kType = DisplayListOpType::kDrawDisplayList;
981
985
987 const sk_sp<DisplayList> display_list;
988
989 void dispatch(DlOpReceiver& receiver) const {
991 }
992
994 return (opacity == other->opacity &&
995 display_list->Equals(other->display_list))
998 }
999};
1000
1001// 4 byte header + 8 payload bytes + an aligned pointer take 24 bytes
1002// (4 unused to align the pointer)
1003struct DrawTextOp final : DrawOpBase {
1004 static constexpr auto kType = DisplayListOpType::kDrawText;
1005
1006 DrawTextOp(const std::shared_ptr<DlText>& text, DlScalar x, DlScalar y)
1007 : DrawOpBase(kType), x(x), y(y), text(text) {}
1008
1011 const std::shared_ptr<DlText> text;
1012
1013 void dispatch(DlOpReceiver& receiver) const { receiver.drawText(text, x, y); }
1014
1016 return Equals(text, other->text) && x == other->x && y == other->y
1019 }
1020};
1021
1022// 4 byte header + 52 byte payload packs evenly into 56 bytes
1023#define DEFINE_DRAW_SHADOW_OP(name, transparent_occluder) \
1024 struct Draw##name##Op final : DrawOpBase { \
1025 static constexpr auto kType = DisplayListOpType::kDraw##name; \
1026 \
1027 Draw##name##Op(const DlPath& path, \
1028 DlColor color, \
1029 DlScalar elevation, \
1030 DlScalar dpr) \
1031 : DrawOpBase(kType), \
1032 color(color), \
1033 elevation(elevation), \
1034 dpr(dpr), \
1035 path(path) {} \
1036 \
1037 const DlColor color; \
1038 const DlScalar elevation; \
1039 const DlScalar dpr; \
1040 const DlPath path; \
1041 \
1042 void dispatch(DlOpReceiver& receiver) const { \
1043 receiver.drawShadow(path, color, elevation, transparent_occluder, dpr); \
1044 } \
1045 \
1046 DisplayListCompare equals(const Draw##name##Op* other) const { \
1047 return color == other->color && elevation == other->elevation && \
1048 dpr == other->dpr && path == other->path \
1049 ? DisplayListCompare::kEqual \
1050 : DisplayListCompare::kNotEqual; \
1051 } \
1052 };
1053DEFINE_DRAW_SHADOW_OP(Shadow, false)
1054DEFINE_DRAW_SHADOW_OP(ShadowTransparentOccluder, true)
1055#undef DEFINE_DRAW_SHADOW_OP
1056
1057#pragma pack(pop, DLOpPackLabel)
1058
1059} // namespace flutter
1060
1061// NOLINTEND(clang-analyzer-core.CallAndMessage)
1062
1063#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