Skip to content

Eliminate some early returns in uber_sdf.frag to fix broken UberSDF AA on Windows - #190260

Merged
auto-submit[bot] merged 5 commits into
flutter:masterfrom
b-luk:windowsubersdfaafix
Jul 31, 2026
Merged

auto-submit[bot] merged 5 commits into
flutter:masterfrom
b-luk:windowsubersdfaafix

Conversation

@b-luk

@b-luk b-luk commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

See #189827 (comment) for some more context. That comment shows 2 issues:

  1. UberSDF AA is broken on Windows
  2. Tessellated AA is broken on OpenGLES

Fixes #189827 (comment)

This PR fixes the first issue. The second issue is tracked at #190060.

This PR flattens some branching in uber_sdf.frag to eliminate some early returns.

Something about the dFdx and dFdy derivatives are incompatible with ANGLE and/or D3D, making uberSDF antialiasing fail on Windows. I don't know what the exact limits are of when dFdx and dFdy are allowed. From asking Gemini, it may be related to branching, non-uniform branching, loops, or early return statements. After some manual testing, eliminating early return statements in functions which use dFdx and dFdy (either directly, or indirectly through a child call) seems sufficient to fix this.

Demo app

Demo:
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return InteractiveViewer(
      maxScale: 10,
      child: Container(
        color: Colors.black,
        child: CustomPaint(painter: TestPainter()),
      ),
    );
  }
}

class TestPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    var filledPaint = Paint()..color = Colors.white;
    var strokedPaint = Paint()
      ..color = Colors.white
      ..style = PaintingStyle.stroke
      ..strokeWidth = 5;
    const rect = Rect.fromLTWH(20, 20, 30.5, 15.5);

    // circle
    canvas.drawCircle(Offset(35, 25), 15.5, filledPaint);
    canvas.save();
    canvas.translate(50, 0);
    canvas.drawCircle(Offset(35, 25), 15.5, strokedPaint);
    canvas.restore();

    // oval
    canvas.translate(0, 50);
    canvas.drawOval(rect, filledPaint);
    canvas.save();
    canvas.translate(50, 0);
    canvas.drawOval(rect, strokedPaint);
    canvas.restore();

    // rounded rect
    canvas.translate(0, 50);
    canvas.drawRRect(RRect.fromRectAndRadius(rect, .circular(5)), filledPaint);
    canvas.save();
    canvas.translate(50, 0);
    canvas.drawRRect(
      RRect.fromRectAndRadius(rect, .circular(5)),
      strokedPaint,
    );
    canvas.restore();

    // column 2
    canvas.translate(120, -150);

    // rect
    canvas.translate(0, 50);
    canvas.drawRect(rect, filledPaint);
    canvas.save();
    canvas.translate(50, 0);
    canvas.drawRect(rect, strokedPaint);
    canvas.restore();

    // rotated rect
    canvas.translate(0, 50);
    canvas.save();
    canvas.rotate(0.3);
    canvas.drawRect(rect, filledPaint);
    canvas.restore();
    canvas.save();
    canvas.translate(50, 0);
    canvas.rotate(0.3);
    canvas.drawRect(rect, strokedPaint);
    canvas.restore();

    // RSuperellipse
    canvas.translate(0, 50);
    canvas.drawRSuperellipse(
      RSuperellipse.fromRectAndRadius(rect, .circular(5)),
      filledPaint,
    );
    canvas.save();
    canvas.translate(50, 0);
    canvas.drawRSuperellipse(
      RSuperellipse.fromRectAndRadius(rect, .circular(5)),
      strokedPaint,
    );
    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

Before:

image

500% zoom:
image

After:

image

500% zoom:
image

Notice that stroked RSuperellipse does not have AA. This confused me for a long time. Eventually I figured out that stroked RSuperellipse is always drawn with a path. So it does not go through the UberSDF code. Paths render with tessellation, which is supposed to use MSAA but is currently not functioning properly on Windows.

Pre-launch Checklist

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

If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.

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.

@b-luk
b-luk requested a review from gaaclarke July 30, 2026 00:28
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Jul 30, 2026
@flutter-dashboard

Copy link
Copy Markdown

It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

@github-actions github-actions Bot added engine flutter/engine related. See also e: labels. e: impeller Impeller rendering backend issues and features requests labels Jul 30, 2026

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

Copy link
Copy Markdown
Contributor

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 refactors "uber_sdf.frag" to unify return paths in "roundRectPixelSize", "filledSDF", and "strokedSDF" by introducing local variables for the calculated pixel size and SDF. The review feedback suggests simplifying "roundRectPixelSize" by initializing "pixel_size" with a default value to eliminate the "else" block, and refactoring "strokedSDF" to extract common calculations for Miter and Bevel joins to reduce duplication.

