Sitelet https://github.com/flutter/flutter/pull/192962
Skip to content

SSBO-based gradients in UberSDF - #192962

Merged
auto-submit[bot] merged 7 commits into
flutter:masterfrom
b-luk:gradient-ssbo
Sep 25, 2026
Merged

auto-submit[bot] merged 7 commits into
flutter:masterfrom
b-luk:gradient-ssbo

Conversation

@b-luk

@b-luk b-luk commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Moves most of the logic of uber_sdf.frag to uber_sdf_common.glsl. New uber_sdf.frag and uber_sdf_ssbo.frag shaders import uber_sdf_common.glsl and implement getGradientColor() with a texture-based or SSBO-based gradient implementation.

Gradient SSBO logic based off the existing SSBO gradient shaders like https://github.com/flutter/flutter/blob/b138043fc75c1270e1bd9f1fa0a5c1299e86e638/engine/src/flutter/impeller/entity/shaders/gradients/linear_gradient_ssbo_fill.frag

Note that for GLES, SSBO is currently not supported.

bool CapabilitiesGLES::SupportsSSBO() const {
return false;
}

This means that for Windows and Linux, which currently always have a GLES backend, this change does not do anything.

This is a prerequisite for addressing #190401. This improves UberSDF gradient rendering when SSBO is supported, but not on Windows. The next step to address #190401 is to make Windows support SSBO: #193162

Tested this with the "Scrolling basic LinearGradient" benchmark app from #190401. I ran it 3 times, on my Mac. The raster time goes down significantly, so that it is on par with the solid color time.

On Mac (my local dev machine, M3 MacBook Pro):

Before:

Avg raster p50
Solid 1.250ms
Gradient 2.596ms
Full results
Note: This says "Windows" because that's hard-coded in the benchmark app. But this was run on my Mac.

flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=1.085/1.661ms | raster p50/p90/p95/p99/max=1.278/1.701/1.764/1.857/1.999ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.460/2.101ms | raster p50/p90/p95/p99/max=2.639/3.182/3.325/3.727/4.102ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=0.904/1.400ms | raster p50/p90/p95/p99/max=1.232/1.635/1.752/1.918/2.125ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.490/2.262ms | raster p50/p90/p95/p99/max=2.686/3.368/3.615/3.863/4.256ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=0.903/1.426ms | raster p50/p90/p95/p99/max=1.240/1.655/1.727/1.879/2.097ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.176/2.259ms | raster p50/p90/p95/p99/max=2.463/3.069/3.270/3.706/3.934ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================

After:

Avg raster p50
Solid 1.271ms
Gradient 1.286ms
Full results
Note: This says "Windows" because that's hard-coded in the benchmark app. But this was run on my Mac.

flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=1.290/1.816ms | raster p50/p90/p95/p99/max=1.365/1.748/1.823/1.953/1.990ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.523/2.281ms | raster p50/p90/p95/p99/max=1.286/1.457/1.528/1.722/1.812ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=0.957/1.108ms | raster p50/p90/p95/p99/max=1.192/1.354/1.385/1.462/1.854ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.572/3.112ms | raster p50/p90/p95/p99/max=1.263/1.455/1.542/1.702/1.859ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=1.044/1.657ms | raster p50/p90/p95/p99/max=1.256/1.721/1.770/1.892/1.919ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.925/3.021ms | raster p50/p90/p95/p99/max=1.308/1.536/1.589/1.722/1.905ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================

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.

@github-actions github-actions Bot added engine flutter/engine related. See also e: labels. e: impeller Impeller rendering backend issues and features requests labels Sep 17, 2026
@b-luk b-luk changed the title commit SSBO-based gradients in UberSDF Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

github PR review UI is bad at detecting that this is mostly copied from uber_sdf.frag.

Here's the full diff reported by git diff -C --find-copies-harder master..HEAD:

diff --git a/engine/src/flutter/impeller/entity/shaders/uber_sdf.frag b/engine/src/flutter/impeller/entity/shaders/uber_sdf_common.glsl
similarity index 93%
copy from engine/src/flutter/impeller/entity/shaders/uber_sdf.frag
copy to engine/src/flutter/impeller/entity/shaders/uber_sdf_common.glsl
index 648b72ef18c..d24cd9ae881 100644
--- a/engine/src/flutter/impeller/entity/shaders/uber_sdf.frag
+++ b/engine/src/flutter/impeller/entity/shaders/uber_sdf_common.glsl
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.

