Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Impeller] Made the new blur support 1D blurs #49001

Merged
merged 1 commit into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4551,7 +4551,21 @@ TEST_P(AiksTest, GaussianBlurWithoutDecalSupport) {
Sigma(20.0), Sigma(20.0), FilterContents::BlurStyle::kNormal,
Entity::TileMode::kDecal),
});
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, GaussianBlurOneDimension) {
Canvas canvas;

canvas.Scale(GetContentScale());
canvas.Scale({0.5, 0.5, 1.0});
std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
canvas.DrawImage(std::make_shared<Image>(boston), Point(100, 100), Paint{});
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
ImageFilter::MakeBlur(Sigma(50.0), Sigma(0.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp));
canvas.Restore();
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/contents/filters/filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ std::shared_ptr<FilterContents> FilterContents::MakeGaussianBlur(
// TODO(https://github.com/flutter/flutter/issues/131580): Remove once the new
// blur handles all cases.
if (use_new_filter) {
auto blur =
std::make_shared<GaussianBlurFilterContents>(sigma_x.sigma, tile_mode);
auto blur = std::make_shared<GaussianBlurFilterContents>(
sigma_x.sigma, sigma_y.sigma, tile_mode);
blur->SetInputs({input});
return blur;
}
Expand Down
43 changes: 26 additions & 17 deletions impeller/entity/contents/filters/gaussian_blur_filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ std::shared_ptr<Texture> MakeBlurSubpass(
const SamplerDescriptor& sampler_descriptor,
Entity::TileMode tile_mode,
const GaussianBlurFragmentShader::BlurInfo& blur_info) {
if (blur_info.blur_sigma < kEhCloseEnough) {
return input_texture;
}

// TODO(gaaclarke): This blurs the whole image, but because we know the clip
// region we could focus on just blurring that.
ISize subpass_size = input_texture->GetSize();
Expand Down Expand Up @@ -202,9 +206,10 @@ std::shared_ptr<Texture> MakeBlurSubpass(
} // namespace

GaussianBlurFilterContents::GaussianBlurFilterContents(
Scalar sigma,
Scalar sigma_x,
Scalar sigma_y,
Entity::TileMode tile_mode)
: sigma_(sigma), tile_mode_(tile_mode) {}
: sigma_x_(sigma_x), sigma_y_(sigma_y), tile_mode_(tile_mode) {}

// This value was extracted from Skia, see:
// * https://github.com/google/skia/blob/d29cc3fe182f6e8a8539004a6a4ee8251677a6fd/src/gpu/ganesh/GrBlurUtils.cpp#L2561-L2576
Expand All @@ -219,10 +224,11 @@ Scalar GaussianBlurFilterContents::CalculateScale(Scalar sigma) {
std::optional<Rect> GaussianBlurFilterContents::GetFilterSourceCoverage(
const Matrix& effect_transform,
const Rect& output_limit) const {
Scalar scaled_sigma = ScaleSigma(sigma_);
Scalar blur_radius = CalculateBlurRadius(scaled_sigma);
Vector2 scaled_sigma = {ScaleSigma(sigma_x_), ScaleSigma(sigma_y_)};
Vector2 blur_radius = {CalculateBlurRadius(scaled_sigma.x),
CalculateBlurRadius(scaled_sigma.y)};
Vector3 blur_radii =
effect_transform.Basis() * Vector3{blur_radius, blur_radius, 0.0};
effect_transform.Basis() * Vector3{blur_radius.x, blur_radius.y, 0.0};
return output_limit.Expand(Point(blur_radii.x, blur_radii.y));
}

Expand All @@ -239,11 +245,12 @@ std::optional<Rect> GaussianBlurFilterContents::GetFilterCoverage(
return {};
}

Scalar scaled_sigma = ScaleSigma(sigma_);
Scalar blur_radius = CalculateBlurRadius(scaled_sigma);
Vector2 scaled_sigma = {ScaleSigma(sigma_x_), ScaleSigma(sigma_y_)};
Vector2 blur_radius = {CalculateBlurRadius(scaled_sigma.x),
CalculateBlurRadius(scaled_sigma.y)};
Vector3 blur_radii =
(inputs[0]->GetTransform(entity).Basis() * effect_transform.Basis() *
Vector3{blur_radius, blur_radius, 0.0})
Vector3{blur_radius.x, blur_radius.y, 0.0})
.Abs();
return input_coverage.value().Expand(Point(blur_radii.x, blur_radii.y));
}
Expand All @@ -259,9 +266,10 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
return std::nullopt;
}

Scalar scaled_sigma = ScaleSigma(sigma_);
Scalar blur_radius = CalculateBlurRadius(scaled_sigma);
Vector2 padding(ceil(blur_radius), ceil(blur_radius));
Vector2 scaled_sigma = {ScaleSigma(sigma_x_), ScaleSigma(sigma_y_)};
Vector2 blur_radius = {CalculateBlurRadius(scaled_sigma.x),
CalculateBlurRadius(scaled_sigma.y)};
Vector2 padding(ceil(blur_radius.x), ceil(blur_radius.y));

// Apply as much of the desired padding as possible from the source. This may
// be ignored so must be accounted for in the downsample pass by adding a
Expand All @@ -281,12 +289,13 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
return std::nullopt;
}

