Graphics Programming Rust Development Jun 09, 2026 1 min de lecture

Stop Using CPU-Bound Renderers! Vello Is the 2D GPU Secret

B
Bright Coding
Auteur
Stop Using CPU-Bound Renderers! Vello Is the 2D GPU Secret
Advertisement

Stop Using CPU-Bound Renderers! Vello Is the 2D GPU Secret Top Developers Are Hiding

What if I told you that everything you know about 2D rendering is fundamentally broken?

For decades, we've accepted the painful reality: complex vector graphics, interactive UI, and high-resolution scenes mean one thing—CPU bottlenecks, stuttering frame rates, and the endless compromise between quality and performance. Skia chokes on massive scenes. Cairo was never built for the GPU era. And don't get me started on the texture atlas nightmares of browser <canvas>.

But here's the secret that engineers at the cutting edge of Rust graphics have already discovered. Vello, a GPU compute-centric 2D renderer from the Linebender collective, doesn't just use your GPU—it weaponizes it. We're talking 177 FPS on the paris-30k test scene at 1600×1600 resolution on an M1 Max. Not a demo. Not a tech talk. Real, measurable performance that traditional renderers simply cannot touch.

The trick? Vello eliminates sequential CPU bottlenecks by leveraging compute shaders and parallel prefix-sum algorithms—the same mathematical machinery that powers supercomputing—applied to the humble task of drawing shapes, text, and gradients. No more sorting on the CPU. No more clipping through intermediary textures. The GPU does what it was designed to do: massive parallel computation.

If you're building a PDF reader, a GUI toolkit, a game engine, or any application where 2D visuals matter, ignoring Vello isn't just conservative—it's actively costing you performance. In this deep dive, I'll expose exactly how Vello works, why it's leaving Skia and Cairo in the dust, and how you can integrate it into your stack today. The future of 2D rendering is compute, not compromise.


What Is Vello? The GPU Compute Renderer Rewriting the Rules

Vello is a 2D graphics rendering engine written in Rust, developed by the Linebender open-source collective. Its mission is deceptively simple yet technically radical: render complex 2D scenes with interactive or near-interactive performance by moving virtually all rendering work to the GPU compute pipeline.

Born from the ashes of piet-gpu—Raph Levien's earlier experimental renderer—Vello represents a deliberate architectural pivot. Where piet-gpu relied on a custom hardware abstraction layer called piet-gpu-hal, Vello embraces wgpu, the cross-platform WebGPU implementation in Rust. This shift, detailed in Levien's blog post Requiem for piet-gpu-hal, wasn't surrender—it was strategic consolidation. By building on WebGPU, Vello gains instant portability across Vulkan, Metal, DirectX 12, and emerging web standards.

Vello occupies the same ecosystem position as Skia (Chrome's renderer), Cairo (the venerable GNOME/Linux workhorse), and its direct predecessor Piet (Linebender's earlier CPU-focused API). It speaks the same visual language: PostScript-inspired paths, Bézier curves, gradients, images, and text—the primitives that power SVG and HTML5 Canvas. But under the hood, it's an entirely different beast.

The project is currently alpha-state software, with active development on blur effects, conflation artifact elimination, GPU memory optimization, and glyph caching. Yet even in this early form, it's already the rendering backend for Xilem, Linebender's emerging Rust GUI toolkit. That production commitment speaks volumes.

Why is Vello trending now? Three converging forces: the maturation of WebGPU across browsers and native platforms, Rust's ascendancy in systems programming, and a genuine industry frustration with the performance ceilings of traditional CPU-GPU hybrid renderers. Developers are hungry for alternatives. Vello delivers.


Key Features: The Technical Architecture That Enables Insane Performance

Vello's feature set isn't a checklist—it's a fundamental reimagining of how 2D rendering maps to modern GPU hardware.

Compute Shader-Centric Pipeline

Traditional renderers use the GPU's rasterization pipeline: vertex shaders, fragment shaders, lots of draw calls, and mountains of state changes. Vello flips this model. It uses compute shaders—GPU programs that can read and write arbitrary memory, not just process triangles—to execute parallel algorithms directly on the GPU.

The crown jewel is the parallel prefix-sum approach to path rendering. In conventional renderers, path filling requires sequential sorting and accumulation of edge crossings. Vello decomposes this into parallel operations using prefix sums (also known as scan algorithms), enabling thousands of path segments to be processed simultaneously. This is the same technique used in GPU-accelerated database queries and machine learning pipelines—now applied to drawing your SVG tiger.

Minimal Temporary Buffer Usage

