docs: deep dive into GPUI dirty propagation, SharedBlink, hierarchy flattening results

This commit is contained in:
Hibryda 2026-03-19 23:47:39 +01:00
parent 6f0f276400
commit 54e68df295

View file

@ -26,6 +26,61 @@ Key mechanisms:
3. **`mark_view_dirty()` walks ancestors** — this is GPUI's fundamental constraint
4. **`refreshing=true` on cache miss** cascades down → children can't cache if parent is dirty
## DEEP DIVE: Why 3% is the floor for div-based views (2026-03-19 late)
### The full dirty propagation chain (confirmed by source analysis)
```
cx.notify(entity_id)
→ App::notify → WindowInvalidator::invalidate_view(entity_id)
→ dirty_views.insert(entity_id)
→ draw() → invalidate_entities() → mark_view_dirty(entity_id)
→ dispatch_tree.view_path_reversed(entity_id) → walks parent chain
→ inserts entity + ALL render-time ancestors into dirty_views
→ AnyView::prepaint checks: dirty_views.contains(MY entity_id)
→ if true: cache MISS, re-render
→ if false: cache HIT, replay GPU commands
```
### Why Zed achieves <1% with the SAME mechanism
Zed's BlinkManager → observer → cx.notify(Editor) → Editor + Pane + Workspace ALL in dirty_views.
ALL re-render. But:
- Workspace::render() = ~5 div builders = <0.1ms
- Pane::render() = ~10 div builders = <0.2ms
- Editor::render() = returns EditorElement struct = <0.01ms
- EditorElement::prepaint/paint = real work, bounded to visible rows
Total: <1ms per blink frame. Our ProjectBox::render() = ~9 divs + 3 tab buttons = ~15ms.
The 15ms includes Taffy layout + element prepaint + paint pipeline overhead per div.
### SharedBlink pattern (Arc<AtomicBool>)
Replaced Entity<BlinkState> with `Arc<AtomicBool>`:
- Background timer toggles atomic bool every 500ms
- Timer calls cx.notify() on ProjectBox directly (no intermediate entity)
- ProjectBox::render() reads bool atomically — no Entity subscription overhead
- Same 3% CPU — confirms cost is in render() itself, not entity machinery
### Hierarchy flattening (4 levels → 2 levels)
Removed ProjectGrid entity level. ProjectBoxes render directly from Workspace.
Dispatch tree: Workspace → ProjectBox (2 levels, same as Zed's Workspace → Pane).
CPU unchanged at 3% — confirms cost is per-frame render(), not ancestor walk count.
### Path to <1%: Custom Element for ProjectBox header
Convert header (accent stripe + dot + name + CWD + tab bar) from div tree to
custom `impl Element` that paints directly via `window.paint_quad()` +
`window.text_system().shape_line().paint()`. This eliminates:
- 9 div() constructor calls
- 9 Taffy layout nodes
- 9 prepaint traversals
- 9 paint traversals
Replaced by ~6 direct GPU primitive insertions (paint_quad × 4 + shape_line × 2).
Expected reduction: 15ms → <1ms per frame.
## Overview
GPUI is the GPU-accelerated UI framework powering the Zed editor. Apache-2.0 licensed (the crate itself; Zed app is GPL-3.0). Pre-1.0 with breaking changes every 2-3 months. 76.7k stars (Zed repo), $32M Sequoia funding.