Skip to content

Conversation

@LongCatIsLooong
Copy link
Contributor

This is not a fix for #166173, it's only a by-product. The fix will be in separate PR, this includes the unrelated code changes to make that PR smaller.

According to bench_material3_semantics, this reduces Semantics.ensureGeometry by ~100 μs (321.6 μs -> 228.9 μs).

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

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 framework flutter/packages/flutter repository. See also f: labels. a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) labels Oct 23, 2025
siblingMergeGroups.addAll(childSemantics.siblingMergeGroups);
}
}
if (!contributesToSemanticsTree) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This only changed indentation (returning early if !contributesToSemanticsTree).

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

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 introduces performance optimizations, primarily by refactoring _SemanticsGeometry.computeChildGeometry to be faster in the common case. This is achieved by adding a new MatrixUtils.multiplyInPlace helper to avoid matrix allocations. The PR also includes several smaller cleanups and refactorings across different rendering objects, which improve code clarity and style. Overall, the changes are beneficial for performance. I've found one potential logic change in the semantics clipping that might be an unintended side effect of the refactoring, which I've commented on.

Comment on lines 6413 to 6417
if (localSemanticsClipInParent != null) {
semanticsClipRect = localSemanticsClipInParent;
} else if (semanticsClipRect != null) {
semanticsClipRect = _intersectRects(semanticsClipRect, localPaintClipInParent);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

There appears to be a subtle logic change in how semanticsClipRect is calculated, which might be an unintentional regression.

Previously, if describeSemanticsClip returned null, the semantics clip would fall back to being based on the paint clip. In the new implementation, if describeSemanticsClip returns null (making localSemanticsClipInParent null) and the inherited semanticsClipRect is also null, the new semanticsClipRect remains null, instead of falling back to the paint clip.

This seems to contradict the intended behavior where a null describeSemanticsClip implies using the paint clip. To restore the original logic and ensure the fallback to the paint clip occurs, consider the following change.

if (localSemanticsClipInParent != null) {
  semanticsClipRect = localSemanticsClipInParent;
} else {
  semanticsClipRect = _intersectRects(semanticsClipRect, localPaintClipInParent);
}

childToCommonAncestor[i - 1],
semanticsClipRect,
paintClipRect,
final RenderObject nodeParent = childToCommonAncestor[i];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the more common codepath the transform is now computed in the same loop and there are less inverse calculations. The overlay portal path still uses _computeClipRect but that path usually isn't as hot.

Copy link
Contributor

Choose a reason for hiding this comment

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

Now Qun's PR is merged, we no longer needed a special path for overlayportal.

Copy link
Contributor Author

@LongCatIsLooong LongCatIsLooong Nov 3, 2025

Choose a reason for hiding this comment

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

I think in theory people can still return a non-descendant node in their custom RenderObject'svisitChildrenForSemantics implementation? (But now that RenderObject.semantcsParent is gone I'm not sure if an implementation like still works).

Copy link
Contributor

Choose a reason for hiding this comment

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

right, I don't think they can have this case where Render tree and semantics tree are differ without semanticsParent

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good, I don't think I've touched that code path in this patch so I'll probably replace that with an assert in a different PR.

clipPath.add(ancestor);
ancestor = ancestor.parent;
}
final SemanticsNode? ancestorNode = ancestor?._semantics.cachedSemanticsNode;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

(at first glance the ancestorNode may not have up-to-date geometry, if it is going to be merged as a sibling, and this function is being called in _updateGeometry?)

Copy link
Contributor

Choose a reason for hiding this comment

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

dirty nodes' ensureSemantics are called from top to bottom, so ancestor should always have up to date geometry

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ensureSemantics

do you ensureGeometry? What if there's a merge sibling ancestor (whose geometry is updated in _updateSiblingNodesGeometries which is called in _produceSemanticsNode? The geometry of that isn't updated when ensureGeometry is called I think?

Copy link
Contributor

Choose a reason for hiding this comment

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

I just realized this is grabing from cached Semantics Node, not the _SemanticsGeometry that stored in the _RenderObjectSemantics, this looks like a bug because ensureGeometry doesn't update the cached semantics node's geomtry.

_updateSiblingNodesGeometries

I think if we fixes the the code to grab from _SemanticsGeometry of the _RenderObjectSemantics this should be fine?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess if this code path is now obsolete then I guess we don't really have to fix this?