+// Shared body of the UberSDF shaders, included by `uber_sdf.frag` and
+// `uber_sdf_ssbo.frag`. Each entrypoint supplies only `getGradientColor()`.
+
 precision mediump float;

 #include <impeller/color.glsl>
@@ -14,8 +17,6 @@ precision mediump float;
 #include "sdf_functions.glsl"
 #include "sdf_utils.glsl"

-uniform sampler2D color_source_sampler;
-
 uniform FragInfo {
   // FragInfo fields are sorted by size (vec4 -> vec2 -> float) to optimize
   // uniform register usage.
@@ -102,13 +103,23 @@ uniform FragInfo {
   ///   2: Mirror
   ///   3: Decal
   float tile_mode;
-  /// Half the size of a single gradient texel in normalized texture
-  /// coordinates along the gradient ramp (x axis).
-  float half_texel;
   /// Inverse gradient length:
   ///   - Linear gradient: 1.0 / dot(delta, delta)
   ///   - Radial gradient: 1.0 / radius
   float inv_gradient_length;
+
+  // --- Variant-Specific Gradient Parameters ---
+  // Exactly one of these is used by any given entrypoint; the other is unset.
+
+  /// Half the size of a single gradient texel in normalized texture
+  /// coordinates along the gradient ramp (x axis).
+  ///
+  /// Only used by the gradient ramp texture variant.
+  float half_texel;
+  /// The number of gradient stops in the color data storage buffer.
+  ///
+  /// Only used by the storage buffer variant.
+  float colors_length;
 }
 frag_info;

@@ -116,6 +127,13 @@ out vec4 frag_color;

 highp in vec2 v_position;

+// Looks up the gradient color at gradient position `t`.
+//
+// `t` is untiled, so implementations apply frag_info.tile_mode themselves.
+// Returns an unpremultiplied color, ignoring frag_info.color.a, which the
+// calling getColor() applies below.
+vec4 getGradientColor(float t);
+
 // Gets the color to use at v_position based on frag_info properties.
 vec4 getColor() {
   vec4 color;
@@ -134,9 +152,7 @@ vec4 getColor() {
       t = IPComputeRadialGradientT(v_position, frag_info.gradient_coords.xy,
                                    frag_info.inv_gradient_length);
     }
-    vec4 gradient_color = IPSampleLinearWithTileMode(
-        color_source_sampler, vec2(t, 0.5), vec2(frag_info.half_texel, 0.5),
-        frag_info.tile_mode, vec4(0.0));
+    vec4 gradient_color = getGradientColor(t);
     color = vec4(gradient_color.rgb, gradient_color.a * frag_info.color.a);
   }
   return color;

@b-luk b-luk added the CICD Run CI/CD label Sep 17, 2026
@b-luk

b-luk commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

Golden changes: https://flutter-gold.skia.org/search?issue=192962&crs=github&patchsets=1&corpus=flutter

Many of the gradient goldens have small changes. All the changes seem visually imperceptible.

@b-luk
b-luk marked this pull request as ready for review September 18, 2026 20:12

@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 adds support for rendering UberSDF shaders using Shader Storage Buffer Objects (SSBO) instead of pre-baked gradient ramp textures when supported by the device. It refactors the UberSDF fragment shader into a shared common file, introduces an SSBO-specific fragment shader, and updates pipeline creation, canvas setup, and rendering logic to conditionally use the SSBO path. The review feedback recommends querying device capabilities consistently, encapsulating the new rendering helper methods as private in UberSDFContents, and defensively ensuring the gradient color stops vector is never empty before binding it to prevent potential graphics backend crashes.

Comment thread engine/src/flutter/impeller/display_list/canvas.cc Outdated
Comment thread engine/src/flutter/impeller/entity/contents/uber_sdf_contents.h
Comment thread engine/src/flutter/impeller/entity/contents/uber_sdf_contents.cc
@flutter-dashboard

Copy link
Copy Markdown

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 package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #192962 at sha 4720fb8

@flutter-dashboard flutter-dashboard Bot added the will affect goldens Changes to golden files label Sep 18, 2026
@flutter-dashboard

Copy link
Copy Markdown

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 #192962 at sha f0a1b62

@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.

I'd like to see a golden test for this. I suspect what will happen is that the golden tests will be swapped over to the SSBO version. We should clone some of the gradient tests to artificially sets the capabilities to say we don't have SSBO.

Otherwise looking good.

@b-luk

b-luk commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

I'd like to see a golden test for this. I suspect what will happen is that the golden tests will be swapped over to the SSBO version. We should clone some of the gradient tests to artificially sets the capabilities to say we don't have SSBO.

Otherwise looking good.

We have SSBO vs texture goldens based on the backend that runs the golden test. The golden test running on the MetalSDF backend supports SSBO and exercises the SSBO rendering path. The golden test running on the OpenGLESSDF backend does not support SSBO and exercises the texture-based rendering path. (If we do update OpenGLES to support SSBO in the future, we'll need another approach to ensure we have golden tests for the texture based path.)

This approach of using the different backends to test different supported capabilities is the same as what the existing non-uberSDF gradient shaders do to golden test their different variants.

@b-luk

b-luk commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

I'd like to see a golden test for this. I suspect what will happen is that the golden tests will be swapped over to the SSBO version. We should clone some of the gradient tests to artificially sets the capabilities to say we don't have SSBO.
Otherwise looking good.

We have SSBO vs texture goldens based on the backend that runs the golden test. The golden test running on the MetalSDF backend supports SSBO and exercises the SSBO rendering path. The golden test running on the OpenGLESSDF backend does not support SSBO and exercises the texture-based rendering path. (If we do update OpenGLES to support SSBO in the future, we'll need another approach to ensure we have golden tests for the texture based path.)

This approach of using the different backends to test different supported capabilities is the same as what the existing non-uberSDF gradient shaders do to golden test their different variants.

I decided to do this and clone some of SSBO tests to non-SSBO versions. This way the tests are more explicit about SSBO vs non-SSBO, instead of implicitly relying on backend capabilities which is harder to follow and may change. I artificially set the capability in a similar way to how the existing ColorFilterAdvancedBlendNoFbFetch test does it, but put into a scoped RAII class for easier reuse across different tests.

@gaaclarke

Copy link
Copy Markdown
Member

I'm going to merge main since the other PR experiencing that cipd problem seems resolved now. If this passes we can close it out and keep an eye open for it in the future.

@walley892 walley892 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.

Mostly good. A few notes

return RenderTexture(renderer, entity, pass);
}

bool UberSDFContents::RenderTexture(const ContentContext& renderer,

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.

Nit: Can we rename this function to RenderWithTextureGradient and the other to RenderWithSSBOGradient?

The way it's named right now, it sounds like this could be a thing that renders to a texture or renders the contents of a texture to a rect or something

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Follows the existing gradient shaders. e.g. for linear:

private:
bool RenderTexture(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;
bool RenderSSBO(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;
bool RenderUniform(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;

@@ -160,6 +161,7 @@ using TiledTexturePipeline = RenderPipelineHandle<TextureUvFillVertexShader, Til
using VerticesUber1Shader = RenderPipelineHandle<PorterDuffBlendVertexShader, VerticesUber1FragmentShader>;
using VerticesUber2Shader = RenderPipelineHandle<PorterDuffBlendVertexShader, VerticesUber2FragmentShader>;
using UberSDFPipeline = RenderPipelineHandle<CircleVertexShader, UberSdfFragmentShader>;

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.

Nit: should this be renamed to UberSDFTexturePipeline or something similar?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Follows the naming of the existing gradient shaders. e.g. for linear:

using LinearGradientFillPipeline = GradientPipelineHandle<LinearGradientFillFragmentShader>;
using LinearGradientSSBOFillPipeline = GradientPipelineHandle<LinearGradientSsboFillFragmentShader>;
using LinearGradientUniformFillPipeline = GradientPipelineHandle<LinearGradientUniformFillFragmentShader>;

FS::BindColorSourceSampler(pass, sampler_binding.texture,
sampler_binding.sampler);
FS::BindFragInfo(pass, data_host_buffer.EmplaceUniform(frag_info));
pass.SetCommandLabel("UberSDF");

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.

Can we change this label to UberSDFTexture?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Follows the naming of the existing gradient shaders. e.g. for linear:

Texture variant:

pass.SetCommandLabel("LinearGradientFill");

SSBO variant:

pass.SetCommandLabel("LinearGradientSSBOFill");

Uniform variant:

pass.SetCommandLabel("LinearGradientUniformFill");


/// The normalized position of each entry in `colors`, in ascending order.
///
/// Always the same length as `colors`.

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.

Always the same length as colors.

I don't think there's an assert for this anywhere, I could be missing it. Should we add one?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These fields are used here https://github.com/flutter/flutter/pull/192962/changes#diff-985034ed2ba76391d344554774ec0419b277508cfbd9979d7256a0045d7c9f57R207-R210, passed to CreateGradientColors.

CreateGradientColors does a check on their lengths:

std::vector<StopData> CreateGradientColors(const std::vector<Color>& colors,
const std::vector<Scalar>& stops) {
FML_DCHECK(stops.size() == colors.size());

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.

Could we do the following rename:

uber_sdf -> uber_sdf_texture or uber_sdf_texture_gradient. contains the implementation of the gradient value fetch based on texture.

uber_sdf_common -> uber_sdf. Contains the bulk of the logic.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Follows the naming of the existing gradient shaders. e.g. for linear:

Texture variant: linear_gradient_fill.frag

SSBO variant: linear_gradient_ssbo_fill.frag

Uniform variant: linear_gradient_uniform_fill.frag

@b-luk b-luk left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Regarding the naming: I did consider whether the existing version should be named with a "texture" suffix. But I based this on the existing gradient shaders, where the texture version is the "base" version with no suffix, and the ssbo and uniform variants get a suffix. I replied to each comment with the existing naming patterns that I followed.

I put a high value consistency and following existing conventions in the codebase, so I followed the existing patterns even though I do agree with you that if I was naming them from scratch I would have given the texture variant a "texture" suffix.

I think I like the RenderTexture to RenderWithTextureGradient change, because that's private to uber_sdf_contents so consistency matters a little less And unlike the gradient-specific shaders which only deal with gradients, inside uber_sdf_contents a name like RenderWithTextureGradient gives helpful context on what the texture is specifically for.

The other renamings suggestions are public across our codebase though, so I think being consistent with the naming matters more than for the RenderTexture case.

Keeping in mind the existing naming patterns in the codebase, if you still think some or all of these should be renamed let me know and I'll rename them.

I think my preference is:

  • Do the RenderTexture to RenderWithTextureGradient (and RenderSSBO to RenderWithSSBOGradient) renaming
  • Keep the other names, for consistency with the existing naming conventions of the codebase
  • File a cleanup issue to rename both uber_sdf and the existing gradient shaders to have a "texture" suffix for the texture variants. That way the naming stays consistent. Although I feel like this issue would be low priority so who knows if anyone will ever get to it.


/// The normalized position of each entry in `colors`, in ascending order.
///
/// Always the same length as `colors`.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These fields are used here https://github.com/flutter/flutter/pull/192962/changes#diff-985034ed2ba76391d344554774ec0419b277508cfbd9979d7256a0045d7c9f57R207-R210, passed to CreateGradientColors.

CreateGradientColors does a check on their lengths:

std::vector<StopData> CreateGradientColors(const std::vector<Color>& colors,
const std::vector<Scalar>& stops) {
FML_DCHECK(stops.size() == colors.size());

return RenderTexture(renderer, entity, pass);
}

bool UberSDFContents::RenderTexture(const ContentContext& renderer,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Follows the existing gradient shaders. e.g. for linear:

private:
bool RenderTexture(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;
bool RenderSSBO(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;
bool RenderUniform(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const;

@@ -160,6 +161,7 @@ using TiledTexturePipeline = RenderPipelineHandle<TextureUvFillVertexShader, Til
using VerticesUber1Shader = RenderPipelineHandle<PorterDuffBlendVertexShader, VerticesUber1FragmentShader>;
using VerticesUber2Shader = RenderPipelineHandle<PorterDuffBlendVertexShader, VerticesUber2FragmentShader>;
using UberSDFPipeline = RenderPipelineHandle<CircleVertexShader, UberSdfFragmentShader>;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Follows the naming of the existing gradient shaders. e.g. for linear:

using LinearGradientFillPipeline = GradientPipelineHandle<LinearGradientFillFragmentShader>;
using LinearGradientSSBOFillPipeline = GradientPipelineHandle<LinearGradientSsboFillFragmentShader>;
using LinearGradientUniformFillPipeline = GradientPipelineHandle<LinearGradientUniformFillFragmentShader>;

FS::BindColorSourceSampler(pass, sampler_binding.texture,
sampler_binding.sampler);
FS::BindFragInfo(pass, data_host_buffer.EmplaceUniform(frag_info));
pass.SetCommandLabel("UberSDF");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Follows the naming of the existing gradient shaders. e.g. for linear:

Texture variant:

pass.SetCommandLabel("LinearGradientFill");

SSBO variant:

pass.SetCommandLabel("LinearGradientSSBOFill");

Uniform variant:

pass.SetCommandLabel("LinearGradientUniformFill");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Follows the naming of the existing gradient shaders. e.g. for linear:

Texture variant: linear_gradient_fill.frag

SSBO variant: linear_gradient_ssbo_fill.frag

Uniform variant: linear_gradient_uniform_fill.frag

@b-luk
b-luk requested a review from walley892 September 23, 2026 20:31
gaaclarke
gaaclarke previously approved these changes Sep 23, 2026

@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.

LGTM. I think @walley892 raises some good points on naming. It's best to keep the names consistent for now. We can reevaluate them as a group if we want to change it to make it more clear. The current system is more an artifact of how the code evolved, not really a conscious design decision.

///
/// Only the Metal playground implements `SetCapabilities`, so `*NoSSBO` tests
/// must skip every other backend.
class ScopedForceNoSSBO {

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.

nit: I think a more robust way may be to have different test suites for this with this set in the SetUp and TearDown methods. I'm not sure if that's something easy to setup with our current system though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

@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.

lgtm!

@flutter-dashboard

Copy link
Copy Markdown

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 #192962 at sha f6335e9

@b-luk b-luk added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 25, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Sep 25, 2026
Merged via the queue into flutter:master with commit 419f9dd Sep 25, 2026
23 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Sep 25, 2026
@b-luk
b-luk deleted the gradient-ssbo branch September 25, 2026 20:11
DanTup pushed a commit to DanTup/flutter that referenced this pull request Sep 28, 2026
Moves most of the logic of uber_sdf.frag to uber_sdf_common.glsl. New
uber_sdf.frag and uber_sdf_ssbo.frag shaders import uber_sdf_common.glsl
and implement `getGradientColor()` with a texture-based or SSBO-based
gradient implementation.

Gradient SSBO logic based off the existing SSBO gradient shaders like
https://github.com/flutter/flutter/blob/b138043fc75c1270e1bd9f1fa0a5c1299e86e638/engine/src/flutter/impeller/entity/shaders/gradients/linear_gradient_ssbo_fill.frag

Note that for GLES, SSBO is currently not supported.

https://github.com/flutter/flutter/blob/b138043fc75c1270e1bd9f1fa0a5c1299e86e638/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc#L277-L279
This means that for Windows and Linux, which currently always have a
GLES backend, this change does not do anything.

This is a prerequisite for addressing
flutter#190401. This improves UberSDF
gradient rendering when SSBO is supported, but not on Windows. The next
step to address flutter#190401 is to
make Windows support SSBO:
flutter#193162

Tested this with the "Scrolling basic LinearGradient" benchmark app from
flutter#190401. I ran it 3 times, on
my Mac. The raster time goes down significantly, so that it is on par
with the solid color time.

## On Mac (my local dev machine, M3 MacBook Pro):

### Before:
| | Avg raster p50 |
|--|--|
| Solid | 1.250ms |
| Gradient | 2.596ms |

<details> <summary> Full results </summary>

```
Note: This says "Windows" because that's hard-coded in the benchmark app. But this was run on my Mac.

flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=1.085/1.661ms | raster p50/p90/p95/p99/max=1.278/1.701/1.764/1.857/1.999ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.460/2.101ms | raster p50/p90/p95/p99/max=2.639/3.182/3.325/3.727/4.102ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=0.904/1.400ms | raster p50/p90/p95/p99/max=1.232/1.635/1.752/1.918/2.125ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.490/2.262ms | raster p50/p90/p95/p99/max=2.686/3.368/3.615/3.863/4.256ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=0.903/1.426ms | raster p50/p90/p95/p99/max=1.240/1.655/1.727/1.879/2.097ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.176/2.259ms | raster p50/p90/p95/p99/max=2.463/3.069/3.270/3.706/3.934ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
```

</details>

### After:

| | Avg raster p50 |
|--|--|
| Solid | 1.271ms |
| Gradient | 1.286ms |

<details> <summary> Full results </summary>

```
Note: This says "Windows" because that's hard-coded in the benchmark app. But this was run on my Mac.

flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=1.290/1.816ms | raster p50/p90/p95/p99/max=1.365/1.748/1.823/1.953/1.990ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.523/2.281ms | raster p50/p90/p95/p99/max=1.286/1.457/1.528/1.722/1.812ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=0.957/1.108ms | raster p50/p90/p95/p99/max=1.192/1.354/1.385/1.462/1.854ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.572/3.112ms | raster p50/p90/p95/p99/max=1.263/1.455/1.542/1.702/1.859ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=1.044/1.657ms | raster p50/p90/p95/p99/max=1.256/1.721/1.770/1.892/1.919ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.925/3.021ms | raster p50/p90/p95/p99/max=1.308/1.536/1.589/1.722/1.905ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
```

</details>

## 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].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant in-code documentation (doc comments with
`///`).
- [x] 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).
- [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.
- [x] 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

---------

Co-authored-by: gaaclarke <30870216+gaaclarke@users.noreply.github.com>
DanTup pushed a commit to DanTup/flutter that referenced this pull request Sep 28, 2026
Moves most of the logic of uber_sdf.frag to uber_sdf_common.glsl. New
uber_sdf.frag and uber_sdf_ssbo.frag shaders import uber_sdf_common.glsl
and implement `getGradientColor()` with a texture-based or SSBO-based
gradient implementation.

Gradient SSBO logic based off the existing SSBO gradient shaders like
https://github.com/flutter/flutter/blob/b138043fc75c1270e1bd9f1fa0a5c1299e86e638/engine/src/flutter/impeller/entity/shaders/gradients/linear_gradient_ssbo_fill.frag

Note that for GLES, SSBO is currently not supported.

https://github.com/flutter/flutter/blob/b138043fc75c1270e1bd9f1fa0a5c1299e86e638/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc#L277-L279
This means that for Windows and Linux, which currently always have a
GLES backend, this change does not do anything.

This is a prerequisite for addressing
flutter#190401. This improves UberSDF
gradient rendering when SSBO is supported, but not on Windows. The next
step to address flutter#190401 is to
make Windows support SSBO:
flutter#193162

Tested this with the "Scrolling basic LinearGradient" benchmark app from
flutter#190401. I ran it 3 times, on
my Mac. The raster time goes down significantly, so that it is on par
with the solid color time.

## On Mac (my local dev machine, M3 MacBook Pro):

### Before:
| | Avg raster p50 |
|--|--|
| Solid | 1.250ms |
| Gradient | 2.596ms |

<details> <summary> Full results </summary>

```
Note: This says "Windows" because that's hard-coded in the benchmark app. But this was run on my Mac.

flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=1.085/1.661ms | raster p50/p90/p95/p99/max=1.278/1.701/1.764/1.857/1.999ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.460/2.101ms | raster p50/p90/p95/p99/max=2.639/3.182/3.325/3.727/4.102ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=0.904/1.400ms | raster p50/p90/p95/p99/max=1.232/1.635/1.752/1.918/2.125ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.490/2.262ms | raster p50/p90/p95/p99/max=2.686/3.368/3.615/3.863/4.256ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=0.903/1.426ms | raster p50/p90/p95/p99/max=1.240/1.655/1.727/1.879/2.097ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.176/2.259ms | raster p50/p90/p95/p99/max=2.463/3.069/3.270/3.706/3.934ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
```

</details>

### After:

| | Avg raster p50 |
|--|--|
| Solid | 1.271ms |
| Gradient | 1.286ms |

<details> <summary> Full results </summary>

```
Note: This says "Windows" because that's hard-coded in the benchmark app. But this was run on my Mac.

flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=1.290/1.816ms | raster p50/p90/p95/p99/max=1.365/1.748/1.823/1.953/1.990ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.523/2.281ms | raster p50/p90/p95/p99/max=1.286/1.457/1.528/1.722/1.812ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=0.957/1.108ms | raster p50/p90/p95/p99/max=1.192/1.354/1.385/1.462/1.854ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.572/3.112ms | raster p50/p90/p95/p99/max=1.263/1.455/1.542/1.702/1.859ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
flutter: === Windows linear-gradient comparison ===
flutter: mode=profile speed=1400px/s
flutter: Solid color | frames=240 fps=59.75 | ui p50/p95=1.044/1.657ms | raster p50/p90/p95/p99/max=1.256/1.721/1.770/1.892/1.919ms | raster_over_budget=0/240 (0.0%)
flutter: Linear gradient | frames=240 fps=59.75 | ui p50/p95=1.925/3.021ms | raster p50/p90/p95/p99/max=1.308/1.536/1.589/1.722/1.905ms | raster_over_budget=0/240 (0.0%)
flutter: ================================================
```

</details>

## 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].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant in-code documentation (doc comments with
`///`).
- [x] 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).
- [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.
- [x] 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

---------

Co-authored-by: gaaclarke <30870216+gaaclarke@users.noreply.github.com>
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Sep 29, 2026
…#13060)

Manual roll Flutter from 4fcd90be0045 to c5a061b18fa2 (222 revisions)

Manual roll requested by quncheng@google.com

flutter/flutter@4fcd90b...c5a061b

2026-09-28 brackenavaron@gmail.com [cross imports] navigator_test.dart (flutter/flutter#190954)
2026-09-28 154381524+flutteractionsbot@users.noreply.github.com Revert: Reland: Only render views that need to be rendered  (flutter/flutter#193360)
2026-09-28 codefu@google.com ci(bringup): android_intent_security_test is green (flutter/flutter#193469)
2026-09-28 154381524+flutteractionsbot@users.noreply.github.com Sync CHANGELOG.md from stable (flutter/flutter#193020)
2026-09-28 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ukukV5lEkKabtOATk... to QdgqP02_cYpRQQQNN... (flutter/flutter#193454)
2026-09-28 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#193460)
2026-09-28 victorsanniay@gmail.com Un-nest sceneBuildDuration and windowRenderDuration in web SceneBuilderRecorder (flutter/flutter#193260)
2026-09-28 zarah@google.com Fix unresolved doc comment references in dev/integration_tests and dev/benchmarks (flutter/flutter#193433)
2026-09-28 engine-flutter-autoroll@skia.org Roll Packages from e55e7ac to ba0364a (9 revisions) (flutter/flutter#193450)
2026-09-28 bkonyi@google.com [tool] Require explicit dependency injection for FlutterDevice and FlutterDevice.create (flutter/flutter#192830)
2026-09-28 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#193442)
2026-09-28 dacoharkes@google.com [flutter_tools] Include data assets from hooks when pubspec.yaml is empty (flutter/flutter#193434)
2026-09-28 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#193438)
2026-09-28 zarah@google.com Fix unresolved doc comment references in Material and Cupertino (flutter/flutter#193283)
2026-09-28 zarah@google.com Fix doc references to Material and Cupertino in the widgets library and its tests (flutter/flutter#193334)
2026-09-26 kevmoo@users.noreply.github.com wasm: enforce WasmGC opt-in capability checks and Firefox < 147 guard (flutter/flutter#193180)
2026-09-26 43054281+camsim99@users.noreply.github.com [Android] Refuse external setters of engine entrypoint and cached engine arguments via `Intent`s (flutter/flutter#190249)
2026-09-26 1961493+harryterkelsen@users.noreply.github.com [web] Unskip TextPainter.getWordBoundary test (flutter/flutter#193378)
2026-09-26 bkonyi@google.com Specify non-obvious types in pattern variable declarations (flutter/flutter#192632)
2026-09-26 30870216+gaaclarke@users.noreply.github.com Removes feedback loop from advanced filters without offscreen msaa and framebufferfetch (flutter/flutter#193306)
2026-09-26 1961493+harryterkelsen@users.noreply.github.com [web] Unskip 8 passing image tests in painting and rendering (flutter/flutter#193377)
2026-09-26 154381524+flutteractionsbot@users.noreply.github.com Revert: Allow resetting test invariants in `addTearDown` (flutter/flutter#193383)
2026-09-25 bkonyi@google.com [tool] Migrate CoverageCollector to modular dependency injection (flutter/flutter#192924)
2026-09-25 zarah@google.com Fix more unresolved doc comment references (flutter/flutter#193336)
2026-09-25 dkwingsmt@users.noreply.github.com Allow resetting test invariants in `addTearDown` (flutter/flutter#192082)
2026-09-25 jhy03261997@gmail.com [a11y] Add a semantics role for slider (flutter/flutter#193324)
2026-09-25 stuartmorgan@google.com Fix plugin tests after Pigeon plugin template changes (flutter/flutter#193302)
2026-09-25 jesswon@google.com [Android 17] Bump Standard Test Apps in flutter/flutter to AGP 9.3.1 (flutter/flutter#193263)
2026-09-25 97480502+b-luk@users.noreply.github.com SSBO-based gradients in UberSDF (flutter/flutter#192962)
2026-09-25 robert.ancell@canonical.com [Linux] Handle FlView being destroyed before rendering is complete. (flutter/flutter#193268)
2026-09-25 bkonyi@google.com [flutter_tools] Handle Windows reserved characters in test target path (flutter/flutter#191900)
2026-09-25 sneurlax@gmail.com docs(tools): nit: say hook/build.dart in CMake native assets comment (flutter/flutter#192205)
2026-09-25 kevmoo@users.noreply.github.com [web] Enable Firefox Skwasm UI CI suites, configure COI configs, and fail fast on loader rejections (flutter/flutter#193187)
2026-09-25 jesswon@google.com [Android 17] Bumped Engine Dependencies to 9.3.1 (flutter/flutter#193265)
2026-09-25 kevmoo@users.noreply.github.com [web] Omit group role on menu scrollables and assign region role to named routes (flutter/flutter#192965)
2026-09-25 engine-flutter-autoroll@skia.org Roll Skia from 8eedeed98e79 to f441ca223b2b (5 revisions) (flutter/flutter#193353)
2026-09-25 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from EbPpoJW-Lnsu-8dyZ... to ukukV5lEkKabtOATk... (flutter/flutter#193326)
2026-09-25 engine-flutter-autoroll@skia.org Roll Packages from 431ea69 to e55e7ac (6 revisions) (flutter/flutter#193351)
2026-09-25 139053348+shikharish@users.noreply.github.com Support DynamicLibrary.codeAsset in Flutter (flutter/flutter#188947)
2026-09-25 engine-flutter-autoroll@skia.org Roll Dart SDK from 75d9e87d4e3d to 0e7642b85457 (1 revision) (flutter/flutter#193346)
2026-09-25 15619084+vashworth@users.noreply.github.com Exclude iOS PRs from macOS link (flutter/flutter#193315)
2026-09-25 engine-flutter-autoroll@skia.org Roll Skia from 6357608543ec to 8eedeed98e79 (4 revisions) (flutter/flutter#193341)
2026-09-25 engine-flutter-autoroll@skia.org Roll Dart SDK from d3aedb186aab to 75d9e87d4e3d (3 revisions) (flutter/flutter#193335)
2026-09-25 nickolasdeluca@live.com Cache the paint offset adjusted line metrics in TextPainter (flutter/flutter#191223)
...
RickyvdBerg added a commit to avio-os/avio-flutter that referenced this pull request Oct 2, 2026
…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 <noreply@anthropic.com>
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.

3 participants