CPU-bound renderers and even GPU hybrids often allocate intermediary textures for clipping, masking, and compositing. These allocations are performance poison: memory bandwidth killers that synchronize CPU and GPU. Vello's compute approach dramatically reduces temporary buffer dependency, keeping data on GPU memory and minimizing PCIe bus traffic.

wgpu Cross-Platform Foundation

By building on wgpu v29.0.1, Vello inherits support for:

  • Vulkan (Linux, Android, Windows)
  • Metal (macOS, iOS)
  • DirectX 12 (Windows)
  • WebGPU (Chrome, emerging Firefox/Safari support)

This isn't theoretical portability. The same Vello code runs native desktop, mobile, and web—with compute shader fidelity preserved.

PostScript-Compatible API

Vello exposes familiar primitives: fill, stroke, push_layer/pop_layer, affine transforms, gradients, and image compositing. This API compatibility means existing SVG and Canvas content ports naturally. The GhostScript Tiger—classic SVG benchmark—renders out of the box in Vello's winit example.

Scene Graph Architecture

Rather than immediate-mode drawing, Vello builds retained scene descriptions. You construct a Scene, populate it with drawing commands, then render that scene. This enables optimizations like scene caching, incremental updates, and efficient re-rendering—critical for UI applications.


Use Cases: Where Vello Destroys the Competition

1. High-Performance GUI Toolkits

Xilem's choice of Vello isn't accidental. Modern GUIs demand: smooth scrolling through complex documents, real-time resizing, blur effects, drop shadows, and 60+ FPS animations. Traditional CPU renderers crumble under this load. Vello's GPU compute approach maintains fluid interactivity even with hundreds of layered elements, transparency groups, and live text.

2. PDF and Document Viewers

PDF rendering is pathological for traditional engines: arbitrary precision paths, complex clipping, embedded fonts, and massive page dimensions. Vello's parallel path processing and GPU-resident scene representation directly address these pain points. The paris-30k benchmark—30,000+ path elements—demonstrates this scaling headroom.

3. Browser-Adjacent Web Applications

With WebGPU maturing in Chrome, Vello enables native-grade 2D performance inside the browser. The cargo-run-wasm toolchain compiles Vello to wasm32-unknown-unknown, producing web deployments that rival desktop performance. For data visualization tools, design applications, and creative coding platforms, this is transformative.

4. Game Engine UI and 2D Content

The bevy_vello integration brings Vello into the Bevy ecosystem. Game developers gain: runtime SVG loading, Lottie animation playback, and procedural 2D content—all GPU-accelerated, all composable with 3D scenes. No more baking UI to texture atlases or accepting blurry rasterized text.

5. Creative Coding and Generative Art

Vello's scene-based API and compute performance make it ideal for generative systems: real-time fractal exploration, particle systems with vector trails, and algorithmic illustration. The with_winit example's test scene collection demonstrates this creative flexibility.


Step-by-Step Installation & Setup Guide

Ready to harness Vello? Here's your complete path from zero to rendering.

Prerequisites

Vello requires Rust 1.88 or later. Verify your toolchain:

rustc --version

If outdated, update via rustup:

rustup update

Clone and Explore the Repository

git clone https://github.com/linebender/vello.git
cd vello

Run the Winit Example (Desktop)

The fastest validation of your setup:

# Run the interactive winit demo with GhostScript Tiger
cargo run -p with_winit

This compiles Vello, its wgpu dependencies, and launches a window rendering the classic SVG benchmark. Add your own SVG files to examples/assets/downloads/ for custom testing.

WebAssembly Build (Web)

For browser deployment, first add the WASM target:

rustup target add wasm32-unknown-unknown

Then build and serve using cargo-run-wasm:

cargo run_wasm -p with_winit --bin with_winit_bin

Warning: WebGPU browser support is evolving. Chrome offers the most stable experience; Firefox and Safari require experimental flags.

Android Build

Mobile deployment uses cargo-apk:

Advertisement
cargo apk run -p with_winit --lib

For release builds, configure signing in examples/with_winit/Cargo.toml:

[package.metadata.android.signing.release]
path = "$HOME/.android/debug.keystore"
keystore_password = "android"

Pass static configuration via environment variables when cargo apk can't forward arguments:

VELLO_STATIC_LOG="vello=trace" VELLO_STATIC_ARGS="--test-scenes" cargo apk run -p with_winit --lib

Dependency Integration

Add to your Cargo.toml:

[dependencies]
vello = "0.3"
wgpu = "29"

The vello crate re-exports kurbo (geometric primitives) and peniko (paint/styling types) for seamless integration.


REAL Code Examples from the Vello Repository

