Skip to content

Add buffer around rerasterized input to fragment shaders to maintain coordinate space when clipped#181743

Merged
gaaclarke merged 12 commits intoflutter:masterfrom
gaaclarke:clipped-fragment-shader-compose
Feb 7, 2026
Merged

Add buffer around rerasterized input to fragment shaders to maintain coordinate space when clipped#181743
gaaclarke merged 12 commits intoflutter:masterfrom
gaaclarke:clipped-fragment-shader-compose

Conversation

@gaaclarke
Copy link
Member

@gaaclarke gaaclarke commented Jan 31, 2026

fixes #181660

This works by changing the rerasterization logic such that we will rerasterize the output from the blur filter to an image that matches the dimensions of the input. The undoes the optimization of the clip rect but standardizes the input to the fragment shader so that it is behaving as if the input was the same as a backdrop filter without the blur before hand.

I think there may be opportunities in the future to find a way to make this more efficient if we could find some way to rerasterize only to the clipped region but tweak the coordinates in the fragment shader to make it act like it has a whole image.

Pre-launch Checklist

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

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

@github-actions github-actions bot added engine flutter/engine related. See also e: labels. e: impeller Impeller rendering backend issues and features requests labels Jan 31, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request aims to fix an issue with fragment shaders by adding a buffer around rerasterized input, which is particularly relevant when clipping is involved. A new test case has been added to validate the fix, and the core logic is updated in RuntimeEffectFilterContents. While the approach of using AnonymousContents to adjust the coverage is sound, the current implementation for calculating the new coverage may lead to unintentional clipping in some scenarios. I've added a specific comment highlighting this potential issue.

@flutter-dashboard
Copy link

Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change).

If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #181743 at sha 701200e

@flutter-dashboard flutter-dashboard bot added the will affect goldens Changes to golden files label Jan 31, 2026
@gaaclarke
Copy link
Member Author

The goldens demonstrate some different behavior when the transformed textcoords are outside the bounds of the image. That's fine since I don't think we've spent any effort making sure that that case is accounted for yet.

