Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit c4b0184

Browse files
authored
[DisplayList] Remove legacy size fields in DLOp records (#56101)
After landing #54676 we had the DLBuilder using legacy size fields in the DLOp records to manage traversing the records, but we constructed a more direct "offset vector" for the DisplayList to enable random access to the ops. The offset vector was created on the fly during the `Build()` method and then the size fields in the DLOp records were largely unused and redundant. This PR gets rid of the remaining uses of the DLOp size fields and has the Builder produce the offsets vector directly during recording.
1 parent b1c2ba8 commit c4b0184

12 files changed

+497
-265
lines changed

ci/licenses_golden/excluded_files

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
../../../flutter/display_list/display_list_unittests.cc
3535
../../../flutter/display_list/dl_color_unittests.cc
3636
../../../flutter/display_list/dl_paint_unittests.cc
37+
../../../flutter/display_list/dl_storage_unittests.cc
3738
../../../flutter/display_list/dl_vertices_unittests.cc
3839
../../../flutter/display_list/effects/dl_color_filter_unittests.cc
3940
../../../flutter/display_list/effects/dl_color_source_unittests.cc

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42525,6 +42525,8 @@ ORIGIN: ../../../flutter/display_list/dl_op_records.h + ../../../flutter/LICENSE
4252542525
ORIGIN: ../../../flutter/display_list/dl_paint.cc + ../../../flutter/LICENSE
4252642526
ORIGIN: ../../../flutter/display_list/dl_paint.h + ../../../flutter/LICENSE
4252742527
ORIGIN: ../../../flutter/display_list/dl_sampling_options.h + ../../../flutter/LICENSE
42528+
ORIGIN: ../../../flutter/display_list/dl_storage.cc + ../../../flutter/LICENSE
42529+
ORIGIN: ../../../flutter/display_list/dl_storage.h + ../../../flutter/LICENSE
4252842530
ORIGIN: ../../../flutter/display_list/dl_tile_mode.h + ../../../flutter/LICENSE
4252942531
ORIGIN: ../../../flutter/display_list/dl_vertices.cc + ../../../flutter/LICENSE
4253042532
ORIGIN: ../../../flutter/display_list/dl_vertices.h + ../../../flutter/LICENSE
@@ -45386,6 +45388,8 @@ FILE: ../../../flutter/display_list/dl_op_records.h
4538645388
FILE: ../../../flutter/display_list/dl_paint.cc
4538745389
FILE: ../../../flutter/display_list/dl_paint.h
4538845390
FILE: ../../../flutter/display_list/dl_sampling_options.h
45391+
FILE: ../../../flutter/display_list/dl_storage.cc
45392+
FILE: ../../../flutter/display_list/dl_storage.h
4538945393
FILE: ../../../flutter/display_list/dl_tile_mode.h
4539045394
FILE: ../../../flutter/display_list/dl_vertices.cc
4539145395
FILE: ../../../flutter/display_list/dl_vertices.h

display_list/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ source_set("display_list") {
4242
"dl_paint.cc",
4343
"dl_paint.h",
4444
"dl_sampling_options.h",
45+
"dl_storage.cc",
46+
"dl_storage.h",
4547
"dl_tile_mode.h",
4648
"dl_vertices.cc",
4749
"dl_vertices.h",
@@ -111,6 +113,7 @@ if (enable_unittests) {
111113
"display_list_unittests.cc",
112114
"dl_color_unittests.cc",
113115
"dl_paint_unittests.cc",
116+
"dl_storage_unittests.cc",
114117
"dl_vertices_unittests.cc",
115118
"effects/dl_color_filter_unittests.cc",
116119
"effects/dl_color_source_unittests.cc",

display_list/display_list.cc

Lines changed: 55 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ const SaveLayerOptions SaveLayerOptions::kWithAttributes =
1515
kNoAttributes.with_renders_with_attributes();
1616

1717
DisplayList::DisplayList()
18-
: byte_count_(0),
19-
op_count_(0),
18+
: op_count_(0),
2019
nested_byte_count_(0),
2120
nested_op_count_(0),
2221
total_depth_(0),
@@ -27,25 +26,13 @@ DisplayList::DisplayList()
2726
modifies_transparent_black_(false),
2827
root_has_backdrop_filter_(false),
2928
root_is_unbounded_(false),
30-
max_root_blend_mode_(DlBlendMode::kClear) {}
31-
32-
// Eventually we should rework DisplayListBuilder to compute these and
33-
// deliver the vector alongside the storage.
34-
static std::vector<size_t> MakeOffsets(const DisplayListStorage& storage,
35-
size_t byte_count) {
36-
std::vector<size_t> offsets;
37-
const uint8_t* start = storage.get();
38-
const uint8_t* end = start + byte_count;
39-
const uint8_t* ptr = start;
40-
while (ptr < end) {
41-
offsets.push_back(ptr - start);
42-
ptr += reinterpret_cast<const DLOp*>(ptr)->size;
43-
}
44-
return offsets;
29+
max_root_blend_mode_(DlBlendMode::kClear) {
30+
FML_DCHECK(offsets_.size() == 0u);
31+
FML_DCHECK(storage_.size() == 0u);
4532
}
4633

4734
DisplayList::DisplayList(DisplayListStorage&& storage,
48-
size_t byte_count,
35+
std::vector<size_t>&& offsets,
4936
uint32_t op_count,
5037
size_t nested_byte_count,
5138
uint32_t nested_op_count,
@@ -59,8 +46,7 @@ DisplayList::DisplayList(DisplayListStorage&& storage,
5946
bool root_is_unbounded,
6047
sk_sp<const DlRTree> rtree)
6148
: storage_(std::move(storage)),
62-
offsets_(MakeOffsets(storage_, byte_count)),
63-
byte_count_(byte_count),
49+
offsets_(std::move(offsets)),
6450
op_count_(op_count),
6551
nested_byte_count_(nested_byte_count),
6652
nested_op_count_(nested_op_count),
@@ -73,11 +59,12 @@ DisplayList::DisplayList(DisplayListStorage&& storage,
7359
root_has_backdrop_filter_(root_has_backdrop_filter),
7460
root_is_unbounded_(root_is_unbounded),
7561
max_root_blend_mode_(max_root_blend_mode),
76-
rtree_(std::move(rtree)) {}
62+
rtree_(std::move(rtree)) {
63+
FML_DCHECK(storage_.capacity() == storage_.size());
64+
}
7765

7866
DisplayList::~DisplayList() {
79-
const uint8_t* ptr = storage_.get();
80-
DisposeOps(ptr, ptr + byte_count_);
67+
DisposeOps(storage_, offsets_);
8168
}
8269

8370
uint32_t DisplayList::next_unique_id() {
@@ -132,7 +119,7 @@ void DisplayList::RTreeResultsToIndexVector(
132119
return;
133120
}
134121
}
135-
const uint8_t* ptr = storage_.get() + offsets_[index];
122+
const uint8_t* ptr = storage_.base() + offsets_[index];
136123
const DLOp* op = reinterpret_cast<const DLOp*>(ptr);
137124
switch (GetOpCategory(op->type)) {
138125
case DisplayListOpCategory::kAttribute:
@@ -193,7 +180,7 @@ void DisplayList::RTreeResultsToIndexVector(
193180
}
194181

195182
void DisplayList::Dispatch(DlOpReceiver& receiver) const {
196-
const uint8_t* base = storage_.get();
183+
const uint8_t* base = storage_.base();
197184
for (size_t offset : offsets_) {
198185
DispatchOneOp(receiver, base + offset);
199186
}
@@ -213,7 +200,7 @@ void DisplayList::Dispatch(DlOpReceiver& receiver,
213200
Dispatch(receiver);
214201
} else {
215202
auto op_indices = GetCulledIndices(cull_rect);
216-
const uint8_t* base = storage_.get();
203+
const uint8_t* base = storage_.base();
217204
for (DlIndex index : op_indices) {
218205
DispatchOneOp(receiver, base + offsets_[index]);
219206
}
@@ -240,11 +227,14 @@ void DisplayList::DispatchOneOp(DlOpReceiver& receiver,
240227
}
241228
}
242229

243-
void DisplayList::DisposeOps(const uint8_t* ptr, const uint8_t* end) {
244-
while (ptr < end) {
245-
auto op = reinterpret_cast<const DLOp*>(ptr);
246-
ptr += op->size;
247-
FML_DCHECK(ptr <= end);
230+
void 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);
248238
switch (op->type) {
249239
#define DL_OP_DISPOSE(name) \
250240
case DisplayListOpType::k##name: \
@@ -362,10 +352,9 @@ DisplayListOpType DisplayList::GetOpType(DlIndex index) const {
362352
}
363353

364354
size_t offset = offsets_[index];
365-
FML_DCHECK(offset < byte_count_);
366-
auto ptr = storage_.get() + offset;
355+
FML_DCHECK(offset < storage_.size());
356+
auto ptr = storage_.base() + offset;
367357
auto op = reinterpret_cast<const DLOp*>(ptr);
368-
FML_DCHECK(ptr + op->size <= storage_.get() + byte_count_);
369358
return op->type;
370359
}
371360

@@ -399,34 +388,32 @@ bool DisplayList::Dispatch(DlOpReceiver& receiver, DlIndex index) const {
399388
}
400389

401390
size_t offset = offsets_[index];
402-
FML_DCHECK(offset < byte_count_);
403-
auto ptr = storage_.get() + offset;
404-
FML_DCHECK(offset + reinterpret_cast<const DLOp*>(ptr)->size <= byte_count_);
391+
FML_DCHECK(offset < storage_.size());
392+
auto ptr = storage_.base() + offset;
405393

406394
DispatchOneOp(receiver, ptr);
407395

408396
return true;
409397
}
410398

411-
static bool CompareOps(const uint8_t* ptrA,
412-
const uint8_t* endA,
413-
const uint8_t* ptrB,
414-
const uint8_t* endB) {
399+
static bool CompareOps(const DisplayListStorage& storageA,
400+
const std::vector<size_t>& offsetsA,
401+
const DisplayListStorage& storageB,
402+
const std::vector<size_t>& offsetsB) {
403+
const uint8_t* base_a = storageA.base();
404+
const uint8_t* base_b = storageB.base();
415405
// These conditions are checked by the caller...
416-
FML_DCHECK((endA - ptrA) == (endB - ptrB));
417-
FML_DCHECK(ptrA != ptrB);
418-
const uint8_t* bulk_start_a = ptrA;
419-
const uint8_t* bulk_start_b = ptrB;
420-
while (ptrA < endA && ptrB < endB) {
421-
auto opA = reinterpret_cast<const DLOp*>(ptrA);
422-
auto opB = reinterpret_cast<const DLOp*>(ptrB);
423-
if (opA->type != opB->type || opA->size != opB->size) {
406+
FML_DCHECK(offsetsA.size() == offsetsB.size());
407+
FML_DCHECK(base_a != base_b);
408+
size_t bulk_start = 0u;
409+
for (size_t i = 0; i < offsetsA.size(); i++) {
410+
size_t offset = offsetsA[i];
411+
FML_DCHECK(offsetsB[i] == offset);
412+
auto opA = reinterpret_cast<const DLOp*>(base_a + offset);
413+
auto opB = reinterpret_cast<const DLOp*>(base_b + offset);
414+
if (opA->type != opB->type) {
424415
return false;
425416
}
426-
ptrA += opA->size;
427-
ptrB += opB->size;
428-
FML_DCHECK(ptrA <= endA);
429-
FML_DCHECK(ptrB <= endB);
430417
DisplayListCompare result;
431418
switch (opA->type) {
432419
#define DL_OP_EQUALS(name) \
@@ -451,23 +438,23 @@ static bool CompareOps(const uint8_t* ptrA,
451438
case DisplayListCompare::kEqual:
452439
// Check if we have a backlog of bytes to bulk compare and then
453440
// reset the bulk compare pointers to the address following this op
454-
auto bulk_bytes = reinterpret_cast<const uint8_t*>(opA) - bulk_start_a;
455-
if (bulk_bytes > 0) {
456-
if (memcmp(bulk_start_a, bulk_start_b, bulk_bytes) != 0) {
441+
if (bulk_start < offset) {
442+
const uint8_t* bulk_start_a = base_a + bulk_start;
443+
const uint8_t* bulk_start_b = base_b + bulk_start;
444+
if (memcmp(bulk_start_a, bulk_start_b, offset - bulk_start) != 0) {
457445
return false;
458446
}
459447
}
460-
bulk_start_a = ptrA;
461-
bulk_start_b = ptrB;
448+
bulk_start =
449+
i + 1 < offsetsA.size() ? offsetsA[i + 1] : storageA.size();
462450
break;
463451
}
464452
}
465-
if (ptrA != endA || ptrB != endB) {
466-
return false;
467-
}
468-
if (bulk_start_a < ptrA) {
453+
if (bulk_start < storageA.size()) {
469454
// Perform a final bulk compare if we have remaining bytes waiting
470-
if (memcmp(bulk_start_a, bulk_start_b, ptrA - bulk_start_a) != 0) {
455+
const uint8_t* bulk_start_a = base_a + bulk_start;
456+
const uint8_t* bulk_start_b = base_b + bulk_start;
457+
if (memcmp(bulk_start_a, bulk_start_b, storageA.size() - bulk_start) != 0) {
471458
return false;
472459
}
473460
}
@@ -478,15 +465,15 @@ bool DisplayList::Equals(const DisplayList* other) const {
478465
if (this == other) {
479466
return true;
480467
}
481-
if (byte_count_ != other->byte_count_ || op_count_ != other->op_count_) {
468+
if (offsets_.size() != other->offsets_.size() ||
469+
storage_.size() != other->storage_.size() ||
470+
op_count_ != other->op_count_) {
482471
return false;
483472
}
484-
const uint8_t* ptr = storage_.get();
485-
const uint8_t* o_ptr = other->storage_.get();
486-
if (ptr == o_ptr) {
473+
if (storage_.base() == other->storage_.base()) {
487474
return true;
488475
}
489-
return CompareOps(ptr, ptr + byte_count_, o_ptr, o_ptr + other->byte_count_);
476+
return CompareOps(storage_, offsets_, other->storage_, other->offsets_);
490477
}
491478

492479
} // namespace flutter

display_list/display_list.h

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,10 @@
55
#ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_H_
66
#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_H_
77

8-
#include <memory>
9-
#include <optional>
10-
118
#include "flutter/display_list/dl_blend_mode.h"
12-
#include "flutter/display_list/dl_sampling_options.h"
9+
#include "flutter/display_list/dl_storage.h"
1310
#include "flutter/display_list/geometry/dl_geometry_types.h"
1411
#include "flutter/display_list/geometry/dl_rtree.h"
15-
#include "flutter/fml/logging.h"
1612

1713
// The Flutter DisplayList mechanism encapsulates a persistent sequence of
1814
// rendering operations.
@@ -263,28 +259,6 @@ class SaveLayerOptions {
263259
};
264260
};
265261

266-
// Manages a buffer allocated with malloc.
267-
class DisplayListStorage {
268-
public:
269-
DisplayListStorage() = default;
270-
DisplayListStorage(DisplayListStorage&&) = default;
271-
272-
uint8_t* get() { return ptr_.get(); }
273-
274-
const uint8_t* get() const { return ptr_.get(); }
275-
276-
void realloc(size_t count) {
277-
ptr_.reset(static_cast<uint8_t*>(std::realloc(ptr_.release(), count)));
278-
FML_CHECK(ptr_);
279-
}
280-
281-
private:
282-
struct FreeDeleter {
283-
void operator()(uint8_t* p) { std::free(p); }
284-
};
285-
std::unique_ptr<uint8_t, FreeDeleter> ptr_;
286-
};
287-
288262
using DlIndex = uint32_t;
289263

290264
// The base class that contains a sequence of rendering operations
@@ -304,7 +278,7 @@ class DisplayList : public SkRefCnt {
304278
// but nested ops are only included if requested. The defaults used
305279
// here for these accessors follow that pattern.
306280
size_t bytes(bool nested = true) const {
307-
return sizeof(DisplayList) + byte_count_ +
281+
return sizeof(DisplayList) + storage_.size() +
308282
(nested ? nested_byte_count_ : 0);
309283
}
310284

@@ -530,7 +504,7 @@ class DisplayList : public SkRefCnt {
530504

531505
private:
532506
DisplayList(DisplayListStorage&& ptr,
533-
size_t byte_count,
507+
std::vector<size_t>&& offsets,
534508
uint32_t op_count,
535509
size_t nested_byte_count,
536510
uint32_t nested_op_count,
@@ -546,13 +520,13 @@ class DisplayList : public SkRefCnt {
546520

547521
static uint32_t next_unique_id();
548522

549-
static void DisposeOps(const uint8_t* ptr, const uint8_t* end);
523+
static void DisposeOps(const DisplayListStorage& storage,
524+
const std::vector<size_t>& offsets);
550525

551526
const DisplayListStorage storage_;
552527
const std::vector<size_t> offsets_;
553-
const size_t byte_count_;
554-
const uint32_t op_count_;
555528

529+
const uint32_t op_count_;
556530
const size_t nested_byte_count_;
557531
const uint32_t nested_op_count_;
558532

0 commit comments

Comments
 (0)