Skip to content

perf(text): change a text view's state only when a parse changes it - #3

Merged
trancong12102 merged 1 commit into
mainfrom
perf/text-view-parse-ack
Oct 1, 2026
Merged

trancong12102 merged 1 commit into
mainfrom
perf/text-view-parse-ack

Conversation

@trancong12102

Copy link
Copy Markdown

A TextViewState wrote itself twice without changing:

  • Its first, synchronous parse ran in the constructor and notified. TextView creates the state as element state inside its holder's render, so under GPUI Fast that notify marks the state as changed while the holder is drawn.
  • The task that receives the background parser's acknowledgement, or a result whose revision is stale, updated the state only to find nothing to commit.

So every text view built for the first time changed twice. A list whose rows build text views, such as a transcript scrolled onto rows it had not shown yet, repainted its scroll layer for every new row until the layer was demoted.

Now a state being made parses without announcing it, since there is no selection to reset and no reader to tell. The receiving task reads the state first and updates it only to commit a current result.

Measured in Slopty with layers compiled in: a finished 80-turn conversation panned at rest goes from 0.524 to 0.4325 ms a frame (median of 8 alternating rounds), and its layer composites 393 of 600 frames instead of 4.5. The test that sees this is on Slopty's side, because it shows only while scroll layers are on.

Written with Claude Code.

A TextViewState parses a small text on the UI thread. Two parts of that
path wrote the state without changing it, and under GPUI Fast each write
counts as a change for every view that read the state:

- The first parse ran in the constructor and notified. TextView makes its
  state as element state, inside the render of the view that holds it, so
  the notify stamped the state as changed while that view was drawn.
- The synchronous parse is still sent to the background parser, so later
  appends extend its document. The task receiving the parser's
  acknowledgement updated the state just to find nothing to commit. It did
  the same for a result whose revision is stale.

A text view built for the first time therefore changed twice, once while it
was drawn and once a frame later. A list whose rows build text views, like a
transcript scrolled to rows it had not shown, repainted its scroll layer for
every new row until the layer was demoted.

A state being made now parses without announcing it: there is no selection
to reset and no reader to tell. The receiving task reads the state first and
updates it only to commit a current result.
@trancong12102
trancong12102 merged commit 6d32ce6 into main Oct 1, 2026
11 of 12 checks passed
trancong12102 added a commit to aislopware/slopty that referenced this pull request Oct 1, 2026
gpui-fast moves to f71b3fe. It compiles scroll layers in on macOS and
iOS (aislopware/gpui-fast#9), and it fixes the overflow in a list layer's
shift when the view holding the list is copied from the last frame (#8).
gpui-kit moves to 25b62b08, whose text view no longer changes its state
when it is first built (aislopware/gpui-kit#3).

Navigator scrolling goes from 0.343 to 0.221 ms a frame, with every
frame composited. A finished conversation panned at rest goes from 0.479
to 0.4215 ms. Every other frame stays within noise. Two tests assert that
both lists composite every frame and are never demoted.

Co-Authored-By: Claude Code
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