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_DISPLAY_LIST_H_ |
6 | #define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_H_ |
7 | |
8 | #include <memory> |
9 | #include <optional> |
10 | |
11 | #include "flutter/display_list/dl_sampling_options.h" |
12 | #include "flutter/display_list/geometry/dl_rtree.h" |
13 | #include "flutter/fml/logging.h" |
14 | |
15 | // The Flutter DisplayList mechanism encapsulates a persistent sequence of |
16 | // rendering operations. |
17 | // |
18 | // This file contains the definitions for: |
19 | // DisplayList: the base class that holds the information about the |
20 | // sequence of operations and can dispatch them to a DlOpReceiver |
21 | // DlOpReceiver: a pure virtual interface which can be implemented to field |
22 | // the requests for purposes such as sending them to an SkCanvas |
23 | // or detecting various rendering optimization scenarios |
24 | // DisplayListBuilder: a class for constructing a DisplayList from DlCanvas |
25 | // method calls and which can act as a DlOpReceiver as well |
26 | // |
27 | // Other files include various class definitions for dealing with display |
28 | // lists, such as: |
29 | // skia/dl_sk_*.h: classes to interact between SkCanvas and DisplayList |
30 | // (SkCanvas->DisplayList adapter and vice versa) |
31 | // |
32 | // display_list_utils.h: various utility classes to ease implementing |
33 | // a DlOpReceiver, including NOP implementations of |
34 | // the attribute, clip, and transform methods, |
35 | // classes to track attributes, clips, and transforms |
36 | // and a class to compute the bounds of a DisplayList |
37 | // Any class implementing DlOpReceiver can inherit from |
38 | // these utility classes to simplify its creation |
39 | // |
40 | // The Flutter DisplayList mechanism is used in a similar manner to the Skia |
41 | // SkPicture mechanism. |
42 | // |
43 | // A DisplayList must be created using a DisplayListBuilder using its stateless |
44 | // methods inherited from DlCanvas. |
45 | // |
46 | // A DisplayList can be read back by implementing the DlOpReceiver virtual |
47 | // methods (with help from some of the classes in the utils file) and |
48 | // passing an instance to the Dispatch() method, or it can be rendered |
49 | // to Skia using a DlSkCanvasDispatcher. |
50 | // |
51 | // The mechanism is inspired by the SkLiteDL class that is not directly |
52 | // supported by Skia, but has been recommended as a basis for custom |
53 | // display lists for a number of their customers. |
54 | |
55 | namespace flutter { |
56 | |
57 | #define FOR_EACH_DISPLAY_LIST_OP(V) \ |
58 | V(SetAntiAlias) \ |
59 | V(SetDither) \ |
60 | V(SetInvertColors) \ |
61 | \ |
62 | V(SetStrokeCap) \ |
63 | V(SetStrokeJoin) \ |
64 | \ |
65 | V(SetStyle) \ |
66 | V(SetStrokeWidth) \ |
67 | V(SetStrokeMiter) \ |
68 | \ |
69 | V(SetColor) \ |
70 | V(SetBlendMode) \ |
71 | \ |
72 | V(SetPodPathEffect) \ |
73 | V(ClearPathEffect) \ |
74 | \ |
75 | V(ClearColorFilter) \ |
76 | V(SetPodColorFilter) \ |
77 | \ |
78 | V(ClearColorSource) \ |
79 | V(SetPodColorSource) \ |
80 | V(SetImageColorSource) \ |
81 | V(SetRuntimeEffectColorSource) \ |
82 | \ |
83 | V(ClearImageFilter) \ |
84 | V(SetPodImageFilter) \ |
85 | V(SetSharedImageFilter) \ |
86 | \ |
87 | V(ClearMaskFilter) \ |
88 | V(SetPodMaskFilter) \ |
89 | \ |
90 | V(Save) \ |
91 | V(SaveLayer) \ |
92 | V(SaveLayerBounds) \ |
93 | V(SaveLayerBackdrop) \ |
94 | V(SaveLayerBackdropBounds) \ |
95 | V(Restore) \ |
96 | \ |
97 | V(Translate) \ |
98 | V(Scale) \ |
99 | V(Rotate) \ |
100 | V(Skew) \ |
101 | V(Transform2DAffine) \ |
102 | V(TransformFullPerspective) \ |
103 | V(TransformReset) \ |
104 | \ |
105 | V(ClipIntersectRect) \ |
106 | V(ClipIntersectRRect) \ |
107 | V(ClipIntersectPath) \ |
108 | V(ClipDifferenceRect) \ |
109 | V(ClipDifferenceRRect) \ |
110 | V(ClipDifferencePath) \ |
111 | \ |
112 | V(DrawPaint) \ |
113 | V(DrawColor) \ |
114 | \ |
115 | V(DrawLine) \ |
116 | V(DrawRect) \ |
117 | V(DrawOval) \ |
118 | V(DrawCircle) \ |
119 | V(DrawRRect) \ |
120 | V(DrawDRRect) \ |
121 | V(DrawArc) \ |
122 | V(DrawPath) \ |
123 | \ |
124 | V(DrawPoints) \ |
125 | V(DrawLines) \ |
126 | V(DrawPolygon) \ |
127 | V(DrawVertices) \ |
128 | \ |
129 | V(DrawImage) \ |
130 | V(DrawImageWithAttr) \ |
131 | V(DrawImageRect) \ |
132 | V(DrawImageNine) \ |
133 | V(DrawImageNineWithAttr) \ |
134 | V(DrawAtlas) \ |
135 | V(DrawAtlasCulled) \ |
136 | \ |
137 | V(DrawDisplayList) \ |
138 | V(DrawTextBlob) \ |
139 | \ |
140 | V(DrawShadow) \ |
141 | V(DrawShadowTransparentOccluder) |
142 | |
143 | #define DL_OP_TO_ENUM_VALUE(name) k##name, |
144 | enum class DisplayListOpType { |
145 | FOR_EACH_DISPLAY_LIST_OP(DL_OP_TO_ENUM_VALUE) |
146 | #ifdef IMPELLER_ENABLE_3D |
147 | DL_OP_TO_ENUM_VALUE(SetSceneColorSource) |
148 | #endif // IMPELLER_ENABLE_3D |
149 | }; |
150 | #undef DL_OP_TO_ENUM_VALUE |
151 | |
152 | class DlOpReceiver; |
153 | class DisplayListBuilder; |
154 | |
155 | class SaveLayerOptions { |
156 | public: |
157 | static const SaveLayerOptions kWithAttributes; |
158 | static const SaveLayerOptions kNoAttributes; |
159 | |
160 | SaveLayerOptions() : flags_(0) {} |
161 | SaveLayerOptions(const SaveLayerOptions& options) : flags_(options.flags_) {} |
162 | SaveLayerOptions(const SaveLayerOptions* options) : flags_(options->flags_) {} |
163 | |
164 | SaveLayerOptions without_optimizations() const { |
165 | SaveLayerOptions options; |
166 | options.fRendersWithAttributes = fRendersWithAttributes; |
167 | return options; |
168 | } |
169 | |
170 | bool renders_with_attributes() const { return fRendersWithAttributes; } |
171 | SaveLayerOptions with_renders_with_attributes() const { |
172 | SaveLayerOptions options(this); |
173 | options.fRendersWithAttributes = true; |
174 | return options; |
175 | } |
176 | |
177 | bool can_distribute_opacity() const { return fCanDistributeOpacity; } |
178 | SaveLayerOptions with_can_distribute_opacity() const { |
179 | SaveLayerOptions options(this); |
180 | options.fCanDistributeOpacity = true; |
181 | return options; |
182 | } |
183 | |
184 | SaveLayerOptions& operator=(const SaveLayerOptions& other) { |
185 | flags_ = other.flags_; |
186 | return *this; |
187 | } |
188 | bool operator==(const SaveLayerOptions& other) const { |
189 | return flags_ == other.flags_; |
190 | } |
191 | bool operator!=(const SaveLayerOptions& other) const { |
192 | return flags_ != other.flags_; |
193 | } |
194 | |
195 | private: |
196 | union { |
197 | struct { |
198 | unsigned fRendersWithAttributes : 1; |
199 | unsigned fCanDistributeOpacity : 1; |
200 | }; |
201 | uint32_t flags_; |
202 | }; |
203 | }; |
204 | |
205 | // Manages a buffer allocated with malloc. |
206 | class DisplayListStorage { |
207 | public: |
208 | DisplayListStorage() = default; |
209 | DisplayListStorage(DisplayListStorage&&) = default; |
210 | |
211 | uint8_t* get() const { return ptr_.get(); } |
212 | |
213 | void realloc(size_t count) { |
214 | ptr_.reset(p: static_cast<uint8_t*>(std::realloc(ptr: ptr_.release(), size: count))); |
215 | FML_CHECK(ptr_); |
216 | } |
217 | |
218 | private: |
219 | struct FreeDeleter { |
220 | void operator()(uint8_t* p) { std::free(ptr: p); } |
221 | }; |
222 | std::unique_ptr<uint8_t, FreeDeleter> ptr_; |
223 | }; |
224 | |
225 | class Culler; |
226 | |
227 | // The base class that contains a sequence of rendering operations |
228 | // for dispatch to a DlOpReceiver. These objects must be instantiated |
229 | // through an instance of DisplayListBuilder::build(). |
230 | class DisplayList : public SkRefCnt { |
231 | public: |
232 | DisplayList(); |
233 | |
234 | ~DisplayList(); |
235 | |
236 | void Dispatch(DlOpReceiver& ctx) const; |
237 | void Dispatch(DlOpReceiver& ctx, const SkRect& cull_rect) const; |
238 | void Dispatch(DlOpReceiver& ctx, const SkIRect& cull_rect) const; |
239 | |
240 | // From historical behavior, SkPicture always included nested bytes, |
241 | // but nested ops are only included if requested. The defaults used |
242 | // here for these accessors follow that pattern. |
243 | size_t bytes(bool nested = true) const { |
244 | return sizeof(DisplayList) + byte_count_ + |
245 | (nested ? nested_byte_count_ : 0); |
246 | } |
247 | |
248 | unsigned int op_count(bool nested = false) const { |
249 | return op_count_ + (nested ? nested_op_count_ : 0); |
250 | } |
251 | |
252 | uint32_t unique_id() const { return unique_id_; } |
253 | |
254 | const SkRect& bounds() const { return bounds_; } |
255 | |
256 | bool has_rtree() const { return rtree_ != nullptr; } |
257 | sk_sp<const DlRTree> rtree() const { return rtree_; } |
258 | |
259 | bool Equals(const DisplayList* other) const; |
260 | bool Equals(const DisplayList& other) const { return Equals(other: &other); } |
261 | bool Equals(const sk_sp<const DisplayList>& other) const { |
262 | return Equals(other: other.get()); |
263 | } |
264 | |
265 | bool can_apply_group_opacity() const { return can_apply_group_opacity_; } |
266 | bool isUIThreadSafe() const { return is_ui_thread_safe_; } |
267 | |
268 | /// @brief Indicates if there are any rendering operations in this |
269 | /// DisplayList that will modify a surface of transparent black |
270 | /// pixels. |
271 | /// |
272 | /// This condition can be used to determine whether to create a cleared |
273 | /// surface, render a DisplayList into it, and then composite the |
274 | /// result into a scene. It is not uncommon for code in the engine to |
275 | /// come across such degenerate DisplayList objects when slicing up a |
276 | /// frame between platform views. |
277 | bool modifies_transparent_black() const { |
278 | return modifies_transparent_black_; |
279 | } |
280 | |
281 | private: |
282 | DisplayList(DisplayListStorage&& ptr, |
283 | size_t byte_count, |
284 | unsigned int op_count, |
285 | size_t nested_byte_count, |
286 | unsigned int nested_op_count, |
287 | const SkRect& bounds, |
288 | bool can_apply_group_opacity, |
289 | bool is_ui_thread_safe, |
290 | bool modifies_transparent_black, |
291 | sk_sp<const DlRTree> rtree); |
292 | |
293 | static uint32_t next_unique_id(); |
294 | |
295 | static void DisposeOps(uint8_t* ptr, uint8_t* end); |
296 | |
297 | const DisplayListStorage storage_; |
298 | const size_t byte_count_; |
299 | const unsigned int op_count_; |
300 | |
301 | const size_t nested_byte_count_; |
302 | const unsigned int nested_op_count_; |
303 | |
304 | const uint32_t unique_id_; |
305 | const SkRect bounds_; |
306 | |
307 | const bool can_apply_group_opacity_; |
308 | const bool is_ui_thread_safe_; |
309 | const bool modifies_transparent_black_; |
310 | |
311 | const sk_sp<const DlRTree> rtree_; |
312 | |
313 | void Dispatch(DlOpReceiver& ctx, |
314 | uint8_t* ptr, |
315 | uint8_t* end, |
316 | Culler& culler) const; |
317 | |
318 | friend class DisplayListBuilder; |
319 | }; |
320 | |
321 | } // namespace flutter |
322 | |
323 | #endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_H_ |
324 | |