Repository navigation
Support wide gamut colors in gradient_generator's CreateGradientTexture - #191980
Conversation
6591f24 to
5bef9f3
Compare
5bef9f3 to
f77116f
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request updates Impeller's gradient generation to support wide-gamut colors by deferring color-to-byte conversion and storing raw Color objects in GradientData. CreateGradientTexture now dynamically selects between kR32G32B32A32Float and kR8G8B8A8UNormInt pixel formats based on whether any color is wide-gamut. Feedback suggests adding static_asserts to verify Color's layout and size, explicitly casting the texture size to avoid narrowing warnings, and simplifying the vector copy logic in CreateGradientBuffer.
| GradientData result = { | ||
| .colors = {}, | ||
| }; | ||
| data.color_bytes.reserve(texture_size * 4); | ||
| result.colors.reserve(texture_size); | ||
|
|
||
| if (texture_size == colors.size() && | ||
| colors.size() <= kMaxGradientTextureSize) { | ||
| for (auto i = 0u; i < colors.size(); i++) { | ||
| AppendColor(colors[i], &data); | ||
| result.colors.push_back(colors[i]); | ||
| } | ||
| } else { |
There was a problem hiding this comment.
Since result.colors is now a std::vector<Color> and we are no longer converting colors to bytes during this step, we can directly assign colors to result.colors instead of manually looping and calling push_back. This also allows us to avoid calling reserve when the direct copy branch is taken.
GradientData result;
if (texture_size == colors.size() &&
colors.size() <= kMaxGradientTextureSize) {
result.colors = colors;
} else {
result.colors.reserve(texture_size);There was a problem hiding this comment.
Code Review
This pull request refactors gradient generation in Impeller to support wide-gamut gradients by updating GradientData to store a vector of Color objects instead of raw bytes. It dynamically selects the texture format (kR32G32B32A32Float for wide-gamut, kR8G8B8A8UNormInt otherwise) based on whether any color in the gradient is wide-gamut. Review feedback suggests adding static_assert guards for safe reinterpretation of Color data, avoiding implicit narrowing conversions when initializing ISize, using an epsilon tolerance in Color::IsWideGamut to prevent unnecessary promotion of standard sRGB gradients due to floating-point precision issues, and adding corresponding unit tests for boundary conditions.
gaaclarke
left a comment
There was a problem hiding this comment.
Looking good. I just have a question about plumbing file formats or more efficient file formats and a note on EXPECT_ vs ASSERT_
|
|
||
| std::vector<uint8_t> bytes; | ||
| if (is_wide_gamut) { | ||
| texture_descriptor.format = PixelFormat::kR32G32B32A32Float; |
There was a problem hiding this comment.
32bit floats seems like overkill, how big are these? Can we use kR16G16B16A16Float? Or can we somehow plumb the framebuffer's pixel format here so we get the BGRA10XR?
There was a problem hiding this comment.
For the most common case of a 2-color gradient, the texture is 2x1, so the texture is 32 bytes with float32 (compared to 8 bytes with non-wide-gamut uint8s). Most gradients will not be much bigger than this, depending on the number of colors and the stop intervals of the gradient.
The worst case is when it uses kMaxGradientTextureSize of 1024, which happens for gradients with 3+ stops and where there is a very large ratio between the smallest and largest stop interval. I'm not expecting this to be a very common case, but with this worst case the texture is 1024x1 and will be 16KB with float32 (compared to 4KB with non-wide-gamut uint8s).
These sizes don't seem like they'd be a big deal to me, but I don't have a lot to base this on so let me know if it actually is a problem.
From asking Gemini about it, textures are sampled in the shader as float32s regardless of the platform's framebuffer pixel format. So using float32s here preserves full color precision and avoids extra conversions (both on the CPU and GPU) back and forth between different pixel formats.
|
|
||
| auto gradient = CreateGradientBuffer(colors, stops); | ||
|
|
||
| ASSERT_EQ(gradient.colors.size(), 2u); |
There was a problem hiding this comment.
| ASSERT_EQ(gradient.colors.size(), 2u); | |
| EXPECT_EQ(gradient.colors.size(), 2u); |
Here and elsewhere.
There was a problem hiding this comment.
Done. Almost all of the rest of this file uses ASSERTs rather than EXPECTs. I don't want to change the entire file, so I just changed all the tests in the Gradient section.
flutter/flutter@c8c5e3b...0cbd1a4 2026-09-01 [email protected] Roll Skia from 6be7f8547c3c to 3911a1fe7f7a (1 revision) (flutter/flutter#192110) 2026-09-01 [email protected] Roll Fuchsia Linux SDK from EPzxifoyt36b5qiBy... to idslm9FikVLy2K_A-... (flutter/flutter#192104) 2026-09-01 [email protected] Roll Skia from 47df2ae3226c to 6be7f8547c3c (1 revision) (flutter/flutter#192103) 2026-09-01 [email protected] Roll Skia from e22ebf131e44 to 47df2ae3226c (4 revisions) (flutter/flutter#192099) 2026-09-01 [email protected] Roll Skia from 5489a16a5998 to e22ebf131e44 (5 revisions) (flutter/flutter#192093) 2026-09-01 [email protected] [flutter_tools] Safely handle broken symlinks and existing files during plugin symlink creation (flutter/flutter#191496) 2026-09-01 [email protected] Support wide gamut colors in gradient_generator's CreateGradientTexture (flutter/flutter#191980) 2026-09-01 [email protected] Clean up semantics code (flutter/flutter#191620) 2026-08-31 [email protected] Add website documentation item to PR pre-launch checklist (flutter/flutter#192080) 2026-08-31 [email protected] [windows] Fix null-deref in HostWindowPopup::UpdatePosition (Fixes #191478) (flutter/flutter#191479) 2026-08-31 [email protected] Removes deprecated ignoreSemantics parementers (flutter/flutter#191493) 2026-08-31 [email protected] Roll Dart SDK from b319095e317b to 9164def35347 (1 revision) (flutter/flutter#192073) 2026-08-31 [email protected] test: dynamic _tapOutside helper for TapRegion navigation tests (flutter/flutter#185397) 2026-08-31 [email protected] [Windows] fix: Remove quotes from compiler warning suppression (flutter/flutter#190873) 2026-08-31 [email protected] Migrate to listen package (flutter/flutter#189111) 2026-08-31 [email protected] Roll Skia from 15db98a90bbd to 5489a16a5998 (2 revisions) (flutter/flutter#192070) 2026-08-31 [email protected] Add regression test for plugin compileSdkExtension warning (flutter/flutter#191281) 2026-08-31 [email protected] Explicitly disable HCPP in platform view benchmarks and integration tests (flutter/flutter#191908) 2026-08-31 [email protected] Documentation and script for Gradle Distribution cache for CI (flutter/flutter#190323) 2026-08-31 [email protected] Roll Skia from 5549c93c9a1c to 15db98a90bbd (2 revisions) (flutter/flutter#192068) 2026-08-31 [email protected] Roll Packages from cd4cdd0 to d642322 (7 revisions) (flutter/flutter#192063) 2026-08-31 [email protected] Roll Dart SDK from 48f641e8b249 to b319095e317b (1 revision) (flutter/flutter#192061) 2026-08-31 [email protected] [tool] Migrate dev/tools from dart_skills_lint to skills_lint package (flutter/flutter#191997) 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 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
flutter#192124) This re-implements flutter#190874, after landing: flutter#191925 - Separated out some of the fixes from the original PR flutter#191980 - Add support for wide gamut colors. This re-implements the rest of the original PR. This is the same exact code as the original PR, minus the changes that have already been merged in flutter#191925. Verified locally that the wide gamut test passes. Related: flutter#190401 Original PR description: ---- Adds direct support for linear and radial gradient color sources to UberSDF, enabling single-pass rendering of these gradients without the multi-pass blending that is currently used. - Adds a color_source_sampler input to UberSDF, which is used to sample a texture representing the gradient color ramp for a linear or radial gradient. This sampler may also be extended in the future for image-based color sources, but that is outside the scope of this PR. - Adds properties to UberSDFParameters and to UberSDF's FragInfo for specifying gradient properties. - Factors out code in `linear_gradient_fill.frag` and `radial_gradient_fill.frag` that samples a texture to get a color for linear and radial gradients. This logic is moved to functions in `gradient.glsl`, to share with `uber_sdf.frag`. - Updates `Canvas::AddRenderSDFEntityToCurrentPass` to fill in the gradient texture and gradient related properties when `paint.color_source` is a gradient supported by UberSDF. This supports only linear and radial gradients. It does not support conical and sweep gradients. According to Gemini, linear and radial gradients make up more than 99% of gradient usage. Supporting conical and sweep gradients would require additional complexity to UberSDF, so it may not be worth it. We can revisit optimizing these other gradients in the future if we see performance related to them in real world use cases. This change by itself speeds up gradient rendering significantly, according to the results below. This can be further improved in a follow up PR by adding caching for gradient textures, similar to TextShadowCache in ContentContext. Addresses flutter#190401. Results from the demo app in flutter#190401, run on my Windows VM. Note that my Windows VM may not necessarily reflect real-world performance, but these numbers still show significant improvements with this PR. Also, my Windows VM reports a refresh rate of 500 hz, so almost all frame render times are considered "over budget". So ignore the "over budget" percentages and just look at the raw timing numbers. before: ``` === Windows linear-gradient comparison === mode=profile speed=1400px/s Solid color | frames=953 fps=238.00 | ui p50/p95=0.669/1.231ms | raster p50/p90/p95/p99/max=4.131/5.154/5.519/6.192/6.830ms | raster_over_budget=949/953 (99.6%) Linear gradient | frames=204 fps=50.75 | ui p50/p95=1.231/1.658ms | raster p50/p90/p95/p99/max=19.094/23.040/23.982/26.812/32.019ms | raster_over_budget=204/204 (100.0%) ================================================ ``` after: ``` === Windows linear-gradient comparison === mode=profile speed=1400px/s Solid color | frames=833 fps=208.00 | ui p50/p95=0.635/1.033ms | raster p50/p90/p95/p99/max=4.752/5.570/5.732/6.134/7.504ms | raster_over_budget=833/833 (100.0%) Linear gradient | frames=687 fps=171.50 | ui p50/p95=1.187/1.804ms | raster p50/p90/p95/p99/max=5.665/7.414/7.925/8.951/12.153ms | raster_over_budget=687/687 (100.0%) ================================================ ``` Skia: ``` === Windows linear-gradient comparison === mode=profile speed=1400px/s Solid color | frames=1375 fps=343.50 | ui p50/p95=0.495/0.845ms | raster p50/p90/p95/p99/max=2.679/3.514/3.851/4.631/5.777ms | raster_over_budget=1160/1375 (84.4%) Linear gradient | frames=1234 fps=308.25 | ui p50/p95=1.087/1.645ms | raster p50/p90/p95/p99/max=1.731/2.251/2.445/2.960/3.903ms | raster_over_budget=319/1234 (25.9%) ================================================ ``` ---- ## 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 in-code documentation (doc comments with `///`). - [ ] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [ ] 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]. 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 [flutter/website]: https://github.com/flutter/website [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
…r#12712) flutter/flutter@c8c5e3b...0cbd1a4 2026-09-01 [email protected] Roll Skia from 6be7f8547c3c to 3911a1fe7f7a (1 revision) (flutter/flutter#192110) 2026-09-01 [email protected] Roll Fuchsia Linux SDK from EPzxifoyt36b5qiBy... to idslm9FikVLy2K_A-... (flutter/flutter#192104) 2026-09-01 [email protected] Roll Skia from 47df2ae3226c to 6be7f8547c3c (1 revision) (flutter/flutter#192103) 2026-09-01 [email protected] Roll Skia from e22ebf131e44 to 47df2ae3226c (4 revisions) (flutter/flutter#192099) 2026-09-01 [email protected] Roll Skia from 5489a16a5998 to e22ebf131e44 (5 revisions) (flutter/flutter#192093) 2026-09-01 [email protected] [flutter_tools] Safely handle broken symlinks and existing files during plugin symlink creation (flutter/flutter#191496) 2026-09-01 [email protected] Support wide gamut colors in gradient_generator's CreateGradientTexture (flutter/flutter#191980) 2026-09-01 [email protected] Clean up semantics code (flutter/flutter#191620) 2026-08-31 [email protected] Add website documentation item to PR pre-launch checklist (flutter/flutter#192080) 2026-08-31 [email protected] [windows] Fix null-deref in HostWindowPopup::UpdatePosition (Fixes #191478) (flutter/flutter#191479) 2026-08-31 [email protected] Removes deprecated ignoreSemantics parementers (flutter/flutter#191493) 2026-08-31 [email protected] Roll Dart SDK from b319095e317b to 9164def35347 (1 revision) (flutter/flutter#192073) 2026-08-31 [email protected] test: dynamic _tapOutside helper for TapRegion navigation tests (flutter/flutter#185397) 2026-08-31 [email protected] [Windows] fix: Remove quotes from compiler warning suppression (flutter/flutter#190873) 2026-08-31 [email protected] Migrate to listen package (flutter/flutter#189111) 2026-08-31 [email protected] Roll Skia from 15db98a90bbd to 5489a16a5998 (2 revisions) (flutter/flutter#192070) 2026-08-31 [email protected] Add regression test for plugin compileSdkExtension warning (flutter/flutter#191281) 2026-08-31 [email protected] Explicitly disable HCPP in platform view benchmarks and integration tests (flutter/flutter#191908) 2026-08-31 [email protected] Documentation and script for Gradle Distribution cache for CI (flutter/flutter#190323) 2026-08-31 [email protected] Roll Skia from 5549c93c9a1c to 15db98a90bbd (2 revisions) (flutter/flutter#192068) 2026-08-31 [email protected] Roll Packages from cd4cdd0 to d642322 (7 revisions) (flutter/flutter#192063) 2026-08-31 [email protected] Roll Dart SDK from 48f641e8b249 to b319095e317b (1 revision) (flutter/flutter#192061) 2026-08-31 [email protected] [tool] Migrate dev/tools from dart_skills_lint to skills_lint package (flutter/flutter#191997) 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 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
…r#12712) flutter/flutter@c8c5e3b...0cbd1a4 2026-09-01 [email protected] Roll Skia from 6be7f8547c3c to 3911a1fe7f7a (1 revision) (flutter/flutter#192110) 2026-09-01 [email protected] Roll Fuchsia Linux SDK from EPzxifoyt36b5qiBy... to idslm9FikVLy2K_A-... (flutter/flutter#192104) 2026-09-01 [email protected] Roll Skia from 47df2ae3226c to 6be7f8547c3c (1 revision) (flutter/flutter#192103) 2026-09-01 [email protected] Roll Skia from e22ebf131e44 to 47df2ae3226c (4 revisions) (flutter/flutter#192099) 2026-09-01 [email protected] Roll Skia from 5489a16a5998 to e22ebf131e44 (5 revisions) (flutter/flutter#192093) 2026-09-01 [email protected] [flutter_tools] Safely handle broken symlinks and existing files during plugin symlink creation (flutter/flutter#191496) 2026-09-01 [email protected] Support wide gamut colors in gradient_generator's CreateGradientTexture (flutter/flutter#191980) 2026-09-01 [email protected] Clean up semantics code (flutter/flutter#191620) 2026-08-31 [email protected] Add website documentation item to PR pre-launch checklist (flutter/flutter#192080) 2026-08-31 [email protected] [windows] Fix null-deref in HostWindowPopup::UpdatePosition (Fixes #191478) (flutter/flutter#191479) 2026-08-31 [email protected] Removes deprecated ignoreSemantics parementers (flutter/flutter#191493) 2026-08-31 [email protected] Roll Dart SDK from b319095e317b to 9164def35347 (1 revision) (flutter/flutter#192073) 2026-08-31 [email protected] test: dynamic _tapOutside helper for TapRegion navigation tests (flutter/flutter#185397) 2026-08-31 [email protected] [Windows] fix: Remove quotes from compiler warning suppression (flutter/flutter#190873) 2026-08-31 [email protected] Migrate to listen package (flutter/flutter#189111) 2026-08-31 [email protected] Roll Skia from 15db98a90bbd to 5489a16a5998 (2 revisions) (flutter/flutter#192070) 2026-08-31 [email protected] Add regression test for plugin compileSdkExtension warning (flutter/flutter#191281) 2026-08-31 [email protected] Explicitly disable HCPP in platform view benchmarks and integration tests (flutter/flutter#191908) 2026-08-31 [email protected] Documentation and script for Gradle Distribution cache for CI (flutter/flutter#190323) 2026-08-31 [email protected] Roll Skia from 5549c93c9a1c to 15db98a90bbd (2 revisions) (flutter/flutter#192068) 2026-08-31 [email protected] Roll Packages from cd4cdd0 to d642322 (7 revisions) (flutter/flutter#192063) 2026-08-31 [email protected] Roll Dart SDK from 48f641e8b249 to b319095e317b (1 revision) (flutter/flutter#192061) 2026-08-31 [email protected] [tool] Migrate dev/tools from dart_skills_lint to skills_lint package (flutter/flutter#191997) 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 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
…lutter#192124, flutter#192962) UberSDF in this fork cannot shade a color source, so every antialiased gradient rect, rrect, oval or circle (Avio's Shell and greeter run with use_sdfs) was blended through a white SDF mask: two snapshots and a blend target per draw, plus a deferred coverage pass in externalLinearBackdrop mode. Upstream fixed this in the owning layer: fdb1d09 (flutter#192124) shades linear and radial gradients inside UberSDF and 419f9dd (flutter#192962) adds the storage-buffer variant used on Vulkan, so no ramp texture is made per draw. Both upstream commits sit on intermediate UberSDF changes this fork does not carry (uniform reordering, rect-path derivatives, stroke pixel size, which would change other SDF output), and Avio's UberSDF carries patch 45's coverage fields, so this is an adapted backport in one commit, not literal cherry-picks: - uber_sdf.frag is split into uber_sdf_common.glsl (shape SDFs, getColor, main) plus uber_sdf.frag (ramp texture) and uber_sdf_ssbo.frag (gradient stops in a storage buffer, the same math as the SSBO gradient shaders). Wherever the backend supports SSBOs (Vulkan), every UberSDF draw uses the SSBO variant, as upstream does. - UberSDFParameters gains GradientParameters; UberSDFContents renders both variants from one FragInfo setup; color filters wrap on the GPU for a gradient, and a gradient is never a background color. - Canvas::AddRenderSDFEntityToCurrentPass shades a linear or radial gradient whose local matrix (with the inverse shape transform) is a similarity. Conical and sweep gradients, images and runtime effects keep the masked kSrcIn path patch 52 slims. Patch 52's no-mask rect still comes first. - A gradient shaded in UberSDF takes the coverage transfer in the shader; defer_coverage no longer includes the color source in that case. Avio deltas against upstream (decision D3, accepted on the condition that Avio's crisp look stays): - Edges keep the old response: a gradient's SDF alpha uses the light-foreground gamma correction of the white mask it was blended through before, not the gradient's luma; the SSBO variant dithers like the SSBO gradient shaders, and like the masked composite it dithers the gradient color before coverage scales it, so a pixel the shape does not cover (the AA band's outside, the quad corners around a rounded shape) stays exactly transparent and srcOver adds nothing to what lies underneath. Upstream does not dither in UberSDF. - Linear gradients also require a similarity matrix (upstream checks only affinity); mapping end points through a shear or non-uniform scale does not map the gradient's field. - flutter#191925 and flutter#191980 are not brought in: the ramp-texture variant uses the fork's current GradientData, and Avio's SDF users take the SSBO variant. - malioc.json is not updated. Nothing else on the branch depends on this commit; its tests use patch 52's Playground::EnsureContextUsesSDFs. Reverting it alone restores the masked path exactly. Tests: - UberSDFContentsTest.ApplyColorFilterWithGradient and AsBackgroundColorGradientReturnsNullopt (from upstream; red as compile failures on the base: GradientParameters did not exist). - On every playground that renders with SDFs (Playground:: EnsureContextUsesSDFs: Vulkan with SDFs enabled, which runs the storage-buffer variant Avio ships, and the OpenGL ES and Metal SDF backends, which run the ramp-texture variant; plain backends skip): AiksTest.SdfLinearGradientRectAllocatesNoOffscreen (expected red on the base: three offscreens), SdfRadialGradientCircleUnderNonUniformScale- AllocatesNoOffscreen, UnsupportedColorSourceStillBlends (a sweep gradient keeps exactly three offscreens), and SdfGradientEdgesMatchMaskedComposite: the pixel guard the user asked for. It renders rect, rounded rect, oval and circle with an opaque dark-to-light gradient and a translucent glass sheen, in platformDefault and externalLinearBackdrop, once shaded in UberSDF and once through the old masked composite (the same horizontal gradient with a y-scale local matrix, which leaves its field unchanged but routes it through the masked path). Every pixel, corners and antialiased edges included, must hold alpha within 2/255 and color within 2/255 (ramp texture, no dither) or 5/255 (storage buffer: the composite dithered in its snapshot's grid, then quantized once more); every pixel the composite leaves fully transparent must stay exactly zero. Green by construction on the base (both renders take the masked path there); after this patch it fails if edges, corners, glass coverage or uncovered pixels drift. - SdfGradientLeavesUncoveredQuadPixelsTransparent: the quad corners around a gradient circle are exactly zero in both coverage modes, opaque and glass. Red on the storage-buffer variant if the dither runs after coverage. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This is a prerequisite to re-implementing #190874. This addresses the unsupported wide gamut issue which was originally present in that PR and which caused it to be reverted.
Related: #190401
Previously:
CreateGradientBufferconverts a gradient's colors and stops to an interpolated list of colors. This interpolated list of colors is converted to bytes withToR8G8B8A8()and is returned in aGradientData.R8G8B8A8GradientDatais passed toCreateGradientTexture, which allocates aPixelFormat::kR8G8B8A8UNormInttexture.Wide gamut colors can't be converted to
R8G8B8A8, so they end up getting clamped.Now:
CreateGradientBufferconverts a gradient's colors and stops to an interpolated list of colors (same as before). But now no conversion to bytes happens here. The interpolated list of colors is directly returned in aGradientData.Color-basedGradientDatais passed toCreateGradientTexture.CreateGradientTexturenow handles the conversion to bytes. If there are wide gamut colors, it converts tokR32G32B32A32Float. Otherwise it does the old behavior of converting toPixelFormat::kR8G8B8A8UNormInt.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.