Comment thread engine/src/flutter/impeller/entity/shaders/uber_sdf.frag
Comment thread engine/src/flutter/impeller/entity/shaders/uber_sdf.frag

@gaaclarke gaaclarke left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks good, awesome find. We need a test of some sort in order to cherry-pick. It would have to be a golden test on windows, or some sort of test on impellerc. A full integration golden test on windows will potentially be a large scope. I'm not familiar with the capabilities of the current windows integration tests.

This is really hard to reason about because the code goes through multiple transformations. glsl->spirv->glsl->hlsl. Can you play around with the technique in #190221 to see if we can come up with something there.

I suspect what is happening is that the derivative functions can't be in branches, but having only one return value allows the compiler to somehow flatten the logic. I'm not sure if the magic is happening in impellerc or in ANGLE though.

Comment thread engine/src/flutter/impeller/entity/shaders/uber_sdf.frag Outdated
"core": "Mali-T880",
"filename": "flutter/impeller/entity/gles/uber_sdf.frag.gles",
"has_uniform_computation": false,
"has_uniform_computation": true,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is the important part, if has_uniform_computation we can infer that the derivatives will work, as we are seeing. We can continue to work on an integration test separately as part of https://www.google.com/url?q=https://github.com/flutter/flutter/issues/190301&source=chat&ust=1785602312219000&usg=AOvVaw3jp4N6wJ0T_3dOcF7CMV7R

@gaaclarke gaaclarke added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 31, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Jul 31, 2026
Merged via the queue into flutter:master with commit ef089e2 Jul 31, 2026
22 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 31, 2026
@b-luk b-luk added the cp: beta cherry pick this pull request to beta release candidate branch label Jul 31, 2026
auto-submit Bot pushed a commit that referenced this pull request Aug 3, 2026
…UberSDF AA on Windows (#190378)

This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request)
Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request.

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

#189827

### Impact Description:
What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)?
Does it impact development (ex. flutter doctor crashes when Android Studio is installed),
or the shipping of production apps (the app crashes on launch).
This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick.

This PR fixes anti-aliasing on some draw calls in Impeller Windows, specifically all draws using UberSDF (almost all draws except for paths and some corner case shapes).

### Changelog Description:
Explain this cherry pick:
* In one line that is accessible to most Flutter developers.
* That describes the state prior to the fix.
* That includes which platforms are impacted.
See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples.

< Replace with changelog description here >
[flutter/189827] When running an app on Windows with Impeller, most raw shape draws had jagged edges.

### Workaround:
Is there a workaround for this issue?

Yes, downgrading to Skia.

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
What are the steps to validate that this fix works?

Verified by running a Flutter app on Windows before and after this fix. See the PR description at #190260.
@b-luk
b-luk deleted the windowsubersdfaafix branch August 4, 2026 17:18
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Aug 10, 2026
…12406)

Manual roll Flutter from e52f01c920ad to b766512c65d8 (42 revisions)

Manual roll requested by [email protected]

flutter/flutter@e52f01c...b766512

