diff --git a/flow/layers/clip_shape_layer.h b/flow/layers/clip_shape_layer.h index e4594f8e2eafc..85f6b4393dada 100644 --- a/flow/layers/clip_shape_layer.h +++ b/flow/layers/clip_shape_layer.h @@ -8,7 +8,6 @@ #include "flutter/flow/layers/cacheable_layer.h" #include "flutter/flow/layers/container_layer.h" #include "flutter/flow/paint_utils.h" -#include "flutter/flow/raster_cache_util.h" namespace flutter { @@ -51,9 +50,6 @@ class ClipShapeLayer : public CacheableContainerLayer { context->cull_rect.setEmpty(); } SkMatrix child_matrix = matrix; - if (context->raster_cache && uses_save_layer) { - child_matrix = RasterCacheUtil::GetIntegralTransCTM(child_matrix); - } // We can use the raster_cache for children only when the use_save_layer is // true so if use_save_layer is false we pass the layer_raster_item is // nullptr which mean we don't do raster cache logic. diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index 8806b88094c40..ff193a16b1d2a 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -38,12 +38,9 @@ void ColorFilterLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); - AutoCache cache = AutoCache(layer_raster_cache_item_.get(), context, matrix); - SkMatrix child_matrix = matrix; - if (context->raster_cache) { - child_matrix = RasterCacheUtil::GetIntegralTransCTM(child_matrix); - } + AutoCache cache = + AutoCache(layer_raster_cache_item_.get(), context, child_matrix); ContainerLayer::Preroll(context, child_matrix); // We always use a saveLayer (or a cached rendering), so we diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index b5fbe9ce1b521..d37bbaf7eac0c 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -100,9 +100,6 @@ void DisplayListLayer::Preroll(PrerollContext* context, TRACE_EVENT0("flutter", "DisplayListLayer::Preroll"); DisplayList* disp_list = display_list(); SkMatrix child_matrix = matrix; - if (context->raster_cache) { - child_matrix = RasterCacheUtil::GetIntegralTransCTM(child_matrix); - } AutoCache cache = AutoCache(display_list_raster_cache_item_.get(), context, child_matrix); diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index 03be2a58a1883..892420f1ab8b5 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -50,14 +50,13 @@ void ImageFilterLayer::Preroll(PrerollContext* context, Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); + SkMatrix child_matrix = matrix; - AutoCache cache = AutoCache(layer_raster_cache_item_.get(), context, matrix); + AutoCache cache = + AutoCache(layer_raster_cache_item_.get(), context, child_matrix); SkRect child_bounds = SkRect::MakeEmpty(); - SkMatrix child_matrix = matrix; - if (context->raster_cache) { - child_matrix = RasterCacheUtil::GetIntegralTransCTM(child_matrix); - } + PrerollChildren(context, child_matrix, &child_bounds); context->subtree_can_inherit_opacity = true; diff --git a/flow/layers/layer_raster_cache_item.cc b/flow/layers/layer_raster_cache_item.cc index 0d2b753283e5d..6e54042f82579 100644 --- a/flow/layers/layer_raster_cache_item.cc +++ b/flow/layers/layer_raster_cache_item.cc @@ -5,6 +5,7 @@ #include "flutter/flow/layers/layer_raster_cache_item.h" #include "flutter/flow/layers/container_layer.h" #include "flutter/flow/raster_cache_item.h" +#include "flutter/flow/raster_cache_util.h" namespace flutter { diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index e1370300c75d7..b9596f5edcf79 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -52,7 +52,7 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { context->mutators_stack.PushOpacity(alpha_); AutoCache auto_cache = - AutoCache(layer_raster_cache_item_.get(), context, matrix); + AutoCache(layer_raster_cache_item_.get(), context, child_matrix); Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); diff --git a/flow/layers/opacity_layer_unittests.cc b/flow/layers/opacity_layer_unittests.cc index cc4c8b78761f5..145fe5403b4c4 100644 --- a/flow/layers/opacity_layer_unittests.cc +++ b/flow/layers/opacity_layer_unittests.cc @@ -8,6 +8,7 @@ #include "flutter/flow/layers/image_filter_layer.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/layers/transform_layer.h" +#include "flutter/flow/raster_cache_util.h" #include "flutter/flow/testing/diff_context_test.h" #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" @@ -662,5 +663,43 @@ TEST_F(OpacityLayerDiffTest, FractionalTranslationWithRasterCache) { EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(11, 11, 61, 61)); } +TEST_F(OpacityLayerTest, FullyOpaqueWithFractionalValues) { + use_mock_raster_cache(); // Ensure non-fractional alignment. + + const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); + const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f); + const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f); + const SkMatrix layer_transform = + SkMatrix::Translate(layer_offset.fX, layer_offset.fY); + const SkPaint child_paint = SkPaint(SkColors::kGreen); + const SkRect expected_layer_bounds = + layer_transform.mapRect(child_path.getBounds()); + auto mock_layer = std::make_shared(child_path, child_paint); + auto layer = std::make_shared(SK_AlphaOPAQUE, layer_offset); + layer->Add(mock_layer); + layer->Preroll(preroll_context(), initial_transform); + + const SkPaint opacity_paint = SkPaint(SkColors::kBlack); // A = 1.0f + SkRect opacity_bounds; + expected_layer_bounds.makeOffset(-layer_offset.fX, -layer_offset.fY) + .roundOut(&opacity_bounds); + auto expected_draw_calls = std::vector( + {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, + MockCanvas::DrawCall{ + 1, MockCanvas::ConcatMatrixData{SkM44(layer_transform)}}, + MockCanvas::DrawCall{ + 1, MockCanvas::SetMatrixData{SkM44( + RasterCacheUtil::GetIntegralTransCTM(layer_transform))}}, + MockCanvas::DrawCall{ + 1, MockCanvas::SaveLayerData{opacity_bounds, opacity_paint, nullptr, + 2}}, + MockCanvas::DrawCall{2, + MockCanvas::DrawPathData{child_path, child_paint}}, + MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, + MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}); + layer->Paint(paint_context()); + EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); +} + } // namespace testing } // namespace flutter diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index a54ee1591d9ec..68b4c391aab15 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -38,10 +38,11 @@ void ShaderMaskLayer::Diff(DiffContext* context, const Layer* old_layer) { void ShaderMaskLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); + SkMatrix child_matrix = matrix; + AutoCache cache = + AutoCache(layer_raster_cache_item_.get(), context, child_matrix); - AutoCache cache = AutoCache(layer_raster_cache_item_.get(), context, matrix); - - ContainerLayer::Preroll(context, matrix); + ContainerLayer::Preroll(context, child_matrix); // We always paint with a saveLayer (or a cached rendering), // so we can always apply opacity in any of those cases. context->subtree_can_inherit_opacity = true; diff --git a/flow/layers/shader_mask_layer_unittests.cc b/flow/layers/shader_mask_layer_unittests.cc index d57a2753d4bea..1c2d7d2d26107 100644 --- a/flow/layers/shader_mask_layer_unittests.cc +++ b/flow/layers/shader_mask_layer_unittests.cc @@ -7,6 +7,7 @@ #include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/layers/opacity_layer.h" #include "flutter/flow/raster_cache.h" +#include "flutter/flow/raster_cache_util.h" #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" @@ -389,5 +390,45 @@ TEST_F(ShaderMaskLayerTest, OpacityInheritance) { EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); } +TEST_F(ShaderMaskLayerTest, SimpleFilterWithRasterCache) { + use_mock_raster_cache(); // Ensure non-fractional alignment. + + const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f); + const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f); + const SkRect layer_bounds = SkRect::MakeLTRB(2.0f, 4.0f, 6.5f, 6.5f); + const SkPath child_path = SkPath().addRect(child_bounds); + const SkPaint child_paint = SkPaint(SkColors::kYellow); + auto layer_filter = + SkPerlinNoiseShader::MakeFractalNoise(1.0f, 1.0f, 1, 1.0f); + auto mock_layer = std::make_shared(child_path, child_paint); + auto layer = std::make_shared(layer_filter, layer_bounds, + SkBlendMode::kSrc); + layer->Add(mock_layer); + layer->Preroll(preroll_context(), initial_transform); + + SkPaint filter_paint; + filter_paint.setBlendMode(SkBlendMode::kSrc); + filter_paint.setShader(layer_filter); + layer->Paint(paint_context()); + EXPECT_EQ( + mock_canvas().draw_calls(), + std::vector({MockCanvas::DrawCall{0, MockCanvas::SetMatrixData{SkM44( + SkMatrix::Translate(0.0, 0.0))}}, + MockCanvas::DrawCall{ + 0, MockCanvas::SaveLayerData{child_bounds, SkPaint(), + nullptr, 1}}, + MockCanvas::DrawCall{ + 1, MockCanvas::DrawPathData{child_path, child_paint}}, + MockCanvas::DrawCall{ + 1, MockCanvas::ConcatMatrixData{SkM44::Translate( + layer_bounds.fLeft, layer_bounds.fTop)}}, + MockCanvas::DrawCall{ + 1, MockCanvas::DrawRectData{SkRect::MakeWH( + layer_bounds.width(), + layer_bounds.height()), + filter_paint}}, + MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); +} + } // namespace testing } // namespace flutter diff --git a/flow/raster_cache.cc b/flow/raster_cache.cc index 45ec9b9aa402f..f63f4cca8e0ee 100644 --- a/flow/raster_cache.cc +++ b/flow/raster_cache.cc @@ -32,8 +32,9 @@ void RasterCacheResult::draw(SkCanvas& canvas, const SkPaint* paint) const { TRACE_EVENT0("flutter", "RasterCacheResult::draw"); SkAutoCanvasRestore auto_restore(&canvas, true); - SkRect bounds = RasterCacheUtil::GetRoundedOutDeviceBounds( - logical_rect_, canvas.getTotalMatrix()); + auto matrix = RasterCacheUtil::GetIntegralTransCTM(canvas.getTotalMatrix()); + SkRect bounds = + RasterCacheUtil::GetRoundedOutDeviceBounds(logical_rect_, matrix); FML_DCHECK(std::abs(bounds.width() - image_->dimensions().width()) <= 1 && std::abs(bounds.height() - image_->dimensions().height()) <= 1); canvas.resetMatrix(); @@ -53,9 +54,9 @@ std::unique_ptr RasterCache::Rasterize( const RasterCache::Context& context, const std::function& draw_function) { TRACE_EVENT0("flutter", "RasterCachePopulate"); - - SkRect dest_rect = RasterCacheUtil::GetRoundedOutDeviceBounds( - context.logical_rect, context.matrix); + auto matrix = RasterCacheUtil::GetIntegralTransCTM(context.matrix); + SkRect dest_rect = + RasterCacheUtil::GetRoundedOutDeviceBounds(context.logical_rect, matrix); const SkImageInfo image_info = SkImageInfo::MakeN32Premul(dest_rect.width(), dest_rect.height(), @@ -73,7 +74,7 @@ std::unique_ptr RasterCache::Rasterize( SkCanvas* canvas = surface->getCanvas(); canvas->clear(SK_ColorTRANSPARENT); canvas->translate(-dest_rect.left(), -dest_rect.top()); - canvas->concat(context.matrix); + canvas->concat(matrix); draw_function(canvas); if (context.checkerboard) { @@ -110,8 +111,7 @@ bool RasterCache::UpdateCacheEntry( int RasterCache::MarkSeen(const RasterCacheKeyID& id, const SkMatrix& matrix, bool visible) const { - RasterCacheKey key = - RasterCacheKey(id, RasterCacheUtil::GetIntegralTransCTM(matrix)); + RasterCacheKey key = RasterCacheKey(id, matrix); Entry& entry = cache_[key]; entry.encountered_this_frame = true; entry.visible_this_frame = visible; @@ -123,8 +123,7 @@ int RasterCache::MarkSeen(const RasterCacheKeyID& id, int RasterCache::GetAccessCount(const RasterCacheKeyID& id, const SkMatrix& matrix) const { - RasterCacheKey key = - RasterCacheKey(id, RasterCacheUtil::GetIntegralTransCTM(matrix)); + RasterCacheKey key = RasterCacheKey(id, matrix); auto entry = cache_.find(key); if (entry != cache_.cend()) { return entry->second.accesses_since_visible; @@ -134,8 +133,7 @@ int RasterCache::GetAccessCount(const RasterCacheKeyID& id, bool RasterCache::HasEntry(const RasterCacheKeyID& id, const SkMatrix& matrix) const { - RasterCacheKey key = - RasterCacheKey(id, RasterCacheUtil::GetIntegralTransCTM(matrix)); + RasterCacheKey key = RasterCacheKey(id, matrix); if (cache_.find(key) != cache_.cend()) { return true; } @@ -145,8 +143,7 @@ bool RasterCache::HasEntry(const RasterCacheKeyID& id, bool RasterCache::Draw(const RasterCacheKeyID& id, SkCanvas& canvas, const SkPaint* paint) const { - auto it = cache_.find(RasterCacheKey( - id, RasterCacheUtil::GetIntegralTransCTM(canvas.getTotalMatrix()))); + auto it = cache_.find(RasterCacheKey(id, canvas.getTotalMatrix())); if (it == cache_.end()) { return false; } diff --git a/flow/testing/mock_layer.cc b/flow/testing/mock_layer.cc index 6ff049469c2b1..90a91e810d82b 100644 --- a/flow/testing/mock_layer.cc +++ b/flow/testing/mock_layer.cc @@ -70,18 +70,20 @@ void MockCacheableContainerLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); - auto cache = AutoCache(layer_raster_cache_item_.get(), context, matrix); + SkMatrix child_matrix = matrix; + auto cache = AutoCache(layer_raster_cache_item_.get(), context, child_matrix); - ContainerLayer::Preroll(context, matrix); + ContainerLayer::Preroll(context, child_matrix); } void MockCacheableLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); - auto cache = AutoCache(raster_cache_item_.get(), context, matrix); + SkMatrix child_matrix = matrix; + auto cache = AutoCache(raster_cache_item_.get(), context, child_matrix); - MockLayer::Preroll(context, matrix); + MockLayer::Preroll(context, child_matrix); } } // namespace testing