Skip to content

[Impeller] New blur has shimmers when sigma > 57 and content animating under it #142753

@gaaclarke

Description

@gaaclarke

At some point content reaches a threshold where it will shimmer under a blur if the sigma is large enough.

In the below test that inflection point is somewhere between sigma 50 and 60. The differences between sigma 50 and sigma 60 is that the scalar drops from 1/2^4 to 1/2^5. We can't clamp the scalar to 1/2^4 because then our blur radius would get too large for the kernel shader. We could expand the size of the kernel shader, and we could also do the sample_size/2+lerp hack to reduce our kernel size.

I suspect this ratio isn't a hard rule either, that the limit we want will depend on the size of the texture being blurred. At a certain point scaling something down to a handful of pixels is going to look bad.

Note: the videos below aren't capturing at high enough quality to represent the quality you see on the screen, but the motion of the blur can be seen

Engine version: 1312954

sigma 50

Untitled.mp4

sigma 60

Untitled2.mp4

reproduction code

TEST_P(AiksTest, GaussianBlurAnimatedBackdrop) {
  // This test is for checking out how stable rendering is when content is
  // translated underneath a blur.  Animating under a blur can cause
  // *shimmering* to happen as a result of pixel alignment.
  // See also: https://github.com/flutter/flutter/issues/140193
  auto boston = std::make_shared<Image>(
      CreateTextureForFixture("boston.jpg", /*enable_mipmapping=*/true));
  ASSERT_TRUE(boston);
  int64_t count = 0;
  Scalar sigma = 20.0;
  Scalar freq = 0.1;
  Scalar amp = 50.0;
  auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
    ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
    {
      ImGui::SliderFloat("Sigma", &sigma, 0, 500);
      ImGui::SliderFloat("Frequency", &freq, 0.01, 2.0);
      ImGui::SliderFloat("Amplitude", &amp, 1, 100);
    }
    ImGui::End();

    Canvas canvas;
    canvas.Scale(GetContentScale());
    Scalar y = amp * sin(freq * 2.0 * M_PI * count / 60);
    canvas.DrawImage(boston,
                     Point(1024 / 2 - boston->GetSize().width / 2,
                           (768 / 2 - boston->GetSize().height / 2) + y),
                     {});
    canvas.ClipRect(Rect::MakeLTRB(100, 100, 900, 700));
    canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
                     ImageFilter::MakeBlur(Sigma(sigma), Sigma(sigma),
                                           FilterContents::BlurStyle::kNormal,
                                           Entity::TileMode::kClamp));
    count += 1;
    return canvas.EndRecordingAsPicture();
  };
  ASSERT_TRUE(OpenPlaygroundHere(callback));
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    e: impellerImpeller rendering backend issues and features requeststeam-engineOwned by Engine team

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions