Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,47 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.20] — 2026-05-11

### Added

- **Layer Tree compositor in production pipeline** (ADR-007 Phase D) — `compositor/` package now drives the render loop. `OffsetLayer`, `PictureLayer`, `ClipRectLayer`, `OpacityLayer` provide structured composition with animated transform/opacity support. Replaces direct widget tree walks with Layer Tree traversal.
- **Persistent Layer Tree** (ADR-007 Phase D.5) — `UpdateLayerTree()` reuses layer objects across frames. 97.9% fewer allocations for 200 boundaries (613 → 13 allocs/op). Enterprise pattern validated by research (Flutter, Chrome, Qt6, Android, Skia all use persistent trees).
- **O(1) flat dirty boundary list** (ADR-028 Phase C) — `HasDirtyBoundaries()` replaces `NeedsRedrawInTreeNonBoundary()` O(n) tree walk for frame skip. 45× faster (1.2ns vs 58ns). Flutter `_nodesNeedingPaint` pattern with `DirtyBoundaryRegistrar` interface.
- **Multi-rect damage** (ADR-030) — per-draw dynamic scissor for multiple dirty rects. Zero pixel waste when dirty widgets are spatially distant. Ring buffer stores rect lists per frame. Threshold >16 rects merges to union (GDK/Sway pattern). Full stack: ui → gg `RenderDirectWithDamageRects` → wgpu `PresentWithDamage`.
- **Overlay content in boundary pipeline** (ADR-029 Phase E) — dropdown menus, dialogs rendered via same Layer Tree + boundary texture pipeline as main widgets. `PaintOverlayBoundaries()`, `AppendOverlaysToLayerTree()`. Scrim for modal overlays only (Flutter ModalBarrier).
- **Overlay hover blocking** — `overlayAwareHitTest()` checks overlay stack before root tree. Background widgets no longer receive hover when overlay is open.
- **Software backend e2e tests** — pixel-exact damage verification through wgpu software backend. HAL-level `RenderPassStats` proves scissor=48×48 (not full window). 9 e2e tests run in CI without GPU.
- **GPU pipeline diagnostic logging** — 7 log points behind `GOGPU_DEBUG_DAMAGE=1`: frame entry, root invalidate, per-boundary render/check, damage tracking, blit, blit path. `renderCount`/`blitCount` counters per frame.
- **~120 new tests**, 6 benchmarks across desktop, app, compositor, state, overlay packages.
- **3 enterprise research reports**: Layer Tree patterns (5 frameworks), multi-rect damage (4 APIs, 5 frameworks), ListView recycling (5 frameworks).

### Changed

- **Frame skip O(1)** — `NeedsRedrawInTreeNonBoundary` O(n) replaced with `HasDirtyBoundaries()` O(1) in desktop.draw frame skip check.
- **os.Getenv cached** — `GOGPU_DEBUG_DAMAGE` and `GOGPU_DAMAGE_BLIT` cached via `sync.Once`. Zero syscalls in hot path.
- **state.Bind deprecated** — use `BindToScheduler` for granular per-widget invalidation (enterprise pattern). `Bind` still works for backward compatibility.
- **Phase 7 documentation** — all docblocks updated from "Phase 4-5" to "Phase 7". Stale/contradictory comments removed.
- **Debug overlay + LoadOpLoad** — force full `canvas.Render` when `GOGPU_DEBUG_DAMAGE=1` to prevent green residue from LoadOpLoad preserved content.

### Fixed

- **Dropdown black background** — overlay boundary incorrectly marked as root (`IsRoot=true` from `Parent()==nil`) → `DrawGPUTextureBase` single-slot overwrote actual root. Fixed: `clearRootOnPictureLayers` after append.
- **Child boundary dirty ≠ root needsRedraw** — `onBoundaryDirty` callback called `ctx.InvalidateRect` which set `window.needsRedraw=true` forcing root re-render every frame. Fixed: use `RegisterDirtyBoundary` only.
- **Dropdown menu ctx.InvalidateRect leak** — menu.go called both `SetNeedsRedraw` AND `ctx.InvalidateRect` on RepaintBoundary. The `InvalidateRect` violated boundary isolation, forcing root re-render. Fixed: removed redundant `ctx.InvalidateRect` calls.
- **Child boundaries invisible** — `renderFromTreeRecursive` had depth limit that prevented child boundaries (spinner, ListView items) from rendering. Fixed: removed depth limit.

### Dependencies

- gg v0.46.7 (multi-rect damage API, per-draw scissor)
- gogpu v0.34.3
- wgpu v0.27.3 (software backend Stats, slog.Debug instrumentation)

