Skip to content

Commit

Permalink
[Impeller] Started expanding the blur clip region (flutter#48535)
Browse files Browse the repository at this point in the history
fixes flutter/flutter#139317
test: AiksTest.CanRenderClippedBlur

This works by double padding. First it applies the padding to clip
region, then it add a transparent gutter around the snapshot to account
for any of the expanded clip region that was ignored. This is suboptimal
since there maybe a considerable region for which blur is calculated
that is clipped. That can be optimized in the future by adjusting the
UVs in the blur phases to match the clip region.

## screenshot of result
<img width="1026" alt="Screenshot 2023-11-30 at 10 28 14 AM"
src="https://github.com/flutter/engine/assets/30870216/a0c673db-8b7a-465e-a75c-09f19d1b98aa">


## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide] and the [C++,
Objective-C, Java style guides].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I added new tests to check the change I am making or feature I am
adding, or the PR is [test-exempt]. See [testing the engine] for
instructions on writing and running engine tests.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I signed the [CLA].
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[test-exempt]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[C++, Objective-C, Java style guides]:
https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
[testing the engine]:
https://github.com/flutter/flutter/wiki/Testing-the-engine
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat
  • Loading branch information
gaaclarke authored Nov 30, 2023
1 parent f92946e commit 3848f50
Showing 1 changed file with 34 additions and 7 deletions.
41 changes: 34 additions & 7 deletions impeller/entity/contents/filters/gaussian_blur_filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ using GaussianBlurVertexShader = GaussianBlurPipeline::VertexShader;
using GaussianBlurFragmentShader = GaussianBlurPipeline::FragmentShader;

namespace {

std::optional<Rect> ExpandCoverageHint(const std::optional<Rect>& coverage_hint,
const Matrix& source_to_local_transform,
const Vector2& padding) {
if (!coverage_hint.has_value()) {
return std::nullopt;
}
Vector2 transformed_padding = (source_to_local_transform * padding).Abs();
return coverage_hint->Expand(transformed_padding);
}

SamplerDescriptor MakeSamplerDescriptor(MinMagFilter filter,
SamplerAddressMode address_mode) {
SamplerDescriptor sampler_desc;
Expand All @@ -43,6 +54,8 @@ Matrix MakeAnchorScale(const Point& anchor, Vector2 scale) {
Matrix::MakeTranslation({-anchor.x, -anchor.y, 0});
}

/// Makes a subpass that will render the scaled down input and add the
/// transparent gutter required for the blur halo.
std::shared_ptr<Texture> MakeDownsampleSubpass(
const ContentContext& renderer,
std::shared_ptr<Texture> input_texture,
Expand All @@ -66,7 +79,8 @@ std::shared_ptr<Texture> MakeDownsampleSubpass(
frame_info.alpha = 1.0;

// Insert transparent gutter around the downsampled image so the blur
// creates a halo effect.
// creates a halo effect. This compensates for when the expanded clip
// region can't give us the full gutter we want.
Vector2 texture_size = Vector2(input_texture->GetSize());
Quad vertices =
MakeAnchorScale({0.5, 0.5},
Expand Down Expand Up @@ -106,6 +120,8 @@ std::shared_ptr<Texture> MakeBlurSubpass(
std::shared_ptr<Texture> input_texture,
const SamplerDescriptor& sampler_descriptor,
const GaussianBlurFragmentShader::BlurInfo& blur_info) {
// 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();
ContentContext::SubpassCallback subpass_callback =
[&](const ContentContext& renderer, RenderPass& pass) {
Expand Down Expand Up @@ -200,9 +216,23 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
return std::nullopt;
}

Scalar blur_radius = CalculateBlurRadius(sigma_);
Vector2 padding(ceil(blur_radius), ceil(blur_radius));

// 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
// transparent gutter.
std::optional<Rect> expanded_coverage_hint = ExpandCoverageHint(
coverage_hint, entity.GetTransform() * effect_transform, padding);
// TODO(gaaclarke): How much of the gutter is thrown away can be used to
// adjust the padding that is added in the downsample pass.
// For example, if we get all the padding we requested from
// the expanded_coverage_hint, there is no need to add a
// transparent gutter.

std::optional<Snapshot> input_snapshot =
inputs[0]->GetSnapshot("GaussianBlur", renderer, entity,
/*coverage_limit=*/coverage_hint);
/*coverage_limit=*/expanded_coverage_hint);
if (!input_snapshot.has_value()) {
return std::nullopt;
}
Expand All @@ -212,14 +242,11 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
entity.GetClipDepth()); // No blur to render.
}

Scalar blur_radius = CalculateBlurRadius(sigma_);
Scalar desired_scalar = CalculateScale(sigma_);
// TODO(jonahwilliams): if scaling value is 1.0, then skip the downsample
// 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.

Vector2 downsample_scalar(desired_scalar, desired_scalar);
Vector2 padding(ceil(blur_radius), ceil(blur_radius));

Vector2 padded_size =
Vector2(input_snapshot->texture->GetSize()) + 2.0 * padding;
Vector2 downsampled_size = padded_size * downsample_scalar;
Expand Down

0 comments on commit 3848f50

Please sign in to comment.