Skip to content

Add some extra slack room for stroked and filled circles that use the SDF shader#183536

Merged
auto-submit[bot] merged 13 commits intoflutter:masterfrom
walley892:circle-geometry
Mar 19, 2026
Merged

Add some extra slack room for stroked and filled circles that use the SDF shader#183536
auto-submit[bot] merged 13 commits intoflutter:masterfrom
walley892:circle-geometry

Conversation

@walley892
Copy link
Contributor

@walley892 walley892 commented Mar 11, 2026

This PR expands the geometry of stroked and filled circles that use the SDF shader. This allows the fading to occur in both the inside and outside of the rendered circle, improving appearance - especially on thinner stroked circles.

This addresses the issues noted in #182708 and #183002

Fixes #183418

Sample using Skia:
circle_geometry_noimp

Sample at HEAD:
circle_geometry_master

Sample after this change:

circle_geometry_change

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I signed the [CLA].
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is [test-exempt].
  • I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
  • 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. 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.

@walley892 walley892 requested review from flar and gaaclarke March 11, 2026 20:42
@github-actions github-actions bot added engine flutter/engine related. See also e: labels. e: impeller Impeller rendering backend issues and features requests labels Mar 11, 2026
@walley892
Copy link
Contributor Author

Will likely have to update goldens

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 expands the geometry for stroked and filled circles that use the SDF shader, which allows for a two-sided fade and improves the appearance of anti-aliasing. The changes involve updating CircleContents and CircleGeometry to handle the expanded geometry, and modifying the circle.frag shader to implement the new fading logic.

My review identified two related issues concerning the handling of stroke_width coordinate spaces. In circle_contents.cc, the stroke width is passed to the shader in local units instead of the required screen units. In circle_geometry.cc, the calculation for the stroke's half-width for the geometry tessellator is incorrect due to a similar coordinate space mismatch. I've provided suggestions to correct these issues.

}

float outer_distance = distanceFromCircle(outer_radius, center, point);
void main() {
Copy link
Member

Choose a reason for hiding this comment

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

I don't usually say this but there is a lot of dense math happening here that takes a while to parse. Some comments outlining the procedure would be helpful so people don't have to parse everything in order to orient themselves.

Copy link
Contributor

Choose a reason for hiding this comment

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

This, in general, in a lot of our code...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think I've got the right understanding here, I took Flar's math directly and looked at it for a while until it made sense. @flar, does the comments sound about right to you?

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps for a general comment at the top of this function we could say something like:

// We need to make sure that for stroked circles we have a cross section
// that is at least as wide as a pixel. The cross section is measured towards
// the center of the circle which is the same direction in both local and screen
// coordinates for uniformly scale transforms and only slightly off for skewed
// transforms.

@flar
Copy link
Contributor

flar commented Mar 11, 2026

Spot checking the Google test results and the results look smoother with this change.

@flar
Copy link
Contributor

flar commented Mar 11, 2026

In some of the flutter gold results, the object changed colors completely...?

@walley892 walley892 added CICD Run CI/CD and removed CICD Run CI/CD labels Mar 12, 2026
@walley892 walley892 requested a review from gaaclarke March 12, 2026 19:21
gaaclarke
gaaclarke previously approved these changes Mar 12, 2026
Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

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

lgtm! It's worth waiting for @flar's approval too since he's given some feedback. I couldn't review the golden changes in github for some reason. I assume those look fine.

flar
flar previously approved these changes Mar 13, 2026
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.

Some nits that I think should be addressed, but I'll leave it to you whether you want me to double check the results...

@github-actions github-actions bot removed the CICD Run CI/CD label Mar 17, 2026
@walley892
Copy link
Contributor Author

Hang on, is the thin stroked circle supposed to be hanging off the bottom of the image?

I changed the translation and the background in the test. Changed back

@walley892 walley892 added the CICD Run CI/CD label Mar 17, 2026
@walley892 walley892 requested a review from flar March 18, 2026 02:35
@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 #183536 at sha d310467

@walley892 walley892 added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 18, 2026
std::unique_ptr<CircleGeometry> geometry,
Color color,
bool stroked) {
geometry->SetAntialiasPadding(kAntiliasPixels);
Copy link
Contributor

Choose a reason for hiding this comment

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

This method is used for both AA and non-AA circles, only the caller knows which. This call should be moved up to the canvas.cc methods that create the geometry and know which type they want.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are you talking about CircleContents::Make? It's only used for AA circles. The contents is the thing that controls which shader to use, and the circle_contents uses the SDF shader which applies antialiasing.

Copy link
Contributor

Choose a reason for hiding this comment

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

The name doesn't suggest that.
It has the same arguments as a constructor that is used for non-AA circles.
How is the caller to know this?

If, in the future, the non-AA case decides it wants to move from a stack allocated contents to a shared_ptr contents, it will suddenly generate the wrong geometry. And vide-versa.

Copy link
Member

Choose a reason for hiding this comment

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

I'm facing a similar situation with the UberSDFContents. I like Jim's point on surfacing the idea of antialiasing somehow into the canvas level. An easy solution is to make the canvas set the antialias amount on the geometry. We're going to have to foist that value up to the canvas level at some point.

On thing that is weird here too is that by adding the antialias amount to the geometry we create data on it that is ignored in other instances. Don't you find that odd? I guess the alternative is to have an AntialiasedCircleGeometry or storing the antialias amount on the contents which might be awkward?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If, in the future, the non-AA case decides it wants to move from a stack allocated contents to a shared_ptr contents, it will suddenly generate the wrong geometry. And vide-versa.

If someone were to somehow refactor the non-AA case to use a CircleContents (and created it via CircleContents::Make()), they may be surprised to end up with both the extra geometry and an SDF-antialiasing shader being applied (the latter being applied with no regard for the geometry).

I guess the alternative is to have an AntialiasedCircleGeometry or storing the antialias amount on the contents which might be awkward?

The contents (in this PR) stores and controls the antialias amount. It needs to at least store it in order to pass it along to the shader.

Maybe we need an AntialiasedCircleGeometry and an AntialiasedCircleContents to disambiguate the API? I also think that this will all change very soon with https://github.com/orgs/flutter/projects/240. My main goal in this PR is to address the immediate visual issues users are experiencing.

Copy link
Contributor

Choose a reason for hiding this comment

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

On thing that is weird here too is that by adding the antialias amount to the geometry we create data on it that is ignored in other instances. Don't you find that odd? I guess the alternative is to have an AntialiasedCircleGeometry or storing the antialias amount on the contents which might be awkward?

It's not "ignored" in other instances. The other instances are simply asking for no padding for antialiasing. It's default is (should be?) 0. But, it is applied in all uses, it just has no effect when it is left at 0.

Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect that the way we reuse the CircleGeometry for both AA and non-AA cases will be reflected in other geometries as well. Their basic role is the same regardless of whether they've been padded for AA.

Copy link
Contributor

Choose a reason for hiding this comment

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

One thing that we will need to decide about. There is a difference between "aa pixels" and "aa padding". For a rectangle, they are the same, but for a circle, the padding is theoretically sqrt2*aa_pixels. Rather than have a configurable "padding amount", the geometries should have a configurable "aa pixels" and then they can decide what their padding is based on how their geometry works.

Of course, in practice, when I brought up the issue of the sqrt2 before, I eventually convinced myself that the slightly larger radius didn't matter. But, it points out that the caller is not necessarily in the best context to know how much padding will be needed.

Copy link
Contributor

@flar flar Mar 19, 2026

Choose a reason for hiding this comment

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

The padding vs pixels may matter more for AA lines which really care more about the angular fidelity compared to a circle where that fidelity is constantly changing through its circumference. Also, we may find that developers will care about the tiny amount of fidelity that padding by sqrt2 matters for circles. It's best not to assume that geometry constructor/callers understand the issues we see today and that we discover tomorrow wrt the actual best number of pixels to pad any given geometry by.

Copy link
Contributor

Choose a reason for hiding this comment

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

@flar we are going to revisit this for the UberSDF. I think this is an acceptable approach for now. How about we accept this and wrap the cleanup into the ubersdf work? We don't want to mix this up with the ubersdf since that will make it hard to cherry-pick. I share your concerns and we'll get it hashed out.

I'm good with punting these issues to the Uber shader. We currently have a misspelling, but we can fix that either here or there as well...

@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Mar 18, 2026
@auto-submit
Copy link
Contributor

auto-submit bot commented Mar 18, 2026

autosubmit label was removed for flutter/flutter/183536, because This PR has not met approval requirements for merging. Changes were requested by {flar}, please make the needed changes and resubmit this PR.
The PR author is a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.

  • Merge guidelines: A PR needs at least one approved review if the author is already part of flutter-hackers or two member reviews if the author is not a flutter-hacker before re-applying the autosubmit label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

circle_geometry->GetPositionBuffer(renderer, entity, pass);
return geometry_result;
}
Scalar kAntiliasPixels = 1.0;
Copy link
Contributor

