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

uber_sdf: removes derivatives from rect path - #192267

Merged
auto-submit[bot] merged 8 commits into
flutter:masterfrom
gaaclarke:pass-pixel-size-rebase-2
Sep 9, 2026
Merged

auto-submit[bot] merged 8 commits into
flutter:masterfrom
gaaclarke:pass-pixel-size-rebase-2

Conversation

@gaaclarke

@gaaclarke gaaclarke commented Sep 3, 2026 •

Copy link
Copy Markdown
Member

This removes derivative calls from the rect renderer in uber_sdf. It rejiggers uniforms for gradients as well to make space for the new uniform. It also removes uber_sdf from the codepath for rendering perspective matrices. That allows us to have a stable derivative when rendering with uber_sdf.

spawned from #192204

Testing: see malioc results for better static analysis

Local performance testing on macos where I removed the derivatives from rects, rrects and circles then drew a lot of those gave this about an 8% improvement in raster time.

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.

@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Sep 3, 2026
@flutter-dashboard

Copy link
Copy Markdown

It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

@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 3, 2026

@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 updates Impeller's SDF rendering path to disable SDF rendering under perspective transforms, refactors gradient parameter calculations to avoid shader-side divisions, and optimizes pixel size calculations in the fragment shader by passing pre-calculated values from the host. Feedback points out that a removed assertion (FML_DCHECK(gradient.texture)) should be restored in SetupGradientParameters to prevent potential null pointer dereferences when retrieving the texture size.

Comment thread engine/src/flutter/impeller/entity/contents/uber_sdf_contents.cc
@gaaclarke

This comment was marked as outdated.

@flutter-dashboard

This comment was marked as outdated.

@flutter-dashboard flutter-dashboard Bot added the will affect goldens Changes to golden files label Sep 4, 2026
@gaaclarke
gaaclarke requested review from b-luk and walley892 September 4, 2026 17:16
@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 #192267 at sha 1c5559c

Comment on lines +126 to +136
float t;
if (frag_info.color_source_type < 1.5) {
// Linear gradient
t = dot(v_position - frag_info.gradient_coords.xy,
frag_info.gradient_coords.zw) *
frag_info.inv_gradient_length;
} else {
// Radial gradient
t = length(v_position - frag_info.gradient_coords.xy) *
frag_info.inv_gradient_length;
}

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.

This code re-implements the t-calculation of the existing shared IPSampleLinearGradient and IPSampleRadialGradient functions, but with some optimizations and by passing in inv_gradient_length.

Can we move these changes up to the shared IPSampleLinearGradient and IPSampleRadialGradient functions, so that the other existing linear and radial gradient texture-sampling shaders do the same thing? You may end up having to change those existing shaders to do stuff like calculating inv_gradient_length. I much prefer that option, so the logic can continue to be shared, rather than adding a divergent re-implementation of the logic here. It also means the non-ubersdf case would benefit from this change as well.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

done, pulled out shared math

Vector2 transform_scaling = entity.GetTransform().GetBasisScaleXY();
frag_info.pixel_size =
Point(transform_scaling.x != 0.0f ? 1.0f / transform_scaling.x : 0.0f,
transform_scaling.y != 0.0f ? 1.0f / transform_scaling.y : 0.0f);

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.

Using GetBasisScaleXY to get the pixel size in local space works if the transformed x and y axes remain at 90 degrees (scaling and rotation). But I think it will not be accurate if the transformed axes are not at 90 degrees (skews). You can see this playing around with AiksTest.PrimitiveShapePlayground

Before:
Screenshot 2026-09-04 at 11 47 39 AM

After:
Screenshot 2026-09-04 at 11 47 42 AM

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That's interesting, I get different results with those inputs. Mine isn't all aliased, but I can find different values that do look like that. That means making a golden test for it might be difficult. This is potentially a precision thing.

Screenshot 2026-09-04 at 1 07 33 PM

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.

Based on how big your screenshot is, I believe you're running this on a screen with high dpi scaling. If you run it with non-scaled native resolution, I think it will match my screenshots.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Here's the non-sdf render for this too.

Screenshot 2026-09-04 at 3 09 05 PM

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

done, fixed the math to consider the determinate for skews

