Skip to content

Commit

Permalink
[Impeller] started only dropping to 1/16 scale if 1/8 would overflow
Browse files Browse the repository at this point in the history
  • Loading branch information
gaaclarke committed Feb 5, 2024
1 parent 69d05ca commit 71e9b0e
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 18 deletions.
4 changes: 4 additions & 0 deletions impeller/aiks/aiks_blur_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,10 @@ TEST_P(AiksTest, GaussianBlurAnimatedBackdrop) {
Point(1024 / 2 - boston->GetSize().width / 2,
(768 / 2 - boston->GetSize().height / 2) + y),
{});
auto [handle_a, handle_b] = IMPELLER_PLAYGROUND_LINE(
Point(100, 100), Point(900, 700), 20, Color::Red(), Color::Red());
canvas.ClipRect(
Rect::MakeLTRB(handle_a.x, handle_a.y, handle_b.x, handle_b.y));
canvas.ClipRect(Rect::MakeLTRB(100, 100, 900, 700));
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
ImageFilter::MakeBlur(Sigma(sigma), Sigma(sigma),
Expand Down
35 changes: 24 additions & 11 deletions impeller/entity/contents/filters/gaussian_blur_filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const int32_t GaussianBlurFilterContents::kBlurFilterRequiredMipCount = 4;

namespace {

// 48 comes from kernel.glsl.
const int32_t kMaxKernelSize = 48;

SamplerDescriptor MakeSamplerDescriptor(MinMagFilter filter,
SamplerAddressMode address_mode) {
SamplerDescriptor sampler_desc;
Expand Down Expand Up @@ -189,6 +192,10 @@ Rect MakeReferenceUVs(const Rect& reference, const Rect& rect) {
rect.GetSize());
return result.Scale(1.0f / Vector2(reference.GetSize()));
}

int ScaleBlurRadius(Scalar radius, Scalar scalar) {
return static_cast<int>(std::round(radius * scalar));
}
} // namespace

std::string_view GaussianBlurFilterContents::kNoMipsError =
Expand All @@ -203,17 +210,25 @@ GaussianBlurFilterContents::GaussianBlurFilterContents(
// 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) {
Scalar GaussianBlurFilterContents::CalculateScale(Scalar sigma,
Scalar blur_radius) {
if (sigma <= 4) {
return 1.0;
}
Scalar result = 4.0 / sigma;
Scalar raw_result = 4.0 / sigma;
// Round to the nearest 1/(2^n) to get the best quality down scaling.
Scalar exponent = round(log2f(result));
Scalar exponent = round(log2f(raw_result));
// Don't scale down below 1/16th to preserve signal.
exponent = std::max(-4.0f, exponent);
Scalar rounded = powf(2.0f, exponent);
return rounded;
Scalar result = rounded;
// Only drop below 1/8 if 1/8 would overflow our kernel.
if (rounded < 0.125f) {
Scalar rounded_plus = powf(2.0f, exponent + 1);
int kernel_size_plus = (ScaleBlurRadius(blur_radius, rounded_plus) * 2) + 1;
result = kernel_size_plus < kMaxKernelSize ? rounded_plus : rounded;
}
return result;
};

std::optional<Rect> GaussianBlurFilterContents::GetFilterSourceCoverage(
Expand Down Expand Up @@ -305,7 +320,8 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
FML_DCHECK(!input_snapshot->texture->NeedsMipmapGeneration());

Scalar desired_scalar =
std::min(CalculateScale(scaled_sigma.x), CalculateScale(scaled_sigma.y));
std::min(CalculateScale(scaled_sigma.x, blur_radius.x),
CalculateScale(scaled_sigma.y, blur_radius.y));
// TODO(jonahwilliams): If desired_scalar is 1.0 and we fully acquired the
// gutter from the expanded_coverage_hint, we can skip the downsample pass.
// pass.
Expand Down Expand Up @@ -370,8 +386,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
BlurParameters{
.blur_uv_offset = Point(0.0, pass1_pixel_size.y),
.blur_sigma = scaled_sigma.y * effective_scalar.y,
.blur_radius =
static_cast<int>(std::round(blur_radius.y * effective_scalar.y)),
.blur_radius = ScaleBlurRadius(blur_radius.y, effective_scalar.y),
.step_size = 1,
},
/*destination_target=*/std::nullopt, blur_uvs);
Expand All @@ -392,8 +407,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
BlurParameters{
.blur_uv_offset = Point(pass1_pixel_size.x, 0.0),
.blur_sigma = scaled_sigma.x * effective_scalar.x,
.blur_radius =
static_cast<int>(std::round(blur_radius.x * effective_scalar.x)),
.blur_radius = ScaleBlurRadius(blur_radius.x, effective_scalar.x),
.step_size = 1,
},
pass3_destination, blur_uvs);
Expand Down Expand Up @@ -457,8 +471,7 @@ KernelPipeline::FragmentShader::KernelSamples GenerateBlurInfo(
KernelPipeline::FragmentShader::KernelSamples result;
result.sample_count =
((2 * parameters.blur_radius) / parameters.step_size) + 1;
// 48 comes from kernel.glsl.
FML_CHECK(result.sample_count < 48);
FML_CHECK(result.sample_count < kMaxKernelSize);

// Chop off the last samples if the radius >= 3 where they account for < 1.56%
// of the result.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class GaussianBlurFilterContents final : public FilterContents {
/// Calculate the scale factor for the downsample pass given a sigma value.
///
/// Visible for testing.
static Scalar CalculateScale(Scalar sigma);
static Scalar CalculateScale(Scalar sigma, Scalar blur_radius);

/// Scales down the sigma value to match Skia's behavior.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,13 @@ TEST(GaussianBlurFilterContentsTest, FilterSourceCoverage) {
}

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(1.0f, 1.f), 1);
EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(2.0f, 1.f), 1);
EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(3.0f, 1.f), 1);
EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(4.0f, 1.f), 1);
EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(16.0f, 1.f), 0.25);
// Downsample clamped to 1/16th.
EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(1024.0f), 0.0625);
EXPECT_EQ(GaussianBlurFilterContents::CalculateScale(1024.0f, 1.f), 0.0625);
}

TEST_P(GaussianBlurFilterContentsTest, RenderCoverageMatchesGetCoverage) {
Expand Down

0 comments on commit 71e9b0e

Please sign in to comment.