2026-08-04 [email protected] Roll Dart SDK from 2a799a2404e9 to 9859c0a39adb (4 revisions) (flutter/flutter#190521)
2026-08-04 [email protected] Revert: iOS: Eliminate use of IOSContextNoop in platform view tests (flutter/flutter#190501)
2026-08-04 [email protected] [Impeller] Enable ETC2/ASTC LDR/BC texture compression features at Vulkan device creation (flutter/flutter#189303)
2026-08-03 [email protected] Remove openglessdf from impeller_unittests. (flutter/flutter#190469)
2026-08-03 [email protected] [web] Unify image decoding and codecs on CanvasKit and Skwasm (flutter/flutter#188573)
2026-08-03 [email protected] iOS: Eliminate use of IOSContextNoop in platform view tests (flutter/flutter#190419)
2026-08-03 [email protected] Add path rendering benchmarks (flutter/flutter#188654)
2026-08-03 [email protected] Add windows platform support for primitive_shape_test integration test (flutter/flutter#190464)
2026-08-03 [email protected] Roll Skia from 958c1c1921a1 to a08d918ebd6a (3 revisions) (flutter/flutter#190467)
2026-08-03 [email protected] tests: add --ios-runtime param (flutter/flutter#190414)
2026-08-03 [email protected] iOS: Remove the synchronous first-frame wait (flutter/flutter#190432)
2026-08-03 [email protected] iOS: Eliminate the Impeller/Skia backend selection params (flutter/flutter#190416)
2026-08-03 [email protected] iOS,macOS: Use @autoclosure in Logger (flutter/flutter#190417)
2026-08-03 [email protected] tools: Support FLUTTER_HOST_ARCH in update_dart_sdk scripts (flutter/flutter#190421)
2026-08-03 [email protected] iOS: Hardcode rendering API to Metal in tests (no-op) (flutter/flutter#190422)
2026-08-03 [email protected] a11y: Map disabled/read-only semantics to AX node restriction (flutter/flutter#190353)
2026-08-03 [email protected] [Infra] Replace defunct umbrella template with Wasm issue form (flutter/flutter#190471)
2026-08-03 [email protected] Roll Skia from abecb0dc02c1 to 958c1c1921a1 (4 revisions) (flutter/flutter#190459)
2026-08-03 [email protected] Roll Dart SDK from 65b163be2485 to 2a799a2404e9 (3 revisions) (flutter/flutter#190454)
2026-08-03 [email protected] Roll Skia from 68efb3f2ad16 to abecb0dc02c1 (1 revision) (flutter/flutter#190443)
2026-08-03 [email protected] Roll Packages from 5351d8c to ac87e65 (4 revisions) (flutter/flutter#190441)
2026-08-03 [email protected] Roll Skia from 5a761eb826c1 to 68efb3f2ad16 (1 revision) (flutter/flutter#190440)
2026-08-03 [email protected] Roll Skia from 4c9f8b4805e2 to 5a761eb826c1 (1 revision) (flutter/flutter#190437)
2026-08-03 [email protected] [macOS] Resume app lifecycle on becomeActive to avoid frozen UI after occlusion (flutter/flutter#188772)
2026-08-03 [email protected] Roll Skia from 39cda9d6d7d2 to 4c9f8b4805e2 (6 revisions) (flutter/flutter#190426)
2026-08-03 [email protected] Roll Skia from df13bfb5a54e to 39cda9d6d7d2 (2 revisions) (flutter/flutter#190425)
2026-08-02 [email protected] iOS: Serialise CADisplayLink access in VSyncClient tests (flutter/flutter#190335)
2026-08-02 [email protected] Roll Skia from 32329e5643b5 to df13bfb5a54e (1 revision) (flutter/flutter#190394)
2026-08-02 [email protected] [Impeller] Skip binding dead-code-eliminated resources on Metal (flutter/flutter#190040)
2026-08-01 [email protected] [Flutter GPU] Raise Dart errors for invalid render pipelines and memoize per-draw pipeline state (flutter/flutter#189899)
2026-08-01 [email protected] Revert "Improve non rect platform view rendering  (#182662)" (flutter/flutter#190003)
2026-08-01 [email protected] Roll Skia from ebf50520d720 to 32329e5643b5 (1 revision) (flutter/flutter#190389)
2026-08-01 [email protected] Roll Skia from f73c4510d12d to ebf50520d720 (6 revisions) (flutter/flutter#190376)
2026-07-31 [email protected] Primitive shape integration test (flutter/flutter#190368)
2026-07-31 [email protected] Eliminate some early returns in uber_sdf.frag to fix broken UberSDF AA on Windows (flutter/flutter#190260)
2026-07-31 [email protected] chore: swiftshader mirrored + llvm16 (flutter/flutter#181225)
2026-07-31 [email protected] [web] Remove in-repo agent documentation (flutter/flutter#190326)
2026-07-31 [email protected] [windows]: Uses offscreen MSAA when implicit msaa isn't available. (flutter/flutter#190256)
2026-07-31 [email protected] flutter_tools: Use new FileSystemExtension from devtools (flutter/flutter#190360)
2026-07-31 [email protected] Roll Dart SDK from c3acfc2479f6 to 65b163be2485 (1 revision) (flutter/flutter#190358)
2026-07-31 [email protected] Use devicectl for screenshots on Xcode 27, remove idevicescreenshot artifact (flutter/flutter#189091)
2026-07-31 [email protected] Roll Skia from 7ef86a5b0eb9 to f73c4510d12d (1 revision) (flutter/flutter#190352)

If this roll has caused a breakage, revert this CL and stop the roller
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD cp: beta cherry pick this pull request to beta release candidate branch e: impeller Impeller rendering backend issues and features requests engine flutter/engine related. See also e: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Impeller][Windows][OpenGLESSDF] Animated rounded BoxDecoration renders jagged and briefly develops square corners during animation

2 participants