-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] new blur: limit uvs to blur region #49299
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -121,7 +121,8 @@ fml::StatusOr<RenderTarget> MakeBlurSubpass( | |
const SamplerDescriptor& sampler_descriptor, | ||
Entity::TileMode tile_mode, | ||
const GaussianBlurFragmentShader::BlurInfo& blur_info, | ||
std::optional<RenderTarget> destination_target) { | ||
std::optional<RenderTarget> destination_target, | ||
const Quad& blur_uvs) { | ||
if (blur_info.blur_sigma < kEhCloseEnough) { | ||
return input_pass; | ||
} | ||
|
@@ -153,10 +154,10 @@ fml::StatusOr<RenderTarget> MakeBlurSubpass( | |
|
||
BindVertices<GaussianBlurVertexShader>(cmd, host_buffer, | ||
{ | ||
{Point(0, 0), Point(0, 0)}, | ||
{Point(1, 0), Point(1, 0)}, | ||
{Point(0, 1), Point(0, 1)}, | ||
{Point(1, 1), Point(1, 1)}, | ||
{blur_uvs[0], blur_uvs[0]}, | ||
{blur_uvs[1], blur_uvs[1]}, | ||
{blur_uvs[2], blur_uvs[2]}, | ||
{blur_uvs[3], blur_uvs[3]}, | ||
}); | ||
|
||
SamplerDescriptor linear_sampler_descriptor = sampler_descriptor; | ||
|
@@ -183,6 +184,14 @@ 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())); | ||
} | ||
|
||
} // namespace | ||
|
||
GaussianBlurFilterContents::GaussianBlurFilterContents( | ||
|
@@ -311,6 +320,29 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter( | |
Vector2 pass1_pixel_size = | ||
1.0 / Vector2(pass1_out.value().GetRenderTargetTexture()->GetSize()); | ||
|
||
std::optional<Rect> input_snapshot_coverage = input_snapshot->GetCoverage(); | ||
Quad blur_uvs = {Point(0, 0), Point(1, 0), Point(0, 1), Point(1, 1)}; | ||
if (expanded_coverage_hint.has_value() && | ||
input_snapshot_coverage.has_value() && | ||
// TODO(https://github.com/flutter/flutter/issues/140890): Remove this | ||
// condition. There is some flaw in coverage stopping us from using this | ||
// today. I attempted to use source coordinates to calculate the uvs, | ||
// but that didn't work either. | ||
input_snapshot.has_value() && | ||
input_snapshot.value().transform.IsTranslationScaleOnly()) { | ||
// Only process the uvs where the blur is happening, not the whole texture. | ||
std::optional<Rect> uvs = MakeReferenceUVs(input_snapshot_coverage.value(), | ||
gaaclarke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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(); | ||
} | ||
} | ||
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. As you pointed out, this doesn't work when the basis of the entity transform isn't identity. Video of the issue: Screen.Recording.2023-12-20.at.7.19.06.PM.movJust so we're on the same page: Snapshots are an instruction for how to render a texture consisting of sampling state, a transform, and the texture itself. The issue in detailThis issue happens because the Filters (and everything else that consumes snapshots) must contend with this behavior. And that's a very good thing! Because absorbing the snapshot would mean burdening the blur workload with a very expensive 4th For other kinds of inputs that aren't already a rasterized image (like, say, a A quick fixSo your solution as written works well when the Entity transform is specifically translation-only. This is because under those circumstances, the Well, backdrop filters and subpass textures are actually rendered by A comprehensive fix (make it work for
|
||
|
||
fml::StatusOr<RenderTarget> pass2_out = | ||
MakeBlurSubpass(renderer, /*input_pass=*/pass1_out.value(), | ||
input_snapshot->sampler_descriptor, tile_mode_, | ||
|
@@ -320,7 +352,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter( | |
.blur_radius = blur_radius.y * effective_scalar.y, | ||
.step_size = 1.0, | ||
}, | ||
/*destination_target=*/std::nullopt); | ||
/*destination_target=*/std::nullopt, blur_uvs); | ||
|
||
if (!pass2_out.ok()) { | ||
return std::nullopt; | ||
|
@@ -341,7 +373,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter( | |
.blur_radius = blur_radius.x * effective_scalar.x, | ||
.step_size = 1.0, | ||
}, | ||
pass3_destination); | ||
pass3_destination, blur_uvs); | ||
|
||
if (!pass3_out.ok()) { | ||
return std::nullopt; | ||
|
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.
I think this needs to:
entity.GetTransform()
(rather than theinput_snapshot
's transform)If either one of these isn't true, then I think
coverage_hint
andinput_snapshot_coverage
could end up being in difference spaces in some situations, which will cause a variation of the UV mapping bug.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.
If you're up for it, one way you could smoke test this issue is by adding a scale param to the interactive Aiks toy.
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.
I added the parameter to the interactive test and added an automated test. Let me know if you are thinking of some other case where this may break.
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.
To be clear it's necessarily that I don't believe there can be a problem; I just don't want to shrink the domain of this optimization without proof that it doesn't work everywhere via a test. That test can serve as the basis for expanding the domain in the future.
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.
Oh yeah, I get you. Also I think you should land this at will, we can patch other issues as we find em. ;)
It would also be good to test a case where the transform+coverage rect is absorbed by the snapshot rather than forwarded. For example: A blur applied to a gradient circle (can't be a solid color since that'll fall into the rrect fast path).
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.
I just tried the interactive clip when drawing a rect with a gradient on a rrect. I wasn't able to see a problem. I'm going to leave the existing test as is since it doesn't seem to demonstrate anything different.
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.
SGTM