Skip to content

Commit

Permalink
backdrop_filter_layer only pushes to the leaf_nodes_canvas (flutter#2…
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Yang authored Sep 27, 2021
1 parent 9dbdc93 commit 6b5e89d
Show file tree
Hide file tree
Showing 16 changed files with 409 additions and 35 deletions.
1 change: 1 addition & 0 deletions flow/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ if (enable_unittests) {
"raster_cache_unittests.cc",
"rtree_unittests.cc",
"skia_gpu_object_unittests.cc",
"testing/auto_save_layer_unittests.cc",
"testing/mock_layer_unittests.cc",
"testing/mock_texture_unittests.cc",
"texture_unittests.cc",
Expand Down
5 changes: 4 additions & 1 deletion flow/layers/backdrop_filter_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ void BackdropFilterLayer::Paint(PaintContext& context) const {
paint.setBlendMode(blend_mode_);
Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create(
context,
SkCanvas::SaveLayerRec{&paint_bounds(), &paint, filter_.get(), 0});
SkCanvas::SaveLayerRec{&paint_bounds(), &paint, filter_.get(), 0},
// BackdropFilter should only happen on the leaf nodes canvas.
// See https:://flutter.dev/go/backdrop-filter-with-overlay-canvas
AutoSaveLayer::SaveMode::kLeafNodesCanvas);
PaintChildren(context);
}

Expand Down
36 changes: 24 additions & 12 deletions flow/layers/layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,35 +58,47 @@ Layer::AutoPrerollSaveLayerState::~AutoPrerollSaveLayerState() {

Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context,
const SkRect& bounds,
const SkPaint* paint)
: paint_context_(paint_context), bounds_(bounds) {
paint_context_.internal_nodes_canvas->saveLayer(bounds_, paint);
const SkPaint* paint,
SaveMode save_mode)
: paint_context_(paint_context),
bounds_(bounds),
canvas_(save_mode == SaveMode::kInternalNodesCanvas
? *(paint_context.internal_nodes_canvas)
: *(paint_context.leaf_nodes_canvas)) {
canvas_.saveLayer(bounds_, paint);
}

Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context,
const SkCanvas::SaveLayerRec& layer_rec)
: paint_context_(paint_context), bounds_(*layer_rec.fBounds) {
paint_context_.internal_nodes_canvas->saveLayer(layer_rec);
const SkCanvas::SaveLayerRec& layer_rec,
SaveMode save_mode)
: paint_context_(paint_context),
bounds_(*layer_rec.fBounds),
canvas_(save_mode == SaveMode::kInternalNodesCanvas
? *(paint_context.internal_nodes_canvas)
: *(paint_context.leaf_nodes_canvas)) {
canvas_.saveLayer(layer_rec);
}

Layer::AutoSaveLayer Layer::AutoSaveLayer::Create(
const PaintContext& paint_context,
const SkRect& bounds,
const SkPaint* paint) {
return Layer::AutoSaveLayer(paint_context, bounds, paint);
const SkPaint* paint,
SaveMode save_mode) {
return Layer::AutoSaveLayer(paint_context, bounds, paint, save_mode);
}

Layer::AutoSaveLayer Layer::AutoSaveLayer::Create(
const PaintContext& paint_context,
const SkCanvas::SaveLayerRec& layer_rec) {
return Layer::AutoSaveLayer(paint_context, layer_rec);
const SkCanvas::SaveLayerRec& layer_rec,
SaveMode save_mode) {
return Layer::AutoSaveLayer(paint_context, layer_rec, save_mode);
}