required Set<int> usedSemanticsIds,
List<SemanticsNode>? semanticsNodes,
}) {
void _buildSemanticsSubtree({required Set<int> usedSemanticsIds}) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The semanticsNodes argument wasn't used.

/// This function does not alter the argument `a`, and is thus useful when you
/// want to left-multiply in-place. For right-multiply in-place, see
/// [Matrix4.multiply].
static void multiplyInPlace(Matrix4 a, Matrix4 b) {
Copy link
Contributor

Choose a reason for hiding this comment

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

we should add a todo to clean this up
google/vector_math.dart#250

Copy link
Contributor Author

Choose a reason for hiding this comment

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

created google/vector_math.dart#354. I'll see if I can bump the dependencies after that PR is merged.

childToCommonAncestor[i - 1],
semanticsClipRect,
paintClipRect,
final RenderObject nodeParent = childToCommonAncestor[i];
Copy link
Contributor

Choose a reason for hiding this comment

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

Now Qun's PR is merged, we no longer needed a special path for overlayportal.

clipPath.add(ancestor);
ancestor = ancestor.parent;
}
final SemanticsNode? ancestorNode = ancestor?._semantics.cachedSemanticsNode;
Copy link
Contributor

Choose a reason for hiding this comment

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

dirty nodes' ensureSemantics are called from top to bottom, so ancestor should always have up to date geometry

@justinmc
Copy link
Contributor

justinmc commented Nov 4, 2025

@LongCatIsLooong FYI this has conflicts.

);
}
} else {
// Otherwise we have to find the closest ancestor RenderObject that
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok I got rid of this path since RenderObject.semanticsParent is now gone so parent must be an ancestor of child.

Copy link
Contributor

@chunhtai chunhtai left a comment

Choose a reason for hiding this comment

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

LGTM, just some minor comments

}
final Rect? localPaintClipInParent = _transformRect(
nodeParent.describeApproximatePaintClip(node),
transform, // paint transform from nodeParent to parent
Copy link
Contributor

Choose a reason for hiding this comment

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

the comment seems to be inaccurate. Isn't this transform going to be from original child to the current ancestor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The comment was ambiguous (rephrased to "paint transform of nodeParent in relation to parent") but I think it was correct. To avoid calculating the inverse in every step we'll have to start from the parent. The transform is applied in-place at the end of each for loop so when we calculate the "local" clips the transform is still the paint transform of nodeParent instead node.

static Rect? _transformRect(
Rect? rect,
Matrix4 transform, [
Rect Function(Matrix4, Rect) apply = MatrixUtils.inverseTransformRect,
Copy link
Contributor

Choose a reason for hiding this comment

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

we should type def this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a typedef. But I don't like the typedef because it doesn't tell me the exact signature of the function _transformRect takes unless I look it up.

Copy link
Contributor

Choose a reason for hiding this comment

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

inline the function signature is also hard to read

@LongCatIsLooong LongCatIsLooong added the autosubmit Merge PR when tree becomes green via auto submit App label Nov 17, 2025
@auto-submit auto-submit bot added this pull request to the merge queue Nov 17, 2025
Merged via the queue into flutter:master with commit f5b0b09 Nov 17, 2025
70 of 71 checks passed
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Nov 17, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Nov 18, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Nov 18, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Nov 18, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Nov 18, 2025
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Nov 18, 2025
flutter/flutter@cc14ef5...cb7b7df

2025-11-18 [email protected] Enable UIScene Migration and update create templates (flutter/flutter#178700)
2025-11-18 Minsuk Jung Fix #160622: change containsWatchConpanion function to detect companion watch apps defined by only the project info file. (flutter/flutter#176832)
2025-11-18 [email protected] Roll Skia from 614e71550fc3 to ca906091e199 (2 revisions) (flutter/flutter#178716)
2025-11-18 [email protected] Revert "[ Tool ] Don't delete `.dart_tool/widget_preview_scaffold` during `flutter clean` (#175664)" (flutter/flutter#178672)
2025-11-18 [email protected] Add missing flutter_lints dev dependencies (flutter/flutter#178105)
2025-11-18 [email protected] Roll Skia from ec2f626cdcad to 614e71550fc3 (3 revisions) (flutter/flutter#178708)
2025-11-18 [email protected] Roll Dart SDK from a8ad764281e3 to 312845b06afc (1 revision) (flutter/flutter#178704)
2025-11-18 [email protected] Roll Skia from d7268f8245f2 to ec2f626cdcad (1 revision) (flutter/flutter#178703)
2025-11-18 [email protected] Refactor SnackBar behavior selection example to use `RadioGroup` (flutter/flutter#178618)
2025-11-18 [email protected] Add framework-side hitTestBehavior support for Semantics widget and apply to ModalRoute (flutter/flutter#177570)
2025-11-18 [email protected] Fix deprecation warning in some API examples using RadioListTile (flutter/flutter#178635)
2025-11-18 [email protected] Roll Skia from 47fd0d9b1044 to d7268f8245f2 (6 revisions) (flutter/flutter#178695)
2025-11-18 [email protected] Roll Dart SDK from cf94632d94a1 to a8ad764281e3 (1 revision) (flutter/flutter#178694)
2025-11-18 [email protected] [fuchsia] Add wrapper for zx_iob_writev (flutter/flutter#178626)
2025-11-17 [email protected] Make a11y `computeChildGeometry` slightly faster (flutter/flutter#177477)
2025-11-17 [email protected] Fix DropdownMenu width when decorationBuilder provides label (flutter/flutter#178465)
2025-11-17 [email protected] Add DropdownMenuFormField.decorationBuilder (flutter/flutter#178640)
2025-11-17 [email protected] Roll Skia from 84c83c0dfb4a to 47fd0d9b1044 (4 revisions) (flutter/flutter#178673)
2025-11-17 [email protected] Small cleanup in `AndroidTouchProcessor.java‎` (flutter/flutter#178574)
2025-11-17 [email protected] Remove unnecessary `final` modifier in `StandardMessageCodec.java‎` (flutter/flutter#178598)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
IvoneDjaja pushed a commit to IvoneDjaja/flutter that referenced this pull request Nov 22, 2025
This is not a fix for flutter#166173, it's only a by-product. The fix will be
in separate PR, this includes the unrelated code changes to make that PR
smaller.

According to `bench_material3_semantics`, this reduces
`Semantics.ensureGeometry` by ~100 μs (321.6 μs -> 228.9 μs).

## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

**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
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
github-merge-queue bot pushed a commit that referenced this pull request Nov 25, 2025
Fixes #173097

The semantics flush is ~200 μs slower with the shortcuircut removed +
#177477 (which reduces the time increase by ~ 100 μs, from 876 μs to 773
μs) I tried to introduce caching in [a different
patch](https://github.com/flutter/flutter/compare/master...LongCatIsLooong:semantics-geometry?expand=1)
but that patch is more risky and still needs a cleanup.

773 μs doesn't seem bad considering there were little to no geometry
updates between frames before the fix. Introducing cache currently only
improves `Semantics.ensureGeometry` by less than 100 μs and is much more
risky / harder to ensure the correctness.

### BEFORE
```
[bench_material3_scroll_semantics] name: bench_material3_scroll_semantics
SEMANTICS: (samples: 98 clean/2 outliers/100 measured/300 total)
 | average: 567.0510204081633 μs
 | outlier average: 799 μs
 | outlier/clean ratio: 1.4090442856885785x
 | noise: 13.95%

Semantics.updateChildren: (samples: 91 clean/9 outliers/100 measured/300 total)
 | average: 58.9010989010989 μs
 | outlier average: 199.88888888888889 μs
 | outlier/clean ratio: 3.3936359867330017x
 | noise: 82.78%

Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total)
 | average: 95.46315789473684 μs
 | outlier average: 299 μs
 | outlier/clean ratio: 3.1320983570404675x
 | noise: 64.29%

Semantics.ensureSemanticsNode: (samples: 100 clean/0 outliers/100 measured/300 total)
 | average: 78.59 μs
 | outlier average: 78.59 μs
 | outlier/clean ratio: 1x
 | noise: 80.86%

drawFrameDuration: (samples: 98 clean/2 outliers/100 measured/300 total)
 | average: 1685.6938775510205 μs
 | outlier average: 2000 μs
 | outlier/clean ratio: 1.1864550418285935x
 | noise: 7.77%```
```
### AFTER (with this and #177477)
```
[bench_material3_scroll_semantics] name: bench_material3_scroll_semantics
SEMANTICS: (samples: 91 clean/9 outliers/100 measured/300 total)
 | average: 773.1098901098901 μs
 | outlier average: 1000 μs
 | outlier/clean ratio: 1.2934771793669069x
 | noise: 10.65%

Semantics.updateChildren: (samples: 94 clean/6 outliers/100 measured/300 total)
 | average: 48.648936170212764 μs
 | outlier average: 200 μs
 | outlier/clean ratio: 4.111086813907719x
 | noise: 102.15%

Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total)
 | average: 239.55789473684212 μs
 | outlier average: 399.6 μs
 | outlier/clean ratio: 1.6680727656208807x
 | noise: 22.05%

Semantics.ensureSemanticsNode: (samples: 99 clean/1 outliers/100 measured/300 total)
 | average: 194.5151515151515 μs
 | outlier average: 400 μs
 | outlier/clean ratio: 2.0563950771148156x
 | noise: 31.31%

drawFrameDuration: (samples: 95 clean/5 outliers/100 measured/300 total)
 | average: 1775.8315789473684 μs
 | outlier average: 2099.6 μs
 | outlier/clean ratio: 1.1823193285280729x
 | noise: 7.56%
```


## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

**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
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
@LongCatIsLooong LongCatIsLooong deleted the make-updateGeometry-slightly-faster branch November 25, 2025 21:59
mboetger pushed a commit to mboetger/flutter that referenced this pull request Dec 2, 2025
This is not a fix for flutter#166173, it's only a by-product. The fix will be
in separate PR, this includes the unrelated code changes to make that PR
smaller.

According to `bench_material3_semantics`, this reduces
`Semantics.ensureGeometry` by ~100 μs (321.6 μs -> 228.9 μs).

## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

**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
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
mboetger pushed a commit to mboetger/flutter that referenced this pull request Dec 2, 2025
Fixes flutter#173097

The semantics flush is ~200 μs slower with the shortcuircut removed +
flutter#177477 (which reduces the time increase by ~ 100 μs, from 876 μs to 773
μs) I tried to introduce caching in [a different
patch](https://github.com/flutter/flutter/compare/master...LongCatIsLooong:semantics-geometry?expand=1)
but that patch is more risky and still needs a cleanup.

773 μs doesn't seem bad considering there were little to no geometry
updates between frames before the fix. Introducing cache currently only
improves `Semantics.ensureGeometry` by less than 100 μs and is much more
risky / harder to ensure the correctness.

### BEFORE
```
[bench_material3_scroll_semantics] name: bench_material3_scroll_semantics
SEMANTICS: (samples: 98 clean/2 outliers/100 measured/300 total)
 | average: 567.0510204081633 μs
 | outlier average: 799 μs
 | outlier/clean ratio: 1.4090442856885785x
 | noise: 13.95%

Semantics.updateChildren: (samples: 91 clean/9 outliers/100 measured/300 total)
 | average: 58.9010989010989 μs
 | outlier average: 199.88888888888889 μs
 | outlier/clean ratio: 3.3936359867330017x
 | noise: 82.78%

Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total)
 | average: 95.46315789473684 μs
 | outlier average: 299 μs
 | outlier/clean ratio: 3.1320983570404675x
 | noise: 64.29%

Semantics.ensureSemanticsNode: (samples: 100 clean/0 outliers/100 measured/300 total)
 | average: 78.59 μs
 | outlier average: 78.59 μs
 | outlier/clean ratio: 1x
 | noise: 80.86%

drawFrameDuration: (samples: 98 clean/2 outliers/100 measured/300 total)
 | average: 1685.6938775510205 μs
 | outlier average: 2000 μs
 | outlier/clean ratio: 1.1864550418285935x
 | noise: 7.77%```
```
### AFTER (with this and flutter#177477)
```
[bench_material3_scroll_semantics] name: bench_material3_scroll_semantics
SEMANTICS: (samples: 91 clean/9 outliers/100 measured/300 total)
 | average: 773.1098901098901 μs
 | outlier average: 1000 μs
 | outlier/clean ratio: 1.2934771793669069x
 | noise: 10.65%

Semantics.updateChildren: (samples: 94 clean/6 outliers/100 measured/300 total)
 | average: 48.648936170212764 μs
 | outlier average: 200 μs
 | outlier/clean ratio: 4.111086813907719x
 | noise: 102.15%

Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total)
 | average: 239.55789473684212 μs
 | outlier average: 399.6 μs
 | outlier/clean ratio: 1.6680727656208807x
 | noise: 22.05%

Semantics.ensureSemanticsNode: (samples: 99 clean/1 outliers/100 measured/300 total)
 | average: 194.5151515151515 μs
 | outlier average: 400 μs
 | outlier/clean ratio: 2.0563950771148156x
 | noise: 31.31%

drawFrameDuration: (samples: 95 clean/5 outliers/100 measured/300 total)
 | average: 1775.8315789473684 μs
 | outlier average: 2099.6 μs
 | outlier/clean ratio: 1.1823193285280729x
 | noise: 7.56%
```


## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

**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
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
reidbaker pushed a commit to AbdeMohlbi/flutter that referenced this pull request Dec 10, 2025
This is not a fix for flutter#166173, it's only a by-product. The fix will be
in separate PR, this includes the unrelated code changes to make that PR
smaller.

According to `bench_material3_semantics`, this reduces
`Semantics.ensureGeometry` by ~100 μs (321.6 μs -> 228.9 μs).

## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

**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
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
reidbaker pushed a commit to AbdeMohlbi/flutter that referenced this pull request Dec 10, 2025
Fixes flutter#173097

The semantics flush is ~200 μs slower with the shortcuircut removed +
flutter#177477 (which reduces the time increase by ~ 100 μs, from 876 μs to 773
μs) I tried to introduce caching in [a different
patch](https://github.com/flutter/flutter/compare/master...LongCatIsLooong:semantics-geometry?expand=1)
but that patch is more risky and still needs a cleanup.

773 μs doesn't seem bad considering there were little to no geometry
updates between frames before the fix. Introducing cache currently only
improves `Semantics.ensureGeometry` by less than 100 μs and is much more
risky / harder to ensure the correctness.

### BEFORE
```
[bench_material3_scroll_semantics] name: bench_material3_scroll_semantics
SEMANTICS: (samples: 98 clean/2 outliers/100 measured/300 total)
 | average: 567.0510204081633 μs
 | outlier average: 799 μs
 | outlier/clean ratio: 1.4090442856885785x
 | noise: 13.95%

Semantics.updateChildren: (samples: 91 clean/9 outliers/100 measured/300 total)
 | average: 58.9010989010989 μs
 | outlier average: 199.88888888888889 μs
 | outlier/clean ratio: 3.3936359867330017x
 | noise: 82.78%

Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total)
 | average: 95.46315789473684 μs
 | outlier average: 299 μs
 | outlier/clean ratio: 3.1320983570404675x
 | noise: 64.29%

Semantics.ensureSemanticsNode: (samples: 100 clean/0 outliers/100 measured/300 total)
 | average: 78.59 μs
 | outlier average: 78.59 μs
 | outlier/clean ratio: 1x
 | noise: 80.86%

drawFrameDuration: (samples: 98 clean/2 outliers/100 measured/300 total)
 | average: 1685.6938775510205 μs
 | outlier average: 2000 μs
 | outlier/clean ratio: 1.1864550418285935x
 | noise: 7.77%```
```
### AFTER (with this and flutter#177477)
```
[bench_material3_scroll_semantics] name: bench_material3_scroll_semantics
SEMANTICS: (samples: 91 clean/9 outliers/100 measured/300 total)
 | average: 773.1098901098901 μs
 | outlier average: 1000 μs
 | outlier/clean ratio: 1.2934771793669069x
 | noise: 10.65%

Semantics.updateChildren: (samples: 94 clean/6 outliers/100 measured/300 total)
 | average: 48.648936170212764 μs
 | outlier average: 200 μs
 | outlier/clean ratio: 4.111086813907719x
 | noise: 102.15%

Semantics.ensureGeometry: (samples: 95 clean/5 outliers/100 measured/300 total)
 | average: 239.55789473684212 μs
 | outlier average: 399.6 μs
 | outlier/clean ratio: 1.6680727656208807x
 | noise: 22.05%

Semantics.ensureSemanticsNode: (samples: 99 clean/1 outliers/100 measured/300 total)
 | average: 194.5151515151515 μs
 | outlier average: 400 μs
 | outlier/clean ratio: 2.0563950771148156x
 | noise: 31.31%

drawFrameDuration: (samples: 95 clean/5 outliers/100 measured/300 total)
 | average: 1775.8315789473684 μs
 | outlier average: 2099.6 μs
 | outlier/clean ratio: 1.1823193285280729x
 | noise: 7.56%
```


## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

**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
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants