openpencil/packages/docs/development/renderer-profiler.md

96 lines
3.1 KiB
Markdown
Raw Normal View History

---
title: Renderer Profiler
description: Use the CanvasKit renderer profiler HUD and frame capture tools to investigate rendering performance.
---
# Renderer Profiler
OpenPencil includes a CanvasKit renderer profiler for debugging frame time, GPU timing, draw calls, cache behavior, and expensive render phases.
## Enable the HUD
In the browser app, open the menu and choose:
```txt
View → Profiler
```
The app toggles `store.toggleProfiler()`, which maps to `editor.renderer.profiler.toggle()`.
The HUD is drawn directly on the Skia canvas so it measures the same rendering path as the document. It is not a DOM overlay.
## HUD metrics
The profiler HUD shows:
- **FPS / frame time** — smoothed frame cadence.
- **CPU** — JavaScript/WASM render time for the frame.
- **GPU** — latest available `EXT_disjoint_timer_query_webgl2` result when the browser exposes it.
- **Nodes / culled nodes** — total visible scene work and viewport culling count.
- **Draws** — WebGL draw calls counted through the instrumented context.
- **Cache** — whether the scene picture cache was reused.
- **Phases** — timings for renderer phases such as scene draw, picture replay/record, volatile overlays, section labels, selection, rulers, and flush.
- **Frame graph** — rolling frame history with 60 fps / 30 fps / slow thresholds and GPU bars when available.
GPU timing is asynchronous. The value shown is the latest completed GPU query, not necessarily the current frame.
## Implementation locations
Core profiler code lives in:
```txt
packages/core/src/profiler/
```
Main entry points:
- `render-profiler.ts``RenderProfiler` facade used by `SkiaRenderer`.
- `frame/stats.ts` — rolling frame statistics.
- `gpu-timer.ts` — WebGL timer query wrapper.
- `draw-call-counter.ts` — WebGL draw-call instrumentation.
- `phase-timer.ts` — phase timing and User Timing integration.
- `hud-renderer.ts` — canvas HUD rendering.
- `frame/capture.ts` and `speedscope-export.ts` — detailed capture and Speedscope export.
Renderer integration lives under:
```txt
packages/core/src/canvas/renderer*.ts
packages/core/src/canvas/renderer/
```
App wiring lives in:
```txt
src/app/editor/profiler/index.ts
src/app/shell/menu/schema.ts
src/app/shell/menu/app-menu.ts
```
## Programmatic use
From app/editor code:
```ts
store.toggleProfiler()
```
From a renderer instance:
```ts
renderer.profiler.toggle()
renderer.profiler.beginCapture()
// render one or more frames
const capture = renderer.profiler.endCapture()
const speedscopeJson = renderer.profiler.exportSpeedscope()
renderer.profiler.downloadSpeedscope()
```
Detailed captures are for targeted debugging. Keep the normal HUD path lightweight and avoid enabling expensive capture work unless a user or developer explicitly asks for it.
## Notes
- The profiler is designed to be safe when disabled: no timing calls or allocations should be added to hot paths unless `profiler.enabled` / `profiler.capturing` is active.
- GPU timing depends on browser and hardware support for `EXT_disjoint_timer_query_webgl2`.
- If GPU timing is unavailable, the HUD still reports CPU time, draw calls, phases, node counts, and cache status.