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

Commit a8b1db1

Browse files
committed
take advantage of DisplayList culling in Impeller
1 parent 8f04b29 commit a8b1db1

File tree

9 files changed

+109
-45
lines changed

9 files changed

+109
-45
lines changed

display_list/display_list.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ void DisplayList::Dispatch(DlOpReceiver& receiver) const {
140140
Dispatch(receiver, ptr, ptr + byte_count_, NopCuller::instance);
141141
}
142142

143+
void DisplayList::Dispatch(DlOpReceiver& receiver,
144+
const SkIRect& cull_rect) const {
145+
Dispatch(receiver, SkRect::Make(cull_rect));
146+
}
147+
143148
void DisplayList::Dispatch(DlOpReceiver& receiver,
144149
const SkRect& cull_rect) const {
145150
if (cull_rect.isEmpty()) {

display_list/display_list.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ class DisplayList : public SkRefCnt {
235235

236236
void Dispatch(DlOpReceiver& ctx) const;
237237
void Dispatch(DlOpReceiver& ctx, const SkRect& cull_rect) const;
238+
void Dispatch(DlOpReceiver& ctx, const SkIRect& cull_rect) const;
238239

239240
// From historical behavior, SkPicture always included nested bytes,
240241
// but nested ops are only included if requested. The defaults used

display_list/display_list_unittests.cc

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,81 +2532,79 @@ TEST_F(DisplayListTest, RTreeRenderCulling) {
25322532
main_receiver.drawRect({20, 20, 30, 30});
25332533
auto main = main_builder.Build();
25342534

2535+
auto test = [main](SkIRect cull_rect, const sk_sp<DisplayList>& expected) {
2536+
{ // Test SkIRect culling
2537+
DisplayListBuilder culling_builder;
2538+
main->Dispatch(ToReceiver(culling_builder), cull_rect);
2539+
2540+
EXPECT_TRUE(DisplayListsEQ_Verbose(culling_builder.Build(), expected));
2541+
}
2542+
2543+
{ // Test SkRect culling
2544+
DisplayListBuilder culling_builder;
2545+
main->Dispatch(ToReceiver(culling_builder), SkRect::Make(cull_rect));
2546+
2547+
EXPECT_TRUE(DisplayListsEQ_Verbose(culling_builder.Build(), expected));
2548+
}
2549+
};
2550+
25352551
{ // No rects
2536-
SkRect cull_rect = {11, 11, 19, 19};
2552+
SkIRect cull_rect = {11, 11, 19, 19};
25372553

25382554
DisplayListBuilder expected_builder;
25392555
auto expected = expected_builder.Build();
25402556

2541-
DisplayListBuilder culling_builder(cull_rect);
2542-
main->Dispatch(ToReceiver(culling_builder), cull_rect);
2543-
2544-
EXPECT_TRUE(DisplayListsEQ_Verbose(culling_builder.Build(), expected));
2557+
test(cull_rect, expected);
25452558
}
25462559

25472560
{ // Rect 1
2548-
SkRect cull_rect = {9, 9, 19, 19};
2561+
SkIRect cull_rect = {9, 9, 19, 19};
25492562

25502563
DisplayListBuilder expected_builder;
25512564
DlOpReceiver& expected_receiver = ToReceiver(expected_builder);
25522565
expected_receiver.drawRect({0, 0, 10, 10});
25532566
auto expected = expected_builder.Build();
25542567

2555-
DisplayListBuilder culling_builder(cull_rect);
2556-
main->Dispatch(ToReceiver(culling_builder), cull_rect);
2557-
2558-
EXPECT_TRUE(DisplayListsEQ_Verbose(culling_builder.Build(), expected));
2568+
test(cull_rect, expected);
25592569
}
25602570

25612571
{ // Rect 2
2562-
SkRect cull_rect = {11, 9, 21, 19};
2572+
SkIRect cull_rect = {11, 9, 21, 19};
25632573

25642574
DisplayListBuilder expected_builder;
25652575
DlOpReceiver& expected_receiver = ToReceiver(expected_builder);
25662576
expected_receiver.drawRect({20, 0, 30, 10});
25672577
auto expected = expected_builder.Build();
25682578

2569-
DisplayListBuilder culling_builder(cull_rect);
2570-
main->Dispatch(ToReceiver(culling_builder), cull_rect);
2571-
2572-
EXPECT_TRUE(DisplayListsEQ_Verbose(culling_builder.Build(), expected));
2579+
test(cull_rect, expected);
25732580
}
25742581

25752582
{ // Rect 3
2576-
SkRect cull_rect = {9, 11, 19, 21};
2583+
SkIRect cull_rect = {9, 11, 19, 21};
25772584

25782585
DisplayListBuilder expected_builder;
25792586
DlOpReceiver& expected_receiver = ToReceiver(expected_builder);
25802587
expected_receiver.drawRect({0, 20, 10, 30});
25812588
auto expected = expected_builder.Build();
25822589

2583-
DisplayListBuilder culling_builder(cull_rect);
2584-
main->Dispatch(ToReceiver(culling_builder), cull_rect);
2585-
2586-
EXPECT_TRUE(DisplayListsEQ_Verbose(culling_builder.Build(), expected));
2590+
test(cull_rect, expected);
25872591
}
25882592

25892593
{ // Rect 4
2590-
SkRect cull_rect = {11, 11, 21, 21};
2594+
SkIRect cull_rect = {11, 11, 21, 21};
25912595

25922596
DisplayListBuilder expected_builder;
25932597
DlOpReceiver& expected_receiver = ToReceiver(expected_builder);
25942598
expected_receiver.drawRect({20, 20, 30, 30});
25952599
auto expected = expected_builder.Build();
25962600

2597-
DisplayListBuilder culling_builder(cull_rect);
2598-
main->Dispatch(ToReceiver(culling_builder), cull_rect);
2599-
2600-
EXPECT_TRUE(DisplayListsEQ_Verbose(culling_builder.Build(), expected));
2601+
test(cull_rect, expected);
26012602
}
26022603

26032604
{ // All 4 rects
2604-
SkRect cull_rect = {9, 9, 21, 21};
2605-
2606-
DisplayListBuilder culling_builder(cull_rect);
2607-
main->Dispatch(ToReceiver(culling_builder), cull_rect);
2605+
SkIRect cull_rect = {9, 9, 21, 21};
26082606

2609-
EXPECT_TRUE(DisplayListsEQ_Verbose(culling_builder.Build(), main));
2607+
test(cull_rect, main);
26102608
}
26112609
}
26122610

impeller/aiks/canvas.cc

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,25 @@
2323
namespace impeller {
2424

2525
Canvas::Canvas() {
26-
Initialize();
26+
Initialize(Rect::MakeLTRB(-1e9, -1e9, 1e9, 1e9));
27+
}
28+
29+
Canvas::Canvas(Rect cull_rect) {
30+
Initialize(cull_rect);
31+
}
32+
33+
Canvas::Canvas(IRect cull_rect) {
34+
Initialize(Rect::MakeLTRB(cull_rect.GetLeft(), cull_rect.GetTop(),
35+
cull_rect.GetRight(), cull_rect.GetBottom()));
2736
}
2837

2938
Canvas::~Canvas() = default;
3039

31-
void Canvas::Initialize() {
40+
void Canvas::Initialize(Rect cull_rect) {
41+
initial_cull_rect_ = cull_rect;
3242
base_pass_ = std::make_unique<EntityPass>();
3343
current_pass_ = base_pass_.get();
34-
xformation_stack_.emplace_back(CanvasStackEntry{});
44+
xformation_stack_.emplace_back(CanvasStackEntry{.clip_bounds = cull_rect});
3545
lazy_glyph_atlas_ = std::make_shared<LazyGlyphAtlas>();
3646
FML_DCHECK(GetSaveCount() == 1u);
3747
FML_DCHECK(base_pass_->GetSubpassesDepth() == 1u);
@@ -54,6 +64,7 @@ void Canvas::Save(
5464
std::optional<EntityPass::BackdropFilterProc> backdrop_filter) {
5565
auto entry = CanvasStackEntry{};
5666
entry.xformation = xformation_stack_.back().xformation;
67+
entry.clip_bounds = xformation_stack_.back().clip_bounds;
5768
entry.stencil_depth = xformation_stack_.back().stencil_depth;
5869
if (create_subpass) {
5970
entry.is_subpass = true;
@@ -109,6 +120,11 @@ const Matrix& Canvas::GetCurrentTransformation() const {
109120
return xformation_stack_.back().xformation;
110121
}
111122

123+
const Rect Canvas::GetCurrentLocalClipBounds() const {
124+
Matrix inverse = xformation_stack_.back().xformation.Invert();
125+
return xformation_stack_.back().clip_bounds.TransformBounds(inverse);
126+
}
127+
112128
void Canvas::Translate(const Vector3& offset) {
113129
Concat(Matrix::MakeTranslation(offset));
114130
}
@@ -257,21 +273,22 @@ void Canvas::DrawCircle(Point center, Scalar radius, const Paint& paint) {
257273
}
258274

259275
void Canvas::ClipPath(const Path& path, Entity::ClipOperation clip_op) {
260-
ClipGeometry(Geometry::MakeFillPath(path), clip_op);
276+
ClipGeometry(Geometry::MakeFillPath(path), clip_op, path.GetBoundingBox());
261277
}
262278

263279
void Canvas::ClipRect(const Rect& rect, Entity::ClipOperation clip_op) {
264-
ClipGeometry(Geometry::MakeRect(rect), clip_op);
280+
ClipGeometry(Geometry::MakeRect(rect), clip_op, rect);
265281
}
266282

267283
void Canvas::ClipRRect(const Rect& rect,
268284
Scalar corner_radius,
269285
Entity::ClipOperation clip_op) {
270-
ClipGeometry(Geometry::MakeRRect(rect, corner_radius), clip_op);
286+
ClipGeometry(Geometry::MakeRRect(rect, corner_radius), clip_op, rect);
271287
}
272288

273289
void Canvas::ClipGeometry(std::unique_ptr<Geometry> geometry,
274-
Entity::ClipOperation clip_op) {
290+
Entity::ClipOperation clip_op,
291+
std::optional<Rect> geometry_bounds) {
275292
auto contents = std::make_shared<ClipContents>();
276293
contents->SetGeometry(std::move(geometry));
277294
contents->SetClipOperation(clip_op);
@@ -283,6 +300,19 @@ void Canvas::ClipGeometry(std::unique_ptr<Geometry> geometry,
283300

284301
GetCurrentPass().AddEntity(entity);
285302

303+
if (geometry_bounds.has_value()) {
304+
if (clip_op == Entity::ClipOperation::kIntersect) {
305+
Rect transformed =
306+
geometry_bounds.value().TransformBounds(GetCurrentTransformation());
307+
auto new_bounds =
308+
xformation_stack_.back().clip_bounds.Intersection(transformed);
309+
xformation_stack_.back().clip_bounds = new_bounds.value_or(Rect{});
310+
}
311+
// else if kDifference we could chop off a side of the clip_bounds if
312+
// the subtracted geometry was a rectangle and it spans the height or
313+
// width of the current bounds.
314+
}
315+
286316
++xformation_stack_.back().stencil_depth;
287317
xformation_stack_.back().contains_clips = true;
288318
}
@@ -364,7 +394,7 @@ Picture Canvas::EndRecordingAsPicture() {
364394
picture.pass = std::move(base_pass_);
365395

366396
Reset();
367-
Initialize();
397+
Initialize(initial_cull_rect_);
368398

369399
return picture;
370400
}

impeller/aiks/canvas.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ class Canvas {
4040

4141
Canvas();
4242

43+
explicit Canvas(Rect cull_rect);
44+
45+
explicit Canvas(IRect cull_rect);
46+
4347
~Canvas();
4448

4549
void Save();
@@ -57,6 +61,8 @@ class Canvas {
5761

5862
const Matrix& GetCurrentTransformation() const;
5963

64+
const Rect GetCurrentLocalClipBounds() const;
65+
6066
void ResetTransform();
6167

6268
void Transform(const Matrix& xformation);
@@ -135,8 +141,9 @@ class Canvas {
135141
EntityPass* current_pass_ = nullptr;
136142
std::deque<CanvasStackEntry> xformation_stack_;
137143
std::shared_ptr<LazyGlyphAtlas> lazy_glyph_atlas_;
144+
Rect initial_cull_rect_;
138145

139-
void Initialize();
146+
void Initialize(Rect cull_rect);
140147

141148
void Reset();
142149

@@ -145,7 +152,8 @@ class Canvas {
145152
size_t GetStencilDepth() const;
146153

147154
void ClipGeometry(std::unique_ptr<Geometry> geometry,
148-
Entity::ClipOperation clip_op);
155+
Entity::ClipOperation clip_op,
156+
std::optional<Rect> geometry_bounds);
149157

150158
void Save(bool create_subpass,
151159
BlendMode = BlendMode::kSourceOver,

impeller/display_list/dl_dispatcher.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ namespace impeller {
4343

4444
DlDispatcher::DlDispatcher() = default;
4545

46+
DlDispatcher::DlDispatcher(Rect cull_rect) : canvas_(cull_rect) {}
47+
48+
DlDispatcher::DlDispatcher(IRect cull_rect) : canvas_(cull_rect) {}
49+
4650
DlDispatcher::~DlDispatcher() = default;
4751

4852
static BlendMode ToBlendMode(flutter::DlBlendMode mode) {
@@ -1053,7 +1057,15 @@ void DlDispatcher::drawDisplayList(
10531057
canvas_.SaveLayer(save_paint);
10541058
}
10551059

1056-
display_list->Dispatch(*this);
1060+
if (display_list->rtree()) {
1061+
Rect clip_bounds = canvas_.GetCurrentLocalClipBounds();
1062+
display_list->Dispatch(
1063+
*this,
1064+
SkRect::MakeLTRB(clip_bounds.GetLeft(), clip_bounds.GetTop(),
1065+
clip_bounds.GetRight(), clip_bounds.GetBottom()));
1066+
} else {
1067+
display_list->Dispatch(*this);
1068+
}
10571069

10581070
// Restore all saved state back to what it was before we interpreted
10591071
// the display_list

impeller/display_list/dl_dispatcher.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ class DlDispatcher final : public flutter::DlOpReceiver {
1515
public:
1616
DlDispatcher();
1717

18+
explicit DlDispatcher(Rect cull_rect);
19+
20+
explicit DlDispatcher(IRect cull_rect);
21+
1822
~DlDispatcher();
1923

2024
Picture EndRecordingAsPicture();

impeller/entity/entity_pass.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ class EntityPass {
236236

237237
struct CanvasStackEntry {
238238
Matrix xformation;
239+
Rect clip_bounds;
239240
size_t stencil_depth = 0u;
240241
bool is_subpass = false;
241242
bool contains_clips = false;

shell/gpu/gpu_surface_metal_impeller.mm

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@
104104
damage_[texture] = SkIRect::MakeEmpty();
105105
}
106106

107+
std::optional<SkIRect> buffer_damage = surface_frame.submit_info().buffer_damage;
107108
std::optional<impeller::IRect> clip_rect;
108-
if (surface_frame.submit_info().buffer_damage.has_value()) {
109-
auto buffer_damage = surface_frame.submit_info().buffer_damage;
109+
if (buffer_damage.has_value()) {
110110
clip_rect = impeller::IRect::MakeXYWH(buffer_damage->x(), buffer_damage->y(),
111111
buffer_damage->width(), buffer_damage->height());
112112
}
@@ -118,8 +118,13 @@
118118
return surface->Present();
119119
}
120120

121-
impeller::DlDispatcher impeller_dispatcher;
122-
display_list->Dispatch(impeller_dispatcher);
121+
if (!buffer_damage.has_value()) {
122+
auto size = surface->GetSize();
123+
buffer_damage = SkIRect::MakeWH(size.width, size.height);
124+
clip_rect = impeller::IRect::MakeXYWH(0, 0, size.width, size.height);
125+
}
126+
impeller::DlDispatcher impeller_dispatcher(clip_rect.value());
127+
display_list->Dispatch(impeller_dispatcher, buffer_damage.value());
123128
auto picture = impeller_dispatcher.EndRecordingAsPicture();
124129

125130
return renderer->Render(

0 commit comments

Comments
 (0)