UberSDF rect handling for thin (line-like) rectangles#188821
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors line-drawing unit tests in aiks_dl_path_unittests.cc using a new helper function and adds support for rendering sub-pixel filled rectangles and gamma-corrected alpha in uber_sdf.frag. The review feedback highlights critical issues in the shader, including potential division by zero and NaN propagation in filledRectSDF when the rectangle size is zero, and a potential NaN propagation in gammaCorrectedAlpha if the alpha value exceeds 1.0. Additionally, the feedback points out that the refactored test helper is missing rotation and translation transformations, which prevents the rotated test cases from functioning correctly.
|
Goldens have completed: https://flutter-gold.skia.org/search?issue=188821&crs=github&patchsets=2&corpus=flutter As expected, there are lots of changes
There are two goldens where I noticed changes which are less subtle: StrokedRectsRenderCorrectly
After this PR, the yellow line is noticeably much brighter than both the before and the non-sdf versions. I think the brighter version after this PR is more correct than the other versions. The test draws the yellow strokes as hairline ( The test positions these draws at integer offsets. At an integer offset, the 1-pixel-wide strokes are positioned exactly between two pixel centers. It ends up being drawn across 2 pixels with a lowered opacity. Ideally the opacity adjustment makes the 2-pixel-wide line look similar to a full opacity 1-pixel-wide line. I think the brighter version looks much more like a full opacity 1-pixel-wide full-brightness-yellow line. To demonstrate this more clearly, I ran the test modified with one adjustment: adding
I recommend clicking to view the image at full resolution. Also using a native (non-hi-dpi-scaled) resolution gives a more accurate view of how it really loooks. The horizontal strokes are now aligned with pixel centers, they are drawn as single pixel full brightness yellow lines. Now compare the 2-pixel-wide vertical strokes with the 1-pixel-wide horizontal strokes. In my perception, the brightened vertical strokes after this PR look much more visually similar to the 1-pixel horizontal stroke. StrokedArcsCoverFullArcWithButtEndsThe test description: flutter/engine/src/flutter/impeller/display_list/aiks_dl_basic_unittests.cc Lines 1366 to 1376 in 0008581 After this PR, the "pixel dirt" around the "erased" part of the arcs is noticeably lessened, especially for the last column with full arcs. I don't really know what this test is supposed to look like. But I assume less "pixel dirt" is better? |
|
@b-luk looking at the videos, did you preserve the behavior that drawing a line of 0px width draws a hairline instead of nothing? That's a magical value that we are supposed to maintain. That's why the LineContents clamped at that width too since it's kind of weird to animate to nothing then jump to what 0px means. |
gaaclarke
left a comment
There was a problem hiding this comment.
We need to special case 0px to drawing a hairline too.
This PR does not have the behavior that drawing a 0px rectangle draws a hairline. drawLine with width 0 does draw a hairline, but drawRect with a width 0 draws nothing. This PR only deals with drawRect, so it doesn't have any special handling for width 0 and will draw nothing. When I go back to working on #188514, I will need to add some special case handling for 0 for hairlines.
It is kind of weird. But I think that's the correct behavior. A width 0 line is a special case that behaves differently than non-zero widths. They are always physically 1 pixel, regardless of any transform. Non-zero widths have their specific widths, which is valid between 1 and 0 to animate to nothing. See https://dartpad.dev/?id=8f2c76261e86434860688eaadfd7b500 for an example in Skia/web. Also note that you can zoom in this dartpad, to see the behavior for non-zero lines vs the 0 hairline at different scaling transforms. |
|
Looking at the goldens, I only got about halfway through but the curves on the new code looked a little smoother than before. The yellow outlines on the purple rects are supposed to be a reference, but it's odd that they have gaps in them. They are drawn with DrawRect and should not have gaps. The fact that they are twice as wide isn't ideal for their crispness, but I think the test is more about whether we get the joins right than about specific pixelization? They should probably use overdraw-rejection, though, which might help with the overdraw on the corners. |
The yellow outlines on the purple rects aren't the main purpose of those specific goldens. But it does demonstrate the gamma correction change from this PR. Some of the new golden tests that I add do specifically test how these lines look. Unfortunately we don't see any results for the existing UberSDF behavior, because the tests are added in this PR which also changes them to the new behavior. But you can compare with the non-SDF versions. For example: OnePixelDrawRectThe new UberSDF behavior looks much more like a consistent 1 pixel white line across different subpixel offsets. ThinDrawRectRotatedThis draws a rectangle with width 0.3 and with some rotation. The new UberSDF behavior is clearly much more consistent looking. edit: inlined images get compressed or something when inlined through github, so I replaced the inlined images with links directly to the images on flutter-gold |
gaaclarke
left a comment
There was a problem hiding this comment.
The code looks good, the before and after video looks good, the malioc diff looks fine. I didn't dig through the goldens. Assuming you and jim are happy with them I'm fine with this change. My biggest concern was the additional performance cost versus the problem we are addressing. These fixes are kind of nice to have in a world where we don't use the ubersdf for line drawing, but that is where we are wanting to go which raises their value.
|
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 Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
|
@flar PTAL. As I discussed with you, I moved the logic for 1-pixel-minimum rectangle sizing and alpha scaling from the shader to the CPU. This did indeed simplify a lot of the shader code. |
| if (renderer_.GetContext()->GetFlags().use_sdfs && | ||
| IsCompatibleWithSDFRendering(paint)) { | ||
| if (rect.IsEmpty()) { | ||
| // Empty rect doesn't need to be drawn. |
There was a problem hiding this comment.
Is this true for stroked rects?
There was a problem hiding this comment.
I tested it out with Skia, and it does draw a rect even with a size of 0. So this was wrong. I removed it. I think it could still apply to filled rectangles, but I'll just keep the code simpler and not try to make optimizations that aren't directly related to what I'm fixing.
There was a problem hiding this comment.
Filled rectangles could just be eliminated if the alpha scale is 0 (or <epsilon) without specifically testing for 0 scale or 0 dimension.
There was a problem hiding this comment.
You're right, we can exit early if alpha scale is close to 0. I added this.
flar
left a comment
There was a problem hiding this comment.
Mostly questions to answer, but I also want to take another look at the goldens. I'm thinking there are too many new goldens, but I want to understand each one and how it might be just a variation on another.
Also, I'm assuming that most of the older golden diffs are due to the new gamma function?
|
|
||
| // Converts linear coverage alpha to perceptual alpha. | ||
| float gammaCorrectedAlpha(float alpha, vec3 foreground_rgb) { | ||
| // Gamma corrected alpha used for dark colors. |
There was a problem hiding this comment.
Is there a source for how sqrt compares to 2.2 gamma?
There was a problem hiding this comment.
It's what Gemini said was standard industry practice to avoid pow, which requires the SFU pipeline and can cause shaders to be slow. From a bit of searching, I can't find any definitive resource about this technique of using sqrt to approximate pow(1/2.2). But there are some stackoverflow/reddit/forum posts, like this.
As for how it actually compares to 2.2 gamma, sqrt would be pow(1/2) compared to pow(1/2.2). Here's a graph for how they compare. pow(1/2.2) is in blue, and sqrt is in green. The difference between the two is shown in dotted green. I also show the non-corrected linear curve and its difference with pow(1/2.2) in purple and dotted purple. The largest difference between the sqrt and 2.2 gamma curve is about 0.035. So at these alpha values, the alpha will be off by 3.5%. We only use this for AA fringes that go across 1-2 pixels, so I think it's good enough to get this close to gamma 2.2. Compare with the purple lines that shows the current non-corrected behavior, where the alpha can be off by about 0.28 or 28%.
There was a problem hiding this comment.
That sounds good. I try to include a pointer to a (non-AI) reference that investigates or demonstrates the point when I can.
|
Golden file changes are available for triage from new commit, Click here to view. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
| // Most tests scale the builder with | ||
| // builder.Scale(GetContentScale().x, GetContentScale().y) in order to | ||
| // maintain the same visual size on different screens. | ||
| // These DrawLines tests explicitly doesn't invoke this scaling, because |
There was a problem hiding this comment.
Done. PTAL. Annoying that every small change like this requires re-approval.
|
Golden file changes are available for triage from new commit, Click here to view. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
…12169) Manual roll Flutter from 91939cc4db78 to dc2a8703e12b (50 revisions) Manual roll requested by [email protected] flutter/flutter@91939cc...dc2a870 2026-07-09 [email protected] [ios,macos] Update swiftc.py flags to match swiftc (flutter/flutter#189174) 2026-07-09 [email protected] [AGP 9] Update Warn Version to AGP 9+ (flutter/flutter#189109) 2026-07-09 [email protected] Sync CHANGELOG.md from stable (flutter/flutter#189203) 2026-07-09 [email protected] [web] Roll Chrome to 145 (framework) (flutter/flutter#182861) 2026-07-09 [email protected] Roll Packages from 52d84d6 to 20928d5 (6 revisions) (flutter/flutter#189194) 2026-07-09 [email protected] [web] Avoid absolute positioning for base CanvasKit canvas (flutter/flutter#188337) 2026-07-09 [email protected] Roll Dart SDK from cdb7217e65aa to a11fb7ed40a5 (6 revisions) (flutter/flutter#189195) 2026-07-09 [email protected] Fix dereference of nullptr in the moved-to-rect signal in the Linux embedder (flutter/flutter#189152) 2026-07-09 [email protected] Fix data for design packages (flutter/flutter#189140) 2026-07-09 [email protected] Roll Skia from 7b42d1251d54 to ab3a7b98c94d (2 revisions) (flutter/flutter#189181) 2026-07-09 [email protected] Roll Skia from 05d9d214e0b7 to 7b42d1251d54 (2 revisions) (flutter/flutter#189175) 2026-07-09 [email protected] Roll Skia from 542c8bdd7f4f to 05d9d214e0b7 (4 revisions) (flutter/flutter#189169) 2026-07-09 [email protected] UberSDF rect handling for thin (line-like) rectangles (flutter/flutter#188821) 2026-07-09 [email protected] Roll Skia from dd572c07f63c to 542c8bdd7f4f (4 revisions) (flutter/flutter#189160) 2026-07-09 [email protected] [flutter_tools] Fix hot restart for WASM web builds (flutter/flutter#187898) 2026-07-08 [email protected] Split FlViewRenderer into OpenGL and software backends (flutter/flutter#188824) 2026-07-08 [email protected] Promote android_hardware_smoke_tests out of bringup in CI (flutter/flutter#189081) 2026-07-08 [email protected] Roll Skia from 8df24be66531 to dd572c07f63c (4 revisions) (flutter/flutter#189150) 2026-07-08 [email protected] Expose LinuxWindowRegistrar on _window_linux.dart in order to better support out of tree LinuxWindowingOwners (flutter/flutter#188917) 2026-07-08 [email protected] Roll pub packages (flutter/flutter#189149) 2026-07-08 [email protected] fix(ci): harden some workflows (flutter/flutter#189087) 2026-07-08 [email protected] Roll Skia from 51a62da33da0 to 8df24be66531 (1 revision) (flutter/flutter#189139) 2026-07-08 [email protected] Roll Dart SDK to Dart 3.13 beta3 (flutter/flutter#189122) 2026-07-08 [email protected] [flutter_tools] Don't crash on non-UTF-8 plugin pubspec.yaml (flutter/flutter#188976) 2026-07-08 [email protected] [flutter_tools] Watch transitive #include headers for FragmentProgram hot reload (flutter/flutter#187945) 2026-07-08 [email protected] Roll Skia from 040d9f55de00 to 51a62da33da0 (1 revision) (flutter/flutter#189135) 2026-07-08 [email protected] Roll Packages from 92525f5 to 52d84d6 (7 revisions) (flutter/flutter#189134) 2026-07-08 [email protected] [flutter_tools] Forcefully kill hung subprocesses 5 seconds after timeout (flutter/flutter#187178) 2026-07-08 [email protected] Expose the app's build name and number as compile-time constants (flutter/flutter#187935) 2026-07-08 [email protected] Roll Skia from 1ff92f879815 to 040d9f55de00 (1 revision) (flutter/flutter#189131) 2026-07-08 [email protected] Roll Skia from 6137414bef5c to 1ff92f879815 (6 revisions) (flutter/flutter#189126) 2026-07-08 [email protected] [test cross imports] More test/rendering + flutter_test/test fixes (flutter/flutter#188954) 2026-07-08 [email protected] engine: explain why each candidate build was skipped in Flutter web loader (flutter/flutter#186254) 2026-07-08 [email protected] vscode: add missing unicode.h (flutter/flutter#189102) 2026-07-08 [email protected] Roll Fuchsia Linux SDK from 7RjQJBW3m-3Jl-7jr... to QcRFUtvCw2EobfJ8s... (flutter/flutter#189104) 2026-07-08 [email protected] Roll Skia from 075fbe4778d9 to 6137414bef5c (10 revisions) (flutter/flutter#189106) 2026-07-08 [email protected] engine: warn on WASM load failure when not crossOriginIsolated (flutter/flutter#186252) 2026-07-08 [email protected] Roll Dart SDK from c9bccc09e733 to db2155f56bf3 (2 revisions) (flutter/flutter#189105) 2026-07-08 [email protected] [flutter_tools] Prevent interactive device selection in machine mode (flutter/flutter#188267) 2026-07-08 [email protected] [flutter_tools] Fix wireless ADB device discovery when serial contains spaces (flutter/flutter#187943) 2026-07-07 [email protected] [web] Fix grouped autofill on iOS Chrome (flutter/flutter#187459) 2026-07-07 [email protected] Fix TextSelectionOverlay crash when layout is degenerate (flutter/flutter#188672) 2026-07-07 [email protected] [flutter_tools] Provision Android NDK in the main Gradle invocation (flutter/flutter#186337) 2026-07-07 [email protected] Android_hardware_smoke_test: Migrate to AGP 9 (flutter/flutter#189082) ...
This fixes thin UberSDF roundrect drawing, in the same way that flutter#188821 fixed it for normal rects. Prerequisite for using UberSDF for lines. - Factors out some of the rect-upscaling code in DrawRect to an UpscaleRect helper function, so it can be shared by DrawRect and DrawRoundRect. - Adds a roundRectPixelSize function in uber_sdf.frag, similar to rectPixelSize but for round rects. - Adds unit tests for UpscaleRect, and a new golden tests for "DrawLinesWithFilledRoundRects" ## Screenshot ### DrawLinesWithFilledRoundRects Before: <img width="1024" height="800" alt="roundrect ubersdf before" src="https://github.com/user-attachments/assets/c490318f-0579-4425-82ec-ca5a7fd51d89" /> After: <img width="1024" height="800" alt="roundrect ubersdf after" src="https://github.com/user-attachments/assets/cd7bc780-fbc8-46aa-a034-6a9c1db69ad9" /> ## Video ### DrawLinesWithFilledRoundRects Before: https://github.com/user-attachments/assets/612af65d-bce5-45d2-a1aa-7636a60f3254 After: https://github.com/user-attachments/assets/4090d72c-eba9-4e28-8c8a-495bcce9b82b ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [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]. - [ ] 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. - [ ] All existing and new tests are passing. 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](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 [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [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
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. This is the first in a set of 3 PRs (#188821, #189224, and #188514) that will be cherry picked in order to fix a set of line-related issues when Impeller with SDF rendering is enabled. ### Issue Link: What is the link to the issue this cherry-pick is addressing? #188329 #188911 #188593 ### 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. Thin ines (including lines rendered with `canvas.drawLine`, thin line-like rectangles rendered with `canvas.drawRect`, and paths drawn with `canvas.drawPath` that consist of a single line or thin rectangle) have various highly visible rendering issues: - opacity is ignored - lines with stroke width less than 1 pixel are incorrectly clamped up to be ~2 pixels wide - lines with stroke width more than 1 pixel are overly thick, with an added thickness proportional to their intended width This issue is present when impeller is enabled Impeller with SDF rendering. In the beta channel, Impeller with SDF rendering is the default when building apps for desktop platforms: macOS, Linux, and Windows. ### 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. [flutter/188329](#188329), [flutter/188911](#188911), [flutter/188593](#188593): Multiple line rendering issues when Impeller with SDF rendering is enabled (default enabled on desktop platforms) ### Workaround: Is there a workaround for this issue? Disable Impeller, falling back to Skia rendering. ### 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? After all 3 PRs are cherry picked, verify the sample apps in the relevant issues (#188329 and #188911) render with expected opacity and with expected line widths.
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. This is the second in a set of 3 PRs (#188821, #189224, and #188514) that will be cherry picked in order to fix a set of line-related issues when Impeller with SDF rendering is enabled. The first PR was cherry picked and merged with #189517 ### Issue Link: What is the link to the issue this cherry-pick is addressing? #188329 #188911 #188593 ### 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. Thin ines (including lines rendered with `canvas.drawLine`, thin line-like rectangles rendered with `canvas.drawRect`, and paths drawn with `canvas.drawPath` that consist of a single line or thin rectangle) have various highly visible rendering issues: - opacity is ignored - lines with stroke width less than 1 pixel are incorrectly clamped up to be ~2 pixels wide - lines with stroke width more than 1 pixel are overly thick, with an added thickness proportional to their intended width This issue is present when impeller is enabled Impeller with SDF rendering. In the beta channel, Impeller with SDF rendering is the default when building apps for desktop platforms: macOS, Linux, and Windows. ### 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. [flutter/188329](#188329), [flutter/188911](#188911), [flutter/188593](#188593): Multiple line rendering issues when Impeller with SDF rendering is enabled (default enabled on desktop platforms) ### Workaround: Is there a workaround for this issue? Disable Impeller, falling back to Skia rendering. ### 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? After all 3 PRs are cherry picked, verify the sample apps in the relevant issues (#188329 and #188911) render with expected opacity and with expected line widths.
…es (#189537) 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. This is the third in a set of 3 PRs (#188821, #189224, and #188514) that will be cherry picked in order to fix a set of line-related issues when Impeller with SDF rendering is enabled. The first PR was cherry picked and merged with #189517 The second PR was cherry picked and merged with #189529 ### Issue Link: What is the link to the issue this cherry-pick is addressing? #188329 #188911 #188593 ### 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. Thin ines (including lines rendered with `canvas.drawLine`, thin line-like rectangles rendered with `canvas.drawRect`, and paths drawn with `canvas.drawPath` that consist of a single line or thin rectangle) have various highly visible rendering issues: - opacity is ignored - lines with stroke width less than 1 pixel are incorrectly clamped up to be ~2 pixels wide - lines with stroke width more than 1 pixel are overly thick, with an added thickness proportional to their intended width This issue is present when impeller is enabled Impeller with SDF rendering. In the beta channel, Impeller with SDF rendering is the default when building apps for desktop platforms: macOS, Linux, and Windows. ### 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. [flutter/188329](#188329), [flutter/188911](#188911), [flutter/188593](#188593): Multiple line rendering issues when Impeller with SDF rendering is enabled (default enabled on desktop platforms) ### Workaround: Is there a workaround for this issue? Disable Impeller, falling back to Skia rendering. ### 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? After all 3 PRs are cherry picked, verify the sample apps in the relevant issues (#188329 and #188911) render with expected opacity and with expected line widths.


Implements a custom filledRectSDF function in UberSDF with some custom behavior in order to properly handle dimensions of around 1 pixel and less.
Similar thin-shape logic may also be applicable for other shapes in UberSDF. But I'm limiting this PR to just change the behavior for filled rectangle behavior. This is the most common use of very thin shapes (thin rects are often used for lines). Other shapes being drawn thinly would be rare corner cases, I'd expect. If we want to consider other shapes, that should be a follow-up.
This change adds gamma correction to the alpha of all SDF shapes. So I expect a lot of golden changes. There will be changes small color changes to the AA fringe of every shape.
Factors out common code in the existing
HairlinePathandHairlineDrawLineplayground/golden tests. Expands these with new versions that draw thin (width=0.3), rotated thin, and one pixel lines. And adds "Rect" versions which draw the same shape withdrawRectinstead ofdrawPathordrawLine.Fixes #188591
Screenshot
UberSDF drawRect with this PR, using the demo app from #188590 which draws lines at every incremental 0.01 offset::

Compare with the screenshots of various drawing lining methods in #188590. The new lines have very consistent brightness, and have no disappearing issues.
Videos
Using the hairline/thinline drawing playground tests.
Note that github's UI seems to not allow showing the video at actual size, so what you see inline is not completely accurate. But it's pretty close. If you want to see what it looks like at full size, I think you'll have to download the videos.
UberSDF drawRect with this PR:
drawrect.-.ubersdf.new.mov
UberSDF drawRect existing behavior:
drawrect.-.ubersdf.old.mov
LineContents AA drawline:
drawline.-.linecontents.mov
Tesselation drawRect
drawrect.-.tesselation.mov
Tesselation drawLine
drawline.-.tesselation.mov
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-assistbot 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.