[Impeller] match sigma scaling to Skia scaling. (#48434)

The Impeller blur is scaling down about twice as fast as the Skia Blur. Instead adopt their approximate constant values, which results in less shaking as the blur gets bigger.

FYI @gaaclarke
diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc
index d3dca81..bcbf85f 100644
--- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc
+++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc
@@ -144,21 +144,21 @@
   return out_texture;
 }
 
-/// Calculate how much to scale down the texture depending on the blur radius.
-/// This curve was taken from |DirectionalGaussianBlurFilterContents|.
-Scalar CalculateScale(Scalar radius) {
-  constexpr Scalar decay = 4.0;   // Larger is more gradual.
-  constexpr Scalar limit = 0.95;  // The maximum percentage of the scaledown.
-  const Scalar curve =
-      std::min(1.0, decay / (std::max(1.0f, radius) + decay - 1.0));
-  return (curve - 1) * limit + 1;
-};
-
 }  // namespace
 
 GaussianBlurFilterContents::GaussianBlurFilterContents(Scalar sigma)
     : sigma_(sigma) {}
 
+// This value was extracted from Skia, see:
+//  * https://github.com/google/skia/blob/d29cc3fe182f6e8a8539004a6a4ee8251677a6fd/src/gpu/ganesh/GrBlurUtils.cpp#L2561-L2576
+//  * https://github.com/google/skia/blob/d29cc3fe182f6e8a8539004a6a4ee8251677a6fd/src/gpu/BlurUtils.h#L57
+Scalar GaussianBlurFilterContents::CalculateScale(Scalar sigma) {
+  if (sigma <= 4) {
+    return 1.0;
+  }
+  return 4.0 / sigma;
+};
+
 std::optional<Rect> GaussianBlurFilterContents::GetFilterSourceCoverage(
     const Matrix& effect_transform,
     const Rect& output_limit) const {
@@ -213,7 +213,10 @@
   }
 
   Scalar blur_radius = CalculateBlurRadius(sigma_);
-  Scalar desired_scalar = CalculateScale(blur_radius);
+  Scalar desired_scalar = CalculateScale(sigma_);
+  // TODO(jonahwilliams): if scaling value is 1.0, then skip the downsample
+  // pass.
+
   Vector2 downsample_scalar(desired_scalar, desired_scalar);
   Vector2 padding(ceil(blur_radius), ceil(blur_radius));
 
diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h
index 0b85fb1..dfeaa8a 100644
--- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h
+++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h
@@ -42,6 +42,11 @@
                            const Entity& entity,
                            const ISize& pass_size);
 
+  /// Calculate the scale factor for the downsample pass given a sigma value.
+  ///
+  /// Visible for testing.
+  static Scalar CalculateScale(Scalar sigma);
+
  private:
   // |FilterContents|
   std::optional<Entity> RenderFilter(
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 88dbb80..85e0b3d 100644
--- a/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc
+++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc
@@ -116,6 +116,15 @@
   ASSERT_EQ(coverage, Rect::MakeLTRB(100 - 2, 100 - 2, 200 + 2, 200 + 2));
 }
 
+TEST(GaussianBlurFilterContentsTest, CalculateSigmaValues) {
+  EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(1.0f), 1);
+  EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(2.0f), 1);
+  EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(3.0f), 1);
+  EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(4.0f), 1);
+  EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(16.0f), 0.25);
+  EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(1024.0f), 4.f / 1024.f);
+}
+
 TEST_P(GaussianBlurFilterContentsTest, RenderCoverageMatchesGetCoverage) {
   TextureDescriptor desc = {
       .storage_mode = StorageMode::kDevicePrivate,