@gaaclarke gaaclarke requested review from flar and walley892 February 2, 2026 17:57
const Entity& entity, RenderPass& pass) -> bool {
return texture_contents.Render(renderer, entity, pass);
},
[maybe_input_coverage,
Copy link
Contributor

@walley892 walley892 Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

maybe_input_coverage is an optional rect, right? Since value() will throw an exception anyway if there's nothing, is it more efficient to just dereference and not take the runtime hit of the .value check?

[coverage, entity_offset](const Entity& entity) -> std::optional<Rect> {
    return Rect::MakeLRTB(entity_offset.x, entity_offset.y, coverage->GetRight(), coverage->GetBottom());
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since value() will throw an exception anyway if there's nothing

Pedantic note: We (google) compile c++ with exceptions disabled.

is it more efficient to just dereference and not take the runtime hit of the .value check

Dereferencing an std::optional works with an operator overload, it has the same cost as .value(). Capturing the value instead of the optional type in the lambda would have a slight memory improvement because sizeof(std::optional) > sizeof(X). But it's just like 1 byte difference, maybe 4 bytes for padding. I believe that should all be on the stack though so it's not a big deal.

Copy link
Contributor

@walley892 walley892 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think flar will have more interesting feedback. Just a minor question

@flar
Copy link
Contributor

flar commented Feb 2, 2026

I'm currently trying to wrap my head around the issue.

@gaaclarke
Copy link
Member Author

I'm currently trying to wrap my head around the issue.

@flar Let me try to say it all another way. The backdrop filter operates on the whole backdrop, so if you do a blur, then a fragment shader, both of them should be operating on the full screen.

compose(inner: blur, outer: shader, input: image{width: 1024, height: 768}) -> image{width: 1024, height: 768}

Where this get's tricky though is if you have a clip rect. Conceptually the backdrop filter is supposed to be running on the whole backdrop, but we know if there is a clip rect, there is no point in blurring content that will be clipped out. So we skipp those pixels. Also, the blur may be returning an image that needs to be scaled up to represent the output since we downsample large sigma blurs, So:

blur(image{width: 1024, height: 768}, clip_rect{width: 200, height: 100}) -> image{width: 100, height: 50, scale: 2}

What this PR does is rerasterizes the output of the blur, revitalizing the space that had been clipped out so that the fragment shader's local sensitive operations operate as if we had done shader(backdrop) when we do shader(blur(backdrop)). So,

compose(inner: blur, outer: shader, input: image{width: 1024, height: 768}) ->
  let x : image{width: 100, height: 50, scale: 2} = blur(image{width: 1024, height: 768}, clip_rect{width: 200, height: 100});
  let y : image{width: 1024, height: 768} = rerasterize(input: x,  width: 1024, height: 768);
  return shader(y);

There is potentially a more optimized fix here where we manipulate the vertices and texture coords of the shader. That's more difficult to implement and I leave that for a future optimization.

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #181743 at sha 59a1e63

@gaaclarke gaaclarke requested a review from walley892 February 2, 2026 22:30
@flar
Copy link
Contributor

flar commented Feb 2, 2026

Where this get's tricky though is if you have a clip rect. Conceptually the backdrop filter is supposed to be running on the whole backdrop, but we know if there is a clip rect, there is no point in blurring content that will be clipped out. So we skipp those pixels. Also, the blur may be returning an image that needs to be scaled up to represent the output since we downsample large sigma blurs, So:

Clipping affects the output pixels used only. The input pixels are usually determined by asking the filter "if you generate results for pixels in xywh, then what region of input pixels do you require to correctly determine those output pixels".

So, for a blur filter that spreads the pixels out over an NxN area, if we need output pixels for R, then we need to run it on input pixels for R.expand(N/2).

But custom fragment programs cannot provide us with this information. Built-in filters can express their "reverse bounds" because they are written in C++ and invoked from our C++ renderer.

Copy link
Contributor

@flar flar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what anonymous context does, but it looks like it lets you lie about the coverage geometry of the input and it looks like this will do what you want with the caveat that I'm assuming a lot about how the anonymous contents does its job.

I do agree with gemini here, I'm not sure xy from one source and right/bottom from another mix in any meaningful way. I think you want xy from one source and width/height from the other, no?

entity_offset](const Entity& entity) -> std::optional<Rect> {
Rect coverage = maybe_input_coverage.value();
return Rect::MakeLTRB(entity_offset.x, entity_offset.y,
coverage.GetRight(), coverage.GetBottom());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't that be MakeXYWH(offset.xy, coverage.wh)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or coverage.Shift(offset.xy)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the input coverage is always 0,0 based then Right == Width and Bottom == Height, and the 2 are the same, but it "reads wrong". Shouldn't you be transferring the dimensions and the fact that the bottom right coordinates match the dimensions is "information not readily transparent from this code"? Even if it doesn't fix any issues, I think that using WH vs RB is the better way to express this line.

Or just using the Shift method...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, actually, that's not the case. Even if the rect is 0,0 based, by not offsetting the RB coordinates you are indeed clipping it. Imagine a clip that is 100x100 but is positioned with a translation of 500,500. You'd end up with a rect that was Left=500, Right=100 which is backwards and therefore empty. Same with the height.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, actually, that's not the case. Even if the rect is 0,0 based, by not offsetting the RB coordinates you are indeed clipping it. Imagine a clip that is 100x100 but is positioned with a translation of 500,500. You'd end up with a rect that was Left=500, Right=100 which is backwards and therefore empty. Same with the height.

I spent a while looking into the width and height of the coverage. That's why I have so many parameters to the added unit test. I too was worried that we could accidentally cause stretching of the circle if we got the width and the height wrong. I switched to the Shift then reverted it. I think this is the correct math and the reason why is that the coordinates are in the global coordinate space. So there is no translation that will make the rect go inside out. If you think there is still an issue with the math I think it would be better if we could express it as a test case to make sure we don't break it in the future.

@flar
Copy link
Contributor

flar commented Feb 3, 2026

I think the issue with the example you gave with the let x ... let y is that since you don't know how much data the custom shader will need, clipping at the blur stage is premature. If, by "revitalize" you mean "rendering the clipped result back into the middle of a full frame image", then I can see what you are trying to accomplish, but you are bypassing the shader to have the blur do the clipping. Really the sequence should be:

Rect context_clip_coverage = {x,y,200,100};
Rect input1_input_coverage = shader.GetInputForOutput(context_clip_coverage);
Rect input2_input_coverage = blur.GetInputForOutput(input1_input_coverage);
Image input = Rasterize(input2_input_coverage);
Image output2 = blur.filter(input);  // Note: likely produces pixels for a superset of input1_input_coverage
Image output1 = shader.filter(output2);  // Note: likely produces pixels for a superset of context_clip_coverage
return output1;

Alternately, you can tell the blur.filter stage to clip its output to input1_input_coverage so you send fewer pixels to the shader, and then tell the shader to clip its output to context_clip_coverage so it does less work, but you need to ask the "how much do you need" questions in reverse.

After looking at the fix, it seems that you are not intending to solve this underlying problem here, you are just adjusting the "reported geometry" of the intermediate output to match the coordinate space that the shader is expecting?

In that case, my code review comment is all I can offer...

@flar
Copy link
Contributor

flar commented Feb 3, 2026

Shouldn't the coverage reported by the previous stage result already be in the proper location in local coordinates?

I think what we might be seeing here is that our internal filters don't care where the pixels are located - they are pixel-relative - so we haven't been producing the proper output coverage values all along and a runtime shader that is written to care about the frag coords is the first to notice?

@gaaclarke
Copy link
Member Author

After looking at the fix, it seems that you are not intending to solve this underlying problem here, you are just adjusting the "reported geometry" of the intermediate output to match the coordinate space that the shader is expecting?

Not quite. I'm not tricking the reported geometry, I'm rasterizing to a texture so that it matches the geometry that is expected in the fragment shader phase.

The AnonymousContents is just a Contents whose rendering and coverage is supplied by functions. That is how we are adding padding when we rasterize the blur output. We render the output of the blur into a texture that matches the size that is expected as the input for the fragment shader.

I think what we might be seeing here is that our internal filters don't care where the pixels are located - they are pixel-relative - so we haven't been producing the proper output coverage values all along and a runtime shader that is written to care about the frag coords is the first to notice?

I don't think they are wrong. The blur is doing an optimization and the coverage is just assuming they it be consumed in a way that doesn't care about the context from which they were rendered. The way backdrop filters interact with clip rects though, that's not the case.

This PR demonstrates a fix to the issue, but it's possible there is a gap in the math. I think the best thing would be to demonstrate any gap in the math so we can codify it as a unit test to prove that it gets addressed or not.

@gaaclarke gaaclarke requested a review from flar February 4, 2026 23:27
@gaaclarke
Copy link
Member Author

@flar I increased the limits on the clip rect so we can see all possible combinations for it to alleviate any concerns that there is a case we are missing.

@gaaclarke
Copy link
Member Author

@flar I also tested this PR against this test that uses the composition on a layer filter that isn't backdrop and has a transform and while I'm not sure if the result is 100% what we want, it behaves similar to HEAD except that it doesn't flicker. I think this addresses you concern about having a translate affecting the coverage? Maybe that can be a jumping off point for you to express your concern.

TEST_P(AiksTest, ClippedImageFilterWithShader) {
  struct FragUniforms {
    Vector2 uSize;
  } frag_uniforms = {.uSize = Vector2(400, 400)};
  auto uniform_data = std::make_shared<std::vector<uint8_t>>();
  uniform_data->resize(sizeof(FragUniforms));
  memcpy(uniform_data->data(), &frag_uniforms, sizeof(FragUniforms));

  auto runtime_stages_result =
      OpenAssetAsRuntimeStage("runtime_stage_border.frag.iplr");
  ABSL_ASSERT_OK(runtime_stages_result);
  std::shared_ptr<RuntimeStage> runtime_stage =
      runtime_stages_result
          .value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
  ASSERT_TRUE(runtime_stage);
  ASSERT_TRUE(runtime_stage->IsDirty());

  std::vector<std::shared_ptr<DlColorSource>> sampler_inputs = {
      nullptr,
  };

  auto runtime_filter = DlImageFilter::MakeRuntimeEffect(
      DlRuntimeEffectImpeller::Make(runtime_stage), sampler_inputs,
      uniform_data);

  Scalar sigma = 20.0;
  Scalar translate_x = 0.0;
  Scalar translate_y = 0.0;

  auto callback = [&]() -> sk_sp<DisplayList> {
    if (AiksTest::ImGuiBegin("Controls", nullptr,
                             ImGuiWindowFlags_AlwaysAutoResize)) {
      ImGui::SliderFloat("sigma", &sigma, 0, 50);
      ImGui::SliderFloat("translate_x", &translate_x, 0, 2048);
      ImGui::SliderFloat("translate_y", &translate_y, 0, 1536);
      ImGui::End();
    }

    auto blur_filter =
        DlImageFilter::MakeBlur(sigma, sigma, DlTileMode::kClamp);
    auto composed_filter =
        DlImageFilter::MakeCompose(runtime_filter, blur_filter);

    DisplayListBuilder builder;

    // Draw a background so we can see the effect against white
    DlPaint background_paint;
    background_paint.setColor(DlColor::kWhite());
    builder.DrawPaint(background_paint);

    builder.Save();

    builder.Translate(translate_x, translate_y);
    // Replicate the clip rect (inset by 66)
    builder.ClipRect(DlRect::MakeXYWH(66, 66, 268, 268));

    DlPaint save_paint;
    save_paint.setImageFilter(composed_filter);
    builder.SaveLayer(std::nullopt, &save_paint, nullptr);

    // Draw some pattern to be filtered
    DlPaint pattern_paint;
    pattern_paint.setColor(DlColor::kRed());
    builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), pattern_paint);
    pattern_paint.setColor(DlColor::kBlue());
    builder.DrawRect(DlRect::MakeXYWH(200, 200, 200, 200), pattern_paint);

    builder.Restore();  // Restore SaveLayer
    builder.Restore();  // Restore Save (Clip)

    return builder.Build();
  };

  ASSERT_TRUE(OpenPlaygroundHere(callback));
}

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #181743 at sha f29c5dc