Choose a reason for hiding this comment

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

This configuration should be similar across all AA rendering so perhaps this should be moved to a more central location. Canvas?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, it's misspelled. Antilias -> Antialias

Copy link
Contributor

Choose a reason for hiding this comment

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

We can leave this for the Uber work to sort.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed the typo.

flar
flar previously approved these changes Mar 19, 2026
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.

The implementation works fine as is. The remaining issues, mostly about internal API, can be fixed as we continue to develop and generalize the basic concepts.

@flar
Copy link
Contributor

flar commented Mar 19, 2026

Hang on, is the thin stroked circle supposed to be hanging off the bottom of the image?

I changed the translation and the background in the test. Changed back

It looks like the background is still different?


flutter::DisplayListBuilder builder;

DlPaint background_paint;
Copy link
Contributor

Choose a reason for hiding this comment

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

Are these deleted lines intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, that's what caused the background diff. I found it easier to look at the result with a white background. Both you and Willie commented on it though, so I'm probably the weird one - changing back.

Copy link
Contributor

Choose a reason for hiding this comment

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

I just wanted to make sure it was intentional...

@github-actions github-actions bot removed the CICD Run CI/CD label Mar 19, 2026
@walley892 walley892 requested review from flar and gaaclarke March 19, 2026 19:40
@walley892 walley892 added CICD Run CI/CD labels Mar 19, 2026
@fluttergithubbot
Copy link
Contributor

An existing Git SHA, ed50dc5ab46d49548dfe536da746e8e9c076d675, was detected, and no actions were taken.

To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with --force) that already was pushed before, push a blank commit (git commit --allow-empty -m "Trigger Build") or rebase to continue.

Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

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

lgtm, thanks

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

@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 #183536 at sha ed50dc5

@walley892 walley892 added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 19, 2026
@auto-submit auto-submit bot added this pull request to the merge queue Mar 19, 2026
Merged via the queue into flutter:master with commit c6cec79 Mar 19, 2026
192 of 193 checks passed
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD 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.

[Impeller] The geometry used for the SDF-based AA circle fragment clips some of its output

4 participants