Skip to content

Commit

Permalink
Specify clip alignment for partial repaint (#31359)
Browse files Browse the repository at this point in the history
* Specify clip alignment for partial repaint
  • Loading branch information
knopp committed Mar 31, 2022
1 parent 848f609 commit b026706
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 7 deletions.
1 change: 1 addition & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ FILE: ../../../flutter/flow/compositor_context.cc
FILE: ../../../flutter/flow/compositor_context.h
FILE: ../../../flutter/flow/diff_context.cc
FILE: ../../../flutter/flow/diff_context.h
FILE: ../../../flutter/flow/diff_context_unittests.cc
FILE: ../../../flutter/flow/embedded_view_params_unittests.cc
FILE: ../../../flutter/flow/embedded_views.cc
FILE: ../../../flutter/flow/embedded_views.h
Expand Down
1 change: 1 addition & 0 deletions flow/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ if (enable_unittests) {
testonly = true

sources = [
"diff_context_unittests.cc",
"embedded_view_params_unittests.cc",
"flow_run_all_unittests.cc",
"flow_test_utils.cc",
Expand Down
4 changes: 3 additions & 1 deletion flow/compositor_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ std::optional<SkRect> FrameDamage::ComputeClipRect(
layer_tree.root_layer()->Diff(&context, prev_root_layer);
}

damage_ = context.ComputeDamage(additional_damage_);
damage_ =
context.ComputeDamage(additional_damage_, horizontal_clip_alignment_,
vertical_clip_alignment_);
return SkRect::Make(damage_->buffer_damage);
} else {
return std::nullopt;
Expand Down
8 changes: 8 additions & 0 deletions flow/compositor_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ class FrameDamage {
additional_damage_.join(damage);
}

// Specifies clip rect alignment.
void SetClipAlignment(int horizontal, int vertical) {
horizontal_clip_alignment_ = horizontal;
vertical_clip_alignment_ = vertical;
}

// Calculates clip rect for current rasterization. This is diff of layer tree
// and previous layer tree + any additional provideddamage.
// If previous layer tree is not specified, clip rect will be nulloptional,
Expand All @@ -90,6 +96,8 @@ class FrameDamage {
SkIRect additional_damage_ = SkIRect::MakeEmpty();
std::optional<Damage> damage_;
const LayerTree* prev_layer_tree_ = nullptr;
int vertical_clip_alignment_ = 1;
int horizontal_clip_alignment_ = 1;
};

class CompositorContext {
Expand Down
36 changes: 34 additions & 2 deletions flow/diff_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,33 @@ SkRect DiffContext::ApplyFilterBoundsAdjustment(SkRect rect) const {
return rect;
}

Damage DiffContext::ComputeDamage(
const SkIRect& accumulated_buffer_damage) const {
void DiffContext::AlignRect(SkIRect& rect,
int horizontal_alignment,
int vertical_alignment) const {
auto top = rect.top();
auto left = rect.left();
auto right = rect.right();
auto bottom = rect.bottom();
if (top % vertical_alignment != 0) {
top -= top % vertical_alignment;
}
if (left % horizontal_alignment != 0) {
left -= left % horizontal_alignment;
}
if (right % horizontal_alignment != 0) {
right += horizontal_alignment - right % horizontal_alignment;
}
if (bottom % vertical_alignment != 0) {
bottom += vertical_alignment - bottom % vertical_alignment;
}
right = std::min(right, frame_size_.width());
bottom = std::min(bottom, frame_size_.height());
rect = SkIRect::MakeLTRB(left, top, right, bottom);
}

Damage DiffContext::ComputeDamage(const SkIRect& accumulated_buffer_damage,
int horizontal_clip_alignment,
int vertical_clip_alignment) const {
SkRect buffer_damage = SkRect::Make(accumulated_buffer_damage);
buffer_damage.join(damage_);
SkRect frame_damage(damage_);
Expand All @@ -90,6 +115,13 @@ Damage DiffContext::ComputeDamage(
SkIRect frame_clip = SkIRect::MakeSize(frame_size_);
res.buffer_damage.intersect(frame_clip);
res.frame_damage.intersect(frame_clip);

if (horizontal_clip_alignment > 1 || vertical_clip_alignment > 1) {
AlignRect(res.buffer_damage, horizontal_clip_alignment,
vertical_clip_alignment);
AlignRect(res.frame_damage, horizontal_clip_alignment,
vertical_clip_alignment);
}
return res;
}

Expand Down
11 changes: 10 additions & 1 deletion flow/diff_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,12 @@ class DiffContext {
//
// additional_damage is the previously accumulated frame_damage for
// current framebuffer
Damage ComputeDamage(const SkIRect& additional_damage) const;
//
// clip_alignment controls the alignment of resulting frame and surface
// damage.
Damage ComputeDamage(const SkIRect& additional_damage,
int horizontal_clip_alignment = 0,
int vertical_clip_alignment = 0) const;

double frame_device_pixel_ratio() const { return frame_device_pixel_ratio_; };

Expand Down Expand Up @@ -230,6 +235,10 @@ class DiffContext {

void AddDamage(const SkRect& rect);

void AlignRect(SkIRect& rect,
int horizontal_alignment,
int vertical_clip_alignment) const;

struct Readback {
// Index of rects_ entry that this readback belongs to. Used to
// determine if subtree has any readback
Expand Down
36 changes: 36 additions & 0 deletions flow/diff_context_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/flow/testing/diff_context_test.h"

namespace flutter {
namespace testing {

TEST_F(DiffContextTest, ClipAlignment) {
MockLayerTree t1;
t1.root()->Add(
CreatePictureLayer(CreatePicture(SkRect::MakeLTRB(30, 30, 50, 50), 1)));
auto damage = DiffLayerTree(t1, MockLayerTree(), SkIRect::MakeEmpty(), 0, 0);
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(30, 30, 50, 50));
EXPECT_EQ(damage.buffer_damage, SkIRect::MakeLTRB(30, 30, 50, 50));

damage = DiffLayerTree(t1, MockLayerTree(), SkIRect::MakeEmpty(), 1, 1);
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(30, 30, 50, 50));
EXPECT_EQ(damage.buffer_damage, SkIRect::MakeLTRB(30, 30, 50, 50));

damage = DiffLayerTree(t1, MockLayerTree(), SkIRect::MakeEmpty(), 8, 1);
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(24, 30, 56, 50));
EXPECT_EQ(damage.buffer_damage, SkIRect::MakeLTRB(24, 30, 56, 50));

damage = DiffLayerTree(t1, MockLayerTree(), SkIRect::MakeEmpty(), 1, 8);
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(30, 24, 50, 56));
EXPECT_EQ(damage.buffer_damage, SkIRect::MakeLTRB(30, 24, 50, 56));

damage = DiffLayerTree(t1, MockLayerTree(), SkIRect::MakeEmpty(), 16, 16);
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(16, 16, 64, 64));
EXPECT_EQ(damage.buffer_damage, SkIRect::MakeLTRB(16, 16, 64, 64));
}

} // namespace testing
} // namespace flutter
6 changes: 6 additions & 0 deletions flow/surface_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ class SurfaceFrame {
// this means that the surface will provide valid existing damage.
bool supports_partial_repaint = false;

// For some targets it may be beneficial or even required to snap clip
// rect to tile grid. I.e. repainting part of a tile may cause performance
// degradation if the tile needs to be decompressed first.
int vertical_clip_alignment = 1;
int horizontal_clip_alignment = 1;

// This is the area of framebuffer that lags behind the front buffer.
//
// Correctly providing exiting_damage is necessary for supporting double and
Expand Down
7 changes: 5 additions & 2 deletions flow/testing/diff_context_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@ DiffContextTest::DiffContextTest()

Damage DiffContextTest::DiffLayerTree(MockLayerTree& layer_tree,
const MockLayerTree& old_layer_tree,
const SkIRect& additional_damage) {
const SkIRect& additional_damage,
int horizontal_clip_alignment,
int vertical_clip_alignment) {
FML_CHECK(layer_tree.size() == old_layer_tree.size());

DiffContext dc(layer_tree.size(), 1, layer_tree.paint_region_map(),
old_layer_tree.paint_region_map());
dc.PushCullRect(
SkRect::MakeIWH(layer_tree.size().width(), layer_tree.size().height()));
layer_tree.root()->Diff(&dc, old_layer_tree.root());
return dc.ComputeDamage(additional_damage);
return dc.ComputeDamage(additional_damage, horizontal_clip_alignment,
vertical_clip_alignment);
}

sk_sp<SkPicture> DiffContextTest::CreatePicture(const SkRect& bounds,
Expand Down
4 changes: 3 additions & 1 deletion flow/testing/diff_context_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ class DiffContextTest : public ThreadTest {

Damage DiffLayerTree(MockLayerTree& layer_tree,
const MockLayerTree& old_layer_tree,
const SkIRect& additional_damage = SkIRect::MakeEmpty());
const SkIRect& additional_damage = SkIRect::MakeEmpty(),
int horizontal_clip_alignment = 0,
int vertical_alignment = 0);

// Create picture consisting of filled rect with given color; Being able
// to specify different color is useful to test deep comparison of pictures
Expand Down
3 changes: 3 additions & 0 deletions shell/common/rasterizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,9 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe(
if (frame->framebuffer_info().existing_damage && !force_full_repaint) {
damage->SetPreviousLayerTree(last_layer_tree_.get());
damage->AddAdditonalDamage(*frame->framebuffer_info().existing_damage);
damage->SetClipAlignment(
frame->framebuffer_info().horizontal_clip_alignment,
frame->framebuffer_info().vertical_clip_alignment);
}
}

Expand Down
7 changes: 7 additions & 0 deletions shell/platform/android/android_surface_gl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ SurfaceFrame::FramebufferInfo AndroidSurfaceGL::GLContextFramebufferInfo()
res.supports_readback = true;
res.supports_partial_repaint = onscreen_surface_->SupportsPartialRepaint();
res.existing_damage = onscreen_surface_->InitialDamage();
// Some devices (Pixel2 XL) needs EGL_KHR_partial_update rect aligned to 4,
// otherwise there are glitches
// (https://github.com/flutter/flutter/issues/97482#)
// Larger alignment might also be beneficial for tile base renderers.
res.horizontal_clip_alignment = 32;
res.vertical_clip_alignment = 32;

return res;
}

Expand Down

0 comments on commit b026706

Please sign in to comment.