diff --git a/impeller/display_list/dl_golden_unittests.cc b/impeller/display_list/dl_golden_unittests.cc index 89f04aa4b55ea..a0c3af88c04e9 100644 --- a/impeller/display_list/dl_golden_unittests.cc +++ b/impeller/display_list/dl_golden_unittests.cc @@ -14,6 +14,7 @@ namespace testing { using impeller::PlaygroundBackend; using impeller::PlaygroundTest; using impeller::Point; +using impeller::Scalar; INSTANTIATE_PLAYGROUND_SUITE(DlGoldenTest); @@ -55,7 +56,7 @@ TEST_P(DlGoldenTest, Bug147807) { Point content_scale = GetContentScale(); auto draw = [content_scale](DlCanvas* canvas, const std::vector>& images) { - canvas->Transform2DAffine(content_scale.x, 0, 0, 0, content_scale.y, 0); + canvas->Scale(content_scale.x, content_scale.y); DlPaint paint; paint.setColor(DlColor(0xfffef7ff)); canvas->DrawRect(SkRect::MakeLTRB(0, 0, 375, 667), paint); @@ -100,5 +101,84 @@ TEST_P(DlGoldenTest, Bug147807) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +namespace { +void DrawBlurGrid(DlCanvas* canvas) { + DlPaint paint; + paint.setColor(DlColor(0xfffef7ff)); + Scalar width = 150; + Scalar height = 150; + Scalar gap = 80; + std::vector blur_radii = {10, 30, 50}; + for (size_t i = 0; i < blur_radii.size(); ++i) { + Scalar blur_radius = blur_radii[i]; + auto blur_filter = std::make_shared( + flutter::DlBlurStyle::kNormal, blur_radius); + paint.setMaskFilter(blur_filter); + SkRRect rrect; + Scalar yval = gap + i * (gap + height); + rrect.setNinePatch(SkRect::MakeXYWH(gap, yval, width, height), 10, 10, 10, + 10); + canvas->DrawRRect(rrect, paint); + rrect.setNinePatch(SkRect::MakeXYWH(2.0 * gap + width, yval, width, height), + 9, 10, 10, 10); + canvas->DrawRRect(rrect, paint); + } +} +} // namespace + +TEST_P(DlGoldenTest, GaussianVsRRectBlur) { + Point content_scale = GetContentScale(); + auto draw = [content_scale](DlCanvas* canvas, + const std::vector>& images) { + canvas->Scale(content_scale.x, content_scale.y); + canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233))); + DrawBlurGrid(canvas); + }; + + DisplayListBuilder builder; + std::vector> images; + draw(&builder, images); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(DlGoldenTest, GaussianVsRRectBlurScaled) { + Point content_scale = GetContentScale(); + auto draw = [content_scale](DlCanvas* canvas, + const std::vector>& images) { + canvas->Scale(content_scale.x, content_scale.y); + canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233))); + canvas->Scale(0.33, 0.33); + DrawBlurGrid(canvas); + }; + + DisplayListBuilder builder; + std::vector> images; + draw(&builder, images); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(DlGoldenTest, GaussianVsRRectBlurScaledRotated) { + Point content_scale = GetContentScale(); + auto draw = [content_scale](DlCanvas* canvas, + const std::vector>& images) { + canvas->Scale(content_scale.x, content_scale.y); + canvas->Translate(200, 200); + canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233))); + canvas->Scale(0.33, 0.33); + canvas->Translate(300, 300); + canvas->Rotate(45); + canvas->Translate(-300, -300); + DrawBlurGrid(canvas); + }; + + DisplayListBuilder builder; + std::vector> images; + draw(&builder, images); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + } // namespace testing } // namespace flutter diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index c6d5e54a8ba14..0dfbdf2211db4 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -24,7 +24,8 @@ const int32_t GaussianBlurFilterContents::kBlurFilterRequiredMipCount = 4; namespace { // 48 comes from gaussian.frag. -const int32_t kMaxKernelSize = 48; +const int32_t kMaxKernelSize = 50; +constexpr Scalar kMaxSigma = 500.0f; SamplerDescriptor MakeSamplerDescriptor(MinMagFilter filter, SamplerAddressMode address_mode) { @@ -363,9 +364,14 @@ std::optional GaussianBlurFilterContents::GetFilterCoverage( return {}; } - Vector2 scaled_sigma = (effect_transform.Basis() * + Vector2 entity_scale_x = entity.GetTransform().Basis() * Vector2(1.0, 0.0); + Vector2 entity_scale_y = entity.GetTransform().Basis() * Vector2(0.0, 1.0); + Vector2 scaled_sigma = (Matrix::MakeScale({entity_scale_x.GetLength(), + entity_scale_y.GetLength(), 1.0}) * Vector2(ScaleSigma(sigma_x_), ScaleSigma(sigma_y_))) .Abs(); + scaled_sigma.x = std::min(scaled_sigma.x, kMaxSigma); + scaled_sigma.y = std::min(scaled_sigma.y, kMaxSigma); Vector2 blur_radius = Vector2(CalculateBlurRadius(scaled_sigma.x), CalculateBlurRadius(scaled_sigma.y)); Vector2 padding(ceil(blur_radius.x), ceil(blur_radius.y)); @@ -384,9 +390,15 @@ std::optional GaussianBlurFilterContents::RenderFilter( return std::nullopt; } + Vector2 entity_scale_x = entity.GetTransform().Basis() * Vector2(1.0, 0.0); + Vector2 entity_scale_y = entity.GetTransform().Basis() * Vector2(0.0, 1.0); Vector2 scaled_sigma = (effect_transform.Basis() * + Matrix::MakeScale({entity_scale_x.GetLength(), + entity_scale_y.GetLength(), 1.0}) * Vector2(ScaleSigma(sigma_x_), ScaleSigma(sigma_y_))) .Abs(); + scaled_sigma.x = std::min(scaled_sigma.x, kMaxSigma); + scaled_sigma.y = std::min(scaled_sigma.y, kMaxSigma); Vector2 blur_radius = Vector2(CalculateBlurRadius(scaled_sigma.x), CalculateBlurRadius(scaled_sigma.y)); Vector2 padding(ceil(blur_radius.x), ceil(blur_radius.y)); @@ -582,7 +594,7 @@ Quad GaussianBlurFilterContents::CalculateUVs( // that puts the minima there and a f(0)=1. Scalar GaussianBlurFilterContents::ScaleSigma(Scalar sigma) { // Limit the kernel size to 1000x1000 pixels, like Skia does. - Scalar clamped = std::min(sigma, 500.0f); + Scalar clamped = std::min(sigma, kMaxSigma); constexpr Scalar a = 3.4e-06; constexpr Scalar b = -3.4e-3; constexpr Scalar c = 1.f; diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc index ec64d46cf1450..dad6c5bc0ba6d 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc @@ -400,7 +400,7 @@ TEST_P(GaussianBlurFilterContentsTest, if (result_coverage.has_value() && contents_coverage.has_value()) { EXPECT_TRUE(RectNear(result_coverage.value(), contents_coverage.value())); EXPECT_TRUE(RectNear(contents_coverage.value(), - Rect::MakeLTRB(98.f, 78.f, 302.f, 282.f))); + Rect::MakeXYWH(94.f, 74.f, 212.f, 212.f))); } } } diff --git a/impeller/entity/shaders/filters/gaussian.frag b/impeller/entity/shaders/filters/gaussian.frag index 0fb5fb3b00ec9..f83a59940896d 100644 --- a/impeller/entity/shaders/filters/gaussian.frag +++ b/impeller/entity/shaders/filters/gaussian.frag @@ -18,7 +18,7 @@ struct KernelSample { uniform KernelSamples { int sample_count; - KernelSample samples[48]; + KernelSample samples[50]; } blur_info; diff --git a/testing/impeller_golden_tests_output.txt b/testing/impeller_golden_tests_output.txt index fb2b34e52ff03..8233f6a34b596 100644 --- a/testing/impeller_golden_tests_output.txt +++ b/testing/impeller_golden_tests_output.txt @@ -798,3 +798,12 @@ impeller_Play_DlGoldenTest_CanDrawPaint_Vulkan.png impeller_Play_DlGoldenTest_CanRenderImage_Metal.png impeller_Play_DlGoldenTest_CanRenderImage_OpenGLES.png impeller_Play_DlGoldenTest_CanRenderImage_Vulkan.png +impeller_Play_DlGoldenTest_GaussianVsRRectBlurScaledRotated_Metal.png +impeller_Play_DlGoldenTest_GaussianVsRRectBlurScaledRotated_OpenGLES.png +impeller_Play_DlGoldenTest_GaussianVsRRectBlurScaledRotated_Vulkan.png +impeller_Play_DlGoldenTest_GaussianVsRRectBlurScaled_Metal.png +impeller_Play_DlGoldenTest_GaussianVsRRectBlurScaled_OpenGLES.png +impeller_Play_DlGoldenTest_GaussianVsRRectBlurScaled_Vulkan.png +impeller_Play_DlGoldenTest_GaussianVsRRectBlur_Metal.png +impeller_Play_DlGoldenTest_GaussianVsRRectBlur_OpenGLES.png +impeller_Play_DlGoldenTest_GaussianVsRRectBlur_Vulkan.png