Skip to content

Make DisplayLists' use of DlPaint, SkPaint, and impeller::Paint agree on the default isAntiAlias - #193939

Merged
auto-submit[bot] merged 7 commits into
flutter:masterfrom
b-luk:paint-antialias-default
Oct 12, 2026
Merged

auto-submit[bot] merged 7 commits into
flutter:masterfrom
b-luk:paint-antialias-default

Conversation

@b-luk

@b-luk b-luk commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

The existing code has a mismatch with the default isAntiAlias value of various initial Paint properties used throughout the code.

  • DisplayListBuilder uses a default DlPaint, which has a default isAntiAlias=false.
  • Skia's DlSkPaintDispatchHelper use a default SkPaint, which has a default isAntiAlias=false.
  • Impeller's DlOpReceivers use a default impeller::Paint, which has a default isAntiAlias=true.

The mismatch of impeller::Paint and DisplayListBuilder's DlPaint causes issues. DisplayListBuilder's setAntiAlias no-op exits if setting the same value as its internal DlPaint state:

void setAntiAlias(bool aa) override {
if (current_.isAntiAlias() != aa) {
onSetAntiAlias(aa);
}
}

That works correctly if all its downstream DlOpReceivers have matching initial values for their Paint state. But this is not the case for impeller::Paint. If we get a Paint with setAntiAlias(false), DisplayListBuilder won't pass this setting to its downstream DlOpReceivers, instead incorrectly assuming that the downstream receivers already have a default false value.

All of these defaults need to agree. We can either change them all to true or all to false. This changes them all to true, which matches the default isAntiAlias=true used for the dart:ui Paint.

  • Adds a new kDefaultAntiAlias = true const to DlPaint, which it uses when initializing itself. Its default value is now true instead of false.
  • Skia's DlSkPaintDispatchHelper explicitly sets its SkPaint using DlPaint::kDefaultAntiAlias. Its default value is now true instead of false.
  • Impeller's impeller::Paint sets its default with DlPaint::kDefaultAntiAlias. This is the same as its existing true default, but setting it this way is more consistent and explicit about matching DlPaint.
  • Updates tests which relied on DlPaint being non-anti-aliased. Adds new tests to ensure the default paint in DlSkPaintDispatchHelper and the default impeller::Paint match DlPaint.

Fixes #193388

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 Oct 6, 2026
@b-luk
b-luk marked this pull request as ready for review October 6, 2026 23:49
@b-luk b-luk added the CICD Run CI/CD label Oct 6, 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 changes the default anti-aliasing value in DlPaint from false to true to match dart:ui Paint.isAntiAlias, updating related tests, builders, and dispatchers accordingly. Feedback suggests updating the in-class initializer for is_anti_alias_ in dl_paint.h to use kDefaultAntiAlias to maintain consistency with the constructor and avoid duplicating state.

@b-luk
b-luk force-pushed the paint-antialias-default branch from b142552 to 8c18b93 Compare October 6, 2026 23:54
@b-luk

b-luk commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

The Google testing shows a bunch of golden screenshot diffs. I examined a handful of them, and all the diffs I saw are barely-visible differences to the edges of some rectangles. This is caused by engine-internal draws (e.g. ShaderMask) on Skia now having AA enabled. I think the new behavior is equally correct, if not a bit more consistent, than the old behavior.

Explanation from Gemini:

