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

Commit c2ad385

Browse files
bderoharryterkelsen
authored andcommitted
[Impeller] Don't cull readbacks outside the damage rect. (#46705)
Resolves flutter/flutter#136058. The damage rect properly expands to include the backdrop filter readback area to a certain extent, but it suddenly gets excluded once it no longer partially overlaps with the damage rect. This caused the illusion of EntityPass improperly culling the backdrop entity, leading me into a bit of a wild goose chase. Before: https://github.com/flutter/engine/assets/919017/94b8c077-0945-4a2c-96e0-27230d980c38 After: https://github.com/flutter/engine/assets/919017/f1c78365-6e9b-46cb-9e69-33472d488831
1 parent d0cf181 commit c2ad385

4 files changed

Lines changed: 51 additions & 14 deletions

File tree

flow/diff_context.cc

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,16 @@ Damage DiffContext::ComputeDamage(const SkIRect& accumulated_buffer_damage,
123123
SkRect frame_damage(damage_);
124124

125125
for (const auto& r : readbacks_) {
126-
SkRect rect = SkRect::Make(r.rect);
127-
if (rect.intersects(frame_damage)) {
128-
frame_damage.join(rect);
129-
}
130-
if (rect.intersects(buffer_damage)) {
131-
buffer_damage.join(rect);
126+
SkRect paint_rect = SkRect::Make(r.paint_rect);
127+
SkRect readback_rect = SkRect::Make(r.readback_rect);
128+
// Changes either in readback or paint rect require repainting both readback
129+
// and paint rect.
130+
if (paint_rect.intersects(frame_damage) ||
131+
readback_rect.intersects(frame_damage)) {
132+
frame_damage.join(readback_rect);
133+
frame_damage.join(paint_rect);
134+
buffer_damage.join(readback_rect);
135+
buffer_damage.join(paint_rect);
132136
}
133137
}
134138

@@ -220,9 +224,11 @@ void DiffContext::AddExistingPaintRegion(const PaintRegion& region) {
220224
}
221225
}
222226

223-
void DiffContext::AddReadbackRegion(const SkIRect& rect) {
227+
void DiffContext::AddReadbackRegion(const SkIRect& paint_rect,
228+
const SkIRect& readback_rect) {
224229
Readback readback;
225-
readback.rect = rect;
230+
readback.paint_rect = paint_rect;
231+
readback.readback_rect = readback_rect;
226232
readback.position = rects_->size();
227233
// Push empty rect as a placeholder for position in current subtree
228234
rects_->push_back(SkRect::MakeEmpty());

flow/diff_context.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,12 @@ class DiffContext {
123123
// The idea of readback region is that if any part of the readback region
124124
// needs to be repainted, then the whole readback region must be repainted;
125125
//
126-
// Readback rect is in screen coordinates.
127-
void AddReadbackRegion(const SkIRect& rect);
126+
// paint_rect - rectangle where the filter paints contents (in screen
127+
// coordinates)
128+
// readback_rect - rectangle where the filter samples from (in screen
129+
// coordinates)
130+
void AddReadbackRegion(const SkIRect& paint_rect,
131+
const SkIRect& readback_rect);
128132

129133
// Returns the paint region for current subtree; Each rect in paint region is
130134
// in screen coordinates; Once a layer accumulates the paint regions of its
@@ -261,8 +265,11 @@ class DiffContext {
261265
// determine if subtree has any readback
262266
size_t position;
263267

264-
// readback area, in screen coordinates
265-
SkIRect rect;
268+
// Paint region of the filter performing readback, in screen coordinates.
269+
SkIRect paint_rect;
270+
271+
// Readback area of the filter, in screen coordinates.
272+
SkIRect readback_rect;
266273
};
267274

268275
std::vector<Readback> readbacks_;

flow/layers/backdrop_filter_layer.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) {
3131
SkIRect filter_input_bounds; // in screen coordinates
3232
filter_->get_input_device_bounds(
3333
filter_target_bounds, context->GetTransform3x3(), filter_input_bounds);
34-
context->AddReadbackRegion(filter_input_bounds);
34+
context->AddReadbackRegion(filter_target_bounds, filter_input_bounds);
3535
}
3636

3737
DiffChildren(context, prev);

flow/layers/backdrop_filter_layer_unittests.cc

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,6 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) {
469469
auto path1 = SkPath().addRect(SkRect::MakeLTRB(180, 180, 190, 190));
470470
l4.root()->Add(std::make_shared<MockLayer>(path1));
471471
damage = DiffLayerTree(l4, l3);
472-
473472
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(180, 180, 190, 190));
474473

475474
MockLayerTree l5;
@@ -482,6 +481,31 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) {
482481
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 190, 190));
483482
}
484483

484+
TEST_F(BackdropLayerDiffTest, ReadbackOutsideOfPaintArea) {
485+
auto filter = DlMatrixImageFilter(SkMatrix::Translate(50, 50),
486+
DlImageSampling::kLinear);
487+
488+
MockLayerTree l1(SkISize::Make(100, 100));
489+
490+
auto clip = std::make_shared<ClipRectLayer>(SkRect::MakeLTRB(60, 60, 80, 80),
491+
Clip::hardEdge);
492+
clip->Add(std::make_shared<BackdropFilterLayer>(filter.shared(),
493+
DlBlendMode::kSrcOver));
494+
l1.root()->Add(clip);
495+
auto damage = DiffLayerTree(l1, MockLayerTree(SkISize::Make(100, 100)));
496+
497+
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(60 - 50, 60 - 50, 80, 80));
498+
499+
MockLayerTree l2(SkISize::Make(100, 100));
500+
// path inside readback area must trigger whole readback repaint + filter
501+
// repaint.
502+
auto path2 = SkPath().addRect(SkRect::MakeXYWH(60 - 50, 60 - 50, 10, 10));
503+
l2.root()->Add(clip);
504+
l2.root()->Add(std::make_shared<MockLayer>(path2));
505+
damage = DiffLayerTree(l2, l1);
506+
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(60 - 50, 60 - 50, 80, 80));
507+
}
508+
485509
TEST_F(BackdropLayerDiffTest, BackdropLayerInvalidTransform) {
486510
auto filter = DlBlurImageFilter(10, 10, DlTileMode::kClamp);
487511

0 commit comments

Comments
 (0)