Let's dissect actual Vello code, straight from the official README and examples. These aren't toy snippets—they're production patterns.

Example 1: Core Rendering Pipeline

This is the canonical integration pattern for using Vello as your application's renderer:

use vello::{
    kurbo::{Affine, Circle},
    peniko::{Color, Fill},
    *,
};

// Initialize wgpu and get handles
let (width, height) = ...;
let device: wgpu::Device = ...;
let queue: wgpu::Queue = ...;

// Create the Vello renderer with default GPU options
let mut renderer = Renderer::new(
   &device,
   RendererOptions::default()
).expect("Failed to create renderer");

// Create scene and draw stuff in it
let mut scene = vello::Scene::new();

// Draw a filled circle with specific color and transform
scene.fill(
   vello::peniko::Fill::NonZero,    // Winding rule: NonZero for standard filling
   vello::Affine::IDENTITY,          // No transformation applied
   vello::Color::from_rgb8(242, 140, 168), // Hot pink color
   None,                             // No gradient or pattern brush
   &vello::Circle::new((420.0, 200.0), 120.0), // Center (420, 200), radius 120
);

// Draw more stuff with layer isolation for complex compositing
scene.push_layer(...);  // Begin isolated blending group
scene.fill(...);        // Draw within layer
scene.stroke(...);      // Add stroked elements
scene.pop_layer(...);   // End layer, composite to parent

// Allocate GPU texture for output
let texture = device.create_texture(&...);

// Execute GPU rendering: scene → texture
renderer
   .render_to_texture(
      &device,
      &queue,
      &scene,
      &texture,
      &vello::RenderParams {
         base_color: palette::css::BLACK, // Clear to black before rendering
         width,                            // Output dimensions
         height,
         antialiasing_method: AaConfig::Msaa16, // 16x MSAA for quality
      },
   )
   .expect("Failed to render to a texture");

// texture now contains rendered pixels; blit to surface with wgpu::util::TextureBlitter

What's happening here? This pattern establishes the complete Vello workflow: wgpu context setup → renderer initialization → scene construction with drawing commands → GPU execution → texture output. The Scene is a retained, serializable description of content—not immediate GPU commands. This enables scene reuse, diffing, and cross-thread construction. The RenderParams configure output format and antialiasing; Msaa16 provides exceptional quality for vector edges.

Example 2: Quickstart Command Execution

The simplest possible Vello experience—run from repository root:

cargo run -p with_winit

This single command demonstrates Vello's workspace architecture. The -p with_winit flag selects the example package, which has independent dependencies for faster builds. The binary renders the GhostScript Tiger SVG and any user-provided SVGs from examples/assets/downloads/.

For test scenes showcasing Vello's capabilities:

cargo run -p with_winit -- --test-scenes

Example 3: WebAssembly Deployment Command

# Ensure WASM target is installed
rustup target add wasm32-unknown-unknown

# Build and serve web version
# --bin with_winit_bin required because package name differs from binary name
cargo run_wasm -p with_winit --bin with_winit_bin

This uses cargo-run-wasm to orchestrate the complex WASM build pipeline: Rust compilation to WASM, web server startup, and browser-ready packaging. The explicit --bin flag resolves naming ambiguity in the workspace.

Example 4: Android Environment Configuration

# Standard Android execution
cargo apk run -p with_winit --lib

# With static logging and argument injection for Android's limited runtime
VELLO_STATIC_LOG="vello=trace" VELLO_STATIC_ARGS="--test-scenes" cargo apk run -p with_winit --lib

Android's application model doesn't permit command-line arguments or environment variable passing at runtime. Vello's workaround—compile-time embedding via VELLO_STATIC_LOG and VELLO_STATIC_ARGS—enables debugging and configuration without platform-specific build variants.


Advanced Usage & Best Practices

Profile Your GPU, Not Just Your CPU. Vello's performance characteristics differ radically from CPU renderers. Use wgpu's profiling labels and GPU timestamps to identify shader bottlenecks. The VELLO_STATIC_LOG="vello=trace" configuration reveals internal pipeline stages.

Batch Scene Construction. Scene is cheap to create but richer operations like push_layer/pop_layer have GPU memory implications. For scrolling lists or animated content, construct scenes off the main thread and swap atomically.

Leverage MSAA Judiciously. AaConfig::Msaa16 produces gorgeous edges but doubles GPU memory bandwidth. For UI chrome and text, AaConfig::Area (analytic antialiasing) often suffices at lower cost. Profile both on your target hardware.

