Renderer & Engine Selection
Glyx has three 2D rendering backends with very different memory profiles. Understanding how the selection works lets you ship the right binary for your audience.
The numbers
Measured on the tasks example (Intel UHD 620 integrated GPU), idle and
under a sustained fast-hover interaction burst β the burst matters as much
as the idle number, since it's what separates a backend with a real,
app-owned memory pool from one that doesn't:
| Backend | Idle RSS | Under interaction burst | Notes |
|---|---|---|---|
| TinySkia (CPU + software present) | ~27β40 MB | No spike β stays flat | No wgpu, no persistent GPU buffer pool |
| Direct2D (Windows only, experimental) | ~77β114 MB | No spike β stays flat | OS/driver-managed GPU caches, not app-owned |
| Vello (wgpu compute) | ~350β430 MB | Spikes to 600β700 MB, slow/erratic recovery | Persistent GPU scene-buffer pool grows under load |
| Vello CPU path | ~340 MB | Also spikes under the same burst | See callout below β not recommended |
Vello's memory cost is structural, not a bug to be fixed. Both Vello modes (GPU and CPU) maintain a scene/compute buffer pool that grows to match rendering load and only shrinks on explicit triggers (occlusion, focus-loss, or periodic idle checks) β never instantly. This is what buys Vello's GPU-parallel rendering throughput on genuinely complex 2D scenes (heavy path/text density, large canvases). For a typical app UI, that throughput ceiling is never reached, so the memory cost is pure downside. Vello's CPU path is worse than both alternatives: it inherits the same buffer-pool architecture and memory cost as Vello GPU, but without the GPU parallelism that cost is meant to buy. Don't reach for it unless you need a Vello-specific feature and have no GPU available at all.
TinySkia's low, flat number is architectural: a CPU rasterizer has no persistent GPU-resident pool to grow in the first place. Direct2D's flat number under the same stress is a different, real finding from the same category of question: its caches are managed by the OS/driver and shared system-wide across every app, not privately allocated per-app the way Vello's (or the removed FemtoVG's) are β see Renderer Roadmap for how that was verified.
How auto works
auto probes the GPU adapter at startup (a lightweight query β no device or
swapchain is created for the probe) and classifies the hardware into one of
four tiers using wgpu::DeviceType and the PCI vendor ID. When the answer is
TinySkia, wgpu is never initialised at all β frames go straight to the window
through the OS software surface:
No GPU / WARP / llvmpipe β TinySkia
Integrated GPU (Intel UHD, iGPU, Apple Silicon) β TinySkia
Intel Arc discrete GPU (vendor 0x8086, discrete) β Vello
NVIDIA or AMD discrete GPU β VelloThe decision is logged at startup so it's always visible:
[glyx] renderMode=auto β skia (Intel(R) UHD Graphics 770, IntegratedGpu)
[glyx] renderMode=auto β vello (Intel(R) Arc A770 Graphics, DiscreteGpu)
[glyx] renderMode=auto β vello (NVIDIA GeForce RTX 4080, DiscreteGpu)GLYX_CPU_RENDER=1 overrides all tiers and forces TinySkia regardless of hardware.
On a typical developer machine (laptop with Intel iGPU), auto picks TinySkia. Vello is selected when a dedicated GPU (NVIDIA, AMD, or Intel Arc) is present.
App persona recommendations
Use this as a starting point when choosing explicitly:
| App persona | Renderer | Notes |
|---|---|---|
| Showcase / portfolio (heavy 2D scenes) | Vello | GPU-parallel path/text throughput actually matters here |
| Indie game (mid-spec) | Vello | Smooth GPU animations on a dedicated GPU |
| 2D casual game | TinySkia | Fast, low RAM, good enough quality |
| 2D game on weak HW | TinySkia | Sub-100 MB story |
| Productivity app | TinySkia | Most common use case β fast, predictable, flat memory |
| Productivity on low-RAM laptop | TinySkia | No GPU allocation |
| Settings / dialog app | TinySkia | JS is glue, RAM matters more than polish |
| Dev tool / asset pipeline | TinySkia | Headless-friendly |
| Headless test / CI | TinySkia | No display required |
| Kiosk / arcade machine | TinySkia | Long-running, low-end target |
| Windows app wanting GPU text/AA quality without Vello's memory cost | Direct2D (experimental) | Windows-only, opt-in β see the callout above |
| 3D content | Vello (2D layer) | Canvas3D itself always uses wgpu directly regardless of 2D backend β see 3D Rendering |
Explicit config
Override auto when you know your target hardware:
// glyx.config.ts
export default defineConfig({
window: {
renderMode: 'skia', // always TinySkia β minimum footprint (recommended default override)
// renderMode: 'gpu', // always Vello β heavy 2D scenes, GPU animations
// renderMode: 'direct2d', // Windows-only, experimental β GPU quality, flat memory
// renderMode: 'auto', // heuristic (default)
},
})Force TinySkia at runtime (useful for CI or debugging):
GLYX_CPU_RENDER=1 glyx dev
GLYX_CPU_RENDER=1 glyx buildFallback chain
If a backend fails to initialise, Glyx falls back automatically:
vello β skia β ERROR
skia β ERROR (cannot render)
direct2d β skia β ERROR (also the path taken on non-Windows targets)The fallback is logged so it's never silent.
Edge cases
Hybrid GPU laptops (switchable graphics)
Laptops with both an iGPU and a dGPU let the OS decide which adapter wgpu sees. With PowerPreference::HighPerformance, wgpu usually gets the dGPU. If the OS pins the iGPU, auto will pick TinySkia.
Vulkan on iGPU (Linux)
The Glyx GPU adapter probe prefers DX12 on Windows to avoid the Vulkan allocator pre-reserving large pools on iGPU hardware. On Linux with Vulkan + iGPU, auto picks TinySkia which bypasses this entirely.
macOS (Apple Silicon)
Apple Silicon reports as IntegratedGpu (Metal). auto picks TinySkia. Set renderMode: 'gpu' explicitly if you want GPU rendering on macOS.
VMs and CI
wgpu::DeviceType::VirtualGpu (VMware, Hyper-V, VirtualBox with GPU passthrough) β TinySkia. Software adapters (no GPU at all) β TinySkia.
Direct2D (Windows, experimental)
renderMode: 'direct2d' draws through Direct2D/DirectWrite (via ID2D1DeviceContext + a DXGI swap chain) instead of Vello or TinySkia. It exists because Vello's memory cost turned out to be structural (see the callout above), and Direct2D's OS/driver-managed resource caches don't have that problem β verified directly: a fast-hover-and-repaint-burst stress test that spiked Vello to 600β700 MB produced zero measurable growth on Direct2D.
Experimental and Windows-only. Never selected by auto β you must opt
in explicitly. On non-Windows targets, requesting 'direct2d' logs a
warning and falls back to 'skia' rather than failing. <Canvas3D> is not
yet supported on a Direct2D-backed window (it's silently skipped with a
log message) β use 'gpu' or 'auto'/'skia' (which upgrades to wgpu
automatically) for apps that need 3D content.
// glyx.config.ts
export default defineConfig({
window: { renderMode: 'direct2d' },
})Keeping the numbers honest
After each release, re-measure and update this guide if the numbers change.
All figures in the table above are from a single 2026-07 session on one
machine (tasks example, Intel UHD 620 integrated GPU) β idle sampling plus
a fast-hover-and-repaint-burst stress test, the same methodology for every
backend so the comparison is apples-to-apples. They are not final,
cross-platform, cross-hardware numbers. If you add heavy assets or large
dependency trees, your app's footprint will differ β use glyx dev --perf
to see live RSS.