Repository navigation
perf: reduce chat rendering overhead with compositor-driven Draw - #340995
Conversation
Share a visibility-aware 30 FPS Draw/shimmer clock and use transform-based input borders. Avoid redundant pet sprite and gaze updates, eliminate drag-induced layouts, release removed toolbar dropdowns, reuse unchanged thinking titles, and skip no-op progress height measurements. Related to #340236; this does not claim to resolve the full layout regression. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
The new input-border regression test is nested inside another test and is not reliably discovered or executed.
1 open finding
What changed in this PR
Reduces chat UI rendering, animation, and object-retention overhead across the workbench and Agents window.
Changes:
- Adds a shared visibility-aware 30 FPS progress-animation clock.
- Optimizes pet rendering, dragging, thinking titles, progress measurements, and toolbar cleanup.
- Expands regression coverage for the optimized paths.
| File | Description |
|---|---|
src/vs/base/browser/animationSync.ts |
Adds visibility callbacks and safer synchronization. |
src/vs/base/browser/ui/toolbar/toolbar.ts |
Releases removed dropdown references and listeners. |
src/vs/base/test/browser/animationSync.test.ts |
Tests visibility and paused-animation handling. |
src/vs/base/test/browser/ui/toolbar/toolbar.test.ts |
Tests dropdown cleanup and context propagation. |
build/lib/stylelint/vscode-known-variables.json |
Updates recognized chat CSS variables. |
src/vs/workbench/contrib/chat/browser/widget/chatProgressAnimation.ts |
Implements the shared animation clock. |
src/vs/workbench/contrib/chat/browser/widget/chatWorkingLogo.ts |
Budgets Draw rendering to 30 FPS. |
src/vs/workbench/contrib/chat/browser/widget/chatWidget.ts |
Manages transcript shimmer animation. |
src/vs/workbench/contrib/chat/browser/widget/chatPetWidget.ts |
Optimizes pet frames, visibility, gaze, and dragging. |
src/vs/workbench/contrib/chat/browser/widget/chatListRenderer.ts |
Avoids unchanged footer measurements. |
src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts |
Adds visibility-aware border animation elements. |
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatProgressContentPart.ts |
Manages shimmer and reports rendered changes. |
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingStyleContentPart.ts |
Manages thinking-title and spinner animations. |
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.ts |
Reuses unchanged rendered titles. |
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSubagentContentPart.ts |
Cleans up managed spinner animation. |
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatToolInputOutputContentPart.ts |
Manages collapsible tool-title shimmer. |
src/vs/workbench/contrib/chat/browser/widget/media/chat.css |
Uses compositor border rotation and managed shimmer. |
src/vs/workbench/contrib/chat/browser/widget/media/chatPet.css |
Supports translated dragging and paused pet animation. |
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatThinkingContent.css |
Styles managed thinking shimmer. |
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatConfirmationWidget.css |
Styles managed confirmation shimmer. |
src/vs/workbench/contrib/chat/test/browser/widget/chatProgressAnimation.test.ts |
Tests clock sharing and cancellation. |
src/vs/workbench/contrib/chat/test/browser/widget/chatWorkingLogo.test.ts |
Tests Draw frame budgeting. |
src/vs/workbench/contrib/chat/test/browser/widget/chatPetWidget.test.ts |
Tests pet rendering and lifecycle optimizations. |
src/vs/workbench/contrib/chat/test/browser/widget/chatListRenderer.test.ts |
Tests footer and title reuse. |
src/vs/workbench/contrib/chat/test/browser/widget/input/chatInputPart.test.ts |
Tests input-border geometry and animation. |
src/vs/workbench/contrib/chat/test/browser/widget/chatContentParts/chatToolProgressPart.test.ts |
Tests shimmer synchronization and visibility. |
src/vs/workbench/contrib/chat/test/browser/widget/chatContentParts/chatThinkingContentPart.test.ts |
Tests title-render caching and invalidation. |
src/vs/sessions/contrib/sessions/browser/views/sessionsList.ts |
Shares the progress clock for session titles. |
src/vs/sessions/contrib/sessions/browser/media/sessionsList.css |
Adds managed and reduced-motion title styling. |
src/vs/sessions/contrib/sessions/test/browser/sessionsList.test.ts |
Tests session-title animation behavior. |
🧠 Review effort: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Merge main while retaining the toolbar lifecycle and pet optimization regressions alongside upstream coverage. Register the input-border regression test at suite scope so it is discovered without running the preceding gutter test. Validated the exact border test independently, all ten affected test files (1374 passing, two existing pending), the client build/typecheck, and targeted ESLint. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Clip oversized decorative gradients at their mask so they cannot increase ancestor scroll ranges or shift the inline-chat composer on focus. Cover compact and working inputs with an overflow regression test. Allow the geometry assertion to account for 1/64px browser layout rounding and computed-style serialization, including fractional input dimensions. Verified Chromium, WebKit, Electron, and stable inline-chat fixtures without accepting a regressed screenshot baseline. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Retain the new upstream attachment-session test alongside border geometry and overflow coverage. Wait for the browser runner's asynchronous CSS imports before making geometry assertions. Validated Chromium and WebKit input tests, 803 Electron input/renderer tests (one existing pending), client typecheck, and targeted lint. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move steady-state Draw playback from SVG path updates to compositor transforms backed by padded, theme- and DPR-aware shared atlases. Preserve reduced-motion and visibility lifecycles with cancellation, bounded resource ownership, and a logged 60 Hz SVG fallback. Keep the rounded ribbon tips consistent across the held-to-moving transition and cover atlas fidelity, cache bounds, theme/DPR changes, cancellation, and disposal. Leave existing shimmer behavior unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Merge main at ffad3bc, preserving both the upstream session-list DOM helpers and the shared-shimmer retry helper. Retain all upstream and branch test coverage without changing the Atlas 120 renderer or existing shimmer behavior. Validated the merged client build and typecheck, 385 Electron tests (4 pending), 233 Chromium tests, 233 WebKit tests, and resolved-file hygiene. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
October 14 merge-conflict resolutionMerged The only conflict was in the imports in sessionsList.test.ts: upstream added Local validation with Node 24.18.0:
|