@flar
Copy link
Contributor

flar commented Feb 6, 2026

There's a heavy lift in this situation wrt how we got here and how this code affects expectations at the Flutter API level. It's going to take a while for me to get my head around why that code works when it makes no sense from how rectangles work.

Pairing an independent xy with a second independent right/bottom is going to have either an intersection or an expansion effect unless it is well documented how the xy and the left/top/right/bottom of the second parameter relate, including what coordinate space each is relative to.

Copy link
Contributor

@flar flar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@gaaclarke gaaclarke added the autosubmit Merge PR when tree becomes green via auto submit App label Feb 7, 2026
@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Feb 7, 2026
@auto-submit
Copy link
Contributor

auto-submit bot commented Feb 7, 2026

autosubmit label was removed for flutter/flutter/181743, because The base commit of the PR is older than 7 days and can not be merged. Please merge the latest changes from the main into this branch and resubmit the PR.

@gaaclarke gaaclarke added this pull request to the merge queue Feb 7, 2026
Merged via the queue into flutter:master with commit 5f3a29a Feb 7, 2026
181 of 182 checks passed
@gaaclarke gaaclarke deleted the clipped-fragment-shader-compose branch February 7, 2026 02:03
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 7, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 7, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 8, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 8, 2026
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Feb 8, 2026
Roll Flutter from f916dd6887bf to e8f9dc50356d (34 revisions)

