Skip to content

perf: reduce per-frame allocations and fix layout bugs#25

Open
Yoshihiko-Ino wants to merge 2 commits into
una-xiv:mainfrom
Yoshihiko-Ino:perf/optimize-layout-rendering
Open

perf: reduce per-frame allocations and fix layout bugs#25
Yoshihiko-Ino wants to merge 2 commits into
una-xiv:mainfrom
Yoshihiko-Ino:perf/optimize-layout-rendering

Conversation

@Yoshihiko-Ino

@Yoshihiko-Ino Yoshihiko-Ino commented May 3, 2026

Copy link
Copy Markdown

Summary

  • Layout.Sizing: Replaced Values.ToArray() and ChildNodes.ToArray() with direct foreach over live collections where safe; removed intermediate LINQ expressions that re-computed totalGapSize after the manual loop.
  • Layout.Position: Eliminated intermediate List<Node> allocations in GetChildrenWidth / GetChildrenHeight by folding visible-node filtering and accumulation into a single foreach loop.
  • Node (query cache): Removed unused using System.Collections.Immutable and using System.Linq imports from Node.Layout.cs and Node.Query.cs.
  • Node.Renderer (Draw loop): Changed _childNodes.ToArray() to a lock-guarded snapshot (lock (_childNodes) { childSnapshot = [.._childNodes]; }) so that the snapshot is taken atomically while still allowing AppendChild/RemoveChild calls from within a child's Draw() to proceed without throwing InvalidOperationException.
  • Node.Renderer (overflow container): Replaced _childNodes.ToArray() with lock (_childNodes) { foreach ... } for the position-override pass, which only reads bounds and never modifies the collection.
  • Node (tag inheritance): Replaced unguarded _childNodes.ToArray() in InheritTagsFromParent() with a lock-guarded snapshot.
  • ObservableHashSet: Fixed Add() firing ItemAdded even when the item was already present.
  • Node.Style: Wrapped ComputeStyle() in try/finally to ensure _isUpdatingStyle and _computeStyleLock are always released.
  • Node: Fixed AppendChild/PrependChild calling RemoveChild(this) instead of RemoveChild(node).
  • Layout: Fixed ComputeLayout() omitting the margin offset when computing ContentRect.
  • Static draw metrics: Converted DrawDeltaTime / DrawTotalTime from instance to static fields.

- Node.cs: fix AppendChild/PrependChild calling RemoveChild(this) instead of RemoveChild(node); fix InheritTagsFromParent() ToArray() -> lock+foreach
- Node.Style.cs: wrap ComputeStyle() in try-finally to guarantee lock release; fix ToArray() -> lock+foreach (2 places)
- Node.Renderer.cs: make DrawDeltaTime/DrawTotalTime static (root-only update); fix BeginOverflowContainer() ToArray() -> lock+foreach
- Node.Layout.cs: remove unused System.Collections.Immutable and System.Linq imports
- Node.Query.cs: remove unused System.Collections.Immutable import
- ObservableHashSet.cs: fix Add() firing ItemAdded on duplicate entries
- Layout.cs: fix ContentRect missing Margin offset in ComputeLayout()
- Layout.Sizing.cs: remove LINQ double-calculation overwriting manual loop result; remove ToArray() from AnchorToChildNodes.Values and ChildNodes iteration; remove unused imports
- Layout.Position.cs: eliminate intermediate List<Node> in GetChildrenWidth/GetChildrenHeight (single-pass loop)
…dification

Co-Authored-By: Yoshihiko-Ino <232758239+Yoshihiko-Ino@users.noreply.github.com>
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