This repository was archived by the owner on Feb 25, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] blur - cropped the downsample pass for backdrop filters #53562
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
2234d77
[Impeller] blur - cropped the downsample pass for backdrop filters
gaaclarke b2b314c
got rid of the shimmering
gaaclarke 203062b
cleanup
gaaclarke 8beff0c
fix tidy
gaaclarke b963253
renamed function
gaaclarke 815ac5b
fixed imagefilter
gaaclarke 45f3f28
added comments
gaaclarke 85619de
update comment
gaaclarke 3e9ca5e
started trimming in the downsample only if the expanded range fits in…
gaaclarke e6d3ffe
tidy
gaaclarke 8d32b77
removed stray pragma
gaaclarke File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -156,6 +156,64 @@ std::optional<Snapshot> GetSnapshot(const std::shared_ptr<FilterInput>& input, | |
| return input_snapshot; | ||
| } | ||
|
|
||
| /// Returns `rect` relative to `reference`, where Rect::MakeXYWH(0,0,1,1) will | ||
| /// be returned when `rect` == `reference`. | ||
| Rect MakeReferenceUVs(const Rect& reference, const Rect& rect) { | ||
| Rect result = Rect::MakeOriginSize(rect.GetOrigin() - reference.GetOrigin(), | ||
| rect.GetSize()); | ||
| return result.Scale(1.0f / Vector2(reference.GetSize())); | ||
| } | ||
|
|
||
| Quad CalculateSnapshotUVs( | ||
| const Snapshot& input_snapshot, | ||
| const std::optional<Rect>& source_expanded_coverage_hint) { | ||
| std::optional<Rect> input_snapshot_coverage = input_snapshot.GetCoverage(); | ||
| Quad blur_uvs = {Point(0, 0), Point(1, 0), Point(0, 1), Point(1, 1)}; | ||
| FML_DCHECK(input_snapshot.transform.IsTranslationScaleOnly()); | ||
| if (source_expanded_coverage_hint.has_value() && | ||
| input_snapshot_coverage.has_value()) { | ||
| // Only process the uvs where the blur is happening, not the whole texture. | ||
| std::optional<Rect> uvs = | ||
| MakeReferenceUVs(input_snapshot_coverage.value(), | ||
| source_expanded_coverage_hint.value()) | ||
| .Intersection(Rect::MakeSize(Size(1, 1))); | ||
| FML_DCHECK(uvs.has_value()); | ||
| if (uvs.has_value()) { | ||
| blur_uvs[0] = uvs->GetLeftTop(); | ||
| blur_uvs[1] = uvs->GetRightTop(); | ||
| blur_uvs[2] = uvs->GetLeftBottom(); | ||
| blur_uvs[3] = uvs->GetRightBottom(); | ||
| } | ||
| } | ||
| return blur_uvs; | ||
| } | ||
|
|
||
| Scalar CeilToDivisible(Scalar val, Scalar divisor) { | ||
| if (divisor == 0.0f) { | ||
| return val; | ||
| } | ||
|
|
||
| Scalar remainder = fmod(val, divisor); | ||
| if (remainder != 0.0f) { | ||
| return val + (divisor - remainder); | ||
| } else { | ||
| return val; | ||
| } | ||
| } | ||
|
|
||
| Scalar FloorToDivisible(Scalar val, Scalar divisor) { | ||
| if (divisor == 0.0f) { | ||
| return val; | ||
| } | ||
|
|
||
| Scalar remainder = fmod(val, divisor); | ||
| if (remainder != 0.0f) { | ||
| return val - remainder; | ||
| } else { | ||
| return val; | ||
| } | ||
| } | ||
|
|
||
| struct DownsamplePassArgs { | ||
| /// The output size of the down-sampling pass. | ||
| ISize subpass_size; | ||
|
|
@@ -166,13 +224,19 @@ struct DownsamplePassArgs { | |
| /// This isn't usually exactly as we'd calculate because it has to be rounded | ||
| /// to integer boundaries for generating the texture for the output. | ||
| Vector2 effective_scalar; | ||
| /// Transforms from unrotated local space to position the output from the | ||
| /// down-sample pass. | ||
| /// This can differ if we request a coverage hint but it is rejected, as is | ||
| /// the case with backdrop filters. | ||
| Matrix transform; | ||
| }; | ||
|
|
||
| /// Calculates info required for the down-sampling pass. | ||
| DownsamplePassArgs CalculateDownsamplePassArgs( | ||
| Vector2 scaled_sigma, | ||
| Vector2 padding, | ||
| ISize input_snapshot_size, | ||
| const Snapshot& input_snapshot, | ||
| const std::optional<Rect>& source_expanded_coverage_hint, | ||
| const std::shared_ptr<FilterInput>& input, | ||
| const Entity& snapshot_entity) { | ||
| Scalar desired_scalar = | ||
|
|
@@ -182,8 +246,6 @@ DownsamplePassArgs CalculateDownsamplePassArgs( | |
| // gutter from the expanded_coverage_hint, we can skip the downsample pass. | ||
| // pass. | ||
| Vector2 downsample_scalar(desired_scalar, desired_scalar); | ||
| Rect source_rect = Rect::MakeSize(input_snapshot_size); | ||
| Rect source_rect_padded = source_rect.Expand(padding); | ||
| // TODO(gaaclarke): The padding could be removed if we know it's not needed or | ||
| // resized to account for the expanded_clip_coverage. There doesn't appear | ||
| // to be the math to make those calculations though. The following | ||
|
|
@@ -192,19 +254,68 @@ DownsamplePassArgs CalculateDownsamplePassArgs( | |
| // | ||
| // !input_snapshot->GetCoverage()->Expand(-local_padding) | ||
| // .Contains(coverage_hint.value())) | ||
| Vector2 downsampled_size = source_rect_padded.GetSize() * downsample_scalar; | ||
| ISize subpass_size = | ||
| ISize(round(downsampled_size.x), round(downsampled_size.y)); | ||
| Vector2 effective_scalar = | ||
| Vector2(subpass_size) / source_rect_padded.GetSize(); | ||
|
|
||
| Quad uvs = GaussianBlurFilterContents::CalculateUVs( | ||
| input, snapshot_entity, source_rect_padded, input_snapshot_size); | ||
| return { | ||
| .subpass_size = subpass_size, | ||
| .uvs = uvs, | ||
| .effective_scalar = effective_scalar, | ||
| }; | ||
|
|
||
| std::optional<Rect> snapshot_coverage = input_snapshot.GetCoverage(); | ||
| if (input_snapshot.transform.IsIdentity() && | ||
| source_expanded_coverage_hint.has_value() && | ||
| snapshot_coverage.has_value() && | ||
| snapshot_coverage->Contains(source_expanded_coverage_hint.value())) { | ||
| // If the snapshot's transform is the identity transform and we have | ||
| // coverage hint that fits inside of the snapshots coverage that means the | ||
| // coverage hint was ignored so we will trim out the area we are interested | ||
| // in the down-sample pass. This usually means we have a backdrop image | ||
| // filter. | ||
| // | ||
| // The region we cut out will be aligned with the down-sample divisor to | ||
| // avoid pixel alignment problems that create shimmering. | ||
| int32_t divisor = std::round(1.0f / desired_scalar); | ||
| Rect aligned_coverage_hint = Rect::MakeLTRB( | ||
| FloorToDivisible(source_expanded_coverage_hint->GetLeft(), divisor), | ||
| FloorToDivisible(source_expanded_coverage_hint->GetTop(), divisor), | ||
| source_expanded_coverage_hint->GetRight(), | ||
| source_expanded_coverage_hint->GetBottom()); | ||
| aligned_coverage_hint = Rect::MakeXYWH( | ||
| aligned_coverage_hint.GetX(), aligned_coverage_hint.GetY(), | ||
| CeilToDivisible(aligned_coverage_hint.GetWidth(), divisor), | ||
| CeilToDivisible(aligned_coverage_hint.GetHeight(), divisor)); | ||
| ISize source_size = ISize(aligned_coverage_hint.GetSize().width, | ||
| aligned_coverage_hint.GetSize().height); | ||
| Vector2 downsampled_size = source_size * downsample_scalar; | ||
| Scalar int_part; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can also add
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I did that in the past and the compiler for fuchsia or windows didn't care =T |
||
| FML_DCHECK(std::modf(downsampled_size.x, &int_part) == 0.0f); | ||
| FML_DCHECK(std::modf(downsampled_size.y, &int_part) == 0.0f); | ||
| (void)int_part; | ||
| ISize subpass_size = ISize(downsampled_size.x, downsampled_size.y); | ||
| Vector2 effective_scalar = Vector2(subpass_size) / source_size; | ||
| FML_DCHECK(effective_scalar == downsample_scalar); | ||
|
|
||
| Quad uvs = CalculateSnapshotUVs(input_snapshot, aligned_coverage_hint); | ||
| return { | ||
| .subpass_size = subpass_size, | ||
| .uvs = uvs, | ||
| .effective_scalar = effective_scalar, | ||
| .transform = Matrix::MakeTranslation( | ||
| {aligned_coverage_hint.GetX(), aligned_coverage_hint.GetY(), 0})}; | ||
| } else { | ||
| ////////////////////////////////////////////////////////////////////////////// | ||
| auto input_snapshot_size = input_snapshot.texture->GetSize(); | ||
| Rect source_rect = Rect::MakeSize(input_snapshot_size); | ||
| Rect source_rect_padded = source_rect.Expand(padding); | ||
| Vector2 downsampled_size = source_rect_padded.GetSize() * downsample_scalar; | ||
| ISize subpass_size = | ||
| ISize(round(downsampled_size.x), round(downsampled_size.y)); | ||
| Vector2 effective_scalar = | ||
| Vector2(subpass_size) / source_rect_padded.GetSize(); | ||
| Quad uvs = GaussianBlurFilterContents::CalculateUVs( | ||
| input, snapshot_entity, source_rect_padded, input_snapshot_size); | ||
| return { | ||
| .subpass_size = subpass_size, | ||
| .uvs = uvs, | ||
| .effective_scalar = effective_scalar, | ||
| .transform = | ||
| input_snapshot.transform * Matrix::MakeTranslation(-padding), | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| /// Makes a subpass that will render the scaled down input and add the | ||
|
|
@@ -326,38 +437,6 @@ fml::StatusOr<RenderTarget> MakeBlurSubpass( | |
| } | ||
| } | ||
|
|
||
| /// Returns `rect` relative to `reference`, where Rect::MakeXYWH(0,0,1,1) will | ||
| /// be returned when `rect` == `reference`. | ||
| Rect MakeReferenceUVs(const Rect& reference, const Rect& rect) { | ||
| Rect result = Rect::MakeOriginSize(rect.GetOrigin() - reference.GetOrigin(), | ||
| rect.GetSize()); | ||
| return result.Scale(1.0f / Vector2(reference.GetSize())); | ||
| } | ||
|
|
||
| Quad CalculateBlurUVs( | ||
| const Snapshot& input_snapshot, | ||
| const std::optional<Rect>& source_expanded_coverage_hint) { | ||
| std::optional<Rect> input_snapshot_coverage = input_snapshot.GetCoverage(); | ||
| Quad blur_uvs = {Point(0, 0), Point(1, 0), Point(0, 1), Point(1, 1)}; | ||
| FML_DCHECK(input_snapshot.transform.IsTranslationScaleOnly()); | ||
| if (source_expanded_coverage_hint.has_value() && | ||
| input_snapshot_coverage.has_value()) { | ||
| // Only process the uvs where the blur is happening, not the whole texture. | ||
| std::optional<Rect> uvs = | ||
| MakeReferenceUVs(input_snapshot_coverage.value(), | ||
| source_expanded_coverage_hint.value()) | ||
| .Intersection(Rect::MakeSize(Size(1, 1))); | ||
| FML_DCHECK(uvs.has_value()); | ||
| if (uvs.has_value()) { | ||
| blur_uvs[0] = uvs->GetLeftTop(); | ||
| blur_uvs[1] = uvs->GetRightTop(); | ||
| blur_uvs[2] = uvs->GetLeftBottom(); | ||
| blur_uvs[3] = uvs->GetRightBottom(); | ||
| } | ||
| } | ||
| return blur_uvs; | ||
| } | ||
|
|
||
| int ScaleBlurRadius(Scalar radius, Scalar scalar) { | ||
| return static_cast<int>(std::round(radius * scalar)); | ||
| } | ||
|
|
@@ -597,8 +676,8 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter( | |
| } | ||
|
|
||
| DownsamplePassArgs downsample_pass_args = CalculateDownsamplePassArgs( | ||
| blur_info.scaled_sigma, blur_info.padding, | ||
| input_snapshot->texture->GetSize(), inputs[0], snapshot_entity); | ||
| blur_info.scaled_sigma, blur_info.padding, input_snapshot.value(), | ||
| source_expanded_coverage_hint, inputs[0], snapshot_entity); | ||
|
|
||
| fml::StatusOr<RenderTarget> pass1_out = MakeDownsampleSubpass( | ||
| renderer, command_buffer, input_snapshot->texture, | ||
|
|
@@ -611,8 +690,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter( | |
| Vector2 pass1_pixel_size = | ||
| 1.0 / Vector2(pass1_out.value().GetRenderTargetTexture()->GetSize()); | ||
|
|
||
| Quad blur_uvs = | ||
| CalculateBlurUVs(input_snapshot.value(), source_expanded_coverage_hint); | ||
| Quad blur_uvs = {Point(0, 0), Point(1, 0), Point(0, 1), Point(1, 1)}; | ||
|
|
||
| fml::StatusOr<RenderTarget> pass2_out = MakeBlurSubpass( | ||
| renderer, command_buffer, /*input_pass=*/pass1_out.value(), | ||
|
|
@@ -676,8 +754,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter( | |
| .transform = | ||
| entity.GetTransform() * // | ||
| Matrix::MakeScale(1.f / blur_info.source_space_scalar) * // | ||
| input_snapshot->transform * // | ||
| Matrix::MakeTranslation(-blur_info.padding) * // | ||
| downsample_pass_args.transform * // | ||
| Matrix::MakeScale(1 / downsample_pass_args.effective_scalar), | ||
| .sampler_descriptor = sampler_desc, | ||
| .opacity = input_snapshot->opacity}, | ||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, the described behavior happens whenever there's a Texture filter input, right? Makes sense that we need to do some extra work to apply the coverage hint for backdrop filters here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, exactly.