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
55namespace 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,
144enum 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
152class DlOpReceiver;
153class DisplayListBuilder;
154
155class 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.
206class 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(static_cast<uint8_t*>(std::realloc(ptr_.release(), 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
225class 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().
230class 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

source code of flutter_engine/flutter/display_list/display_list.h