From a15f97bc2387d8ce8fdd91bf7d254c0036aa30d7 Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Thu, 9 Mar 2023 16:39:40 +0800 Subject: [PATCH 1/2] [Impeller] Make matrix image filter in saving layer work as expected --- impeller/aiks/aiks_unittests.cc | 2 +- impeller/aiks/paint.cc | 11 +++--- impeller/aiks/paint.h | 9 ++--- .../display_list/display_list_dispatcher.cc | 35 +++++++++++-------- .../display_list/display_list_unittests.cc | 33 +++++++++++++++++ .../contents/filters/filter_contents.cc | 8 +++-- .../entity/contents/filters/filter_contents.h | 4 ++- .../filters/gaussian_blur_filter_contents.cc | 4 +-- .../filters/matrix_filter_contents.cc | 19 ++++++---- .../contents/filters/matrix_filter_contents.h | 3 ++ .../filters/morphology_filter_contents.cc | 4 +-- impeller/entity/entity_pass.cc | 3 +- impeller/entity/entity_pass.h | 3 +- 13 files changed, 98 insertions(+), 40 deletions(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 634bf58f27642..aab4fbd0cfebd 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -1931,7 +1931,7 @@ TEST_P(AiksTest, PaintWithFilters) { ASSERT_TRUE(paint.HasColorFilter()); paint.image_filter = [](const FilterInput::Ref& input, - const Matrix& effect_transform) { + const Matrix& effect_transform, bool is_subpass) { return FilterContents::MakeGaussianBlur( input, Sigma(1.0), Sigma(1.0), FilterContents::BlurStyle::kNormal, Entity::TileMode::kClamp, effect_transform); diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index bf738951cfb0e..f157652b413e8 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc @@ -63,15 +63,15 @@ std::shared_ptr Paint::WithFilters( input = WithColorFilter(input); input = WithInvertFilter(input); input = WithMaskBlur(input, is_solid_color_val, effect_transform); - input = WithImageFilter(input, effect_transform); + input = WithImageFilter(input, effect_transform, /*is_subpass=*/false); return input; } std::shared_ptr Paint::WithFiltersForSubpassTarget( std::shared_ptr input, const Matrix& effect_transform) const { - input = WithImageFilter(input, effect_transform); - input = WithColorFilter(input, /**absorb_opacity=*/true); + input = WithImageFilter(input, effect_transform, /*is_subpass=*/true); + input = WithColorFilter(input, /*absorb_opacity=*/true); return input; } @@ -88,10 +88,11 @@ std::shared_ptr Paint::WithMaskBlur( std::shared_ptr Paint::WithImageFilter( std::shared_ptr input, - const Matrix& effect_transform) const { + const Matrix& effect_transform, + bool is_subpass) const { if (image_filter.has_value()) { const ImageFilterProc& filter = image_filter.value(); - input = filter(FilterInput::Make(input), effect_transform); + input = filter(FilterInput::Make(input), effect_transform, is_subpass); } return input; } diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index 990f829fc4067..b0f1f266ea1a4 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -22,7 +22,8 @@ namespace impeller { struct Paint { using ImageFilterProc = std::function( FilterInput::Ref, - const Matrix& effect_transform)>; + const Matrix& effect_transform, + bool is_subpass)>; using ColorFilterProc = std::function(FilterInput::Ref)>; using MaskFilterProc = std::function( @@ -118,9 +119,9 @@ struct Paint { bool is_solid_color, const Matrix& effect_transform) const; - std::shared_ptr WithImageFilter( - std::shared_ptr input, - const Matrix& effect_transform) const; + std::shared_ptr WithImageFilter(std::shared_ptr input, + const Matrix& effect_transform, + bool is_subpass) const; std::shared_ptr WithColorFilter(std::shared_ptr input, bool absorb_opacity = false) const; diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index afe8e8422722c..58343b8846d94 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -653,7 +653,8 @@ static std::optional ToImageFilterProc( auto tile_mode = ToTileMode(blur->tile_mode()); return [sigma_x, sigma_y, tile_mode](const FilterInput::Ref& input, - const Matrix& effect_transform) { + const Matrix& effect_transform, + bool is_subpass) { return FilterContents::MakeGaussianBlur( input, sigma_x, sigma_y, FilterContents::BlurStyle::kNormal, tile_mode, effect_transform); @@ -670,7 +671,8 @@ static std::optional ToImageFilterProc( auto radius_x = Radius(dilate->radius_x()); auto radius_y = Radius(dilate->radius_y()); return [radius_x, radius_y](FilterInput::Ref input, - const Matrix& effect_transform) { + const Matrix& effect_transform, + bool is_subpass) { return FilterContents::MakeMorphology( std::move(input), radius_x, radius_y, FilterContents::MorphType::kDilate, effect_transform); @@ -686,7 +688,8 @@ static std::optional ToImageFilterProc( auto radius_x = Radius(erode->radius_x()); auto radius_y = Radius(erode->radius_y()); return [radius_x, radius_y](FilterInput::Ref input, - const Matrix& effect_transform) { + const Matrix& effect_transform, + bool is_subpass) { return FilterContents::MakeMorphology( std::move(input), radius_x, radius_y, FilterContents::MorphType::kErode, effect_transform); @@ -699,8 +702,9 @@ static std::optional ToImageFilterProc( auto matrix = ToMatrix(matrix_filter->matrix()); auto desc = ToSamplerDescriptor(matrix_filter->sampling()); return [matrix, desc](FilterInput::Ref input, - const Matrix& effect_transform) { - return FilterContents::MakeMatrixFilter(std::move(input), matrix, desc); + const Matrix& effect_transform, bool is_subpass) { + return FilterContents::MakeMatrixFilter(std::move(input), matrix, desc, + effect_transform, is_subpass); }; break; } @@ -719,10 +723,13 @@ static std::optional ToImageFilterProc( } FML_DCHECK(outer_proc.has_value() && inner_proc.has_value()); return [outer_filter = outer_proc.value(), - inner_filter = inner_proc.value()]( - FilterInput::Ref input, const Matrix& effect_transform) { - auto contents = inner_filter(std::move(input), effect_transform); - contents = outer_filter(FilterInput::Make(contents), effect_transform); + inner_filter = inner_proc.value()](FilterInput::Ref input, + const Matrix& effect_transform, + bool is_subpass) { + auto contents = + inner_filter(std::move(input), effect_transform, is_subpass); + contents = outer_filter(FilterInput::Make(contents), effect_transform, + is_subpass); return contents; }; break; @@ -736,9 +743,8 @@ static std::optional ToImageFilterProc( return std::nullopt; } return [color_filter = color_filter_proc.value()]( - FilterInput::Ref input, const Matrix& effect_transform) { - return color_filter(std::move(input)); - }; + FilterInput::Ref input, const Matrix& effect_transform, + bool is_subpass) { return color_filter(std::move(input)); }; break; } case flutter::DlImageFilterType::kLocalMatrixFilter: { @@ -755,9 +761,10 @@ static std::optional ToImageFilterProc( auto matrix = ToMatrix(local_matrix_filter->matrix()); return [matrix, filter_proc = image_filter_proc.value()]( - FilterInput::Ref input, const Matrix& effect_transform) { + FilterInput::Ref input, const Matrix& effect_transform, + bool is_subpass) { std::shared_ptr filter = - filter_proc(std::move(input), effect_transform); + filter_proc(std::move(input), effect_transform, is_subpass); return FilterContents::MakeLocalMatrixFilter(FilterInput::Make(filter), matrix); }; diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index 0c5c9565b69f3..fef9d306ce93b 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -932,6 +932,39 @@ TEST_P(DisplayListTest, CanDrawWithMatrixFilter) { ASSERT_TRUE(OpenPlaygroundHere(callback)); } +TEST_P(DisplayListTest, CanDrawWithMatrixFilterWhenSavingLayer) { + flutter::DisplayListBuilder builder; + builder.Save(); + builder.Scale(2.0, 2.0); + flutter::DlPaint paint; + paint.setColor(flutter::DlColor::kYellow()); + builder.DrawRect(SkRect::MakeWH(300, 300), paint); + paint.setStrokeWidth(1.0); + paint.setDrawStyle(flutter::DlDrawStyle::kStroke); + paint.setColor(flutter::DlColor::kBlack().withAlpha(0x80)); + builder.DrawLine(SkPoint::Make(150, 0), SkPoint::Make(150, 300), paint); + builder.DrawLine(SkPoint::Make(0, 150), SkPoint::Make(300, 150), paint); + + SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100); + flutter::DlPaint save_paint; + SkMatrix filter_matrix = SkMatrix::I(); + filter_matrix.postTranslate(-150, -150); + filter_matrix.postScale(0.2f, 0.2f); + filter_matrix.postTranslate(150, 150); + + auto filter = flutter::DlMatrixImageFilter( + filter_matrix, flutter::DlImageSampling::kNearestNeighbor); + save_paint.setImageFilter(filter.shared()); + + builder.SaveLayer(&bounds, &save_paint); + flutter::DlPaint paint2; + paint2.setColor(flutter::DlColor::kBlue()); + builder.DrawRect(bounds, paint2); + builder.Restore(); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + TEST_P(DisplayListTest, CanDrawRectWithLinearToSrgbColorFilter) { flutter::DlPaint paint; paint.setColor(flutter::DlColor(0xFF2196F3).withAlpha(128)); diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index 48c0b08ebd6a3..23a59b118d212 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -113,11 +113,15 @@ std::shared_ptr FilterContents::MakeMorphology( std::shared_ptr FilterContents::MakeMatrixFilter( FilterInput::Ref input, const Matrix& matrix, - const SamplerDescriptor& desc) { + const SamplerDescriptor& desc, + const Matrix& effect_transform, + bool is_subpass) { auto filter = std::make_shared(); filter->SetInputs({std::move(input)}); filter->SetMatrix(matrix); filter->SetSamplerDescriptor(desc); + filter->SetEffectTransform(effect_transform); + filter->SetSubpass(is_subpass); return filter; } @@ -154,7 +158,7 @@ void FilterContents::SetCoverageCrop(std::optional coverage_crop) { } void FilterContents::SetEffectTransform(Matrix effect_transform) { - effect_transform_ = effect_transform.Basis(); + effect_transform_ = effect_transform; } bool FilterContents::Render(const ContentContext& renderer, diff --git a/impeller/entity/contents/filters/filter_contents.h b/impeller/entity/contents/filters/filter_contents.h index 00959b69d4e96..c02c2ca30678c 100644 --- a/impeller/entity/contents/filters/filter_contents.h +++ b/impeller/entity/contents/filters/filter_contents.h @@ -78,7 +78,9 @@ class FilterContents : public Contents { static std::shared_ptr MakeMatrixFilter( FilterInput::Ref input, const Matrix& matrix, - const SamplerDescriptor& desc); + const SamplerDescriptor& desc, + const Matrix& effect_transform, + bool is_subpass); static std::shared_ptr MakeLocalMatrixFilter( FilterInput::Ref input, diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 29543df5aa80c..56b3665e38e1b 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -113,7 +113,7 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( auto radius = Radius{blur_sigma_}.radius; - auto transform = entity.GetTransformation() * effect_transform; + auto transform = entity.GetTransformation() * effect_transform.Basis(); auto transformed_blur_radius = transform.TransformDirection(blur_direction_ * radius); @@ -311,7 +311,7 @@ std::optional DirectionalGaussianBlurFilterContents::GetFilterCoverage( return std::nullopt; } - auto transform = inputs[0]->GetTransform(entity) * effect_transform; + auto transform = inputs[0]->GetTransform(entity) * effect_transform.Basis(); auto transformed_blur_vector = transform.TransformDirection(blur_direction_* Radius{blur_sigma_}.radius) .Abs(); diff --git a/impeller/entity/contents/filters/matrix_filter_contents.cc b/impeller/entity/contents/filters/matrix_filter_contents.cc index 45b6aad04d87c..62283d3504fe8 100644 --- a/impeller/entity/contents/filters/matrix_filter_contents.cc +++ b/impeller/entity/contents/filters/matrix_filter_contents.cc @@ -14,6 +14,10 @@ void MatrixFilterContents::SetMatrix(Matrix matrix) { matrix_ = matrix; } +void MatrixFilterContents::SetSubpass(bool is_subpass) { + is_subpass_ = is_subpass; +} + void MatrixFilterContents::SetSamplerDescriptor(SamplerDescriptor desc) { sampler_descriptor_ = std::move(desc); } @@ -29,9 +33,10 @@ std::optional MatrixFilterContents::RenderFilter( return std::nullopt; } - snapshot->transform = entity.GetTransformation() * // - matrix_ * // - entity.GetTransformation().Invert() * // + auto& transform = is_subpass_ ? effect_transform : entity.GetTransformation(); + snapshot->transform = transform * // + matrix_ * // + transform.Invert() * // snapshot->transform; snapshot->sampler_descriptor = sampler_descriptor_; return Contents::EntityFromSnapshot(snapshot, entity.GetBlendMode(), @@ -50,10 +55,10 @@ std::optional MatrixFilterContents::GetFilterCoverage( if (!coverage.has_value()) { return std::nullopt; } - - auto transform = inputs[0]->GetTransform(entity) * // - matrix_ * // - inputs[0]->GetTransform(entity).Invert(); + auto& m = is_subpass_ ? effect_transform : inputs[0]->GetTransform(entity); + auto transform = m * // + matrix_ * // + m.Invert(); // return coverage->TransformBounds(transform); } diff --git a/impeller/entity/contents/filters/matrix_filter_contents.h b/impeller/entity/contents/filters/matrix_filter_contents.h index 2ccdd2b4ff694..bbaee97f70537 100644 --- a/impeller/entity/contents/filters/matrix_filter_contents.h +++ b/impeller/entity/contents/filters/matrix_filter_contents.h @@ -17,6 +17,8 @@ class MatrixFilterContents final : public FilterContents { void SetMatrix(Matrix matrix); + void SetSubpass(bool is_subpass); + void SetSamplerDescriptor(SamplerDescriptor desc); // |FilterContents| @@ -35,6 +37,7 @@ class MatrixFilterContents final : public FilterContents { Matrix matrix_; SamplerDescriptor sampler_descriptor_ = {}; + bool is_subpass_; FML_DISALLOW_COPY_AND_ASSIGN(MatrixFilterContents); }; diff --git a/impeller/entity/contents/filters/morphology_filter_contents.cc b/impeller/entity/contents/filters/morphology_filter_contents.cc index ca49965856071..3386a74eef844 100644 --- a/impeller/entity/contents/filters/morphology_filter_contents.cc +++ b/impeller/entity/contents/filters/morphology_filter_contents.cc @@ -93,7 +93,7 @@ std::optional DirectionalMorphologyFilterContents::RenderFilter( frame_info.texture_sampler_y_coord_scale = input_snapshot->texture->GetYCoordScale(); - auto transform = entity.GetTransformation() * effect_transform; + auto transform = entity.GetTransformation() * effect_transform.Basis(); auto transformed_radius = transform.TransformDirection(direction_ * radius_.radius); auto transformed_texture_vertices = @@ -162,7 +162,7 @@ std::optional DirectionalMorphologyFilterContents::GetFilterCoverage( if (!coverage.has_value()) { return std::nullopt; } - auto transform = inputs[0]->GetTransform(entity) * effect_transform; + auto transform = inputs[0]->GetTransform(entity) * effect_transform.Basis(); auto transformed_vector = transform.TransformDirection(direction_ * radius_.radius).Abs(); diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 487c56d063976..6adf1faf3f834 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -309,7 +309,8 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( // Render the backdrop texture before any of the pass elements. const auto& proc = subpass->backdrop_filter_proc_.value(); backdrop_filter_contents = - proc(FilterInput::Make(std::move(texture)), subpass->xformation_); + proc(FilterInput::Make(std::move(texture)), subpass->xformation_, + /*is_subpass*/ true); // The subpass will need to read from the current pass texture when // rendering the backdrop, so if there's an active pass, end it prior to diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index c958420157d13..49d954f7ab89c 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -27,7 +27,8 @@ class EntityPass { using Element = std::variant>; using BackdropFilterProc = std::function( FilterInput::Ref, - const Matrix& effect_transform)>; + const Matrix& effect_transform, + bool is_subpass)>; EntityPass(); From ad21ac50ae1dfe847e899064f47ef606672a0d02 Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Mon, 13 Mar 2023 14:40:16 +0800 Subject: [PATCH 2/2] Clean code --- impeller/entity/contents/filters/filter_contents.cc | 2 +- impeller/entity/contents/filters/matrix_filter_contents.cc | 2 +- impeller/entity/contents/filters/matrix_filter_contents.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index 23a59b118d212..5458b5e05dbd3 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -121,7 +121,7 @@ std::shared_ptr FilterContents::MakeMatrixFilter( filter->SetMatrix(matrix); filter->SetSamplerDescriptor(desc); filter->SetEffectTransform(effect_transform); - filter->SetSubpass(is_subpass); + filter->SetIsSubpass(is_subpass); return filter; } diff --git a/impeller/entity/contents/filters/matrix_filter_contents.cc b/impeller/entity/contents/filters/matrix_filter_contents.cc index 62283d3504fe8..8960fda8b289f 100644 --- a/impeller/entity/contents/filters/matrix_filter_contents.cc +++ b/impeller/entity/contents/filters/matrix_filter_contents.cc @@ -14,7 +14,7 @@ void MatrixFilterContents::SetMatrix(Matrix matrix) { matrix_ = matrix; } -void MatrixFilterContents::SetSubpass(bool is_subpass) { +void MatrixFilterContents::SetIsSubpass(bool is_subpass) { is_subpass_ = is_subpass; } diff --git a/impeller/entity/contents/filters/matrix_filter_contents.h b/impeller/entity/contents/filters/matrix_filter_contents.h index bbaee97f70537..bf2e49b2904d2 100644 --- a/impeller/entity/contents/filters/matrix_filter_contents.h +++ b/impeller/entity/contents/filters/matrix_filter_contents.h @@ -17,7 +17,7 @@ class MatrixFilterContents final : public FilterContents { void SetMatrix(Matrix matrix); - void SetSubpass(bool is_subpass); + void SetIsSubpass(bool is_subpass); void SetSamplerDescriptor(SamplerDescriptor desc); @@ -37,7 +37,7 @@ class MatrixFilterContents final : public FilterContents { Matrix matrix_; SamplerDescriptor sampler_descriptor_ = {}; - bool is_subpass_; + bool is_subpass_ = false; FML_DISALLOW_COPY_AND_ASSIGN(MatrixFilterContents); };