if (scaled_sigma < kEhCloseEnough) {
if (scaled_sigma.x < kEhCloseEnough && scaled_sigma.y < kEhCloseEnough) {
return Entity::FromSnapshot(input_snapshot.value(), entity.GetBlendMode(),
entity.GetClipDepth()); // No blur to render.
}

Scalar desired_scalar = CalculateScale(scaled_sigma);
Scalar desired_scalar =
std::min(CalculateScale(scaled_sigma.x), CalculateScale(scaled_sigma.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 @@ -314,8 +323,8 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
input_snapshot->sampler_descriptor, tile_mode_,
GaussianBlurFragmentShader::BlurInfo{
.blur_uv_offset = Point(0.0, pass1_pixel_size.y),
.blur_sigma = scaled_sigma * effective_scalar.y,
.blur_radius = blur_radius * effective_scalar.y,
.blur_sigma = scaled_sigma.y * effective_scalar.y,
.blur_radius = blur_radius.y * effective_scalar.y,
.step_size = 1.0,
});

Expand All @@ -325,8 +334,8 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
input_snapshot->sampler_descriptor, tile_mode_,
GaussianBlurFragmentShader::BlurInfo{
.blur_uv_offset = Point(pass1_pixel_size.x, 0.0),
.blur_sigma = scaled_sigma * effective_scalar.x,
.blur_radius = blur_radius * effective_scalar.x,
.blur_sigma = scaled_sigma.x * effective_scalar.x,
.blur_radius = blur_radius.x * effective_scalar.x,
.step_size = 1.0,
});

Expand Down
10 changes: 7 additions & 3 deletions impeller/entity/contents/filters/gaussian_blur_filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ namespace impeller {
/// Note: This will replace `DirectionalGaussianBlurFilterContents`.
class GaussianBlurFilterContents final : public FilterContents {
public:
explicit GaussianBlurFilterContents(Scalar sigma, Entity::TileMode tile_mode);
explicit GaussianBlurFilterContents(Scalar sigma_x,
Scalar sigma_y,
Entity::TileMode tile_mode);

Scalar GetSigma() const { return sigma_; }
Scalar GetSigmaX() const { return sigma_x_; }
Scalar GetSigmaY() const { return sigma_y_; }

// |FilterContents|
std::optional<Rect> GetFilterSourceCoverage(
Expand Down Expand Up @@ -67,7 +70,8 @@ class GaussianBlurFilterContents final : public FilterContents {
const Rect& coverage,
const std::optional<Rect>& coverage_hint) const override;

const Scalar sigma_ = 0.0;
const Scalar sigma_x_ = 0.0;
const Scalar sigma_y_ = 0.0;
const Entity::TileMode tile_mode_;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,15 @@ class GaussianBlurFilterContentsTest : public EntityPlayground {
INSTANTIATE_PLAYGROUND_SUITE(GaussianBlurFilterContentsTest);

TEST(GaussianBlurFilterContentsTest, Create) {
GaussianBlurFilterContents contents(/*sigma=*/0.0, Entity::TileMode::kDecal);
ASSERT_EQ(contents.GetSigma(), 0.0);
GaussianBlurFilterContents contents(/*sigma_x=*/0.0, /*sigma_y=*/0.0,
Entity::TileMode::kDecal);
EXPECT_EQ(contents.GetSigmaX(), 0.0);
EXPECT_EQ(contents.GetSigmaY(), 0.0);
}

TEST(GaussianBlurFilterContentsTest, CoverageEmpty) {
GaussianBlurFilterContents contents(/*sigma=*/0.0, Entity::TileMode::kDecal);
GaussianBlurFilterContents contents(/*sigma_x=*/0.0, /*sigma_y=*/0.0,
Entity::TileMode::kDecal);
FilterInput::Vector inputs = {};
Entity entity;
std::optional<Rect> coverage =
Expand All @@ -76,7 +79,8 @@ TEST(GaussianBlurFilterContentsTest, CoverageEmpty) {
}

TEST(GaussianBlurFilterContentsTest, CoverageSimple) {
GaussianBlurFilterContents contents(/*sigma=*/0.0, Entity::TileMode::kDecal);
GaussianBlurFilterContents contents(/*sigma_x=*/0.0, /*sigma_y=*/0.0,
Entity::TileMode::kDecal);
FilterInput::Vector inputs = {
FilterInput::Make(Rect::MakeLTRB(10, 10, 110, 110))};
Entity entity;
Expand All @@ -87,7 +91,8 @@ TEST(GaussianBlurFilterContentsTest, CoverageSimple) {

TEST(GaussianBlurFilterContentsTest, CoverageWithSigma) {
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
GaussianBlurFilterContents contents(/*sigma=*/sigma_radius_1,
GaussianBlurFilterContents contents(/*sigma_x=*/sigma_radius_1,
/*sigma_y=*/sigma_radius_1,
Entity::TileMode::kDecal);
FilterInput::Vector inputs = {
FilterInput::Make(Rect::MakeLTRB(100, 100, 200, 200))};
Expand All @@ -107,7 +112,8 @@ TEST_P(GaussianBlurFilterContentsTest, CoverageWithTexture) {
.size = ISize(100, 100),
};
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
GaussianBlurFilterContents contents(/*sigma=*/sigma_radius_1,
GaussianBlurFilterContents contents(/*sigma_X=*/sigma_radius_1,
/*sigma_y=*/sigma_radius_1,
Entity::TileMode::kDecal);
std::shared_ptr<Texture> texture =
GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
Expand All @@ -130,7 +136,8 @@ TEST_P(GaussianBlurFilterContentsTest, CoverageWithEffectTransform) {
.size = ISize(100, 100),
};
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
GaussianBlurFilterContents contents(/*sigma=*/sigma_radius_1,
GaussianBlurFilterContents contents(/*sigma_x=*/sigma_radius_1,
/*sigma_y=*/sigma_radius_1,
Entity::TileMode::kDecal);
std::shared_ptr<Texture> texture =
GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
Expand All @@ -150,7 +157,7 @@ TEST_P(GaussianBlurFilterContentsTest, CoverageWithEffectTransform) {
TEST(GaussianBlurFilterContentsTest, FilterSourceCoverage) {
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<GaussianBlurFilterContents>(
sigma_radius_1, Entity::TileMode::kDecal);
sigma_radius_1, sigma_radius_1, Entity::TileMode::kDecal);
std::optional<Rect> coverage = contents->GetFilterSourceCoverage(
/*effect_transform=*/Matrix::MakeScale({2.0, 2.0, 1.0}),
/*output_limit=*/Rect::MakeLTRB(100, 100, 200, 200));
Expand All @@ -175,7 +182,7 @@ TEST_P(GaussianBlurFilterContentsTest, RenderCoverageMatchesGetCoverage) {
std::shared_ptr<Texture> texture = MakeTexture(desc);
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<GaussianBlurFilterContents>(
sigma_radius_1, Entity::TileMode::kDecal);
sigma_radius_1, sigma_radius_1, Entity::TileMode::kDecal);
contents->SetInputs({FilterInput::Make(texture)});
std::shared_ptr<ContentContext> renderer = GetContentContext();

Expand Down Expand Up @@ -208,7 +215,7 @@ TEST_P(GaussianBlurFilterContentsTest,
std::shared_ptr<Texture> texture = MakeTexture(desc);
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<GaussianBlurFilterContents>(
sigma_radius_1, Entity::TileMode::kDecal);
sigma_radius_1, sigma_radius_1, Entity::TileMode::kDecal);
contents->SetInputs({FilterInput::Make(texture)});
std::shared_ptr<ContentContext> renderer = GetContentContext();

Expand Down Expand Up @@ -243,7 +250,7 @@ TEST_P(GaussianBlurFilterContentsTest,
std::shared_ptr<Texture> texture = MakeTexture(desc);
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<GaussianBlurFilterContents>(
sigma_radius_1, Entity::TileMode::kDecal);
sigma_radius_1, sigma_radius_1, Entity::TileMode::kDecal);
contents->SetInputs({FilterInput::Make(texture)});
std::shared_ptr<ContentContext> renderer = GetContentContext();

Expand Down Expand Up @@ -303,7 +310,7 @@ TEST_P(GaussianBlurFilterContentsTest, TextureContentsWithDestinationRect) {

Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<GaussianBlurFilterContents>(
sigma_radius_1, Entity::TileMode::kDecal);
sigma_radius_1, sigma_radius_1, Entity::TileMode::kDecal);
contents->SetInputs({FilterInput::Make(texture_contents)});
std::shared_ptr<ContentContext> renderer = GetContentContext();

Expand Down Expand Up @@ -342,7 +349,7 @@ TEST_P(GaussianBlurFilterContentsTest,

Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<GaussianBlurFilterContents>(
sigma_radius_1, Entity::TileMode::kDecal);
sigma_radius_1, sigma_radius_1, Entity::TileMode::kDecal);
contents->SetInputs({FilterInput::Make(texture_contents)});
std::shared_ptr<ContentContext> renderer = GetContentContext();

Expand Down
3 changes: 2 additions & 1 deletion impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,8 @@ TEST_P(EntityTest, GaussianBlurFilter) {
switch (selected_pass_variation) {
case 0:
blur = std::make_shared<GaussianBlurFilterContents>(
blur_sigma_x.sigma, tile_modes[selected_tile_mode]);
blur_sigma_x.sigma, blur_sigma_y.sigma,
tile_modes[selected_tile_mode]);
blur->SetInputs({FilterInput::Make(input)});
break;
case 1:
Expand Down