Skip to content

perf: optimize render layout invalidation#85

Open
KoalaHao wants to merge 3 commits into
Norbert515:mainfrom
marsup-space:codex/nocterm-layout-optimization
Open

perf: optimize render layout invalidation#85
KoalaHao wants to merge 3 commits into
Norbert515:mainfrom
marsup-space:codex/nocterm-layout-optimization

Conversation

@KoalaHao

Copy link
Copy Markdown
Contributor

Summary

  • Add relayout-boundary behavior so children whose parents do not depend on their size can relayout without marking ancestors dirty.
  • Downgrade same-footprint text and paint-only decoration changes from layout invalidation to paint invalidation.
  • Keep paint invalidation propagating to the root so visual updates are still scheduled correctly.
  • Ensure RenderLayoutBuilder child dirty marks always cascade when its child can affect layout.
  • Add regression coverage for relayout boundaries, paint/layout invalidation, and LayoutBuilder cascades.

Tests

  • dart analyze
  • dart test test/framework/layout_invalidation_optimization_test.dart test/framework/relayout_boundary_test.dart test/framework/render_object_invalidation_optimization_test.dart test/framework/render_pipeline_test.dart

KoalaHao added 2 commits June 16, 2026 23:34
The optimization commit 2450c6d ('Optimize render layout
invalidation') introduced relayout boundaries that skip
cascading markNeedsLayout up to the parent when the parent
doesn't use the child's size. RenderLayoutBuilder was passing
'parentUsesSize: !constraints.isTight' to its child, which
evaluated to false under tight constraints and broke the
propagation chain. When the chat toolbar's LayoutBuilder's
container child marked itself dirty (e.g. from inner streaming
widgets), the dirty mark never reached LayoutBuilder or its
parent, so the toolbar's _layoutCallback never re-ran and
children rendered with stale state.

Fix: always pass 'parentUsesSize: true' because
RenderLayoutBuilder ALWAYS derives its size from its child
(size = constraints.constrain(child.size) at the bottom of
performLayout). The previous code was a lie that the
optimization was happily exploiting.

Adds 17 tests in layout_invalidation_optimization_test.dart
covering:

  - Relayout boundaries (parentUsesSize=false/true propagation)
  - RenderText.text setter optimization (same-footprint skip,
    size-changing relayout, _layoutResult updates, style-only)
  - markNeedsLayout propagation semantics
  - RenderLayoutBuilder child chain (incl. direct regression
    test that catches the bug — fails under old code, passes
    after fix)
  - Streaming widget repaint path (style-only, same-width,
    size-changing, multi-update cascade)

All 1428 nocterm tests pass.
@KoalaHao KoalaHao marked this pull request as draft June 17, 2026 01:02
@KoalaHao KoalaHao marked this pull request as ready for review June 18, 2026 06:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant