Skip to content

Adds geometry dirty nodes#180375

Merged
auto-submit[bot] merged 44 commits into
flutter:masterfrom
chunhtai:issues/166173
Mar 9, 2026
Merged

Adds geometry dirty nodes#180375
auto-submit[bot] merged 44 commits into
flutter:masterfrom
chunhtai:issues/166173

Conversation

@chunhtai

@chunhtai chunhtai commented Dec 29, 2025

Copy link
Copy Markdown
Contributor

fixes #166173

Highlevel:

instead of clearing the entire geometry from the node that markSemanticsNeedsUpdate up to the first semantics boundary. and recalculate everything in between. This code now only clear the geometry for node that are markSemanticsNeedsUpdate. This requires us to keep a separate list for geomtry dirty node. Thus this change.

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 the framework flutter/packages/flutter repository. See also f: labels. label Dec 29, 2025
@chunhtai
chunhtai force-pushed the issues/166173 branch 2 times, most recently from 1b7d1ca to fbd95d6 Compare January 8, 2026 21:34
@github-actions github-actions Bot added a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) f: scrolling Viewports, list views, slivers, etc. labels Jan 13, 2026
@github-actions github-actions Bot removed a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) f: scrolling Viewports, list views, slivers, etc. labels Jan 13, 2026
@chunhtai

chunhtai commented Jan 13, 2026

Copy link
Copy Markdown
Contributor Author

before
image

after
image

YEEEEEESSSSSSSS, cut half of total semantics calculation from the framework side

@chunhtai chunhtai changed the title [WIP]Adds geometry dirty nodes Adds geometry dirty nodes Jan 14, 2026
@chunhtai
chunhtai marked this pull request as ready for review January 14, 2026 17:39

@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 introduces a more granular mechanism for tracking semantics geometry updates by adding a _nodesNeedingSemanticsGeometryUpdate set to PipelineOwner. This should improve performance by avoiding unnecessary geometry recalculations. The changes are well-contained and include necessary test updates. I have one suggestion to improve the readability of a complex loop.

Comment thread packages/flutter/lib/src/rendering/object.dart Outdated
@chunhtai
chunhtai requested a review from justinmc January 14, 2026 18:13

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