Layer::AutoSaveLayer::~AutoSaveLayer() {
if (paint_context_.checkerboard_offscreen_layers) {
DrawCheckerboard(paint_context_.internal_nodes_canvas, bounds_);
DrawCheckerboard(&canvas_, bounds_);
}
paint_context_.internal_nodes_canvas->restore();
canvas_.restore();
}

} // namespace flutter
48 changes: 41 additions & 7 deletions flow/layers/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,26 +157,60 @@ class Layer {
// draws a checkerboard over the layer if that is enabled in the PaintContext.
class AutoSaveLayer {
public:
[[nodiscard]] static AutoSaveLayer Create(const PaintContext& paint_context,
const SkRect& bounds,
const SkPaint* paint);

// Indicates which canvas the layer should be saved on.
//
// Usually layers are saved on the internal_nodes_canvas, so that all
// the canvas keep track of the current state of the layer tree.
// In some special cases, layers should only save on the leaf_nodes_canvas,
// See https:://flutter.dev/go/backdrop-filter-with-overlay-canvas for why
// it is the case for Backdrop filter layer.
enum SaveMode {
// The layer is saved on the internal_nodes_canvas.
kInternalNodesCanvas,
// The layer is saved on the leaf_nodes_canvas.
kLeafNodesCanvas
};

// Create a layer and save it on the canvas.
//
// The layer is restored from the canvas in destructor.
//
// By default, the layer is saved on and restored from
// `internal_nodes_canvas`. The `save_mode` parameter can be modified to
// save the layer on other canvases.
[[nodiscard]] static AutoSaveLayer Create(
const PaintContext& paint_context,
const SkRect& bounds,
const SkPaint* paint,
SaveMode save_mode = SaveMode::kInternalNodesCanvas);
// Create a layer and save it on the canvas.
//
// The layer is restored from the canvas in destructor.
//
// By default, the layer is saved on and restored from
// `internal_nodes_canvas`. The `save_mode` parameter can be modified to
// save the layer on other canvases.
[[nodiscard]] static AutoSaveLayer Create(
const PaintContext& paint_context,
const SkCanvas::SaveLayerRec& layer_rec);
const SkCanvas::SaveLayerRec& layer_rec,
SaveMode save_mode = SaveMode::kInternalNodesCanvas);

~AutoSaveLayer();

private:
AutoSaveLayer(const PaintContext& paint_context,
const SkRect& bounds,
const SkPaint* paint);
const SkPaint* paint,
SaveMode save_mode = SaveMode::kInternalNodesCanvas);

AutoSaveLayer(const PaintContext& paint_context,
const SkCanvas::SaveLayerRec& layer_rec);
const SkCanvas::SaveLayerRec& layer_rec,
SaveMode save_mode = SaveMode::kInternalNodesCanvas);

const PaintContext& paint_context_;
const SkRect bounds_;
// The canvas that this layer is saved on and popped from.
SkCanvas& canvas_;
};

virtual void Paint(PaintContext& context) const = 0;
Expand Down
117 changes: 117 additions & 0 deletions flow/testing/auto_save_layer_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// 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/layer_test.h"

#include "gtest/gtest.h"

