Repository navigation
UberSDF round rectangles are sometimes incorrectly drawn as non-rounded rectangles #189807
Description
Activity
- addedc: renderingUI glitches reported at the engine/skia or impeller rendering levelUI glitches reported at the engine/skia or impeller rendering levele: impellerImpeller rendering backend issues and features requestsImpeller rendering backend issues and features requeststeam-engineOwned by Engine teamOwned by Engine team
on Jul 21, 2026 Originally reported internally: b/537444793
I actually think the optimization to simplify the output to a normal rectangle is a bad idea as well. Fixing that will fix the problem without worrying whether we slightly disturb the bit-precision of the result.
The reason it is an issue is that a rounded rectangle will have ends that are less opaque than the pixels along its length even when it is just a single pixel across. As a result, if we continue to allow simplifying it to a simple rect we will see a snap when the round rect goes from 0.99 pixels wide to 1.0 pixels wide. The 0.99 pixel wide round rect will actually have more opaque ends than the one at 1.0 pixels wide. Growing the round rect would make it dimmer (on the end pixels). That's a problem.
So, I think the main way this should be fixed should be to not simplify the round rect to a rectangle when it "appears" to have been adjusted. Doing that would fix the problem identified in the issue as well as other problems we would see with rectangles that are transitioning across the pixel wide threshold.
I can reproduce this on Windows with Impeller OpenGLESSDF using ordinary Flutter widgets. Seven cards are assigned fractional widths through (constraints.maxWidth - spacing) / 7. A Container with a rounded BoxDecoration renders square corners under Impeller, while Skia renders it correctly. Note how it happens only for some of the cards. This appears consistent with the fractional-width root cause described here.
see these screenshots with impeller (1st one) and with skia (2nd one):

- added a commit that references this issue
on Jul 22, 2026 - added a commit that references this issue
on Jul 23, 2026 This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.- locked as resolved and limited conversation to collaborators
on Aug 5, 2026
Affects platforms where UberSDF is enabled (desktop platforms).
Demo:
Expected: two rounded rectangles
Actual:

The first rounded rectangle, with fractional width, renders as a non-rounded rectangle.
Root cause and fix
Rect::ExpandToMinTransformedSize always constructs a new expanded rectangle from the input Rect from its center point and half-extents.
If the input rectangle is already large enough and does not need expansion, this should return an identical rectangle. The returned rectangle is equality-checked against the input in Canvas::DrawRoundRect to determine whether expansion happened. That code assumes that if the output does not equal the input, pixel-expansion happened, which means that the rounded rect had sub-pixel dimensions and can be safely drawn as a non-rounded rectangle.
The issue is that for certain cases, particularly with non-integer sizes, ExpandToMinTransformedSize returns a different rectangle even if no expansion happened. This is due to small floating point imprecisions when constructing the new rectangle using the input rectangle's center and half-extents. If the returned rectangle incorrectly is not equal to the input, a non-rounded rectangle gets drawn instead of a rounded rectangle.
To fix this, ExpandToMinTransformedSize should not construct a new rectangle unless expansion is actually needed.