Flutter Engine
 
Loading...
Searching...
No Matches
display_list.cc
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#include <type_traits>
6
11
12namespace flutter {
13
16 kNoAttributes.with_renders_with_attributes();
17
19 : op_count_(0),
20 nested_byte_count_(0),
21 nested_op_count_(0),
22 total_depth_(0),
23 unique_id_(0),
24 can_apply_group_opacity_(true),
25 is_ui_thread_safe_(true),
26 modifies_transparent_black_(false),
27 root_has_backdrop_filter_(false),
28 root_is_unbounded_(false),
29 max_root_blend_mode_(DlBlendMode::kClear) {
30 FML_DCHECK(offsets_.size() == 0u);
31 FML_DCHECK(storage_.size() == 0u);
32}
33
35 std::vector<size_t>&& offsets,
36 uint32_t op_count,
37 size_t nested_byte_count,
38 uint32_t nested_op_count,
39 uint32_t total_depth,
40 const DlRect& bounds,
41 bool can_apply_group_opacity,
42 bool is_ui_thread_safe,
43 bool modifies_transparent_black,
44 DlBlendMode max_root_blend_mode,
45 bool root_has_backdrop_filter,
46 bool root_is_unbounded,
47 sk_sp<const DlRTree> rtree)
48 : storage_(std::move(storage)),
49 offsets_(std::move(offsets)),
50 op_count_(op_count),
51 nested_byte_count_(nested_byte_count),
52 nested_op_count_(nested_op_count),
53 total_depth_(total_depth),
54 unique_id_(next_unique_id()),
55 bounds_(bounds),
56 can_apply_group_opacity_(can_apply_group_opacity),
57 is_ui_thread_safe_(is_ui_thread_safe),
58 modifies_transparent_black_(modifies_transparent_black),
59 root_has_backdrop_filter_(root_has_backdrop_filter),
60 root_is_unbounded_(root_is_unbounded),
61 max_root_blend_mode_(max_root_blend_mode),
62 rtree_(std::move(rtree)) {
63 FML_DCHECK(storage_.capacity() == storage_.size());
64}
65
67 DisposeOps(storage_, offsets_);
68}
69
70uint32_t DisplayList::next_unique_id() {
71 static std::atomic<uint32_t> next_id{1};
72 uint32_t id;
73 do {
74 id = next_id.fetch_add(+1, std::memory_order_relaxed);
75 } while (id == 0);
76 return id;
77}
78
87
88void DisplayList::RTreeResultsToIndexVector(
89 std::vector<DlIndex>& indices,
90 const std::vector<int>& rtree_results) const {
91 FML_DCHECK(rtree_);
92 auto cur_rect = rtree_results.begin();
93 auto end_rect = rtree_results.end();
94 if (cur_rect >= end_rect) {
95 return;
96 }
97 DlIndex next_render_index = rtree_->id(*cur_rect++);
98 DlIndex next_restore_index = std::numeric_limits<DlIndex>::max();
99 std::vector<SaveInfo> save_infos;
100 for (DlIndex index = 0u; index < offsets_.size(); index++) {
101 while (index > next_render_index) {
102 if (cur_rect < end_rect) {
103 next_render_index = rtree_->id(*cur_rect++);
104 } else {
105 // Nothing left to render.
106 // Nothing left to do, but match our restores from the stack.
107 while (!save_infos.empty()) {
108 SaveInfo& info = save_infos.back();
109 // stack top boolean tells us whether the local variable
110 // next_restore_index should be executed. The local variable
111 // then gets reset to the value stored in the stack top
112 if (info.save_was_needed) {
113 FML_DCHECK(next_restore_index < offsets_.size());
114 indices.push_back(next_restore_index);
115 }
116 next_restore_index = info.previous_restore_index;
117 save_infos.pop_back();
118 }
119 return;
120 }
121 }
122 const uint8_t* ptr = storage_.base() + offsets_[index];
123 const DLOp* op = reinterpret_cast<const DLOp*>(ptr);
124 switch (GetOpCategory(op->type)) {
126 // Attributes are always needed
127 indices.push_back(index);
128 break;
129
132 if (next_render_index < next_restore_index) {
133 indices.push_back(index);
134 }
135 break;
136
139 if (index == next_render_index) {
140 indices.push_back(index);
141 }
142 break;
143
146 bool needed = (next_render_index < next_restore_index);
147 save_infos.emplace_back(next_restore_index, needed);
148 switch (op->type) {
149 case DisplayListOpType::kSave:
150 case DisplayListOpType::kSaveLayer:
151 case DisplayListOpType::kSaveLayerBackdrop:
152 next_restore_index =
153 static_cast<const SaveOpBase*>(op)->restore_index;
154 break;
155 default:
157 }
158 if (needed) {
159 indices.push_back(index);
160 }
161 break;
162 }
163
165 FML_DCHECK(!save_infos.empty());
166 FML_DCHECK(index == next_restore_index);
167 SaveInfo& info = save_infos.back();
168 next_restore_index = info.previous_restore_index;
169 if (info.save_was_needed) {
170 indices.push_back(index);
171 }
172 save_infos.pop_back();
173 break;
174 }
175
178 }
179 }
180}
181
182void DisplayList::Dispatch(DlOpReceiver& receiver) const {
183 const uint8_t* base = storage_.base();
184 for (size_t offset : offsets_) {
185 DispatchOneOp(receiver, base + offset);
186 }
187}
188
190 const DlIRect& cull_rect) const {
191 Dispatch(receiver, DlRect::Make(cull_rect));
192}
193
195 const DlRect& cull_rect) const {
196 if (cull_rect.IsEmpty()) {
197 return;
198 }
199 if (!has_rtree() || cull_rect.Contains(GetBounds())) {
200 Dispatch(receiver);
201 } else {
202 auto op_indices = GetCulledIndices(cull_rect);
203 const uint8_t* base = storage_.base();
204 for (DlIndex index : op_indices) {
205 DispatchOneOp(receiver, base + offsets_[index]);
206 }
207 }
208}
209
210void DisplayList::DispatchOneOp(DlOpReceiver& receiver,
211 const uint8_t* ptr) const {
212 auto op = reinterpret_cast<const DLOp*>(ptr);
213 switch (op->type) {
214#define DL_OP_DISPATCH(name) \
215 case DisplayListOpType::k##name: \
216 static_cast<const name##Op*>(op)->dispatch(receiver); \
217 break;
218
220
221#undef DL_OP_DISPATCH
222
224 default:
225 FML_DCHECK(false) << "Unrecognized op type: "
226 << static_cast<int>(op->type);
227 }
228}
229
230void DisplayList::DisposeOps(const DisplayListStorage& storage,
231 const std::vector<size_t>& offsets) {
232 const uint8_t* base = storage.base();
233 if (!base) {
234 return;
235 }
236 for (size_t offset : offsets) {
237 auto op = reinterpret_cast<const DLOp*>(base + offset);
238 switch (op->type) {
239#define DL_OP_DISPOSE(name) \
240 case DisplayListOpType::k##name: \
241 if (!std::is_trivially_destructible_v<name##Op>) { \
242 static_cast<const name##Op*>(op)->~name##Op(); \
243 } \
244 break;
245
247
248#undef DL_OP_DISPOSE
249
250 default:
252 }
253 }
254}
255
259
261 switch (type) {
262 case DisplayListOpType::kSetAntiAlias:
263 case DisplayListOpType::kSetInvertColors:
264 case DisplayListOpType::kSetStrokeCap:
265 case DisplayListOpType::kSetStrokeJoin:
266 case DisplayListOpType::kSetStyle:
267 case DisplayListOpType::kSetStrokeWidth:
268 case DisplayListOpType::kSetStrokeMiter:
269 case DisplayListOpType::kSetColor:
270 case DisplayListOpType::kSetBlendMode:
271 case DisplayListOpType::kClearColorFilter:
272 case DisplayListOpType::kSetPodColorFilter:
273 case DisplayListOpType::kClearColorSource:
274 case DisplayListOpType::kSetPodColorSource:
275 case DisplayListOpType::kSetImageColorSource:
276 case DisplayListOpType::kSetRuntimeEffectColorSource:
277 case DisplayListOpType::kClearImageFilter:
278 case DisplayListOpType::kSetPodImageFilter:
279 case DisplayListOpType::kSetSharedImageFilter:
280 case DisplayListOpType::kClearMaskFilter:
281 case DisplayListOpType::kSetPodMaskFilter:
283
284 case DisplayListOpType::kSave:
286 case DisplayListOpType::kSaveLayer:
287 case DisplayListOpType::kSaveLayerBackdrop:
289 case DisplayListOpType::kRestore:
291
292 case DisplayListOpType::kTranslate:
293 case DisplayListOpType::kScale:
294 case DisplayListOpType::kRotate:
295 case DisplayListOpType::kSkew:
296 case DisplayListOpType::kTransform2DAffine:
297 case DisplayListOpType::kTransformFullPerspective:
298 case DisplayListOpType::kTransformReset:
300
301 case DisplayListOpType::kClipIntersectRect:
302 case DisplayListOpType::kClipIntersectOval:
303 case DisplayListOpType::kClipIntersectRoundRect:
304 case DisplayListOpType::kClipIntersectRoundSuperellipse:
305 case DisplayListOpType::kClipIntersectPath:
306 case DisplayListOpType::kClipDifferenceRect:
307 case DisplayListOpType::kClipDifferenceOval:
308 case DisplayListOpType::kClipDifferenceRoundRect:
309 case DisplayListOpType::kClipDifferenceRoundSuperellipse:
310 case DisplayListOpType::kClipDifferencePath:
312
313 case DisplayListOpType::kDrawPaint:
314 case DisplayListOpType::kDrawColor:
315 case DisplayListOpType::kDrawLine:
316 case DisplayListOpType::kDrawDashedLine:
317 case DisplayListOpType::kDrawRect:
318 case DisplayListOpType::kDrawOval:
319 case DisplayListOpType::kDrawCircle:
320 case DisplayListOpType::kDrawRoundRect:
321 case DisplayListOpType::kDrawDiffRoundRect:
322 case DisplayListOpType::kDrawRoundSuperellipse:
323 case DisplayListOpType::kDrawArc:
324 case DisplayListOpType::kDrawPath:
325 case DisplayListOpType::kDrawPoints:
326 case DisplayListOpType::kDrawLines:
327 case DisplayListOpType::kDrawPolygon:
328 case DisplayListOpType::kDrawVertices:
329 case DisplayListOpType::kDrawImage:
330 case DisplayListOpType::kDrawImageWithAttr:
331 case DisplayListOpType::kDrawImageRect:
332 case DisplayListOpType::kDrawImageNine:
333 case DisplayListOpType::kDrawImageNineWithAttr:
334 case DisplayListOpType::kDrawAtlas:
335 case DisplayListOpType::kDrawAtlasCulled:
336 case DisplayListOpType::kDrawText:
337 case DisplayListOpType::kDrawShadow:
338 case DisplayListOpType::kDrawShadowTransparentOccluder:
340
341 case DisplayListOpType::kDrawDisplayList:
343
346 }
347}
348
350 // Assert unsigned type so we can eliminate >= 0 comparison
351 static_assert(std::is_unsigned_v<DlIndex>);
352 if (index >= offsets_.size()) {
354 }
355
356 size_t offset = offsets_[index];
357 FML_DCHECK(offset < storage_.size());
358 auto ptr = storage_.base() + offset;
359 auto op = reinterpret_cast<const DLOp*>(ptr);
360 return op->type;
361}
362
363static void FillAllIndices(std::vector<DlIndex>& indices, DlIndex size) {
364 indices.reserve(size);
365 for (DlIndex i = 0u; i < size; i++) {
366 indices.push_back(i);
367 }
368}
369
370std::vector<DlIndex> DisplayList::GetCulledIndices(
371 const DlRect& cull_rect) const {
372 std::vector<DlIndex> indices;
373 if (!cull_rect.IsEmpty()) {
374 if (rtree_) {
375 std::vector<int> rect_indices;
376 rtree_->search(cull_rect, &rect_indices);
377 RTreeResultsToIndexVector(indices, rect_indices);
378 } else {
379 FillAllIndices(indices, offsets_.size());
380 }
381 }
382 return indices;
383}
384
385bool DisplayList::Dispatch(DlOpReceiver& receiver, DlIndex index) const {
386 // Assert unsigned type so we can eliminate >= 0 comparison
387 static_assert(std::is_unsigned_v<DlIndex>);
388 if (index >= offsets_.size()) {
389 return false;
390 }
391
392 size_t offset = offsets_[index];
393 FML_DCHECK(offset < storage_.size());
394 auto ptr = storage_.base() + offset;
395
396 DispatchOneOp(receiver, ptr);
397
398 return true;
399}
400
401static bool CompareOps(const DisplayListStorage& storageA,
402 const std::vector<size_t>& offsetsA,
403 const DisplayListStorage& storageB,
404 const std::vector<size_t>& offsetsB) {
405 const uint8_t* base_a = storageA.base();
406 const uint8_t* base_b = storageB.base();
407 // These conditions are checked by the caller...
408 FML_DCHECK(offsetsA.size() == offsetsB.size());
409 FML_DCHECK(base_a != base_b);
410 size_t bulk_start = 0u;
411 for (size_t i = 0; i < offsetsA.size(); i++) {
412 size_t offset = offsetsA[i];
413 FML_DCHECK(offsetsB[i] == offset);
414 auto opA = reinterpret_cast<const DLOp*>(base_a + offset);
415 auto opB = reinterpret_cast<const DLOp*>(base_b + offset);
416 if (opA->type != opB->type) {
417 return false;
418 }
419 DisplayListCompare result;
420 switch (opA->type) {
421#define DL_OP_EQUALS(name) \
422 case DisplayListOpType::k##name: \
423 result = static_cast<const name##Op*>(opA)->equals( \
424 static_cast<const name##Op*>(opB)); \
425 break;
426
428
429#undef DL_OP_EQUALS
430
431 default:
432 FML_DCHECK(false);
433 return false;
434 }
435 switch (result) {
437 return false;
439 break;
441 // Check if we have a backlog of bytes to bulk compare and then
442 // reset the bulk compare pointers to the address following this op
443 if (bulk_start < offset) {
444 const uint8_t* bulk_start_a = base_a + bulk_start;
445 const uint8_t* bulk_start_b = base_b + bulk_start;
446 if (memcmp(bulk_start_a, bulk_start_b, offset - bulk_start) != 0) {
447 return false;
448 }
449 }
450 bulk_start =
451 i + 1 < offsetsA.size() ? offsetsA[i + 1] : storageA.size();
452 break;
453 }
454 }
455 if (bulk_start < storageA.size()) {
456 // Perform a final bulk compare if we have remaining bytes waiting
457 const uint8_t* bulk_start_a = base_a + bulk_start;
458 const uint8_t* bulk_start_b = base_b + bulk_start;
459 if (memcmp(bulk_start_a, bulk_start_b, storageA.size() - bulk_start) != 0) {
460 return false;
461 }
462 }
463 return true;
464}
465
466bool DisplayList::Equals(const DisplayList* other) const {
467 if (this == other) {
468 return true;
469 }
470 if (offsets_.size() != other->offsets_.size() ||
471 storage_.size() != other->storage_.size() ||
472 op_count_ != other->op_count_) {
473 return false;
474 }
475 if (storage_.base() == other->storage_.base()) {
476 return true;
477 }
478 return CompareOps(storage_, offsets_, other->storage_, other->offsets_);
479}
480
481} // namespace flutter
GLenum type
DisplayListOpType GetOpType(DlIndex index) const
Return an enum describing the specific op type stored at the indicated index.
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
bool Equals(const DisplayList *other) const
bool has_rtree() 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
uint8_t * base()
Returns a pointer to the base of the storage.
Definition dl_storage.h:23
size_t size() const
Returns the currently allocated size.
Definition dl_storage.h:27
size_t capacity() const
Returns the maximum currently allocated space.
Definition dl_storage.h:30
Internal API for rendering recorded display lists to backends.
static const SaveLayerOptions kNoAttributes
SaveLayerOptions with_renders_with_attributes() const
static const SaveLayerOptions kWithAttributes
#define DL_OP_EQUALS(name)
#define DL_OP_DISPOSE(name)
#define DL_OP_DISPATCH(name)
#define FOR_EACH_DISPLAY_LIST_OP(V)
#define FML_UNREACHABLE()
Definition logging.h:128
#define FML_DCHECK(condition)
Definition logging.h:122
uint32_t DlIndex
DisplayListOpCategory
static void FillAllIndices(std::vector< DlIndex > &indices, DlIndex size)
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 keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
static bool CompareOps(const DisplayListStorage &storageA, const std::vector< size_t > &offsetsA, const DisplayListStorage &storageB, const std::vector< size_t > &offsetsB)
BlendMode
Definition color.h:58
Definition ref_ptr.h:261
flutter::SaveLayerOptions SaveLayerOptions
const DisplayListOpType type
SaveInfo(DlIndex previous_restore_index, bool save_was_needed)
DlIndex previous_restore_index
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition rect.h:297
constexpr bool Contains(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
Definition rect.h:231
static constexpr std::enable_if_t< std::is_floating_point_v< FT >, TRect > Make(const TRect< U > &rect)
Definition rect.h:157
const uintptr_t id