Makes sense to me at a high level, but @LongCatIsLooong should definitely review and follow up on his old ideas (#166173 (comment)). Otherwise LGTM 👍

Comment thread packages/flutter/lib/src/rendering/object.dart Outdated
Comment thread packages/flutter/lib/src/rendering/object.dart Outdated

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

Hmm could you add a comment somewhere to explain when a RenderObject gets added to _nodesNeedingSemanticsGeometryUpdate? For a RenderObject author what should I do to make sure the semantics geometry is updated, when I skip layout and only do repaint (I think you can safely do that to re-align a child today since the child subtree's layout does not change at all). From the looks of it the RenderObject author must call markNeedsSemanticsUpdate when they re-align the child?

(RenderObject object) =>
!object._needsLayout &&
object.owner == this &&
!object._semantics.parentDataDirty,

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.

Is this for skipping dirty RenderObjectSemantics that will need geometry updates anyways because the parent data also needs updating? I'm thinking maybe instead of boolean flags we should be using an int/enum for indicating the dirtiness?

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.

so it is slightly complicated, if at this point the parent data is still dirty, it is a blocked branch. so parentDataDirty doesn't imply it is blocked, it depends on the phase of update as well. I will add some more 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.

for a RenderObjectSemantics to find out if it is in a blocked branch, does it only have to check its own parentDataDirty or it has to check all the way up to the root node? I assume its the former based on the implementation here, so even for a "blocked" branch we still recursively update parentDataDirty for all descendant nodes that are going to be blocked?

@chunhtai chunhtai Jan 29, 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.

does it only have to check its own parentDataDirty

yes

It is a delicate condition that makes this true, the node in the list should have their parentdata clear in _RenderObjectSemantics.markNeedsUpdate is called. if it is still dirty here, it means the updateChild hasn't update the the parentdata of this node, and that can only happen if it is blocked.

This is controlled by this line in _RenderObjectSemantics.markNeedsUpdate

    if (node != renderObject && producedSemanticsNode != null && node._semantics.parentDataDirty) {
      // If `this` node has already been added to [owner._nodesNeedingSemantics]
      // remove it as it is no longer guaranteed that its semantics
      // node will continue to be in the tree. If it still is in the tree, the
      // ancestor `node` added to [owner._nodesNeedingSemantics] at the end of
      // this block will ensure that the semantics of `this` node actually gets
      // updated.
      // (See semantics_10_test.dart for an example why this is required).
      renderObject.owner!._nodesNeedingSemantics.remove(renderObject);
    }

This is where the block node be excluded from updateChildren if it is blocked (if it is not blocked, the parent of this semantics boundary will call updateChildren on this subtree)

so even for a "blocked" branch we still recursively update parentDataDirty for all descendant nodes that are going to be blocked?

For a node in a blocked branch that got added to this list, its parentData must be dirty at this point due to the reason above, so the situation you mentioned should never happen

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.

Thanks for the explanation! Interestingly when I comment out that if block all tests still pass (I had to use --update-goldens tho since golden tests never pass without that on my macbook).

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.

I think some of the google tests may fail, that is why I know about this blocked node shenanigan.

In the long term we should remove the block node logic as it cause state loss for live region which is not good. There is currently an effort to remove blockSemantics usage and hopefully deprecates it.

Comment thread packages/flutter/lib/src/rendering/object.dart
Comment thread packages/flutter/lib/src/rendering/object.dart Outdated
@chunhtai

Copy link
Copy Markdown
Contributor Author

Added doc comment on _nodesNeedingSemanticsGeometryUpdate not sure if that is the best place, let me know if you think otherwise.

From the looks of it the RenderObject author must call markNeedsSemanticsUpdate when they re-align the child?

This is already the case though, I am not changing the behavior.

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

So from reading this my observations are:

Every RenderObject will be added to _nodesNeedingSemanticsGeometryUpdate when it's markedNeedsSemanticsUpdate. But at that point we can't skip adding them to the set because the semantics tree structure has not been updated and we do not know which of them will form semantics nodes and who their parents will be after updateChildren.

For that reason, it is after updateChildren, that we traverse the _nodesNeedingSemanticsGeometryUpdate to figure out which branches need geometry updates and reset geometry to null to evict the geometry cache and to indicate that these branches will need to be processed for geometry update.

After that step we "Conduct the geometry update". This is done by locating geometry update roots, from the nodes in _nodesNeedingSemanticsGeometryUpdate, and calling ensureGeometry on these "root" nodes. ensureGeometry walks down the tree and if one of its immediate child still has geometry cache it would skip that branch.

(Reminder to myself that I still have a question regarding sibling merge groups).

Comment thread packages/flutter/lib/src/rendering/object.dart
// In both cases, the renderobject will be added to the list of nodes needing
// geometry update.
//
// This specific casecan happen if a renderobject decided to conditionally include

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: missing space between "case" and "can". By this sentence do you mean that the visitChildrenForSemantics of that RenderObject having a branching condition which doesn't call markNeedsSemanticsUpdate when changed? Is there an example?

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.

Since geometry is only reset to null after updateChildren in the ensureGeometry step (barring clear), so this is for a brand new subtree that has never been incorporated into the tree?

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.

I think this may be an old code that no longer needed, that me remove it and see

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.

ok turns out this is a corner case

I added the code comment explain the situation, I will also paste it here

    // This specific case can happen if a parent somwhere above this node decided to
    // conditionally include this node.
    //
    // For example, render object A->B->C, where A is the root and all of them
    // creates semantics nodes.
    //
    // Frame 1: B and C both mark layout dirty, and B suddenly decide not to
    // inlcude C in the semantics tree.
    //
    // In this case, C's geometry will remain dirty because it is considered as
    // blocked.
    //
    // Frame 2: B is marked dirty again and decide C should be included
    // in the semantics tree. We will run into this situation where C's geometry
    // is dirty but it is not in the _nodesNeedingSemanticsGeometryUpdate.

bool isBlocked = target.parentDataDirty;
// Find the first render object semantics that forms a semantics node
// and whose geometry is not dirty as the anchor point to start the geometry update.
while (!isBlocked &&

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.

Would it be easier /faster if each RenderObjectSemantics knows who the parent RenderObjectSemantics that formed the semantics boundary is?

@chunhtai chunhtai Jan 29, 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.

I think we could, but since this is easy enough and efficient enough to find it on the spot, I try avoid adding more cache to this class unless necessary. That will probably create some corner cases.

(RenderObject object) =>
!object._needsLayout &&
object.owner == this &&
!object._semantics.parentDataDirty,

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.

for a RenderObjectSemantics to find out if it is in a blocked branch, does it only have to check its own parentDataDirty or it has to check all the way up to the root node? I assume its the former based on the implementation here, so even for a "blocked" branch we still recursively update parentDataDirty for all descendant nodes that are going to be blocked?

Comment thread packages/flutter/lib/src/rendering/object.dart
Comment thread packages/flutter/lib/src/rendering/object.dart Outdated
Comment thread packages/flutter/lib/src/rendering/object.dart Outdated
Comment thread packages/flutter/lib/src/rendering/object.dart Outdated
@chunhtai

chunhtai commented Jan 29, 2026

Copy link
Copy Markdown
Contributor Author

So from reading this my observations are:

Every RenderObject will be added to _nodesNeedingSemanticsGeometryUpdate when it's markedNeedsSemanticsUpdate. But at that point we can't skip adding them to the set because the semantics tree structure has not been updated and we do not know which of them will form semantics nodes and who their parents will be after updateChildren.

For that reason, it is after updateChildren, that we traverse the _nodesNeedingSemanticsGeometryUpdate to figure out which branches need geometry updates and reset geometry to null to evict the geometry cache and to indicate that these branches will need to be processed for geometry update.

After that step we "Conduct the geometry update". This is done by locating geometry update roots, from the nodes in _nodesNeedingSemanticsGeometryUpdate, and calling ensureGeometry on these "root" nodes. ensureGeometry walks down the tree and if one of its immediate child still has geometry cache it would skip that branch.

(Reminder to myself that I still have a question regarding sibling merge groups).

Yes the entire statement is accurate

Comment thread packages/flutter/lib/src/rendering/object.dart
(RenderObject object) =>
!object._needsLayout &&
object.owner == this &&
!object._semantics.parentDataDirty,

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.

Thanks for the explanation! Interestingly when I comment out that if block all tests still pass (I had to use --update-goldens tho since golden tests never pass without that on my macbook).

continue;
}
for (final _RenderObjectSemantics child in node._semantics._children) {
child.geometry = null;

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.

Also why only removing the geometry cache on child nodes? In this case if node also happens to be a relayout boundary that changed its size (but its parent wasn't notified because it was a relayout boundary), if we only remove geometry from node's children, then in the "conduct the geometry update" step, ensureGeometry will be called on node but not on its semantics parent? But in this case I think it should be called on the semantics parent because node's geometry will need updating right?

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.

in this case I think it should be called on the semantics parent because node's geometry will need updating right?

this is already the case. the target after the while loop must either be a root node, or shouldformsemanticsnode while geometry is not dirty

ensureGeometry() is called on the immediate parent, that form a semantics node, of the node in _nodesNeedingSemanticsGeometryUpdate.

@LongCatIsLooong LongCatIsLooong Feb 10, 2026

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.

ensureGeometry() is called on the immediate parent, that form a semantics node

      for (final node in nodesToProcessGeometry) {
        _RenderObjectSemantics target = node._semantics;
        bool isBlocked = target.parentDataDirty;
        while (!isBlocked &&Collapse
            !target.isRoot &&
            (target.geometryDirty || !target.shouldFormSemanticsNode)) {
          target = target.parent!;
          isBlocked = target.parentDataDirty;
        }

        if (!isBlocked) {
          target.ensureGeometry();
        }
      }

if node.shouldFormSemanticsNode is true, we won't go into the while loop at all I think? In that case the final target will be node instead of node.parent? But if node's sized changed, it should be node.parent.ensureGeometry() instead of node.ensureGeometry?

@chunhtai chunhtai Feb 10, 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.

interesting, I think you are right that this is a corner case. IIRC before the whole renderobjectsemantics refactoring, it is already like this that only the parent semantics node would ever update the geometry of the current node. I guess we just never hit this corner case.

let me look into this and get back to you

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.

fixed the corner case by clear the geometry cache if the node shouldformSemanticsnode= true.
also added tests in
semantics_layout_sized_test.dart

// represents a group of render objects in the subtree, where node that
// forms a semantics node is in its _children.
for (final _RenderObjectSemantics nodeInSubtree in child._children) {
assert(nodeInSubtree.shouldFormSemanticsNode);

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.

hmm interesting, so the merge-up tree is guaranteed to have a max depth of 2?

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.

all the immediate semantics node are cached for non-semantics-node-forming renderbojectsemantics until it reach the a renderbojectsemantics that will form a semantics node.

It is this way to avoid walking the intermediate nodes to collect all renderbojectsemantics that will form semantics node

continue;
}
node._semantics.ensureGeometry();
if (!node._semantics.contributesToSemanticsTree) {

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.

So here contributesToSemanticsTree is checked instead of shouldFormSemanticsNode because _children is only updated in updateChildren if contributesToSemanticsTree is true? And that's less children that needs to be marked dirty for geometry?

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.

right

@LongCatIsLooong LongCatIsLooong 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 with questions regarding the RelayoutBoundary + shouldFormSemanticsNode case (see #180375 (comment)).

@github-actions github-actions Bot added the a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) label Feb 11, 2026
@chunhtai chunhtai added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 9, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Mar 9, 2026
Merged via the queue into flutter:master with commit 1797fe2 Mar 9, 2026
73 of 74 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Mar 9, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 10, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 10, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 10, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 10, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 10, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 10, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Mar 10, 2026
Roll Flutter from 2ec61af30672 to 195ae7b3a122 (36 revisions)

flutter/flutter@2ec61af...195ae7b

2026-03-10 [email protected] [web] Updates to the README (flutter/flutter#176292)
2026-03-10 [email protected] [Impeller] Do not log VK_ERROR_SURFACE_LOST_KHR errors returned by vkAcquireNextImageKHR (flutter/flutter#183338)
2026-03-10 [email protected] DlDeferredImageGPUImpeller::ImageWrapper texture thread safety improvements (flutter/flutter#183429)
2026-03-10 [email protected] refactor: remove material imports from system_context_menu_test, table_test (flutter/flutter#183368)
2026-03-10 [email protected] refactor: remove material from baseline_test, slivers_test (flutter/flutter#183367)
2026-03-10 [email protected] Migrated circle sdf to euclidean 2d derivative (flutter/flutter#183184)
2026-03-10 [email protected] Roll Packages from c717018 to ee460d6 (2 revisions) (flutter/flutter#183451)
2026-03-10 [email protected] Roll Skia from 68f24903b592 to 4b35832cc7ea (1 revision) (flutter/flutter#183449)
2026-03-10 [email protected] Roll Skia from 8eda160375ea to 68f24903b592 (1 revision) (flutter/flutter#183444)
2026-03-10 [email protected] Roll Skia from e7b957806202 to 8eda160375ea (2 revisions) (flutter/flutter#183440)
2026-03-10 [email protected] Roll Fuchsia Linux SDK from ox-II3wPpa818y78_... to 8C_qfgWgoNhkV0_Mn... (flutter/flutter#183437)
2026-03-10 [email protected] Roll Skia from 887df915a95e to e7b957806202 (1 revision) (flutter/flutter#183434)
2026-03-10 [email protected] Remove material from scrollable_test.dart (flutter/flutter#181429)
2026-03-09 [email protected] Update 'a: text input' globs (flutter/flutter#183405)
2026-03-09 [email protected] Roll Skia from 3aa442e0624a to 887df915a95e (7 revisions) (flutter/flutter#183423)
2026-03-09 [email protected] Adds geometry dirty nodes (flutter/flutter#180375)
2026-03-09 [email protected] Roll Dart SDK from 5b1aa4f8db14 to ebef6c849489 (1 revision) (flutter/flutter#183417)
2026-03-09 [email protected] Add Alexander Dmitriev to AUTHORS (flutter/flutter#183357)
2026-03-09 [email protected] Update org triage (flutter/flutter#183254)
2026-03-09 [email protected] [Android] Avoid plugin auto-registration during FlutterFragmentActivity recreate timing window (flutter/flutter#182963)
2026-03-09 [email protected] Standardize skia includes. (flutter/flutter#183404)
2026-03-09 [email protected] Add a note to `arcTo` docs about the 2PI drawing angle issue (flutter/flutter#183293)
2026-03-09 [email protected] Roll pub packages (flutter/flutter#183411)
2026-03-09 [email protected] [ Tool ] Fix --print-dtd not working for web targets (flutter/flutter#183171)
2026-03-09 [email protected] Add await or ignore lint to flutter_driver unawaited callsites (flutter/flutter#183334)
2026-03-09 [email protected] Cleanup MockVulkan when the vulkan instance is destroyed (flutter/flutter#183324)
2026-03-09 [email protected] Updates tests commit (flutter/flutter#183301)
2026-03-09 [email protected] Implements `ClipRSuperellipse` on backdrop filter on platform view (flutter/flutter#182643)
2026-03-09 [email protected] Roll Skia from ea4fd0e1472a to 3aa442e0624a (1 revision) (flutter/flutter#183397)
2026-03-09 [email protected] Roll Dart SDK from 050b2f646425 to 5b1aa4f8db14 (1 revision) (flutter/flutter#183393)
2026-03-09 [email protected] Roll Packages from fe3de64 to c717018 (10 revisions) (flutter/flutter#183396)
2026-03-09 [email protected] Roll Skia from a83dca75c531 to ea4fd0e1472a (1 revision) (flutter/flutter#183389)
2026-03-09 [email protected] Roll Skia from 254e44141861 to a83dca75c531 (7 revisions) (flutter/flutter#183388)
2026-03-09 [email protected] Roll Fuchsia Linux SDK from giLoee6arX5CRHuRh... to ox-II3wPpa818y78_... (flutter/flutter#183386)
2026-03-09 [email protected] Roll Dart SDK from 1604910613c7 to 050b2f646425 (1 revision) (flutter/flutter#183383)
2026-03-08 [email protected] Roll Skia from af994ae4d990 to 254e44141861 (2 revisions) (flutter/flutter#183377)

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

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

To report a problem with the AutoRoller itself, please file a bug:
...
xxxOVALxxx pushed a commit to xxxOVALxxx/flutter that referenced this pull request Mar 10, 2026
<!--
Thanks for filing a pull request!
Reviewers are typically assigned within a week of filing a request.
To learn more about code review, see our documentation on Tree Hygiene:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
-->

fixes flutter#166173

Highlevel:

instead of clearing the entire geometry from the node that
markSemanticsNeedsUpdate up to the first semantics boundary. and
recalculate everything in between. This code now only clear the geometry
for node that are markSemanticsNeedsUpdate. This requires us to keep a
separate list for geomtry dirty node. Thus this change.

## 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
@chunhtai

Copy link
Copy Markdown
Contributor Author

it was expected to regress a bit, but not this much, taking a look

@chunhtai

Copy link
Copy Markdown
Contributor Author

After taking a closer look, this jump in the ensuregeometry is minimal compare to the total frame, and is still in the expected range. (barely see any increase for total frame time which was ~600,000us)

This pr however reduced the run time in more common scrolling scenario, and cut the total frame time from 17,000us to 14,000us.

I think this is still a trade off worth making since the bench_material3_semantics is the worst case scenario where user close and open a new page every frame.

I also have future plan to further optimize this part, but I will fix forward instead of revert and reland.

Let me know if you think otherwise @gaaclarke

@gaaclarke

Copy link
Copy Markdown
Member

Let me know if you think otherwise @gaaclarke

Your take sounds reasonable to me. Thanks for looking into it.

okorohelijah pushed a commit to okorohelijah/packages that referenced this pull request Mar 26, 2026
…r#11222)

Roll Flutter from 2ec61af30672 to 195ae7b3a122 (36 revisions)

flutter/flutter@2ec61af...195ae7b

2026-03-10 [email protected] [web] Updates to the README (flutter/flutter#176292)
2026-03-10 [email protected] [Impeller] Do not log VK_ERROR_SURFACE_LOST_KHR errors returned by vkAcquireNextImageKHR (flutter/flutter#183338)
2026-03-10 [email protected] DlDeferredImageGPUImpeller::ImageWrapper texture thread safety improvements (flutter/flutter#183429)
2026-03-10 [email protected] refactor: remove material imports from system_context_menu_test, table_test (flutter/flutter#183368)
2026-03-10 [email protected] refactor: remove material from baseline_test, slivers_test (flutter/flutter#183367)
2026-03-10 [email protected] Migrated circle sdf to euclidean 2d derivative (flutter/flutter#183184)
2026-03-10 [email protected] Roll Packages from c717018 to ee460d6 (2 revisions) (flutter/flutter#183451)
2026-03-10 [email protected] Roll Skia from 68f24903b592 to 4b35832cc7ea (1 revision) (flutter/flutter#183449)
2026-03-10 [email protected] Roll Skia from 8eda160375ea to 68f24903b592 (1 revision) (flutter/flutter#183444)
2026-03-10 [email protected] Roll Skia from e7b957806202 to 8eda160375ea (2 revisions) (flutter/flutter#183440)
2026-03-10 [email protected] Roll Fuchsia Linux SDK from ox-II3wPpa818y78_... to 8C_qfgWgoNhkV0_Mn... (flutter/flutter#183437)
2026-03-10 [email protected] Roll Skia from 887df915a95e to e7b957806202 (1 revision) (flutter/flutter#183434)
2026-03-10 [email protected] Remove material from scrollable_test.dart (flutter/flutter#181429)
2026-03-09 [email protected] Update 'a: text input' globs (flutter/flutter#183405)
2026-03-09 [email protected] Roll Skia from 3aa442e0624a to 887df915a95e (7 revisions) (flutter/flutter#183423)
2026-03-09 [email protected] Adds geometry dirty nodes (flutter/flutter#180375)
2026-03-09 [email protected] Roll Dart SDK from 5b1aa4f8db14 to ebef6c849489 (1 revision) (flutter/flutter#183417)
2026-03-09 [email protected] Add Alexander Dmitriev to AUTHORS (flutter/flutter#183357)
2026-03-09 [email protected] Update org triage (flutter/flutter#183254)
2026-03-09 [email protected] [Android] Avoid plugin auto-registration during FlutterFragmentActivity recreate timing window (flutter/flutter#182963)
2026-03-09 [email protected] Standardize skia includes. (flutter/flutter#183404)
2026-03-09 [email protected] Add a note to `arcTo` docs about the 2PI drawing angle issue (flutter/flutter#183293)
2026-03-09 [email protected] Roll pub packages (flutter/flutter#183411)
2026-03-09 [email protected] [ Tool ] Fix --print-dtd not working for web targets (flutter/flutter#183171)
2026-03-09 [email protected] Add await or ignore lint to flutter_driver unawaited callsites (flutter/flutter#183334)
2026-03-09 [email protected] Cleanup MockVulkan when the vulkan instance is destroyed (flutter/flutter#183324)
2026-03-09 [email protected] Updates tests commit (flutter/flutter#183301)
2026-03-09 [email protected] Implements `ClipRSuperellipse` on backdrop filter on platform view (flutter/flutter#182643)
2026-03-09 [email protected] Roll Skia from ea4fd0e1472a to 3aa442e0624a (1 revision) (flutter/flutter#183397)
2026-03-09 [email protected] Roll Dart SDK from 050b2f646425 to 5b1aa4f8db14 (1 revision) (flutter/flutter#183393)
2026-03-09 [email protected] Roll Packages from fe3de64 to c717018 (10 revisions) (flutter/flutter#183396)
2026-03-09 [email protected] Roll Skia from a83dca75c531 to ea4fd0e1472a (1 revision) (flutter/flutter#183389)
2026-03-09 [email protected] Roll Skia from 254e44141861 to a83dca75c531 (7 revisions) (flutter/flutter#183388)
2026-03-09 [email protected] Roll Fuchsia Linux SDK from giLoee6arX5CRHuRh... to ox-II3wPpa818y78_... (flutter/flutter#183386)
2026-03-09 [email protected] Roll Dart SDK from 1604910613c7 to 050b2f646425 (1 revision) (flutter/flutter#183383)
2026-03-08 [email protected] Roll Skia from af994ae4d990 to 254e44141861 (2 revisions) (flutter/flutter#183377)

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

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

To report a problem with the AutoRoller itself, please file a bug:
...
mboetger pushed a commit to mboetger/flutter that referenced this pull request Mar 26, 2026
<!--
Thanks for filing a pull request!
Reviewers are typically assigned within a week of filing a request.
To learn more about code review, see our documentation on Tree Hygiene:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
-->

fixes flutter#166173

Highlevel:

instead of clearing the entire geometry from the node that
markSemanticsNeedsUpdate up to the first semantics boundary. and
recalculate everything in between. This code now only clear the geometry
for node that are markSemanticsNeedsUpdate. This requires us to keep a
separate list for geomtry dirty node. Thus this change.

## 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
chunhtai added a commit to chunhtai/flutter that referenced this pull request Mar 30, 2026
ahmedsameha1 pushed a commit to ahmedsameha1/flutter that referenced this pull request Apr 14, 2026
<!--
Thanks for filing a pull request!
Reviewers are typically assigned within a week of filing a request.
To learn more about code review, see our documentation on Tree Hygiene:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
-->

fixes flutter#166173

Highlevel:

instead of clearing the entire geometry from the node that
markSemanticsNeedsUpdate up to the first semantics boundary. and
recalculate everything in between. This code now only clear the geometry
for node that are markSemanticsNeedsUpdate. This requires us to keep a
separate list for geomtry dirty node. Thus this change.

## 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
creatorpiyush pushed a commit to creatorpiyush/packages that referenced this pull request Jun 10, 2026
…r#11222)

Roll Flutter from 2ec61af30672 to 195ae7b3a122 (36 revisions)

flutter/flutter@2ec61af...195ae7b

2026-03-10 [email protected] [web] Updates to the README (flutter/flutter#176292)
2026-03-10 [email protected] [Impeller] Do not log VK_ERROR_SURFACE_LOST_KHR errors returned by vkAcquireNextImageKHR (flutter/flutter#183338)
2026-03-10 [email protected] DlDeferredImageGPUImpeller::ImageWrapper texture thread safety improvements (flutter/flutter#183429)
2026-03-10 [email protected] refactor: remove material imports from system_context_menu_test, table_test (flutter/flutter#183368)
2026-03-10 [email protected] refactor: remove material from baseline_test, slivers_test (flutter/flutter#183367)
2026-03-10 [email protected] Migrated circle sdf to euclidean 2d derivative (flutter/flutter#183184)
2026-03-10 [email protected] Roll Packages from c717018 to ee460d6 (2 revisions) (flutter/flutter#183451)
2026-03-10 [email protected] Roll Skia from 68f24903b592 to 4b35832cc7ea (1 revision) (flutter/flutter#183449)
2026-03-10 [email protected] Roll Skia from 8eda160375ea to 68f24903b592 (1 revision) (flutter/flutter#183444)
2026-03-10 [email protected] Roll Skia from e7b957806202 to 8eda160375ea (2 revisions) (flutter/flutter#183440)
2026-03-10 [email protected] Roll Fuchsia Linux SDK from ox-II3wPpa818y78_... to 8C_qfgWgoNhkV0_Mn... (flutter/flutter#183437)
2026-03-10 [email protected] Roll Skia from 887df915a95e to e7b957806202 (1 revision) (flutter/flutter#183434)
2026-03-10 [email protected] Remove material from scrollable_test.dart (flutter/flutter#181429)
2026-03-09 [email protected] Update 'a: text input' globs (flutter/flutter#183405)
2026-03-09 [email protected] Roll Skia from 3aa442e0624a to 887df915a95e (7 revisions) (flutter/flutter#183423)
2026-03-09 [email protected] Adds geometry dirty nodes (flutter/flutter#180375)
2026-03-09 [email protected] Roll Dart SDK from 5b1aa4f8db14 to ebef6c849489 (1 revision) (flutter/flutter#183417)
2026-03-09 [email protected] Add Alexander Dmitriev to AUTHORS (flutter/flutter#183357)
2026-03-09 [email protected] Update org triage (flutter/flutter#183254)
2026-03-09 [email protected] [Android] Avoid plugin auto-registration during FlutterFragmentActivity recreate timing window (flutter/flutter#182963)
2026-03-09 [email protected] Standardize skia includes. (flutter/flutter#183404)
2026-03-09 [email protected] Add a note to `arcTo` docs about the 2PI drawing angle issue (flutter/flutter#183293)
2026-03-09 [email protected] Roll pub packages (flutter/flutter#183411)
2026-03-09 [email protected] [ Tool ] Fix --print-dtd not working for web targets (flutter/flutter#183171)
2026-03-09 [email protected] Add await or ignore lint to flutter_driver unawaited callsites (flutter/flutter#183334)
2026-03-09 [email protected] Cleanup MockVulkan when the vulkan instance is destroyed (flutter/flutter#183324)
2026-03-09 [email protected] Updates tests commit (flutter/flutter#183301)
2026-03-09 [email protected] Implements `ClipRSuperellipse` on backdrop filter on platform view (flutter/flutter#182643)
2026-03-09 [email protected] Roll Skia from ea4fd0e1472a to 3aa442e0624a (1 revision) (flutter/flutter#183397)
2026-03-09 [email protected] Roll Dart SDK from 050b2f646425 to 5b1aa4f8db14 (1 revision) (flutter/flutter#183393)
2026-03-09 [email protected] Roll Packages from fe3de64 to c717018 (10 revisions) (flutter/flutter#183396)
2026-03-09 [email protected] Roll Skia from a83dca75c531 to ea4fd0e1472a (1 revision) (flutter/flutter#183389)
2026-03-09 [email protected] Roll Skia from 254e44141861 to a83dca75c531 (7 revisions) (flutter/flutter#183388)
2026-03-09 [email protected] Roll Fuchsia Linux SDK from giLoee6arX5CRHuRh... to ox-II3wPpa818y78_... (flutter/flutter#183386)
2026-03-09 [email protected] Roll Dart SDK from 1604910613c7 to 050b2f646425 (1 revision) (flutter/flutter#183383)
2026-03-08 [email protected] Roll Skia from af994ae4d990 to 254e44141861 (2 revisions) (flutter/flutter#183377)

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

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

To report a problem with the AutoRoller itself, please file a bug:
...
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.

[A11y] Further optimize geometry calculation in semantics

4 participants