Skip to content

Commit 5d0c8dd

Browse files
authored
Rtree from displaylist (flutter#34809)
1 parent 5211c9c commit 5d0c8dd

File tree

10 files changed

+611
-101
lines changed

10 files changed

+611
-101
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ FILE: ../../../flutter/display_list/display_list_paint_unittests.cc
100100
FILE: ../../../flutter/display_list/display_list_path_effect.cc
101101
FILE: ../../../flutter/display_list/display_list_path_effect.h
102102
FILE: ../../../flutter/display_list/display_list_path_effect_unittests.cc
103+
FILE: ../../../flutter/display_list/display_list_rtree.cc
104+
FILE: ../../../flutter/display_list/display_list_rtree.h
103105
FILE: ../../../flutter/display_list/display_list_sampling_options.h
104106
FILE: ../../../flutter/display_list/display_list_test_utils.cc
105107
FILE: ../../../flutter/display_list/display_list_test_utils.h

display_list/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ source_set("display_list") {
4949
"display_list_paint.h",
5050
"display_list_path_effect.cc",
5151
"display_list_path_effect.h",
52+
"display_list_rtree.cc",
53+
"display_list_rtree.h",
5254
"display_list_sampling_options.h",
5355
"display_list_tile_mode.h",
5456
"display_list_utils.cc",

display_list/display_list.cc

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,23 @@ DisplayList::~DisplayList() {
5353
}
5454

5555
void DisplayList::ComputeBounds() {
56-
DisplayListBoundsCalculator calculator(&bounds_cull_);
56+
RectBoundsAccumulator accumulator;
57+
DisplayListBoundsCalculator calculator(accumulator, &bounds_cull_);
5758
Dispatch(calculator);
58-
bounds_ = calculator.bounds();
59+
if (calculator.is_unbounded()) {
60+
FML_LOG(INFO) << "returning partial bounds for unbounded DisplayList";
61+
}
62+
bounds_ = accumulator.bounds();
63+
}
64+
65+
void DisplayList::ComputeRTree() {
66+
RTreeBoundsAccumulator accumulator;
67+
DisplayListBoundsCalculator calculator(accumulator, &bounds_cull_);
68+
Dispatch(calculator);
69+
if (calculator.is_unbounded()) {
70+
FML_LOG(INFO) << "returning partial rtree for unbounded DisplayList";
71+
}
72+
rtree_ = accumulator.rtree();
5973
}
6074

6175
void DisplayList::Dispatch(Dispatcher& dispatcher,

display_list/display_list.h

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

8+
#include <memory>
89
#include <optional>
910

11+
#include "flutter/display_list/display_list_rtree.h"
1012
#include "flutter/display_list/display_list_sampling_options.h"
1113
#include "flutter/display_list/types.h"
1214
#include "flutter/fml/logging.h"
@@ -254,6 +256,13 @@ class DisplayList : public SkRefCnt {
254256
return bounds_;
255257
}
256258

259+
sk_sp<const DlRTree> rtree() {
260+
if (!rtree_) {
261+
ComputeRTree();
262+
}
263+
return rtree_;
264+
}
265+
257266
bool Equals(const DisplayList* other) const;
258267
bool Equals(const DisplayList& other) const { return Equals(&other); }
259268
bool Equals(sk_sp<const DisplayList> other) const {
@@ -282,13 +291,15 @@ class DisplayList : public SkRefCnt {
282291

283292
uint32_t unique_id_;
284293
SkRect bounds_;
294+
sk_sp<const DlRTree> rtree_;
285295

286296
// Only used for drawPaint() and drawColor()
287297
SkRect bounds_cull_;
288298

289299
bool can_apply_group_opacity_;
290300

291301
void ComputeBounds();
302+
void ComputeRTree();
292303
void Dispatch(Dispatcher& ctx, uint8_t* ptr, uint8_t* end) const;
293304

294305
friend class DisplayListBuilder;

display_list/display_list_rtree.cc

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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 "flutter/display_list/display_list_rtree.h"
6+
7+
#include "flutter/fml/logging.h"
8+
9+
namespace flutter {
10+
11+
DlRTree::DlRTree() : bbh_{SkRTreeFactory{}()}, all_ops_count_(0) {}
12+
13+
void DlRTree::insert(const SkRect boundsArray[],
14+
const SkBBoxHierarchy::Metadata metadata[],
15+
int N) {
16+
FML_DCHECK(0 == all_ops_count_);
17+
bbh_->insert(boundsArray, metadata, N);
18+
for (int i = 0; i < N; i++) {
19+
if (metadata == nullptr || metadata[i].isDraw) {
20+
draw_op_[i] = boundsArray[i];
21+
}
22+
}
23+
all_ops_count_ = N;
24+
}
25+
26+
void DlRTree::insert(const SkRect boundsArray[], int N) {
27+
insert(boundsArray, nullptr, N);
28+
}
29+
30+
void DlRTree::search(const SkRect& query, std::vector<int>* results) const {
31+
bbh_->search(query, results);
32+
}
33+
34+
std::list<SkRect> DlRTree::searchNonOverlappingDrawnRects(
35+
const SkRect& query) const {
36+
// Get the indexes for the operations that intersect with the query rect.
37+
std::vector<int> intermediary_results;
38+
search(query, &intermediary_results);
39+
40+
std::list<SkRect> final_results;
41+
for (int index : intermediary_results) {
42+
auto draw_op = draw_op_.find(index);
43+
// Ignore records that don't draw anything.
44+
if (draw_op == draw_op_.end()) {
45+
continue;
46+
}
47+
auto current_record_rect = draw_op->second;
48+
auto replaced_existing_rect = false;
49+
// // If the current record rect intersects with any of the rects in the
50+
// // result list, then join them, and update the rect in final_results.
51+
std::list<SkRect>::iterator curr_rect_itr = final_results.begin();
52+
std::list<SkRect>::iterator first_intersecting_rect_itr;
53+
while (!replaced_existing_rect && curr_rect_itr != final_results.end()) {
54+
if (SkRect::Intersects(*curr_rect_itr, current_record_rect)) {
55+
replaced_existing_rect = true;
56+
first_intersecting_rect_itr = curr_rect_itr;
57+
curr_rect_itr->join(current_record_rect);
58+
}
59+
curr_rect_itr++;
60+
}
61+
// It's possible that the result contains duplicated rects at this point.
62+
// For example, consider a result list that contains rects A, B. If a
63+
// new rect C is a superset of A and B, then A and B are the same set after
64+
// the merge. As a result, find such cases and remove them from the result
65+
// list.
66+
while (replaced_existing_rect && curr_rect_itr != final_results.end()) {
67+
if (SkRect::Intersects(*curr_rect_itr, *first_intersecting_rect_itr)) {
68+
first_intersecting_rect_itr->join(*curr_rect_itr);
69+
curr_rect_itr = final_results.erase(curr_rect_itr);
70+
} else {
71+
curr_rect_itr++;
72+
}
73+
}
74+
if (!replaced_existing_rect) {
75+
final_results.push_back(current_record_rect);
76+
}
77+
}
78+
return final_results;
79+
}
80+
81+
size_t DlRTree::bytesUsed() const {
82+
return bbh_->bytesUsed();
83+
}
84+
85+
DlRTreeFactory::DlRTreeFactory() {
86+
r_tree_ = sk_make_sp<DlRTree>();
87+
}
88+
89+
sk_sp<DlRTree> DlRTreeFactory::getInstance() {
90+
return r_tree_;
91+
}
92+
93+
sk_sp<SkBBoxHierarchy> DlRTreeFactory::operator()() const {
94+
return r_tree_;
95+
}
96+
97+
} // namespace flutter

display_list/display_list_rtree.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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_RTREE_H_
6+
#define FLUTTER_DISPLAY_LIST_RTREE_H_
7+
8+
#include <list>
9+
#include <map>
10+
11+
#include "third_party/skia/include/core/SkBBHFactory.h"
12+
#include "third_party/skia/include/core/SkRect.h"
13+
14+
namespace flutter {
15+
16+
/**
17+
* An R-Tree implementation that forwards calls to an SkRTree. This is just
18+
* a copy of flow/rtree.h/cc until we can figure out where these utilities
19+
* can live with appropriate linking visibility.
20+
*
21+
* This implementation provides a searchNonOverlappingDrawnRects method,
22+
* which can be used to query the rects for the operations recorded in the tree.
23+
*/
24+
class DlRTree : public SkBBoxHierarchy {
25+
public:
26+
DlRTree();
27+
28+
void insert(const SkRect[],
29+
const SkBBoxHierarchy::Metadata[],
30+
int N) override;
31+
void insert(const SkRect[], int N) override;
32+
void search(const SkRect& query, std::vector<int>* results) const override;
33+
size_t bytesUsed() const override;
34+
35+
// Finds the rects in the tree that represent drawing operations and intersect
36+
// with the query rect.
37+
//
38+
// When two rects intersect with each other, they are joined into a single
39+
// rect which also intersects with the query rect. In other words, the bounds
40+
// of each rect in the result list are mutually exclusive.
41+
std::list<SkRect> searchNonOverlappingDrawnRects(const SkRect& query) const;
42+
43+
// Insertion count (not overall node count, which may be greater).
44+
int getCount() const { return all_ops_count_; }
45+
46+
private:
47+
// A map containing the draw operation rects keyed off the operation index
48+
// in the insert call.
49+
std::map<int, SkRect> draw_op_;
50+
sk_sp<SkBBoxHierarchy> bbh_;
51+
int all_ops_count_;
52+
};
53+
54+
class DlRTreeFactory : public SkBBHFactory {
55+
public:
56+
DlRTreeFactory();
57+
58+
// Gets the instance to the R-tree.
59+
sk_sp<DlRTree> getInstance();
60+
sk_sp<SkBBoxHierarchy> operator()() const override;
61+
62+
private:
63+
sk_sp<DlRTree> r_tree_;
64+
};
65+
66+
} // namespace flutter
67+
68+
#endif // FLUTTER_DISPLAY_LIST_RTREE_H_

0 commit comments

Comments
 (0)