Renderer Roadmap
Glyx ships three 2D rendering backends today: TinySkia, Vello, and (Windows, experimental) Direct2D. This page explains why, and corrects an earlier version of this page that framed Vello as a consolidation target — that framing turned out to be wrong once real memory measurements were taken.
Current backend selection
| Backend | When selected | Status |
|---|---|---|
| TinySkia (via softbuffer) | Integrated/no GPU, or explicit renderMode: 'skia' | ✅ Stable — zero wgpu, flat ~27–40 MB RSS under interaction load |
| Vello (wgpu) | Discrete GPU, or explicit renderMode: 'gpu'/'cpu' | ✅ Stable — GPU-parallel vector renderer, real memory cost under load |
| Direct2D (Windows) | Explicit renderMode: 'direct2d' only — never auto-selected | 🧪 Experimental — see Renderer Selection |
Selection is automatic at startup via a GPU capability probe (auto, the
default). Override with renderMode in glyx.config — see
Renderer & Engine Selection for the full
config reference, decision matrix, and per-backend memory numbers.
There is no GLYX_RENDER_MODE environment variable — that was a stale
reference in an earlier version of this page. The config field is
window.renderMode ('auto' | 'skia' | 'gpu' | 'cpu' | 'direct2d').
GLYX_CPU_RENDER=1 is a real env var, but it only forces TinySkia
(renderMode: 'skia''s equivalent) — it doesn't select between backends
generally.
FemtoVG — removed
FemtoVG was a legacy OpenGL-style renderer. It has been removed from Glyx.
Why it was removed
- FemtoVG created a new wgpu
BindGroupfor every distinct draw-state per frame, causing per-frame GPU buffer churn. Measured directly this session: under the same fast-hover-repaint-burst stress test used to evaluate every backend on this page, FemtoVG spiked even higher than Vello — the proper fix (dynamic uniform offsets) was a significant change to femtovg internals, not something maintainable long-term as a patch. - The upstream
femtovgcrate had slowed maintenance. We vendored it only to keep the fallback path alive. - TinySkia (CPU rasterizer via softbuffer) already outperforms FemtoVG on integrated GPUs in both memory and visual quality.
What changed
RenderMode::FemtoVGis gone from the native API and therenderModeconfig field.- Hardware that previously routed to FemtoVG (Intel Arc discrete GPUs) now
routes to Vello under
auto.
Migration
No app-level changes are needed. Backends are an implementation detail — the
Canvas2D, View, Text, and Image APIs are identical across backends.
If you set renderMode: 'femtovg' explicitly, remove it.
Vello — a real cost, not a bug
An earlier version of this page framed Vello as the long-term "consolidation target" for Glyx's 2D rendering. That framing was wrong. Direct measurement (fast-hover-and-repaint-burst stress test, same methodology used for every backend on this page) found Vello's memory behavior is not a tuning problem to be fixed with a bigger buffer-pool trim schedule — it's structural:
- Vello (GPU and CPU modes both) keeps a persistent scene/compute buffer pool that grows to match rendering load and only releases on occlusion, focus-loss, or periodic idle checks — never instantly.
- Under the stress test, idle RSS around ~350–430 MB spiked to 600–700 MB under interaction, with slow, erratic recovery afterward.
- Vello's CPU path is not a lighter-weight fallback — it inherits the same buffer-pool memory cost as Vello GPU, without the GPU-parallel throughput that cost exists to buy. It is not recommended; only reach for it if you need Vello-specific rendering features with no GPU available.
None of this makes Vello a bad renderer — it's the right tool when a scene's
2D rendering load is genuinely GPU-throughput-bound (dense paths/text, large
canvases, heavy gradients at scale), which is exactly the workload its
architecture is built for. It's the wrong default for typical app UI, which
is why auto only selects it on discrete GPUs and TinySkia remains the
default elsewhere.
Roadmap items for Vello:
- Investigate whether the buffer-pool trim schedule can be made more aggressive without regressing throughput on the workloads Vello is actually meant for, as a partial mitigation — not a fix for the structural cost itself.
- Layer compositing (
RepaintBoundary→ GPU render layer → blit-only on clean frames). - Text subpixel rendering on Vello (Parley integration improvement).
TinySkia — the default, not a compromise
TinySkia via softbuffer (zero wgpu) is the right choice for the large majority of apps, not a fallback for weak hardware:
- No wgpu device, no GPU buffer pool of any kind — nothing to grow under load. Measured flat (~27–40 MB) both idle and under the same stress burst that spiked Vello to 600–700 MB.
- CPU rasterization at 60 fps is viable for typical app UIs on any machine made after 2015.
- On integrated GPUs specifically, GPU buffer memory is system RAM — skipping wgpu entirely avoids that cost outright, not just reduces it.
TinySkia will remain and be maintained alongside Vello. The selection
heuristic (GpuTier::Integrated → TinySkia) is intentional, not temporary.
Direct2D — Windows, experimental
Added after Vello's structural memory cost was understood: Direct2D
(ID2D1DeviceContext + DXGI swap chain, with a DirectWrite text bridge)
gives GPU-accelerated output on Windows with TinySkia-like flat memory
behavior — because its resource caches are managed by the OS/graphics
driver and shared system-wide across every app, not privately allocated
per-app the way Vello's (or FemtoVG's) are.
This was verified before any integration work started: a standalone spike
(bare HWND, no Glyx code) measured 32.5 MB idle with zero memory growth
under a 500-repaint invalidate burst. The real integration, once built,
confirmed the same flat-memory pattern on a full app (tasks, all
primitives — shapes, gradients, text, images, layers/opacity) under the
same fast-hover-burst stress test used to evaluate every other backend.
Current scope:
| Capability | Status |
|---|---|
| Shapes (rects, circles, lines, paths) | ✅ |
| Gradient/brush fills | ✅ |
| Text (DirectWrite bridge) | ✅ |
| Images | ✅ |
| Layers, clipping, real per-layer opacity | ✅ |
<Canvas3D> on a Direct2D window | ❌ — no safe D3D11/wgpu device-sharing pattern investigated yet; silently skipped with a log message |
| macOS equivalent (CoreGraphics) | Not started — needs its own validation spike on real macOS hardware |
Explicitly not on a path to replacing Vello or TinySkia — see Renderer & Engine Selection for opt-in config and current limitations.
3D (Canvas3D / glyx-3d)
The 3D layer uses wgpu directly, independent of the 2D backend. It is always
GPU-accelerated and always present when a Canvas3D node exists (TinySkia
and Vello both support lazily standing up a wgpu device on first
Canvas3D use; Direct2D does not yet — see above). See the
3D Rendering roadmap for what's planned there.