### Known Issues

- Dropdown menu items: cyan/green debug overlays do not show on overlay menu items (debug visualization only, menu renders and functions correctly)
- GPU 10% for spinner 48×48 at 30fps (target <3%, scissor proven correct at HAL level)

## [0.1.19] — 2026-05-10

### Added
Expand Down
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func main() {
| `core/dialog` | Modal dialog: backdrop overlay, action buttons, focus trapping, Alert/Confirm | 96.9% |
| `core/dropdown` | Dropdown/select with overlay menu, keyboard navigation, signal bindings | 96%+ |
| `overlay` | Overlay/popup stack, container, position helper | 95%+ |
| `primitives` | Box, Text, Image, RepaintBoundary (pixel caching + tile-parallel scene.Scene) | 94.4% |
| `primitives` | Box, Text, Image, RepaintBoundary (GPU texture caching via Layer Tree compositor) | 94.4% |
| `theme/material3` | Material Design 3 — theme (HCT color science) + 21 component painters | 97%+ |
| `focus` | Keyboard focus management with Tab/Shift+Tab navigation | 95.2% |
| `internal/focus` | Internal focus manager implementation | 15.2% |
Expand Down Expand Up @@ -206,9 +206,9 @@ func main() {
| `uitest` | Testing utilities: MockCanvas, MockContext, event factories, widget helpers, assertions | 93.1% |
| `internal/dirty` | Dirty region tracking: Collector, Tracker, merge algorithm, partial repaints | 100% |

| `compositor` | Layer Tree: OffsetLayer, PictureLayer, ClipRectLayer, OpacityLayer | 95%+ |
| `compositor` | Layer Tree compositor: OffsetLayer, PictureLayer, ClipRectLayer, OpacityLayer — production render pipeline | 95%+ |

**Total: ~170,000+ lines of code | 56+ packages | ~6,800+ tests | 97%+ average coverage**
**Total: ~189,000+ lines of code | 56+ packages | ~7,200+ tests | 97%+ average coverage**

---

Expand Down Expand Up @@ -240,8 +240,8 @@ func main() {
├─────────────────────────────────────────────────────────────┤
│ app/ + FocusManager │ focus/ │ overlay/ │ render/ │
├─────────────────────────────────────────────────────────────┤
│ desktop/ (Layer Tree Compositor, ADR-007)
│ compositor/ (OffsetLayer, PictureLayer, Compositor)│
│ desktop/ (Layer Tree Compositor + Damage-Aware Blit)
│ compositor/ (Production: OffsetLayer, PictureLayer, Opacity)│
│ offscreen/ (headless widget → *image.RGBA) │
├─────────────────────────────────────────────────────────────┤
│ layout/ │ state/ │ a11y/ │
Expand Down Expand Up @@ -275,6 +275,19 @@ gg → wgpu → naga ← internal to gg

**ui never imports gogpu, wgpu, or naga directly.**

### Render Pipeline

Enterprise-grade retained-mode rendering (ADR-007):

1. **O(1) frame skip** -- flat dirty boundary set, no tree walks when idle (0% GPU)
2. **Layer Tree composition** -- OffsetLayer, PictureLayer, OpacityLayer, ClipRectLayer
3. **Per-boundary GPU textures** -- dirty boundaries re-render to MSAA offscreen texture, clean reuse cached
4. **Damage-aware blit** -- LoadOpLoad + multi-rect scissor, only dirty pixels touch the GPU
5. **Persistent tree** -- layer objects reused across frames (97.9% fewer allocations)

Validated by enterprise research: Flutter, Chrome, Qt6, Android, Skia patterns.
Software backend e2e tests prove scissor=48x48 at HAL level.

---

## Examples
Expand Down
12 changes: 6 additions & 6 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# gogpu/ui Roadmap

> **Version:** 0.1.19 (Phase 3 RC + Layer Tree Compositor)
> **Version:** 0.1.20 (Enterprise Render Pipeline + Layer Tree Compositor)
> **Updated:** May 2026
> **Go Version:** 1.25+

Expand Down Expand Up @@ -31,12 +31,12 @@
| Metric | Value |
|--------|-------|
| Packages | 56+ |
| Go Source Files | ~370 |
| Test Files | ~160 |
| Total LOC | ~170,000+ |
| Test Functions | ~6,800+ |
| Go Source Files | ~612 |
| Test Files | ~200 |
| Total LOC | ~189,000+ |
| Test Functions | ~7,200+ |
| Test Coverage | 97%+ |
| Linter Issues | 0 (new code) |
| Linter Issues | 0 |

---

Expand Down
Loading
Loading