Flutter Engine
 
Loading...
Searching...
No Matches
display_list.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_DISPLAY_LIST_H_
6#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_H_
7
12
13// The Flutter DisplayList mechanism encapsulates a persistent sequence of
14// rendering operations.
15//
16// This file contains the definitions for:
17// DisplayList: the base class that holds the information about the
18// sequence of operations and can dispatch them to a DlOpReceiver
19// DlOpReceiver: a pure virtual interface which can be implemented to field
20// the requests for purposes such as sending them to an SkCanvas
21// or detecting various rendering optimization scenarios
22// DisplayListBuilder: a class for constructing a DisplayList from DlCanvas
23// method calls and which can act as a DlOpReceiver as well
24//
25// Other files include various class definitions for dealing with display
26// lists, such as:
27// skia/dl_sk_*.h: classes to interact between SkCanvas and DisplayList
28// (SkCanvas->DisplayList adapter and vice versa)
29//
30// display_list_utils.h: various utility classes to ease implementing
31// a DlOpReceiver, including NOP implementations of
32// the attribute, clip, and transform methods,
33// classes to track attributes, clips, and transforms
34// and a class to compute the bounds of a DisplayList
35// Any class implementing DlOpReceiver can inherit from
36// these utility classes to simplify its creation
37//
38// The Flutter DisplayList mechanism is used in a similar manner to the Skia
39// SkPicture mechanism.
40//
41// A DisplayList must be created using a DisplayListBuilder using its stateless
42// methods inherited from DlCanvas.
43//
44// A DisplayList can be read back by implementing the DlOpReceiver virtual
45// methods (with help from some of the classes in the utils file) and
46// passing an instance to the Dispatch() method, or it can be rendered
47// to Skia using a DlSkCanvasDispatcher.
48//
49// The mechanism is inspired by the SkLiteDL class that is not directly
50// supported by Skia, but has been recommended as a basis for custom
51// display lists for a number of their customers.
52
53namespace flutter {
54
55#define FOR_EACH_DISPLAY_LIST_OP(V) \
56 V(SetAntiAlias) \
57 V(SetInvertColors) \
58 \
59 V(SetStrokeCap) \
60 V(SetStrokeJoin) \
61 \
62 V(SetStyle) \
63 V(SetStrokeWidth) \
64 V(SetStrokeMiter) \
65 \
66 V(SetColor) \
67 V(SetBlendMode) \
68 \
69 V(ClearColorFilter) \
70 V(SetPodColorFilter) \
71 \
72 V(ClearColorSource) \
73 V(SetPodColorSource) \
74 V(SetImageColorSource) \
75 V(SetRuntimeEffectColorSource) \
76 \
77 V(ClearImageFilter) \
78 V(SetPodImageFilter) \
79 V(SetSharedImageFilter) \
80 \
81 V(ClearMaskFilter) \
82 V(SetPodMaskFilter) \
83 \
84 V(Save) \
85 V(SaveLayer) \
86 V(SaveLayerBackdrop) \
87 V(Restore) \
88 \
89 V(Translate) \
90 V(Scale) \
91 V(Rotate) \
92 V(Skew) \
93 V(Transform2DAffine) \
94 V(TransformFullPerspective) \
95 V(TransformReset) \
96 \
97 V(ClipIntersectRect) \
98 V(ClipIntersectOval) \
99 V(ClipIntersectRoundRect) \
100 V(ClipIntersectRoundSuperellipse) \
101 V(ClipIntersectPath) \
102 V(ClipDifferenceRect) \
103 V(ClipDifferenceOval) \
104 V(ClipDifferenceRoundRect) \
105 V(ClipDifferenceRoundSuperellipse) \
106 V(ClipDifferencePath) \
107 \
108 V(DrawPaint) \
109 V(DrawColor) \
110 \
111 V(DrawLine) \
112 V(DrawDashedLine) \
113 V(DrawRect) \
114 V(DrawOval) \
115 V(DrawCircle) \
116 V(DrawRoundRect) \
117 V(DrawDiffRoundRect) \
118 V(DrawRoundSuperellipse) \
119 V(DrawArc) \
120 V(DrawPath) \
121 \
122 V(DrawPoints) \
123 V(DrawLines) \
124 V(DrawPolygon) \
125 V(DrawVertices) \
126 \
127 V(DrawImage) \
128 V(DrawImageWithAttr) \
129 V(DrawImageRect) \
130 V(DrawImageNine) \
131 V(DrawImageNineWithAttr) \
132 V(DrawAtlas) \
133 V(DrawAtlasCulled) \
134 \
135 V(DrawDisplayList) \
136 V(DrawText) \
137 \
138 V(DrawShadow) \
139 V(DrawShadowTransparentOccluder)
140
141#define DL_OP_TO_ENUM_VALUE(name) k##name,
144
145 // empty comment to make formatter happy
148};
149#undef DL_OP_TO_ENUM_VALUE
150
163
164class DlOpReceiver;
165class DisplayListBuilder;
166
168 public:
171
173 SaveLayerOptions(const SaveLayerOptions& options) : flags_(options.flags_) {}
174 explicit SaveLayerOptions(const SaveLayerOptions* options)
175 : flags_(options->flags_) {}
176
183
186 SaveLayerOptions options(this);
187 options.fRendersWithAttributes = true;
188 return options;
189 }
190
193 SaveLayerOptions options(this);
194 options.fCanDistributeOpacity = true;
195 return options;
196 }
197
198 // Returns true iff the bounds for the saveLayer operation were provided
199 // by the caller, otherwise the bounds will have been computed by the
200 // DisplayListBuilder and provided for reference.
201 bool bounds_from_caller() const { return fBoundsFromCaller; }
203 SaveLayerOptions options(this);
204 options.fBoundsFromCaller = true;
205 return options;
206 }
208 SaveLayerOptions options(this);
209 options.fBoundsFromCaller = false;
210 return options;
211 }
213
214 // Returns true iff the bounds for the saveLayer do not fully cover the
215 // contained rendering operations. This will only occur if the original
216 // caller supplied bounds and those bounds were not a strict superset
217 // of the content bounds computed by the DisplayListBuilder.
218 bool content_is_clipped() const { return fContentIsClipped; }
220 SaveLayerOptions options(this);
221 options.fContentIsClipped = true;
222 return options;
223 }
224
227 SaveLayerOptions options(this);
228 options.fHasBackdropFilter = true;
229 return options;
230 }
231
234 SaveLayerOptions options(this);
235 options.fContentIsUnbounded = true;
236 return options;
237 }
238
240 flags_ = other.flags_;
241 return *this;
242 }
243 bool operator==(const SaveLayerOptions& other) const {
244 return flags_ == other.flags_;
245 }
246
247 private:
248 union {
249 struct {
252 unsigned fBoundsFromCaller : 1;
253 unsigned fContentIsClipped : 1;
254 unsigned fHasBackdropFilter : 1;
256 };
257 uint32_t flags_;
258 };
259};
260
261using DlIndex = uint32_t;
262
263// The base class that contains a sequence of rendering operations
264// for dispatch to a DlOpReceiver. These objects must be instantiated
265// through an instance of DisplayListBuilder::build().
266class DisplayList : public SkRefCnt {
267 public:
268 DisplayList();
269
270 ~DisplayList();
271
272 void Dispatch(DlOpReceiver& ctx) const;
273 void Dispatch(DlOpReceiver& ctx, const DlRect& cull_rect) const;
274 void Dispatch(DlOpReceiver& ctx, const DlIRect& cull_rect) const;
275
276 // From historical behavior, SkPicture always included nested bytes,
277 // but nested ops are only included if requested. The defaults used
278 // here for these accessors follow that pattern.
279 size_t bytes(bool nested = true) const {
280 return sizeof(DisplayList) + storage_.size() +
281 (nested ? nested_byte_count_ : 0);
282 }
283
284 uint32_t op_count(bool nested = false) const {
285 return op_count_ + (nested ? nested_op_count_ : 0);
286 }
287
288 uint32_t total_depth() const { return total_depth_; }
289
290 uint32_t unique_id() const { return unique_id_; }
291
292 const DlRect& GetBounds() const { return bounds_; }
293
294 bool has_rtree() const { return rtree_ != nullptr; }
295 sk_sp<const DlRTree> rtree() const { return rtree_; }
296
297 bool Equals(const DisplayList* other) const;
298 bool Equals(const DisplayList& other) const { return Equals(&other); }
299 bool Equals(const sk_sp<const DisplayList>& other) const {
300 return Equals(other.get());
301 }
302
303 bool can_apply_group_opacity() const { return can_apply_group_opacity_; }
304 bool isUIThreadSafe() const { return is_ui_thread_safe_; }
305
306 /// @brief Indicates if there are any rendering operations in this
307 /// DisplayList that will modify a surface of transparent black
308 /// pixels.
309 ///
310 /// This condition can be used to determine whether to create a cleared
311 /// surface, render a DisplayList into it, and then composite the
312 /// result into a scene. It is not uncommon for code in the engine to
313 /// come across such degenerate DisplayList objects when slicing up a
314 /// frame between platform views.
316 return modifies_transparent_black_;
317 }
318
319 const DisplayListStorage& GetStorage() const { return storage_; }
320
321 /// @brief Indicates if there are any saveLayer operations at the root
322 /// surface level of the DisplayList that use a backdrop filter.
323 ///
324 /// This condition can be used to determine what kind of surface to create
325 /// for the root layer into which to render the DisplayList as some GPUs
326 /// can support surfaces that do or do not support the readback that would
327 /// be required for the backdrop filter to do its work.
328 bool root_has_backdrop_filter() const { return root_has_backdrop_filter_; }
329
330 /// @brief Indicates if a rendering operation at the root level of the
331 /// DisplayList had an unbounded result, not otherwise limited by
332 /// a clip operation.
333 ///
334 /// This condition can occur in a number of situations. The most common
335 /// situation is when there is a drawPaint or drawColor rendering
336 /// operation which fills out the entire drawable surface unless it is
337 /// bounded by a clip. Other situations include an operation rendered
338 /// through an ImageFilter that cannot compute the resulting bounds or
339 /// when an unclipped backdrop filter is applied by a save layer.
340 bool root_is_unbounded() const { return root_is_unbounded_; }
341
342 /// @brief Indicates the maximum DlBlendMode used on any rendering op
343 /// in the root surface of the DisplayList.
344 ///
345 /// This condition can be used to determine what kind of surface to create
346 /// for the root layer into which to render the DisplayList as some GPUs
347 /// can support surfaces that do or do not support the readback that would
348 /// be required for the indicated blend mode to do its work.
349 DlBlendMode max_root_blend_mode() const { return max_root_blend_mode_; }
350
351 /// @brief Iterator utility class used for the |DisplayList::begin|
352 /// and |DisplayList::end| methods. It implements just the
353 /// basic methods to enable iteration-style for loops.
354 class Iterator {
355 public:
356 DlIndex operator*() const { return value_; }
357 bool operator!=(const Iterator& other) { return value_ != other.value_; }
359 value_++;
360 return *this;
361 }
362
363 private:
364 explicit Iterator(DlIndex value) : value_(value) {}
365
366 DlIndex value_;
367
368 friend class DisplayList;
369 };
370
371 /// @brief Return the number of stored records in the DisplayList.
372 ///
373 /// Each stored record represents a dispatchable operation that will be
374 /// sent to a |DlOpReceiver| by the |Dispatch| method. You can directly
375 /// simulate the |Dispatch| method using a simple for loop on the indices:
376 ///
377 /// {
378 /// for (DlIndex i = 0u; i < display_list->GetRecordCount(); i++) {
379 /// display_list->Dispatch(my_receiver, i);
380 /// }
381 /// }
382 ///
383 /// @see |Dispatch(receiver, index)|
384 /// @see |begin|
385 /// @see |end|
386 /// @see |GetCulledIndices|
387 DlIndex GetRecordCount() const { return offsets_.size(); }
388
389 /// @brief Return an iterator to the start of the stored records,
390 /// enabling the iteration form of a for loop.
391 ///
392 /// Each stored record represents a dispatchable operation that will be
393 /// sent to a |DlOpReceiver| by the |Dispatch| method. You can directly
394 /// simulate the |Dispatch| method using a simple for loop on the indices:
395 ///
396 /// {
397 /// for (DlIndex i : *display_list) {
398 /// display_list->Dispatch(my_receiver, i);
399 /// }
400 /// }
401 ///
402 /// @see |end|
403 /// @see |GetCulledIndices|
404 Iterator begin() const { return Iterator(0u); }
405
406 /// @brief Return an iterator to the end of the stored records,
407 /// enabling the iteration form of a for loop.
408 ///
409 /// Each stored record represents a dispatchable operation that will be
410 /// sent to a |DlOpReceiver| by the |Dispatch| method. You can directly
411 /// simulate the |Dispatch| method using a simple for loop on the indices:
412 ///
413 /// {
414 /// for (DlIndex i : *display_list) {
415 /// display_list->Dispatch(my_receiver, i);
416 /// }
417 /// }
418 ///
419 /// @see |begin|
420 /// @see |GetCulledIndices|
421 Iterator end() const { return Iterator(offsets_.size()); }
422
423 /// @brief Dispatch a single stored operation by its index.
424 ///
425 /// Each stored record represents a dispatchable operation that will be
426 /// sent to a |DlOpReceiver| by the |Dispatch| method. You can use this
427 /// method to dispatch a single operation to your receiver with an index
428 /// between |0u| (inclusive) and |GetRecordCount()| (exclusive), as in:
429 ///
430 /// {
431 /// for (DlIndex i = 0u; i < display_list->GetRecordCount(); i++) {
432 /// display_list->Dispatch(my_receiver, i);
433 /// }
434 /// }
435 ///
436 /// If the index is out of the range of the stored records, this method
437 /// will not call any methods on the receiver and return false. You can
438 /// check the return value for true if you want to make sure you are
439 /// using valid indices.
440 ///
441 /// @see |GetRecordCount|
442 /// @see |begin|
443 /// @see |end|
444 /// @see |GetCulledIndices|
445 bool Dispatch(DlOpReceiver& receiver, DlIndex index) const;
446
447 /// @brief Return an enum describing the specific op type stored at
448 /// the indicated index.
449 ///
450 /// The specific types of the records are subject to change without notice
451 /// as the DisplayList code is developed and optimized. These values are
452 /// useful mostly for debugging purposes and should not be used in
453 /// production code.
454 ///
455 /// @see |GetOpCategory| for a more stable description of the records
457
458 /// @brief Return an enum describing the general category of the
459 /// operation record stored at the indicated index.
460 ///
461 /// The categories are general and stable and can be used fairly safely
462 /// in production code to plan how to dispatch or reorder ops during
463 /// final rendering.
464 ///
465 /// @see |GetOpType| for a more detailed description of the records
466 /// primarily for debugging use
468
469 /// @brief Return an enum describing the general category of the
470 /// operation record with the given type.
471 ///
472 /// @see |GetOpType| for a more detailed description of the records
473 /// primarily for debugging use
475
476 /// @brief Return a vector of valid indices for records stored in
477 /// the DisplayList that must be dispatched if you are
478 /// restricted to the indicated cull_rect.
479 ///
480 /// This method can be used along with indexed dispatching to implement
481 /// RTree culling while still maintaining control over planning of
482 /// operations to be rendered, as in:
483 ///
484 /// {
485 /// std::vector<DlIndex> indices =
486 /// display_list->GetCulledIndices(cull-rect);
487 /// for (DlIndex i : indices) {
488 /// display_list->Dispatch(my_receiver, i);
489 /// }
490 /// }
491 ///
492 /// The indices returned in the vector will automatically deal with
493 /// including or culling related operations such as attributes, clips
494 /// and transforms that will provide state for any rendering operations
495 /// selected by the culling checks.
496 ///
497 /// @see |GetOpType| for a more detailed description of the records
498 /// primarily for debugging use
499 ///
500 /// @see |Dispatch(receiver, index)|
501 std::vector<DlIndex> GetCulledIndices(const DlRect& cull_rect) const;
502
503 private:
505 std::vector<size_t>&& offsets,
506 uint32_t op_count,
507 size_t nested_byte_count,
508 uint32_t nested_op_count,
509 uint32_t total_depth,
510 const DlRect& bounds,
512 bool is_ui_thread_safe,
517 sk_sp<const DlRTree> rtree);
518
519 static uint32_t next_unique_id();
520
521 static void DisposeOps(const DisplayListStorage& storage,
522 const std::vector<size_t>& offsets);
523
524 const DisplayListStorage storage_;
525 const std::vector<size_t> offsets_;
526
527 const uint32_t op_count_;
528 const size_t nested_byte_count_;
529 const uint32_t nested_op_count_;
530
531 const uint32_t total_depth_;
532
533 const uint32_t unique_id_;
534 const DlRect bounds_;
535
536 const bool can_apply_group_opacity_;
537 const bool is_ui_thread_safe_;
538 const bool modifies_transparent_black_;
539 const bool root_has_backdrop_filter_;
540 const bool root_is_unbounded_;
541 const DlBlendMode max_root_blend_mode_;
542
543 const sk_sp<const DlRTree> rtree_;
544
545 void DispatchOneOp(DlOpReceiver& receiver, const uint8_t* ptr) const;
546
547 void RTreeResultsToIndexVector(std::vector<DlIndex>& indices,
548 const std::vector<int>& rtree_results) const;
549
550 friend class DisplayListBuilder;
551};
552
553} // namespace flutter
554
555#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_H_
GLenum type
Iterator utility class used for the |DisplayListbegin| and |DisplayListend| methods....
bool operator!=(const Iterator &other)
DlIndex GetRecordCount() const
Return the number of stored records in the DisplayList.
bool Equals(const sk_sp< const DisplayList > &other) const
DisplayListOpType GetOpType(DlIndex index) const
Return an enum describing the specific op type stored at the indicated index.
bool root_has_backdrop_filter() const
Indicates if there are any saveLayer operations at the root surface level of the DisplayList that use...
bool Equals(const DisplayList &other) const
Iterator end() const
Return an iterator to the end of the stored records, enabling the iteration form of a for loop.
uint32_t unique_id() const
DisplayListOpCategory GetOpCategory(DlIndex index) const
Return an enum describing the general category of the operation record stored at the indicated index.
const DlRect & GetBounds() const
const DisplayListStorage & GetStorage() const
bool modifies_transparent_black() const
Indicates if there are any rendering operations in this DisplayList that will modify a surface of tra...
bool can_apply_group_opacity() const
DlBlendMode max_root_blend_mode() const
Indicates the maximum DlBlendMode used on any rendering op in the root surface of the DisplayList.
bool Equals(const DisplayList *other) const
bool root_is_unbounded() const
Indicates if a rendering operation at the root level of the DisplayList had an unbounded result,...
uint32_t total_depth() const
Iterator begin() const
Return an iterator to the start of the stored records, enabling the iteration form of a for loop.
size_t bytes(bool nested=true) const
bool isUIThreadSafe() const
bool has_rtree() const
uint32_t op_count(bool nested=false) const
std::vector< DlIndex > GetCulledIndices(const DlRect &cull_rect) const
Return a vector of valid indices for records stored in the DisplayList that must be dispatched if you...
void Dispatch(DlOpReceiver &ctx) const
sk_sp< const DlRTree > rtree() const
size_t size() const
Returns the currently allocated size.
Definition dl_storage.h:27
Internal API for rendering recorded display lists to backends.
bool content_is_clipped() const
SaveLayerOptions with_content_is_unbounded() const
static const SaveLayerOptions kNoAttributes
SaveLayerOptions with_renders_with_attributes() const
SaveLayerOptions & operator=(const SaveLayerOptions &other)
SaveLayerOptions with_can_distribute_opacity() const
bool renders_with_attributes() const
bool operator==(const SaveLayerOptions &other) const
SaveLayerOptions with_bounds_from_caller() const
SaveLayerOptions(const SaveLayerOptions *options)
bool bounds_from_caller() const
bool content_is_unbounded() const
bool bounds_were_calculated() const
SaveLayerOptions with_contains_backdrop_filter() const
SaveLayerOptions without_bounds_from_caller() const
static const SaveLayerOptions kWithAttributes
SaveLayerOptions without_optimizations() const
bool contains_backdrop_filter() const
SaveLayerOptions with_content_is_clipped() const
SaveLayerOptions(const SaveLayerOptions &options)
bool can_distribute_opacity() const
#define FOR_EACH_DISPLAY_LIST_OP(V)
#define DL_OP_TO_ENUM_VALUE(name)
int32_t value
uint32_t DlIndex
DisplayListOpCategory
BlendMode
Definition color.h:58