@gaaclarke
gaaclarke requested a review from b-luk September 4, 2026 23:54
@gaaclarke
gaaclarke force-pushed the pass-pixel-size-rebase-2 branch from f237bbe to e775588 Compare September 8, 2026 15:47
Comment on lines +141 to +144
frag_info.gradient_coords = Vector4();
frag_info.half_texel = 0.0f;
frag_info.tile_mode = 0.0f;
frag_info.inv_gradient_length = 0.0f;

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 these be omitted, if they are the default values?

If they can't be omitted, maybe put it in the "else" branch of "if (params_.gradient)" so it's clear that this is mutually exclusive with these fields getting set by SetupGradientParameters.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

They can't be omitted, they aren't the default values. The struct that defines them is autogenerated code, so we can't override that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Sorry, didn't respond to the second suggestion. I think it's best to keep some consistent value in there instead of junk values.

Comment on lines +413 to +414
/// pixel_size.x = ||\nabla x|| = ||Basis Y 2D|| / |det 2D|
/// pixel_size.y = ||\nabla y|| = ||Basis X 2D|| / |det 2D|

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.

What is "\nabla"? edit: it's how to tell LaTeX to write the "∇" symbol. Maybe we can just use the ∇ symbol directly?

I don't know enough about math to know if the math in this function is correct. But if the unit tests and golden tests look good then I guess it LGTM.

@gaaclarke gaaclarke Sep 8, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Nabla is the name of the symbol. It's best to keep thing in ASCII characters for compatibility with compilers. I think in practice it probably doesn't matter for the compilers we are using but doing this doesn't seem problematic enough to add a potential friction point.

The intuition you need to understand the math is:

  • The area of a parallelogram defined by an affine transform is (det M)
  • The area of a parallelogram is Base*height
  • We have the area, and the lengths of the sides, we use that to get the axis aligned size of the pixels.
p0dn52m2

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.

If you want the height then you need area/base, but you are computing base/area. I don't think base/area has any geometric meaning, does it?

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.

