Skip to content

Commit

Permalink
Enable partial repaint for iOS/Metal (flutter#28801)
Browse files Browse the repository at this point in the history
  • Loading branch information
knopp authored Nov 2, 2021
1 parent 6095a13 commit 4dbdc08
Show file tree
Hide file tree
Showing 73 changed files with 438 additions and 354 deletions.
6 changes: 0 additions & 6 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ config("config") {
cflags = [ "/WX" ] # Treat warnings as errors.
}
}

defines = []

if (is_debug) {
defines += [ "FLUTTER_ENABLE_DIFF_CONTEXT" ]
}
}

config("export_dynamic_symbols") {
Expand Down
51 changes: 49 additions & 2 deletions flow/compositor_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,45 @@

#include "flutter/flow/compositor_context.h"

#include <optional>
#include "flutter/flow/layers/layer_tree.h"
#include "third_party/skia/include/core/SkCanvas.h"

namespace flutter {

std::optional<SkRect> FrameDamage::ComputeClipRect(
flutter::LayerTree& layer_tree) {
if (layer_tree.root_layer()) {
PaintRegionMap empty_paint_region_map;
DiffContext context(layer_tree.frame_size(),
layer_tree.device_pixel_ratio(),
layer_tree.paint_region_map(),
prev_layer_tree_ ? prev_layer_tree_->paint_region_map()
: empty_paint_region_map);
context.PushCullRect(SkRect::MakeIWH(layer_tree.frame_size().width(),
layer_tree.frame_size().height()));
{
DiffContext::AutoSubtreeRestore subtree(&context);
const Layer* prev_root_layer = nullptr;
if (!prev_layer_tree_ ||
prev_layer_tree_->frame_size() != layer_tree.frame_size()) {
// If there is no previous layer tree assume the entire frame must be
// repainted.
context.MarkSubtreeDirty(SkRect::MakeIWH(
layer_tree.frame_size().width(), layer_tree.frame_size().height()));
} else {
prev_root_layer = prev_layer_tree_->root_layer();
}
layer_tree.root_layer()->Diff(&context, prev_root_layer);
}

damage_ = context.ComputeDamage(additional_damage_);
return SkRect::Make(damage_->buffer_damage);
} else {
return std::nullopt;
}
}

CompositorContext::CompositorContext(fml::Milliseconds frame_budget)
: raster_time_(frame_budget), ui_time_(frame_budget) {}

Expand Down Expand Up @@ -68,9 +102,15 @@ CompositorContext::ScopedFrame::~ScopedFrame() {

RasterStatus CompositorContext::ScopedFrame::Raster(
flutter::LayerTree& layer_tree,
bool ignore_raster_cache) {
bool ignore_raster_cache,
FrameDamage* frame_damage) {
TRACE_EVENT0("flutter", "CompositorContext::ScopedFrame::Raster");
bool root_needs_readback = layer_tree.Preroll(*this, ignore_raster_cache);

std::optional<SkRect> clip_rect =
frame_damage ? frame_damage->ComputeClipRect(layer_tree) : std::nullopt;

bool root_needs_readback = layer_tree.Preroll(
*this, ignore_raster_cache, clip_rect ? *clip_rect : kGiantRect);
bool needs_save_layer = root_needs_readback && !surface_supports_readback();
PostPrerollResult post_preroll_result = PostPrerollResult::kSuccess;
if (view_embedder_ && raster_thread_merger_) {
Expand All @@ -84,9 +124,16 @@ RasterStatus CompositorContext::ScopedFrame::Raster(
if (post_preroll_result == PostPrerollResult::kSkipAndRetryFrame) {
return RasterStatus::kSkipAndRetry;
}

SkAutoCanvasRestore restore(canvas(), clip_rect.has_value());

// Clearing canvas after preroll reduces one render target switch when preroll
// paints some raster cache.
if (canvas()) {
if (clip_rect) {
canvas()->clipRect(*clip_rect);
}

if (needs_save_layer) {
FML_LOG(INFO) << "Using SaveLayer to protect non-readback surface";
SkRect bounds = SkRect::Make(layer_tree.frame_size());
Expand Down
41 changes: 40 additions & 1 deletion flow/compositor_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <string>

#include "flutter/common/graphics/texture.h"
#include "flutter/flow/diff_context.h"
#include "flutter/flow/embedded_views.h"
#include "flutter/flow/instrumentation.h"
#include "flutter/flow/raster_cache.h"
Expand Down Expand Up @@ -54,6 +55,43 @@ enum class RasterStatus {
kYielded,
};

class FrameDamage {
public:
// Sets previous layer tree for calculating frame damage. If not set, entire
// frame will be repainted.
void SetPreviousLayerTree(const LayerTree* prev_layer_tree) {
prev_layer_tree_ = prev_layer_tree;
}

// Adds additional damage (accumulated for double / triple buffering).
// This is area that will be repainted alongside any changed part.
void AddAdditonalDamage(const SkIRect& damage) {
additional_damage_.join(damage);
}

// 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,
// but the paint region of layer_tree will be calculated so that it can be
// used for diffing of subsequent frames.
std::optional<SkRect> ComputeClipRect(flutter::LayerTree& layer_tree);

// See Damage::frame_damage.
std::optional<SkIRect> GetFrameDamage() const {
return damage_ ? std::make_optional(damage_->frame_damage) : std::nullopt;
}

// See Damage::buffer_damage.
std::optional<SkIRect> GetBufferDamage() {
return damage_ ? std::make_optional(damage_->buffer_damage) : std::nullopt;
}

private:
SkIRect additional_damage_ = SkIRect::MakeEmpty();
std::optional<Damage> damage_;
const LayerTree* prev_layer_tree_ = nullptr;
};

class CompositorContext {
public:
class ScopedFrame {
Expand Down Expand Up @@ -84,7 +122,8 @@ class CompositorContext {
GrDirectContext* gr_context() const { return gr_context_; }

virtual RasterStatus Raster(LayerTree& layer_tree,
bool ignore_raster_cache);
bool ignore_raster_cache,
FrameDamage* frame_damage);

private:
CompositorContext& context_;
Expand Down
10 changes: 6 additions & 4 deletions flow/diff_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@

namespace flutter {

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

DiffContext::DiffContext(SkISize frame_size,
double frame_device_pixel_ratio,
PaintRegionMap& this_frame_paint_region_map,
Expand Down Expand Up @@ -118,6 +116,12 @@ void DiffContext::MarkSubtreeDirty(const PaintRegion& previous_paint_region) {
state_.dirty = true;
}

void DiffContext::MarkSubtreeDirty(const SkRect& previous_paint_region) {
FML_DCHECK(!IsSubtreeDirty());
AddDamage(previous_paint_region);
state_.dirty = true;
}

void DiffContext::AddLayerBounds(const SkRect& rect) {
// During painting we cull based on non-overriden transform and then
// override the transform right before paint. Do the same thing here to get
Expand Down Expand Up @@ -200,6 +204,4 @@ void DiffContext::Statistics::LogStatistics() {
#endif // !FLUTTER_RELEASE
}

#endif // FLUTTER_ENABLE_DIFF_CONTEXT

} // namespace flutter
5 changes: 1 addition & 4 deletions flow/diff_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@

namespace flutter {

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

class Layer;

// Represents area that needs to be updated in front buffer (frame_damage) and
Expand Down Expand Up @@ -102,6 +100,7 @@ class DiffContext {
// added to damage.
void MarkSubtreeDirty(
const PaintRegion& previous_paint_region = PaintRegion());
void MarkSubtreeDirty(const SkRect& previous_paint_region);

bool IsSubtreeDirty() const { return state_.dirty; }

Expand Down Expand Up @@ -237,8 +236,6 @@ class DiffContext {
Statistics statistics_;
};

#endif // FLUTTER_ENABLE_DIFF_CONTEXT

} // namespace flutter

#endif // FLUTTER_FLOW_DIFF_CONTEXT_H_
22 changes: 10 additions & 12 deletions flow/layers/backdrop_filter_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ BackdropFilterLayer::BackdropFilterLayer(sk_sp<SkImageFilter> filter,
SkBlendMode blend_mode)
: filter_(std::move(filter)), blend_mode_(blend_mode) {}

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) {
DiffContext::AutoSubtreeRestore subtree(context);
auto* prev = static_cast<const BackdropFilterLayer*>(old_layer);
Expand All @@ -26,24 +24,24 @@ void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) {
auto paint_bounds = context->GetCullRect();
context->AddLayerBounds(paint_bounds);

// convert paint bounds and filter to screen coordinates
context->GetTransform().mapRect(&paint_bounds);
auto input_filter_bounds = paint_bounds.roundOut();
auto filter = filter_->makeWithLocalMatrix(context->GetTransform());
if (filter_) {
// convert paint bounds and filter to screen coordinates
context->GetTransform().mapRect(&paint_bounds);
auto input_filter_bounds = paint_bounds.roundOut();
auto filter = filter_->makeWithLocalMatrix(context->GetTransform());

auto filter_bounds = // in screen coordinates
filter->filterBounds(input_filter_bounds, SkMatrix::I(),
SkImageFilter::kReverse_MapDirection);
auto filter_bounds = // in screen coordinates
filter->filterBounds(input_filter_bounds, SkMatrix::I(),
SkImageFilter::kReverse_MapDirection);

context->AddReadbackRegion(filter_bounds);
context->AddReadbackRegion(filter_bounds);
}

DiffChildren(context, prev);

context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
}

#endif // FLUTTER_ENABLE_DIFF_CONTEXT

void BackdropFilterLayer::Preroll(PrerollContext* context,
const SkMatrix& matrix) {
Layer::AutoPrerollSaveLayerState save =
Expand Down
4 changes: 0 additions & 4 deletions flow/layers/backdrop_filter_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,8 @@ class BackdropFilterLayer : public ContainerLayer {
public:
BackdropFilterLayer(sk_sp<SkImageFilter> filter, SkBlendMode blend_mode);

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

void Diff(DiffContext* context, const Layer* old_layer) override;

#endif // FLUTTER_ENABLE_DIFF_CONTEXT

void Preroll(PrerollContext* context, const SkMatrix& matrix) override;

void Paint(PaintContext& context) const override;
Expand Down
4 changes: 0 additions & 4 deletions flow/layers/backdrop_filter_layer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,6 @@ TEST_F(BackdropFilterLayerTest, Readback) {
EXPECT_FALSE(preroll_context()->surface_needs_readback);
}

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

using BackdropLayerDiffTest = DiffContextTest;

TEST_F(BackdropLayerDiffTest, BackdropLayer) {
Expand Down Expand Up @@ -329,7 +327,5 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) {
EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 190, 190));
}

#endif

} // namespace testing
} // namespace flutter
4 changes: 0 additions & 4 deletions flow/layers/clip_path_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ ClipPathLayer::ClipPathLayer(const SkPath& clip_path, Clip clip_behavior)
FML_DCHECK(clip_behavior != Clip::none);
}

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

void ClipPathLayer::Diff(DiffContext* context, const Layer* old_layer) {
DiffContext::AutoSubtreeRestore subtree(context);
auto* prev = static_cast<const ClipPathLayer*>(old_layer);
Expand All @@ -30,8 +28,6 @@ void ClipPathLayer::Diff(DiffContext* context, const Layer* old_layer) {
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
}

#endif // FLUTTER_ENABLE_DIFF_CONTEXT

void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "ClipPathLayer::Preroll");

Expand Down
4 changes: 0 additions & 4 deletions flow/layers/clip_path_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@ class ClipPathLayer : public ContainerLayer {
public:
ClipPathLayer(const SkPath& clip_path, Clip clip_behavior = Clip::antiAlias);

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

void Diff(DiffContext* context, const Layer* old_layer) override;

#endif // FLUTTER_ENABLE_DIFF_CONTEXT

void Preroll(PrerollContext* context, const SkMatrix& matrix) override;

void Paint(PaintContext& context) const override;
Expand Down
4 changes: 0 additions & 4 deletions flow/layers/clip_rect_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ ClipRectLayer::ClipRectLayer(const SkRect& clip_rect, Clip clip_behavior)
FML_DCHECK(clip_behavior != Clip::none);
}

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

void ClipRectLayer::Diff(DiffContext* context, const Layer* old_layer) {
DiffContext::AutoSubtreeRestore subtree(context);
auto* prev = static_cast<const ClipRectLayer*>(old_layer);
Expand All @@ -30,8 +28,6 @@ void ClipRectLayer::Diff(DiffContext* context, const Layer* old_layer) {
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
}

#endif // FLUTTER_ENABLE_DIFF_CONTEXT

void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "ClipRectLayer::Preroll");

Expand Down
4 changes: 0 additions & 4 deletions flow/layers/clip_rect_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@ class ClipRectLayer : public ContainerLayer {
public:
ClipRectLayer(const SkRect& clip_rect, Clip clip_behavior);

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

void Diff(DiffContext* context, const Layer* old_layer) override;

#endif // FLUTTER_ENABLE_DIFF_CONTEXT

void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;

Expand Down
4 changes: 0 additions & 4 deletions flow/layers/clip_rrect_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ ClipRRectLayer::ClipRRectLayer(const SkRRect& clip_rrect, Clip clip_behavior)
FML_DCHECK(clip_behavior != Clip::none);
}

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

void ClipRRectLayer::Diff(DiffContext* context, const Layer* old_layer) {
DiffContext::AutoSubtreeRestore subtree(context);
auto* prev = static_cast<const ClipRRectLayer*>(old_layer);
Expand All @@ -30,8 +28,6 @@ void ClipRRectLayer::Diff(DiffContext* context, const Layer* old_layer) {
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
}

#endif // FLUTTER_ENABLE_DIFF_CONTEXT

void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "ClipRRectLayer::Preroll");

Expand Down
4 changes: 0 additions & 4 deletions flow/layers/clip_rrect_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@ class ClipRRectLayer : public ContainerLayer {
public:
ClipRRectLayer(const SkRRect& clip_rrect, Clip clip_behavior);

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

void Diff(DiffContext* context, const Layer* old_layer) override;

#endif // FLUTTER_ENABLE_DIFF_CONTEXT

void Preroll(PrerollContext* context, const SkMatrix& matrix) override;

void Paint(PaintContext& context) const override;
Expand Down
4 changes: 0 additions & 4 deletions flow/layers/color_filter_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ namespace flutter {
ColorFilterLayer::ColorFilterLayer(sk_sp<SkColorFilter> filter)
: filter_(std::move(filter)) {}

#ifdef FLUTTER_ENABLE_DIFF_CONTEXT

void ColorFilterLayer::Diff(DiffContext* context, const Layer* old_layer) {
DiffContext::AutoSubtreeRestore subtree(context);
auto* prev = static_cast<const ColorFilterLayer*>(old_layer);
Expand All @@ -26,8 +24,6 @@ void ColorFilterLayer::Diff(DiffContext* context, const Layer* old_layer) {
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
}

#endif // FLUTTER_ENABLE_DIFF_CONTEXT

void ColorFilterLayer::Preroll(PrerollContext* context,
const SkMatrix& matrix) {
Layer::AutoPrerollSaveLayerState save =
Expand Down
Loading

0 comments on commit 4dbdc08

Please sign in to comment.