Google-internal golden test results
The internal presubmit flagged ~70 golden-screenshot test targets (Linux host
tests, Skia software renderer). I looked at the diffs; all of them are the same
mechanism and none show a change to actual widget content:

  • Every diff is a 1‑px outline of an axis-aligned rectangle — the bounds of an
    internal layer (ShaderMask is the common culprit, e.g. shimmer/skeleton
    placeholders and gradient-outlined "loading" pills), not the visible shape inside it.
    Pixel counts per screenshot are small (~100–1200 px out of ~250k–700k).
  • Cause: engine-internal draws that use a default-constructed DlPaint — e.g.
    ShaderMaskLayer::Paint's DrawRect(shader_rect, dl_paint) — go from non‑AA to
    AA on the Skia backend. When the layer's bounds fall on a fractional pixel, the
    edge row/column now gets partial coverage instead of being either fully covered
    or skipped. User-level paints are unaffected because dart:ui always sets
    isAntiAlias explicitly.
  • Impeller already defaulted to AA=true for these draws, so Skia now matches
    Impeller. Note this is a (tiny) real rendering change for apps shipping Skia —
    e.g. internal apps default to Skia on Android — not just a test artifact; the
    effect is the 1‑px edge behavior described above. Web is unaffected (the web
    engine doesn't go through this code path).
  • The new result is also more consistent: in the old goldens, the top and bottom
    edges of the same box could render differently depending on which side of the
    pixel centre each landed (e.g. one edge left a visible dark line where the mask
    skipped the row entirely).

@b-luk
b-luk requested a review from flar October 7, 2026 18:06
@b-luk

b-luk commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Discussed with flar, and decided to manually set AA=false for the ShaderMaskLayer rect mask draws to preserve Skia's existing behavior.

@b-luk

b-luk commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor Author

Discussed with flar, and decided to manually set AA=false for the ShaderMaskLayer rect mask draws to preserve Skia's existing behavior.

With the change to make AA=false for ShaderMaskLayer, almost all of the google testing goldens are unchanged. But there is one remaining golden change: https://fusion2.corp.google.com/presubmit/995352717/OCL:995352717:BASE:995434909:1791416516403:9ab040c4;groups=PossiblyNewlyFailing,Pending/targets. Gemini tells me this is for the TextureLayer::Paint case. We could add a change to make AA=false for TextureLayer. Or we can go with the alternate all-default-false approach in #193971.

The all-default-false approach would be safer in terms of maintaining existing behavior without having to hope we find all corner cases like ShaderMaskLayer and TextureLayer. And it's a smaller change overall. The downsides are that 1. it's less "copacetic", as you say, with the Flutter default, 2. it misses out on a small optimization of omitting SetAntiAlias ops in the DL, and 3. it involves more complicated test changes to maintain our AA=true impeller golden tests.

@b-luk

b-luk commented Oct 10, 2026

Copy link
Copy Markdown
Contributor Author

As you suggested, also added AA=false to TextureLayer. Let's see if all the tests pass now.

@flar

flar commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

Looking through the unit test failures these are due to the fact that we record the DL that the layers produce and compare them to a manually constructed DL that needs to have the AA=false added to the code that generates it.

Oddly, one of the test files generates verbose descriptions of the 2 DLs and the other just reports that they are different. I'm not sure why they do that since they are both using the same EQVerbose facility...?

@b-luk
b-luk requested a review from a team as a code owner October 12, 2026 19:22
@b-luk
b-luk requested review from jesswrd and removed request for a team October 12, 2026 19:22
@github-actions github-actions Bot added platform-android Android applications specifically team-android Owned by Android platform team labels Oct 12, 2026
@b-luk

b-luk commented Oct 12, 2026

Copy link
Copy Markdown
Contributor Author

Updated the unit tests to reflect ShaderLayerMask and TextureLayer setting their internal DlPaints to have AA=false.

Also the remaining google testing failure was due to an internal DlPaint in android/surface_texture_external_texture.cc needing AA=false to preserve existing behavior. I updated that.

With this I'm expecting all tests to pass. Let's wait and see.

@b-luk

b-luk commented Oct 12, 2026

Copy link
Copy Markdown
Contributor Author

Oddly, one of the test files generates verbose descriptions of the 2 DLs and the other just reports that they are different. I'm not sure why they do that since they are both using the same EQVerbose facility...?

Which specific test outputs are you looking at? Every one I looked has similar verbose descriptions on failure.

@flar

flar commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Oddly, one of the test files generates verbose descriptions of the 2 DLs and the other just reports that they are different. I'm not sure why they do that since they are both using the same EQVerbose facility...?

Which specific test outputs are you looking at? Every one I looked has similar verbose descriptions on failure.

It turns out that the verbose output gets separated from the GTest output in the logs. They're all recorded there somewhere nearby.

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

LGTM ... if we're done ... oh, looks like we are!

@b-luk b-luk added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 12, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Oct 12, 2026
Merged via the queue into flutter:master with commit 3a6417f Oct 12, 2026
23 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Oct 12, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Oct 14, 2026
Roll Flutter from 4249ccbc18a3 to 426be968b5eb (44 revisions)

flutter/flutter@4249ccb...426be96

2026-10-14 [email protected] Allow color delta tolerance in in-memory fuzzy image comparator (flutter/flutter#193937)
2026-10-14 [email protected] [web] Drop stale composing range after text is replaced mid-composition (flutter/flutter#194096)
2026-10-14 [email protected] Roll Skia from 2a2bbea66844 to acde3755d2e2 (1 revision) (flutter/flutter#194376)
2026-10-14 [email protected] Roll Skia from 128c983b12de to 2a2bbea66844 (1 revision) (flutter/flutter#194371)
2026-10-14 [email protected] Roll Skia from 48a294ed4955 to 128c983b12de (3 revisions) (flutter/flutter#194353)
2026-10-14 [email protected] feat(flutter_tools): extract WebDebugConfig from DebuggingOptions (flutter/flutter#194312)
2026-10-14 [email protected] Roll Skia from ea6781c5b6d1 to 48a294ed4955 (2 revisions) (flutter/flutter#194349)
2026-10-14 [email protected] Include <vector> in Android proc_table.h. (flutter/flutter#194325)
2026-10-14 [email protected] Roll Dart SDK from 5933cb486b4a to 6b50116630d0 (28 revisions) (flutter/flutter#194341)
2026-10-14 [email protected] Move GLES3 instancing API entry points to FOR_EACH_IMPELLER_GLES3_PROC (flutter/flutter#194319)
2026-10-14 [email protected] feat(flutter_tools): extract AndroidGradleConfig and move toGradleConfig to AndroidBuildInfo (flutter/flutter#194016)
2026-10-14 [email protected] Roll Skia from ae297bec6012 to ea6781c5b6d1 (8 revisions) (flutter/flutter#194331)
2026-10-14 [email protected] [flutter_tools] Migrate gradle_errors and deferred_components_prebuild_validator away from globals (flutter/flutter#193649)
2026-10-14 [email protected] [Impeller] Cache GLES sampler configuration in RenderPassStateCache (flutter/flutter#193922)
2026-10-14 [email protected] Roll pub packages (flutter/flutter#194332)
2026-10-13 [email protected] [tool] Migrate RunCommand to modular dependency injection (flutter/flutter#190791)
2026-10-13 [email protected] Include `engine/src/flutter/.ci.yaml` in quarterly `goldctl` checklist (flutter/flutter#194316)
2026-10-13 [email protected] [flutter_tools] Remove the last AMD module system support (flutter/flutter#193607)
2026-10-13 [email protected] Roll Skia from 8b3394a60654 to ae297bec6012 (5 revisions) (flutter/flutter#194310)
2026-10-13 [email protected] [web] Remove the a11y placeholder only after the gesture ends (flutter/flutter#194109)
2026-10-13 [email protected] Upgrade goldctl to the latest version (flutter/flutter#193932)
2026-10-13 [email protected] [flutter_tools] Lazily initialize AndroidStudio validation and optimize candidate selection (flutter/flutter#191968)
2026-10-13 [email protected] [flutter_tools] Clean up outdated widget preview TODOs and refactor static state (flutter/flutter#189437)
2026-10-13 [email protected] Roll Skia from e5b5db6d0d6f to 8b3394a60654 (2 revisions) (flutter/flutter#194306)
2026-10-13 [email protected] Redistribute TESTOWNERS for Android team (flutter/flutter#193861)
2026-10-13 [email protected] feat(flutter_tools): introduce Test and Drive specification objects (flutter/flutter#194017)
2026-10-13 [email protected] [Impeller] Keep the aspect ratio when shrinking images to the max texture size (flutter/flutter#194010)
2026-10-13 [email protected] [flutter tool] preserve inherited `DASH__SUPPRESS_ANALYTICS=true` for sub-tools (flutter/flutter#194261)
2026-10-13 [email protected] Roll Packages from d8d9e97 to a1ed23c (9 revisions) (flutter/flutter#194302)
2026-10-13 [email protected] Use PE/COFF AOT snapshots for Windows x64 (flutter/flutter#187594)
2026-10-13 [email protected] Fix Expansible crash when PageStorage holds a non-bool value (flutter/flutter#192195)
2026-10-13 [email protected] Roll Skia from ffeccb3ca58a to e5b5db6d0d6f (1 revision) (flutter/flutter#194297)
2026-10-13 [email protected] Explain why initState() is too early to depend on an inherited widget (flutter/flutter#192727)
2026-10-13 [email protected] Refactor TestPlatformDispatcher (flutter/flutter#192747)
2026-10-13 [email protected] Roll Skia from 3de0984208ec to ffeccb3ca58a (2 revisions) (flutter/flutter#194291)
2026-10-13 [email protected] Roll Skia from 0580c2b780f6 to 3de0984208ec (2 revisions) (flutter/flutter#194281)
2026-10-13 [email protected] Roll Skia from f641d55e07a8 to 0580c2b780f6 (3 revisions) (flutter/flutter#194275)
2026-10-13 [email protected] Roll Skia from 0e5d8d1be81b to f641d55e07a8 (1 revision) (flutter/flutter#194266)
2026-10-13 [email protected] Scaffold view metrics overrides (flutter/flutter#192764)
2026-10-13 [email protected] [web] Add SemanticsRole.listBox and SemanticsRole.option (flutter/flutter#192971)
2026-10-13 [email protected] Pin mac_unopt to macOS 15 (flutter/flutter#194254)
2026-10-13 [email protected] Roll pub packages (flutter/flutter#194257)
2026-10-12 [email protected] Roll Skia from 17f6986c226c to 0e5d8d1be81b (4 revisions) (flutter/flutter#194249)
2026-10-12 [email protected] Make DisplayLists' use of DlPaint, SkPaint, and impeller::Paint agree on the default isAntiAlias (flutter/flutter#193939)

If this roll has caused a breakage, revert this CL and set the roller
...
suryaKommana2662 pushed a commit to suryaKommana2662/flutter that referenced this pull request Oct 29, 2026
… on the default isAntiAlias (flutter#193939)

The existing code has a mismatch with the default `isAntiAlias` value of
various initial `Paint` properties used throughout the code.
- `DisplayListBuilder` uses a default `DlPaint`, which has a default
`isAntiAlias=false`.
- Skia's `DlSkPaintDispatchHelper` use a default `SkPaint`, which has a
default `isAntiAlias=false`.
- Impeller's `DlOpReceiver`s use a default `impeller::Paint`, which has
a default `isAntiAlias=true`.

The mismatch of `impeller::Paint` and `DisplayListBuilder`'s `DlPaint`
causes issues. `DisplayListBuilder`'s `setAntiAlias` no-op exits if
setting the same value as its internal `DlPaint` state:

https://github.com/flutter/flutter/blob/d454b1b841d223f28bb725bb2928e2ac337b5611/engine/src/flutter/display_list/dl_builder.h#L277-L281

That works correctly if all its downstream `DlOpReceiver`s have matching
initial values for their `Paint` state. But this is not the case for
`impeller::Paint`. If we get a `Paint` with `setAntiAlias(false)`,
`DisplayListBuilder` won't pass this setting to its downstream
`DlOpReceiver`s, instead incorrectly assuming that the downstream
receivers already have a default `false` value.

All of these defaults need to agree. We can either change them all to
`true` or all to `false`. This changes them all to `true`, which matches
the default `isAntiAlias=true` used for the `dart:ui` `Paint`.
- Adds a new `kDefaultAntiAlias = true` const to `DlPaint`, which it
uses when initializing itself. Its default value is now `true` instead
of `false`.
- Skia's `DlSkPaintDispatchHelper` explicitly sets its `SkPaint` using
`DlPaint::kDefaultAntiAlias`. Its default value is now `true` instead of
`false`.
- Impeller's `impeller::Paint` sets its default with
`DlPaint::kDefaultAntiAlias`. This is the same as its existing `true`
default, but setting it this way is more consistent and explicit about
matching `DlPaint`.
- Updates tests which relied on `DlPaint` being non-anti-aliased. Adds
new tests to ensure the default paint in `DlSkPaintDispatchHelper` and
the default `impeller::Paint` match `DlPaint`.

Fixes flutter#193388

## 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. platform-android Android applications specifically team-android Owned by Android platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Impeller] Paint.isAntiAlias = false is ignored when no earlier draw in the picture set it to true, so the SDF opt-out from #186020 does not apply

2 participants