(Similarly if you want base then you need area/height, not height/area.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yea, it's the inverse which is what we want here.

@gaaclarke
gaaclarke requested a review from b-luk September 8, 2026 17:25
b-luk
b-luk previously approved these changes Sep 8, 2026
@gaaclarke

Copy link
Copy Markdown
Member Author

@b-luk sorry, i had to update malioc. The results are better than previously. I thought i had updated them already.

@gaaclarke
gaaclarke requested a review from b-luk September 8, 2026 20:45
b-luk
b-luk previously approved these changes Sep 8, 2026
if (paint.mask_blur_descriptor.has_value()) {
return false;
}
if (transform.HasPerspective()) {

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.

Alternatively I've been thinking it might make sense to treat perspective as "distorted affine rendering". During a 3D flip transition I think the developer might want the flip to be performant rather than pixel perfect.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I was thinking we could make a different uber_sdf shader that uses derivatives for those. It didn't seem a high priority to address.

@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 #192267 at sha 05c537b

@flar

flar commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Something still seems off about the math here. dFdx provides "the change in F for each device pixel", but the CPU calculation you are computing is "how far can we move in X to advance a pixel in that direction" and they are not the same thing.

I ran your fix against the PrimitiveShapePlayground test and got the following screenshot. The white hairline stroke is breaking up in a very odd way. (Perhaps download and view at full scale with no interpolated scaling, or just run it locally and set the associated values in the controls.)

% out/host_debug_unopt_arm64/impeller_unittests --gtest_filter="*PrimitiveShapePlay*/MetalSDF" --enable_playground
Screenshot 2026-09-09 at 4 32 05 AM

@flar

flar commented Sep 9, 2026 •

Copy link
Copy Markdown
Contributor

A potential key to why the math isn't mathing is that you probably want the basis vector lengths of the inverted matrix. A matrix inversion divides by the determinant, but it also swizzles the main 2x2 entries from:

| a b |
| c d |

to

| d -b |
| -c a |

So, GetBasisX2D() is (m[0], m[1]) and GetBasisY2D() is (m[4], m[5]) but you'd want to use the vectors (m[5], -m[1]) and (-m[4], m[0]). (Some liberty may be taken by avoiding the negations if you are just squaring the value.)

Hmmm, on the other hand, the code in the shader was mixing and matching the dFdx and dFdy vector elements so that also comes into play...

@gaaclarke

Copy link
Copy Markdown
Member Author

Something still seems off about the math here. dFdx provides "the change in F for each device pixel", but the CPU calculation you are computing is "how far can we move in X to advance a pixel in that direction" and they are not the same thing.

Here is the same thing drawn with the derivatives. It demonstrates the same artifacts as this PR. So this PR is no better or worse for those combinations of scale/rotation/skew.

Screenshot 2026-09-09 at 8 56 25 AM

@gaaclarke
gaaclarke requested a review from flar September 9, 2026 15:58
@walley892

Copy link
Copy Markdown
Contributor

Why only change rect rendering?

@gaaclarke

Copy link
Copy Markdown
Member Author

Why only change rect rendering?

To make the PR simple. Every change requires a bit of fiddling to make sure the uniform register count is down.

@b-luk

b-luk commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Here is the same thing drawn with the derivatives. It demonstrates the same artifacts as this PR. So this PR is no better or worse for those combinations of scale/rotation/skew.

I believe the bad hairline stroking is due to uber_sdf.frag calculating pixel size for stroked shapes using pixelSize(sdf) here. pixelSize(sdf) can give incorrect results when dealing with shapes/strokes with width that is close to or less than 1 pixel (due to resolution limits of the dFdx(sdf), dFdy(sdf)) that it uses. That's why filled rectangles were changed in #188821 to use a new rectPixelSize(p) function instead of using pixelSize(sdf). But I didn't bother thinking through stroked rectangles in that PR.

I think for stroked shapes, we can simply use the pixel size of the base filled shape and it should just work. Testing this out:

Patch
diff --git a/engine/src/flutter/impeller/entity/shaders/uber_sdf.frag b/engine/src/flutter/impeller/entity/shaders/uber_sdf.frag
index 1bcb66c42a0..eec8ac378c0 100644
--- a/engine/src/flutter/impeller/entity/shaders/uber_sdf.frag
+++ b/engine/src/flutter/impeller/entity/shaders/uber_sdf.frag
@@ -307,19 +307,17 @@ vec2 filledSDF(vec2 p) {
 vec2 strokedSDF(vec2 p) {
   vec2 base_sdf_and_pixel_size = filledSDF(p);
   float base_sdf = base_sdf_and_pixel_size.x;
-  float base_pixel_size = base_sdf_and_pixel_size.y;
+  float pixel_size = base_sdf_and_pixel_size.y;

-  float half_stroke = max(frag_info.stroke_width, base_pixel_size) * 0.5;
+  float half_stroke = max(frag_info.stroke_width, pixel_size) * 0.5;

   float sdf;
-  float pixel_size;
   if (frag_info.type >= 0.5 && frag_info.type < 1.5 &&
       frag_info.stroke_join < 0.5) {
     // Rect with Miter join
     float outer = distanceFromRect(p, frag_info.size + half_stroke);
     float inner = base_sdf + half_stroke;
     sdf = max(outer, -inner);
-    pixel_size = pixelSize(sdf);
   } else if (frag_info.type >= 0.5 && frag_info.type < 1.5 &&
              frag_info.stroke_join >= 0.5 && frag_info.stroke_join < 1.5) {
     // Rect with Bevel join
@@ -327,13 +325,11 @@ vec2 strokedSDF(vec2 p) {
         distanceFromChamferRect(p, frag_info.size + half_stroke, half_stroke);
     float inner = base_sdf + half_stroke;
     sdf = max(outer, -inner);
-    pixel_size = pixelSize(sdf);
   } else {
     // All other shapes
     vec2 sdf_and_pixel_size =
-        SDFStroke(base_sdf, base_pixel_size, frag_info.stroke_width);
+        SDFStroke(base_sdf, pixel_size, frag_info.stroke_width);
     sdf = sdf_and_pixel_size.x;
-    pixel_size = sdf_and_pixel_size.y;
   }
   return vec2(sdf, pixel_size);
 }

Screenshots

Before/After:
image

Before/After 4x zoom on left stroke:
image

I'll create a PR to fix this. I'll wait until after this current PR is merged to create my PR in order to avoid merge conflicts.

@flar

flar commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

OK, so combining the fact that the dFdxy version didn't use the vectors directly, but swapped their values around then I can see that the current implementation of the GetPixelSize function is doing something similar, but both are wrong.

Also "GetPixelSize" is a misleading name for the method as it should be "GetThoseValuesWeWereUsingInTheUberSDFShader" or something that is closer to that than "PixelSize".

I don't see how this PR would make the results worse, but I don't like it introducing a method that implies a return value that it isn't really delivering.

And if we are happier with Benson's results, why not just go directly to that math rather than merging this method with a poorly named method?

@gaaclarke

Copy link
Copy Markdown
Member Author

OK, so combining the fact that the dFdxy version didn't use the vectors directly, but swapped their values around then I can see that the current implementation of the GetPixelSize function is doing something similar, but both are wrong.

Also "GetPixelSize" is a misleading name for the method as it should be "GetThoseValuesWeWereUsingInTheUberSDFShader" or something that is closer to that than "PixelSize".

Maybe it's not the perfect name, but it does match the nomenclature used in uber_sdf, so it's probably better to stick with that for now.

I don't see how this PR would make the results worse, but I don't like it introducing a method that implies a return value that it isn't really delivering.

And if we are happier with Benson's results, why not just go directly to that math rather than merging this method with a poorly named method?

Benson's fix is something that can be applied on either HEAD or this PR. It addresses a whole different issue that is mutually exclusive from this change. We'll land his fix after this to avoid merge conflicts (but technically it could have landed on HEAD).

@gaaclarke
gaaclarke requested a review from b-luk September 9, 2026 19:59

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

Seems to maintain status quo without the dFdxy functions...

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

LGTM

@gaaclarke gaaclarke added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 9, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Sep 9, 2026
Merged via the queue into flutter:master with commit 4e6768e Sep 9, 2026
23 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Sep 9, 2026
pull Bot pushed a commit to Mu-L/flutter that referenced this pull request Sep 16, 2026
See
flutter#192267 (comment):

We get bad hairline stroking due to uber_sdf.frag calculating pixel size
for stroked shapes using `pixelSize(sdf)`
[here](https://github.com/flutter/flutter/blob/63b9518f16bc0548f0d9daeaa3966ffcb0a7e28b/engine/src/flutter/impeller/entity/shaders/uber_sdf.frag#L322).
`pixelSize(sdf)` can give incorrect results when dealing with
shapes/strokes with width that is close to or less than 1 pixel (due to
resolution limits of the `dFdx(sdf), dFdy(sdf)` that it uses). For
stroked shapes, we can simply use the pixel size of the base filled
shape.

Fixes flutter#192658

Added a new golden test that draws the shape from those comments.

### Before:
<img width="1024" height="768"
alt="impeller_Play_AiksTest_CanRenderTransformedRectWithNearVerticalEdgeHairline_MetalSDF" src="/sitelet?url=https%3A%2F%2Fgithub.com%2Fflutter%2Fflutter%2Fpull%2F%253Ca%2520href%3D"/sitelet?url=https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2Fc80c13ce-cc8d-4639-a806-e128981f8fa6">https://github.com/user-attachments/assets/c80c13ce-cc8d-4639-a806-e128981f8fa6"
/>

### After:
<img width="1024" height="768"
alt="impeller_Play_AiksTest_CanRenderTransformedRectWithNearVerticalEdgeHairline_MetalSDF" src="/sitelet?url=https%3A%2F%2Fgithub.com%2Fflutter%2Fflutter%2Fpull%2F%253Ca%2520href%3D"/sitelet?url=https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2Fdd0b10bf-6bb1-4c11-9367-dfdaf74a56a7">https://github.com/user-attachments/assets/dd0b10bf-6bb1-4c11-9367-dfdaf74a56a7"
/>

### Zoomed in version of before/after from
flutter#192267 (comment):
<img width="366" height="1028" alt="image" src="/sitelet?url=https%3A%2F%2Fgithub.com%2Fflutter%2Fflutter%2Fpull%2F%253Ca%2520href%3D"/sitelet?url=https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2F09f1ebf9-d14f-4b31-bc65-a545d3a3317b">https://github.com/user-attachments/assets/09f1ebf9-d14f-4b31-bc65-a545d3a3317b"
/>


## 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.
- [ ] 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
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.

4 participants