diff --git a/engine/src/flutter/flow/layers/clip_path_layer_unittests.cc b/engine/src/flutter/flow/layers/clip_path_layer_unittests.cc index fbcbe43b6be..15ba6ecdb8c 100644 --- a/engine/src/flutter/flow/layers/clip_path_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/clip_path_layer_unittests.cc @@ -498,5 +498,42 @@ TEST_F(ClipPathLayerTest, OpacityInheritanceSaveLayerPainting) { EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); } +TEST_F(ClipPathLayerTest, LayerCached) { + auto path1 = SkPath().addRect({10, 10, 30, 30}); + auto mock1 = MockLayer::MakeOpacityCompatible(path1); + auto layer_clip = SkPath() + .addRect(SkRect::MakeLTRB(5, 5, 25, 25)) + .addOval(SkRect::MakeLTRB(20, 20, 40, 50)); + auto layer = + std::make_shared(layer_clip, Clip::antiAliasWithSaveLayer); + layer->Add(mock1); + + auto initial_transform = SkMatrix::Translate(50.0, 25.5); + SkMatrix cache_ctm = initial_transform; + SkCanvas cache_canvas; + cache_canvas.setMatrix(cache_ctm); + + use_mock_raster_cache(); + + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); + EXPECT_FALSE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); + + layer->Preroll(preroll_context(), initial_transform); + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); + EXPECT_FALSE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); + + layer->Preroll(preroll_context(), initial_transform); + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); + EXPECT_FALSE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); + + layer->Preroll(preroll_context(), initial_transform); + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1); + EXPECT_TRUE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/flow/layers/clip_rect_layer_unittests.cc b/engine/src/flutter/flow/layers/clip_rect_layer_unittests.cc index 8db48940b68..64e7ce9ea04 100644 --- a/engine/src/flutter/flow/layers/clip_rect_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/clip_rect_layer_unittests.cc @@ -488,5 +488,40 @@ TEST_F(ClipRectLayerTest, OpacityInheritanceSaveLayerPainting) { EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); } +TEST_F(ClipRectLayerTest, LayerCached) { + auto path1 = SkPath().addRect({10, 10, 30, 30}); + auto mock1 = MockLayer::MakeOpacityCompatible(path1); + SkRect clip_rect = SkRect::MakeWH(500, 500); + auto layer = + std::make_shared(clip_rect, Clip::antiAliasWithSaveLayer); + layer->Add(mock1); + + auto initial_transform = SkMatrix::Translate(50.0, 25.5); + SkMatrix cache_ctm = initial_transform; + SkCanvas cache_canvas; + cache_canvas.setMatrix(cache_ctm); + + use_mock_raster_cache(); + + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); + EXPECT_FALSE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); + + layer->Preroll(preroll_context(), initial_transform); + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); + EXPECT_FALSE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); + + layer->Preroll(preroll_context(), initial_transform); + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); + EXPECT_FALSE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); + + layer->Preroll(preroll_context(), initial_transform); + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1); + EXPECT_TRUE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/flow/layers/clip_rrect_layer_unittests.cc b/engine/src/flutter/flow/layers/clip_rrect_layer_unittests.cc index 390d1f6244a..3ca52e2e6c0 100644 --- a/engine/src/flutter/flow/layers/clip_rrect_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/clip_rrect_layer_unittests.cc @@ -498,5 +498,41 @@ TEST_F(ClipRRectLayerTest, OpacityInheritanceSaveLayerPainting) { EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); } +TEST_F(ClipRRectLayerTest, LayerCached) { + auto path1 = SkPath().addRect({10, 10, 30, 30}); + auto mock1 = MockLayer::MakeOpacityCompatible(path1); + SkRect clip_rect = SkRect::MakeWH(500, 500); + SkRRect clip_r_rect = SkRRect::MakeRectXY(clip_rect, 20, 20); + auto layer = std::make_shared(clip_r_rect, + Clip::antiAliasWithSaveLayer); + layer->Add(mock1); + + auto initial_transform = SkMatrix::Translate(50.0, 25.5); + SkMatrix cache_ctm = initial_transform; + SkCanvas cache_canvas; + cache_canvas.setMatrix(cache_ctm); + + use_mock_raster_cache(); + + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); + EXPECT_FALSE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); + + layer->Preroll(preroll_context(), initial_transform); + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); + EXPECT_FALSE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); + + layer->Preroll(preroll_context(), initial_transform); + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); + EXPECT_FALSE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); + + layer->Preroll(preroll_context(), initial_transform); + EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1); + EXPECT_TRUE(raster_cache()->Draw(layer.get(), cache_canvas, + RasterCacheLayerStrategy::kLayer)); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/flow/layers/clip_shape_layer.h b/engine/src/flutter/flow/layers/clip_shape_layer.h index 7781a4c211b..08489b4e2ea 100644 --- a/engine/src/flutter/flow/layers/clip_shape_layer.h +++ b/engine/src/flutter/flow/layers/clip_shape_layer.h @@ -15,7 +15,9 @@ class ClipShapeLayer : public ContainerLayer { public: using ClipShape = T; ClipShapeLayer(const ClipShape& clip_shape, Clip clip_behavior) - : clip_shape_(clip_shape), clip_behavior_(clip_behavior) { + : clip_shape_(clip_shape), + clip_behavior_(clip_behavior), + render_count_(1) { FML_DCHECK(clip_behavior != Clip::none); } @@ -58,6 +60,12 @@ class ClipShapeLayer : public ContainerLayer { // of our children and apply it in the saveLayer. if (UsesSaveLayer()) { context->subtree_can_inherit_opacity = true; + if (render_count_ >= kMinimumRendersBeforeCachingLayer) { + TryToPrepareRasterCache(context, this, matrix, + RasterCacheLayerStrategy::kLayer); + } else { + render_count_++; + } } context->mutators_stack.Pop(); @@ -76,16 +84,16 @@ class ClipShapeLayer : public ContainerLayer { } AutoCachePaint cache_paint(context); - TRACE_EVENT0("flutter", "Canvas::saveLayer"); - context.internal_nodes_canvas->saveLayer(paint_bounds(), - cache_paint.paint()); - - PaintChildren(context); - - context.internal_nodes_canvas->restore(); - if (context.checkerboard_offscreen_layers) { - DrawCheckerboard(context.internal_nodes_canvas, paint_bounds()); + if (context.raster_cache && + context.raster_cache->Draw(this, *context.leaf_nodes_canvas, + RasterCacheLayerStrategy::kLayer, + cache_paint.paint())) { + return; } + + Layer::AutoSaveLayer save_layer = Layer::AutoSaveLayer::Create( + context, paint_bounds(), cache_paint.paint()); + PaintChildren(context); } bool UsesSaveLayer() const { @@ -105,6 +113,9 @@ class ClipShapeLayer : public ContainerLayer { const ClipShape clip_shape_; Clip clip_behavior_; + static constexpr int kMinimumRendersBeforeCachingLayer = 3; + int render_count_; + FML_DISALLOW_COPY_AND_ASSIGN(ClipShapeLayer); };