flutter/flutter@f916dd6...e8f9dc5

2026-02-08 [email protected] Roll Skia from 9325111e6ee4 to b7db9f35f0f2 (1 revision) (flutter/flutter#182062)
2026-02-08 [email protected] Roll Skia from 3167229206b5 to 9325111e6ee4 (1 revision) (flutter/flutter#182061)
2026-02-08 [email protected] Roll Fuchsia Linux SDK from sYqpDF9l9-kldd9_Q... to iqtwdXlgKIyZkL5Li... (flutter/flutter#182058)
2026-02-08 [email protected] Roll Skia from ae78024b261e to 3167229206b5 (1 revision) (flutter/flutter#182055)
2026-02-07 [email protected] Roll Dart SDK from ad6368edbe02 to 965b51c219d3 (1 revision) (flutter/flutter#182050)
2026-02-07 [email protected] Roll Skia from a471f253b941 to ae78024b261e (1 revision) (flutter/flutter#182049)
2026-02-07 [email protected] Roll Fuchsia Linux SDK from IOzzhWfhdzhu3zHsz... to sYqpDF9l9-kldd9_Q... (flutter/flutter#182043)
2026-02-07 [email protected] Roll Dart SDK from 02092faa97c5 to ad6368edbe02 (2 revisions) (flutter/flutter#182040)
2026-02-07 [email protected] Roll Skia from 9a983f6c2c06 to a471f253b941 (24 revisions) (flutter/flutter#182039)
2026-02-07 [email protected] Add buffer around rerasterized input to fragment shaders to maintain coordinate space when clipped (flutter/flutter#181743)
2026-02-07 [email protected] Update Flutter's style guide for dot shorthands and extension methods (flutter/flutter#181934)
2026-02-06 [email protected] Manual roll Skia from 39aa2a70213a to 9a983f6c2c06 (flutter/flutter#181986)
2026-02-06 [email protected] Update doc in foundation to match the style guide (flutter/flutter#181972)
2026-02-06 [email protected] Roll Dart SDK from ec674bdb3ae4 to 02092faa97c5 (11 revisions) (flutter/flutter#182017)
2026-02-06 [email protected] Roll Packages from c197455 to 7805d3e (4 revisions) (flutter/flutter#182016)
2026-02-06 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[cupertino.dart] Implement CupertinoMenuAnchor and CupertinoMenuItem using RawMenuAnchor (#174695)" (flutter/flutter#182010)
2026-02-06 [email protected] Update Dart SDK to 3.12 beta1 (flutter/flutter#181948)
2026-02-06 [email protected] [cupertino.dart] Implement CupertinoMenuAnchor and CupertinoMenuItem using RawMenuAnchor (flutter/flutter#174695)
2026-02-06 [email protected] `flutter_tool` : Remove redundant enum types inside the enum definition scope (flutter/flutter#181910)
2026-02-06 [email protected] Roll pub packages (flutter/flutter#181973)
2026-02-05 [email protected] Roll Fuchsia Linux SDK from J2QdLcY2gyt4NP_xV... to IOzzhWfhdzhu3zHsz... (flutter/flutter#181971)
2026-02-05 [email protected] Directly generate a Mach-O dynamic library using gen_snapshot. [reland] (flutter/flutter#181539)
2026-02-05 [email protected] macOS: Implement tooltip window controller (flutter/flutter#180895)
2026-02-05 [email protected] Constrain RawAutocomplete options by soft keyboard (flutter/flutter#181930)
2026-02-05 [email protected] Roll Skia from 079d092f49e6 to 39aa2a70213a (1 revision) (flutter/flutter#181970)
2026-02-05 [email protected] perf: web ui loadFontFromList (flutter/flutter#181440)
2026-02-05 [email protected] Improve accessibility contrast for pre-test message (flutter/flutter#180469)
2026-02-05 [email protected] Roll pub packages (flutter/flutter#181965)
2026-02-05 [email protected] Roll Skia from 8543ce512d5c to 079d092f49e6 (8 revisions) (flutter/flutter#181964)
2026-02-05 [email protected] Add `clearError` API to Form and FormFieldState (flutter/flutter#180752)
2026-02-05 [email protected] Bump minimum required Xcode version to 15 and recommended to 16 (flutter/flutter#180531)
2026-02-05 [email protected] Rename "widgetTester" parameter to "tester" in "WidgetTesterCallback" (flutter/flutter#180944)
2026-02-05 [email protected] Roll Packages from 3bddf2c to c197455 (3 revisions) (flutter/flutter#181962)
2026-02-05 [email protected] Temporarily remove the Pixel 9/API 36 device from the Firebase Test Lab tests. (flutter/flutter#181956)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

...
flutter-zl pushed a commit to flutter-zl/flutter that referenced this pull request Feb 10, 2026
…coordinate space when clipped (flutter#181743)

fixes flutter#181660

This works by changing the rerasterization logic such that we will
rerasterize the output from the blur filter to an image that matches the
dimensions of the input. The undoes the optimization of the clip rect
but standardizes the input to the fragment shader so that it is behaving
as if the input was the same as a backdrop filter without the blur
before hand.

I think there may be opportunities in the future to find a way to make
this more efficient if we could find some way to rerasterize only to the
clipped region but tweak the coordinates in the fragment shader to make
it act like it has a whole image.

## 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], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

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

**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
@gaaclarke gaaclarke added the cp: stable cherry pick this pull request to stable release candidate branch label Feb 17, 2026
flutteractionsbot pushed a commit to flutteractionsbot/flutter that referenced this pull request Feb 17, 2026
…coordinate space when clipped (flutter#181743)

fixes flutter#181660

This works by changing the rerasterization logic such that we will
rerasterize the output from the blur filter to an image that matches the
dimensions of the input. The undoes the optimization of the clip rect
but standardizes the input to the fragment shader so that it is behaving
as if the input was the same as a backdrop filter without the blur
before hand.

I think there may be opportunities in the future to find a way to make
this more efficient if we could find some way to rerasterize only to the
clipped region but tweak the coordinates in the fragment shader to make
it act like it has a whole image.

## 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], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

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

**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
rickhohler pushed a commit to rickhohler/flutter that referenced this pull request Feb 19, 2026
…coordinate space when clipped (flutter#181743)

fixes flutter#181660

This works by changing the rerasterization logic such that we will
rerasterize the output from the blur filter to an image that matches the
dimensions of the input. The undoes the optimization of the clip rect
but standardizes the input to the fragment shader so that it is behaving
as if the input was the same as a backdrop filter without the blur
before hand.

I think there may be opportunities in the future to find a way to make
this more efficient if we could find some way to rerasterize only to the
clipped region but tweak the coordinates in the fragment shader to make
it act like it has a whole image.

## 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], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

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

**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
b3nni97 pushed a commit to b3nni97/flutter_liquid_glass that referenced this pull request Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cp: stable cherry pick this pull request to stable release candidate branch e: impeller Impeller rendering backend issues and features requests engine flutter/engine related. See also e: labels. will affect goldens Changes to golden files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BackdropFilter shader UV sampling is incorrect on beta when using ClipRect and a composed blur

3 participants