namespace flutter {
namespace testing {

using AutoSaveLayerTests = LayerTest;

TEST_F(AutoSaveLayerTests, SaveLayerOnInternalNodesCanvasByDefault) {
// For:
// static AutoSaveLayer Create(const PaintContext& paint_context,
// const SkRect& bounds,
// const SkPaint* paint,
// SaveMode save_mode);
{
int saved_count_before =
paint_context().internal_nodes_canvas->getSaveCount();
{
const SkPaint paint;
const SkRect rect = SkRect::MakeEmpty();
Layer::AutoSaveLayer save =
Layer::AutoSaveLayer::Create(paint_context(), rect, &paint);
EXPECT_EQ(paint_context().internal_nodes_canvas->getSaveCount(),
saved_count_before + 1);
EXPECT_EQ(paint_context().leaf_nodes_canvas->getSaveCount(),
saved_count_before + 1);
}
EXPECT_EQ(paint_context().internal_nodes_canvas->getSaveCount(),
saved_count_before);
EXPECT_EQ(paint_context().leaf_nodes_canvas->getSaveCount(),
saved_count_before);
}
// For:
// static AutoSaveLayer Create(const PaintContext& paint_context,
// const SkCanvas::SaveLayerRec& layer_rec,
// SaveMode save_mode);
{
int saved_count_before =
paint_context().internal_nodes_canvas->getSaveCount();
{
const SkPaint paint;
const SkRect rect = SkRect::MakeEmpty();
const SkCanvas::SaveLayerRec save_layer_rect =
SkCanvas::SaveLayerRec{&rect, &paint, nullptr, 0};
Layer::AutoSaveLayer save =
Layer::AutoSaveLayer::Create(paint_context(), save_layer_rect);
EXPECT_EQ(paint_context().internal_nodes_canvas->getSaveCount(),
saved_count_before + 1);
EXPECT_EQ(paint_context().leaf_nodes_canvas->getSaveCount(),
saved_count_before + 1);
}
EXPECT_EQ(paint_context().internal_nodes_canvas->getSaveCount(),
saved_count_before);
EXPECT_EQ(paint_context().leaf_nodes_canvas->getSaveCount(),
saved_count_before);
}
}

TEST_F(AutoSaveLayerTests, SaveLayerOnlyOnLeafNodesCanvas) {
// For:
// static AutoSaveLayer Create(const PaintContext& paint_context,
// const SkRect& bounds,
// const SkPaint* paint,
// SaveMode save_mode);
{
int saved_count_before =
paint_context().internal_nodes_canvas->getSaveCount();
{
const SkPaint paint;
const SkRect rect = SkRect::MakeEmpty();
Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create(
paint_context(), rect, &paint,
Layer::AutoSaveLayer::SaveMode::kLeafNodesCanvas);
EXPECT_EQ(paint_context().internal_nodes_canvas->getSaveCount(),
saved_count_before);
EXPECT_EQ(paint_context().leaf_nodes_canvas->getSaveCount(),
saved_count_before + 1);
}
EXPECT_EQ(paint_context().internal_nodes_canvas->getSaveCount(),
saved_count_before);
EXPECT_EQ(paint_context().leaf_nodes_canvas->getSaveCount(),
saved_count_before);
}
// For:
// static AutoSaveLayer Create(const PaintContext& paint_context,
// const SkCanvas::SaveLayerRec& layer_rec,
// SaveMode save_mode);
{
int saved_count_before =
paint_context().internal_nodes_canvas->getSaveCount();
{
const SkPaint paint;
const SkRect rect = SkRect::MakeEmpty();
const SkCanvas::SaveLayerRec save_layer_rect =
SkCanvas::SaveLayerRec{&rect, &paint, nullptr, 0};
Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create(
paint_context(), save_layer_rect,
Layer::AutoSaveLayer::SaveMode::kLeafNodesCanvas);
EXPECT_EQ(paint_context().internal_nodes_canvas->getSaveCount(),
saved_count_before);
EXPECT_EQ(paint_context().leaf_nodes_canvas->getSaveCount(),
saved_count_before + 1);
}
EXPECT_EQ(paint_context().internal_nodes_canvas->getSaveCount(),
saved_count_before);
EXPECT_EQ(paint_context().leaf_nodes_canvas->getSaveCount(),
saved_count_before);
}
}

} // namespace testing
} // namespace flutter
9 changes: 9 additions & 0 deletions flow/testing/mock_layer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,14 @@ TEST_F(MockLayerTest, FakePlatformView) {
EXPECT_EQ(preroll_context()->has_platform_view, true);
}

TEST_F(MockLayerTest, SaveLayerOnLeafNodesCanvas) {
auto layer = std::make_shared<MockLayer>(SkPath(), SkPaint(),
true /* fake_has_platform_view */);
EXPECT_EQ(preroll_context()->has_platform_view, false);

layer->Preroll(preroll_context(), SkMatrix());
EXPECT_EQ(preroll_context()->has_platform_view, true);
}

} // namespace testing
} // namespace flutter
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,6 @@
SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(int view_id) {
// Any UIKit related code has to run on main thread.
FML_DCHECK([[NSThread currentThread] isMainThread]);

// Do nothing if the view doesn't need to be composited.
if (views_to_recomposite_.count(view_id) == 0) {
return picture_recorders_[view_id]->getRecordingCanvas();
Expand Down
Loading

0 comments on commit 6b5e89d

Please sign in to comment.