Cache Glyph Renders. Vello's glyph caching (in active development) currently requires manual intervention. Pre-render text to Scene fragments and reuse—especially for static labels and icons.

Monitor WebGPU Evolution. Browser WebGPU implementations vary. Test Chrome stable for production web deployments; track Firefox Nightly and Safari Technology Preview for emerging compatibility.


Comparison with Alternatives: Why Vello Wins

Dimension Vello Skia Cairo Web Canvas
GPU Architecture Compute shaders (parallel prefix-sum) Raster pipeline + compute hybrids CPU-only (no GPU) Raster pipeline
Path Rendering Direct GPU parallelization CPU pre-processing, GPU tessellation CPU rasterization CPU tessellation or GPU tessellation
Temporary Buffers Minimal Moderate (intermediate surfaces) Extensive (image surfaces) Moderate
Cross-Platform Native + Web via WebGPU Native only (complex web ports) Native only Web only
Language Rust (memory-safe) C++ C JavaScript↗ Bright Coding Blog
Scene Complexity Scaling Excellent (177 FPS paris-30k) Good (degrades with path count) Poor (CPU-bound) Poor (single-threaded)
Integration Ecosystem Xilem, Bevy, winit Chrome, Flutter, Android GTK, Firefox (legacy) Browser only
License Apache-2.0/MIT + Unlicense (shaders) BSD-style LGPL/MPL N/A

The Verdict: Skia remains formidable for mobile-optimized 2D and established platform integration. Cairo is legacy—capable but architecturally obsolete. Web Canvas is ubiquitous but performance-constrained. Vello uniquely combines: GPU compute scalability, Rust's safety guarantees, web-native deployment, and open licensing that encourages research adoption.


FAQ: Your Vello Questions Answered

Q: Does Vello require a dedicated GPU, or will integrated graphics work? A: Any GPU supporting WebGPU default limits suffices—including Intel integrated graphics and Apple Silicon. Performance scales with compute shader throughput, but Vello runs broadly.

Q: Can I use Vello without wgpu? A: No. Vello is architecturally bound to wgpu for cross-platform GPU abstraction. This is a deliberate, strategic choice—not a limitation.

Q: Is Vello production-ready today? A: Alpha status with active development. Suitable for experimental projects, research, and early adopters. Not yet recommended for mission-critical deployments without risk assessment.

Q: How does Vello compare to WebGPU-based renderers in other languages? A: Vello's compute-centric approach is distinctive. Most WebGPU renderers still use traditional raster pipelines. The parallel prefix-sum methodology is Vello's research contribution.

Q: Can I render existing SVG content with Vello? A: Yes, via vello_svg. Lottie animations through velato. Bevy integration through bevy_vello.

Q: What's the migration path from Piet or piet-gpu? A: Vello supersedes piet-gpu. API concepts translate, but implementation differs substantially. The Linebender Zulip community provides migration guidance.

Q: Why Rust specifically? A: Memory safety without garbage collection, zero-cost abstractions, and excellent wgpu bindings. Rust's ownership model eliminates entire categories of GPU resource leaks.


Conclusion: The Compute Revolution in 2D Rendering Starts Now

Vello isn't incrementally better than existing 2D renderers—it's architecturally different. By committing fully to GPU compute shaders and parallel algorithms, it escapes the performance traps that have constrained vector graphics for decades. The 177 FPS paris-30k benchmark isn't a fluke; it's a demonstration of what becomes possible when you stop forcing sequential CPU thinking onto massively parallel GPU hardware.

Yes, Vello is alpha software. Yes, you'll encounter rough edges: incomplete blur effects, evolving glyph caching, and WebGPU's maturing browser support. But the trajectory is unmistakable. Xilem's production commitment, the Bevy integration, and the active Linebender community signal that this isn't experimental abandonware—it's the foundation of next-generation 2D graphics in Rust.

The question isn't whether GPU compute rendering will dominate 2D graphics. It's whether you'll be early to the transition or scrambling to catch up. Skia and Cairo had their decades. The future belongs to engines that treat every pixel as a parallel computation opportunity.

Clone the repository. Run the winit demo. Measure the performance yourself. The code is at github.com/linebender/vello—Apache-2.0/MIT licensed, with shader code even released to the public domain via Unlicense. Join the discussion on Linebender Zulip's #vello channel. Contribute, benchmark, and help shape the future of 2D rendering.

The GPU compute revolution isn't coming. It's already rendering at 177 FPS on your hardware. Stop waiting. Start building with Vello today.

Advertisement
Advertisement

Commentaires 0

Aucun commentaire pour l'instant. Soyez le premier à réagir !

Laisser un commentaire

Advertisement