Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 7b6227f

Browse files
authored
[Impeller] new blur: refactored math and fixed expanded padding size (#49206)
This refactors the math so that it makes it easier to conditionally add padding. That optimization was removed for now since it wasn't quite working satisfactorily yet. This also fixes the math used to expand the coverage hint. There is no visual test for it since it would only ever result in wasteful expansion that would show up in the benchmarks. ## 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
1 parent b24076e commit 7b6227f

File tree

4 files changed

+44
-65
lines changed

4 files changed

+44
-65
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3976,6 +3976,5 @@ TEST_P(AiksTest, SubpassWithClearColorOptimization) {
39763976
// will be filled with NaNs and may produce a magenta texture on macOS or iOS.
39773977
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
39783978
}
3979-
39803979
} // namespace testing
39813980
} // namespace impeller

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 38 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,6 @@ using GaussianBlurFragmentShader = GaussianBlurPipeline::FragmentShader;
1919

2020
namespace {
2121

22-
std::optional<Rect> ExpandCoverageHint(const std::optional<Rect>& coverage_hint,
23-
const Matrix& source_to_local_transform,
24-
const Vector2& padding) {
25-
if (!coverage_hint.has_value()) {
26-
return std::nullopt;
27-
}
28-
Vector2 transformed_padding = (source_to_local_transform * padding).Abs();
29-
return coverage_hint->Expand(transformed_padding);
30-
}
31-
3222
SamplerDescriptor MakeSamplerDescriptor(MinMagFilter filter,
3323
SamplerAddressMode address_mode) {
3424
SamplerDescriptor sampler_desc;
@@ -48,12 +38,6 @@ void BindVertices(Command& cmd,
4838
cmd.BindVertices(vtx_builder.CreateVertexBuffer(host_buffer));
4939
}
5040

51-
Matrix MakeAnchorScale(const Point& anchor, Vector2 scale) {
52-
return Matrix::MakeTranslation({anchor.x, anchor.y, 0}) *
53-
Matrix::MakeScale(scale) *
54-
Matrix::MakeTranslation({-anchor.x, -anchor.y, 0});
55-
}
56-
5741
void SetTileMode(SamplerDescriptor* descriptor,
5842
const ContentContext& renderer,
5943
Entity::TileMode tile_mode) {
@@ -87,7 +71,6 @@ std::shared_ptr<Texture> MakeDownsampleSubpass(
8771
const SamplerDescriptor& sampler_descriptor,
8872
const Quad& uvs,
8973
const ISize& subpass_size,
90-
const Vector2 padding,
9174
Entity::TileMode tile_mode) {
9275
ContentContext::SubpassCallback subpass_callback =
9376
[&](const ContentContext& renderer, RenderPass& pass) {
@@ -104,23 +87,13 @@ std::shared_ptr<Texture> MakeDownsampleSubpass(
10487
frame_info.texture_sampler_y_coord_scale = 1.0;
10588
frame_info.alpha = 1.0;
10689

107-
// Insert transparent gutter around the downsampled image so the blur
108-
// creates a halo effect. This compensates for when the expanded clip
109-
// region can't give us the full gutter we want.
110-
Vector2 texture_size = Vector2(input_texture->GetSize());
111-
Quad guttered_uvs =
112-
MakeAnchorScale({0.5, 0.5},
113-
(texture_size + padding * 2) / texture_size)
114-
.Transform(uvs);
115-
116-
BindVertices<TextureFillVertexShader>(
117-
cmd, host_buffer,
118-
{
119-
{Point(0, 0), guttered_uvs[0]},
120-
{Point(1, 0), guttered_uvs[1]},
121-
{Point(0, 1), guttered_uvs[2]},
122-
{Point(1, 1), guttered_uvs[3]},
123-
});
90+
BindVertices<TextureFillVertexShader>(cmd, host_buffer,
91+
{
92+
{Point(0, 0), uvs[0]},
93+
{Point(1, 0), uvs[1]},
94+
{Point(0, 1), uvs[2]},
95+
{Point(1, 1), uvs[3]},
96+
});
12497

12598
SamplerDescriptor linear_sampler_descriptor = sampler_descriptor;
12699
SetTileMode(&linear_sampler_descriptor, renderer, tile_mode);
@@ -270,17 +243,17 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
270243
Vector2 blur_radius = {CalculateBlurRadius(scaled_sigma.x),
271244
CalculateBlurRadius(scaled_sigma.y)};
272245
Vector2 padding(ceil(blur_radius.x), ceil(blur_radius.y));
246+
Vector2 local_padding =
247+
(entity.GetTransform().Basis() * effect_transform.Basis() * padding)
248+
.Abs();
273249

274250
// Apply as much of the desired padding as possible from the source. This may
275251
// be ignored so must be accounted for in the downsample pass by adding a
276252
// transparent gutter.
277-
std::optional<Rect> expanded_coverage_hint = ExpandCoverageHint(
278-
coverage_hint, entity.GetTransform() * effect_transform, padding);
279-
// TODO(gaaclarke): How much of the gutter is thrown away can be used to
280-
// adjust the padding that is added in the downsample pass.
281-
// For example, if we get all the padding we requested from
282-
// the expanded_coverage_hint, there is no need to add a
283-
// transparent gutter.
253+
std::optional<Rect> expanded_coverage_hint;
254+
if (coverage_hint.has_value()) {
255+
expanded_coverage_hint = coverage_hint->Expand(local_padding);
256+
}
284257

285258
std::optional<Snapshot> input_snapshot =
286259
inputs[0]->GetSnapshot("GaussianBlur", renderer, entity,
@@ -300,21 +273,28 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
300273
// gutter from the expanded_coverage_hint, we can skip the downsample pass.
301274
// pass.
302275
Vector2 downsample_scalar(desired_scalar, desired_scalar);
303-
Vector2 padded_size =
304-
Vector2(input_snapshot->texture->GetSize()) + 2.0 * padding;
305-
Vector2 downsampled_size = padded_size * downsample_scalar;
306-
// TODO(gaaclarke): I don't think we are correctly handling this fractional
307-
// amount we are throwing away.
276+
Rect source_rect = Rect::MakeSize(input_snapshot->texture->GetSize());
277+
Rect source_rect_padded = source_rect.Expand(padding);
278+
Matrix padding_snapshot_adjustment = Matrix::MakeTranslation(-padding);
279+
// TODO(gaaclarke): The padding could be removed if we know it's not needed or
280+
// resized to account for the expanded_clip_coverage. There doesn't appear
281+
// to be the math to make those calculations though. The following
282+
// optimization works, but causes a shimmer as a result of
283+
// https://github.com/flutter/flutter/issues/140193 so it isn't applied.
284+
//
285+
// !input_snapshot->GetCoverage()->Expand(-local_padding)
286+
// .Contains(coverage_hint.value()))
287+
Vector2 downsampled_size = source_rect_padded.size * downsample_scalar;
308288
ISize subpass_size =
309289
ISize(round(downsampled_size.x), round(downsampled_size.y));
310-
Vector2 effective_scalar = subpass_size / padded_size;
290+
Vector2 effective_scalar = Vector2(subpass_size) / source_rect_padded.size;
311291

312-
Quad uvs =
313-
CalculateUVs(inputs[0], entity, input_snapshot->texture->GetSize());
292+
Quad uvs = CalculateUVs(inputs[0], entity, source_rect_padded,
293+
input_snapshot->texture->GetSize());
314294

315295
std::shared_ptr<Texture> pass1_out_texture = MakeDownsampleSubpass(
316296
renderer, input_snapshot->texture, input_snapshot->sampler_descriptor,
317-
uvs, subpass_size, padding, tile_mode_);
297+
uvs, subpass_size, tile_mode_);
318298

319299
Vector2 pass1_pixel_size = 1.0 / Vector2(pass1_out_texture->GetSize());
320300

@@ -343,13 +323,12 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
343323
MinMagFilter::kLinear, SamplerAddressMode::kClampToEdge);
344324

345325
return Entity::FromSnapshot(
346-
Snapshot{
347-
.texture = pass3_out_texture,
348-
.transform = input_snapshot->transform *
349-
Matrix::MakeTranslation({-padding.x, -padding.y, 0}) *
350-
Matrix::MakeScale(1 / effective_scalar),
351-
.sampler_descriptor = sampler_desc,
352-
.opacity = input_snapshot->opacity},
326+
Snapshot{.texture = pass3_out_texture,
327+
.transform = input_snapshot->transform *
328+
padding_snapshot_adjustment *
329+
Matrix::MakeScale(1 / effective_scalar),
330+
.sampler_descriptor = sampler_desc,
331+
.opacity = input_snapshot->opacity},
353332
entity.GetBlendMode(), entity.GetClipDepth());
354333
}
355334

@@ -360,11 +339,10 @@ Scalar GaussianBlurFilterContents::CalculateBlurRadius(Scalar sigma) {
360339
Quad GaussianBlurFilterContents::CalculateUVs(
361340
const std::shared_ptr<FilterInput>& filter_input,
362341
const Entity& entity,
342+
const Rect& source_rect,
363343
const ISize& texture_size) {
364344
Matrix input_transform = filter_input->GetLocalTransform(entity);
365-
Rect snapshot_rect =
366-
Rect::MakeXYWH(0, 0, texture_size.width, texture_size.height);
367-
Quad coverage_quad = snapshot_rect.GetTransformedPoints(input_transform);
345+
Quad coverage_quad = source_rect.GetTransformedPoints(input_transform);
368346

369347
Matrix uv_transform = Matrix::MakeScale(
370348
{1.0f / texture_size.width, 1.0f / texture_size.height, 1.0f});

impeller/entity/contents/filters/gaussian_blur_filter_contents.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ class GaussianBlurFilterContents final : public FilterContents {
4141
/// Calculate the UV coordinates for rendering the filter_input.
4242
/// @param filter_input The FilterInput that should be rendered.
4343
/// @param entity The associated entity for the filter_input.
44-
/// @param texture_size The size of the texture_size the uvs will be used for.
44+
/// @param source_rect The rect in source coordinates to convert to uvs.
45+
/// @param texture_size The rect to convert in source coordinates.
4546
static Quad CalculateUVs(const std::shared_ptr<FilterInput>& filter_input,
4647
const Entity& entity,
47-
const ISize& pass_size);
48+
const Rect& source_rect,
49+
const ISize& texture_size);
4850

4951
/// Calculate the scale factor for the downsample pass given a sigma value.
5052
///

impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,8 @@ TEST_P(GaussianBlurFilterContentsTest, CalculateUVsSimple) {
285285
std::shared_ptr<Texture> texture = MakeTexture(desc);
286286
auto filter_input = FilterInput::Make(texture);
287287
Entity entity;
288-
Quad uvs = GaussianBlurFilterContents::CalculateUVs(filter_input, entity,
289-
ISize(100, 100));
288+
Quad uvs = GaussianBlurFilterContents::CalculateUVs(
289+
filter_input, entity, Rect::MakeSize(ISize(100, 100)), ISize(100, 100));
290290
std::optional<Rect> uvs_bounds = Rect::MakePointBounds(uvs);
291291
EXPECT_TRUE(uvs_bounds.has_value());
292292
if (uvs_bounds.has_value()) {

0 commit comments

Comments
 (0)