Summary
Reduce redundant rendering and component-lifetime retention when several chat sessions are active. Related to #340236, but this is not a claim that the full reported layout regression is resolved.
Adds/extends regression coverage for these rendering and ownership paths. No dependency manifests, new settings, persistent-progress configuration defaults, pet sprite assets, or screenshot baseline hashes change. The pixel spinner is unchanged. Atlas 120 is a source sampling density, not a forced 120 Hz JavaScript loop or a guarantee that every display presents 120 frames/s.
Performance evidence
Production Draw atlas
The native production-component probe verified five shared-atlas widgets, accelerated transform layers, and zero steady-state renderer Layout, UpdateLayoutTree, Paint, or FireAnimationFrame events. A separate real Code OSS workbench smoke run used five independently connected local mock requests: all five displayed the production atlas, shared one resource, advanced their native timelines, and removed their playback surfaces when the editors closed.
A matched production-source 60/120 comparison on an M2 Pro used five visible 12 CSS-pixel logos at DPR 2, six counterbalanced samples per option and six static controls. Only the frame-count constant was changed in the isolated 60 Hz candidate; the product remains at 120. Each primary measurement followed atlas readiness, GC, and three seconds of warmup, then measured 5.334 seconds without tracing or per-frame polling.
The 60 candidate saved about 1.28 renderer ms/s and 24.7% of GPU-process CPU time in this isolated comparison. Both had zero steady-state layout/paint/RAF events, and their native held-pose screenshots were byte-identical. We retain 120 to preserve more motion detail on higher-refresh displays; the compositor presents at its available cadence rather than forcing 120 redraws on a 60 Hz screen.
These are component measurements, not whole-app CPU, hardware GPU utilization, battery savings, or a fresh final-branch-versus-main workbench benchmark. Earlier production batches had higher/noisier absolute renderer totals; compare within matched batches rather than combining their numbers. Other workbench animations can also keep the compositor active. The cache budget accounts for decoded source pixels, not total GPU/process memory; temporary canvases, encoded images, and per-layer overhead are additional. Background preparation is not chat response latency, and SVG fallback remains animated while it runs.
Earlier workbench and component measurements
The following measurements predate the atlas integration. They describe the earlier animation/pet improvements, not a newly measured aggregate percentage for the final PR. Values are renderer main-thread task milliseconds per wall-clock second on an M2 Pro.
These are three-sample diagnostic comparisons of actual component/rendering paths, not release-level statistical claims. Additional checks:
The original multi-second GC stalls and all possible application DOM retention remain unproven. In one retained CI text-only pair from #340236, roughly 67% of the extra layout duration occurred before the request started; these response-rendering changes cannot explain or fix the whole issue. No CI metric changes or speculative startup/layout rewrites are included.
Validation
Atlas 120 update
The following checks passed with Node 24.18.0. Client compilation and scoped hygiene were rerun for publication; successful typecheck, test, and live-rendering evidence was reused for unchanged inputs.
npm exec --yes --package=node@24.18.0 -- npm run build-fast -- --client-only— passed.npm exec --yes --package=node@24.18.0 -- npm run typecheck-client— passed.npm exec --yes --package=node@24.18.0 -- bash scripts/test.sh --run src/vs/workbench/contrib/chat/test/browser/widget/chatWorkingLogoAtlas.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatWorkingLogo.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatListRenderer.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatContentParts/chatToolProgressPart.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatContentParts/chatThinkingContentPart.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatProgressAnimation.test.ts --reporter dot— 1,011 passed, 1 pre-existing pending.npm exec --yes --package=node@24.18.0 -- node test/unit/browser/index.js --browser chromium --browser webkit --run src/vs/workbench/contrib/chat/test/browser/widget/chatWorkingLogoAtlas.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatWorkingLogo.test.ts --reporter dot— 29 passed in each browser.npm exec --yes --package=node@24.18.0 -- npm run eslint -- src/vs/workbench/contrib/chat/browser/widget/chatWorkingLogo.ts src/vs/workbench/contrib/chat/browser/widget/chatWorkingLogoAtlas.ts src/vs/workbench/contrib/chat/browser/widget/chatWorkingLogoDraw.ts src/vs/workbench/contrib/chat/test/browser/widget/chatWorkingLogo.test.ts src/vs/workbench/contrib/chat/test/browser/widget/chatWorkingLogoAtlas.test.ts— passed.npm exec --yes --package=node@24.18.0 -- npm run stylelint -- src/vs/workbench/contrib/chat/browser/widget/media/chatWorkingLogo.css— passed.npm exec --yes --package=node@24.18.0 -- npm run precommit -- src/vs/workbench/contrib/chat/browser/widget/chatWorkingLogo.ts src/vs/workbench/contrib/chat/browser/widget/chatWorkingLogoAtlas.ts src/vs/workbench/contrib/chat/browser/widget/chatWorkingLogoDraw.ts src/vs/workbench/contrib/chat/browser/widget/media/chatWorkingLogo.css src/vs/workbench/contrib/chat/test/browser/widget/chatWorkingLogo.test.ts src/vs/workbench/contrib/chat/test/browser/widget/chatWorkingLogoAtlas.test.ts src/vs/workbench/contrib/chat/test/browser/widget/__snapshots__/ChatWorkingLogo_Draw_mask_geometry_preserves_moving_caps_and_fully_revealed_bands.0.snap— passed; six eligible files checked from seven requested paths.Atlas coverage includes resource sharing and bounds, pending-generation cancellation, late-result disposal, failed-request retry, source-frame fidelity and padding, hidden/remount behavior, reduced motion, theme/DPR replacement, no-icon/inactive states, and logged SVG fallback. Native component probes and the real five-chat workbench smoke also passed.
October 13 merge and feedback validation
Merged
mainat68343b4619bin signed merge commit49f739bef80, preserving both sides of the toolbar and pet test conflicts. Fixed the selected review comment: the border regression test is a sibling of the gutter test, rather than being registered inside it.npm exec --yes --package=node@24.18.0 -- bash scripts/test.sh --run src/vs/workbench/contrib/chat/test/browser/widget/input/chatInputPart.test.ts --grep '^ChatInputPart working borders rotate fixed gradients inside masks at any input aspect ratio$' --reporter spec— 1 independently discovered test passed.npm exec --yes --package=node@24.18.0 -- bash scripts/test.sh --run src/vs/base/test/browser/ui/toolbar/toolbar.test.ts --run src/vs/base/test/browser/animationSync.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatPetWidget.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatProgressAnimation.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatWorkingLogo.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/input/chatInputPart.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatContentParts/chatThinkingContentPart.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatContentParts/chatToolProgressPart.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatListRenderer.test.ts --run src/vs/sessions/contrib/sessions/test/browser/sessionsList.test.ts --reporter dot— 1,374 passed, 2 existing pending.Cross-browser and inline-chat CI follow-up
Commits
eafb7800b7bandf0d27923970fixed the failures found after the merge:overflow: clipon the decorative mask removes that overflow without clipping the input itself. Tests cover active/idle and compact/non-compact inputs.mainatb0e941623ad.Validation at that revision:
npm exec --yes --package=node@24.18.0 -- npm run test-browser-no-install -- --browser chromium --browser webkit --run src/vs/workbench/contrib/chat/test/browser/widget/input/chatInputPart.test.ts --reporter dot— 4 passed in each browser.npm exec --yes --package=node@24.18.0 -- bash scripts/test.sh --run src/vs/workbench/contrib/chat/test/browser/widget/input/chatInputPart.test.ts --run src/vs/workbench/contrib/chat/test/browser/widget/chatListRenderer.test.ts --reporter dot— 803 passed, 1 existing pending.On
f0d27923970, GitHub CI passed Screenshots & Tests, Screenshots, Playwright Fixture Tests, macOS Browser, Linux Browser, all Electron-Unit platforms, and Compile & Hygiene. Separate Linux smoke failures involved a timeout and a settings-editor click; they were not addressed through unrelated source changes. These historical results are not a claim that CI for the new atlas commit has passed.Not run for the atlas update: Windows/Linux live rendering or hardware-power/battery measurements, a complete post-patch production comparison of all eight regressed scenarios, or a matched reproduction of the original long user workload/GC stalls. Universal native OS-hide/minimize suspension is not claimed: production uses document/intersection and widget lifecycle signals, and the isolated Electron hide/minimize probe did not always report a hidden document. The component-explorer service was unavailable for the atlas follow-up; native production-component and real-workbench checks provided the live evidence instead. Performance scripts, traces, heap snapshots, and videos remain local investigation artifacts, not product files.
Manual testing
Draft status
Remains a draft. The branch contains the merge-conflict, test-discovery, screenshot/browser, rounded-tail, and Atlas 120 fixes without rewriting history. Local validation passed; GitHub CI for the updated head and broader cross-platform/performance review must complete before marking it ready for review.