vello_hybrid Reference
Hybrid CPU/GPU 2D vector renderer. CPU handles path processing and strip generation; GPU handles rendering and compositing.
Quick Reference
| Operation | Method | Notes |
|---|---|---|
| Create scene | Scene::new(width: u16, height: u16) | Dimensions are u16 |
| Reset between frames | scene.reset() | Required - clears state and encoded paints |
| Set paint | scene.set_paint(impl Into<Paint>) | Solid, Gradient, or Image |
| Fill rect | scene.fill_rect(&Rect) | Fast path for rectangles |
| Fill path | scene.fill_path(&BezPath) | General path filling |
| Stroke path | scene.stroke_path(&BezPath) | Uses current stroke settings |
| Set stroke | scene.set_stroke(Stroke) | Width, caps, joins |
| Set transform | scene.set_transform(Affine) | Applied to geometry |
| Set paint transform | scene.set_paint_transform(Affine) | Applied to paint coordinates |
Clipping: Two Mechanisms
code
push_clip_path() push_clip_layer()
│ │
▼ ▼
Fast, immediate Uses GPU slots
No blend modes Supports blend/opacity
No layer overhead Requires slot cleanup
│ │
▼ ▼
pop_clip_path() pop_clip_layer()
Use push_clip_path() for simple geometric clipping.
Use push_clip_layer() only when you need blend modes or layer opacity.
Rendering (wgpu)
rust
use vello_hybrid::{Renderer, RenderTargetConfig, RenderSize};
let config = RenderTargetConfig {
format: surface.format(), // or Rgba8Unorm for headless
width: window_width, // u32
height: window_height, // u32
};
let mut renderer = Renderer::new(&device, &config);
let render_size = RenderSize { width, height }; // u32 values
renderer.render(&scene, &device, &queue, &mut encoder, &render_size, &view)?;
Scene vs RenderSize: Scene uses u16 dimensions (coordinate space). RenderSize uses u32 (output resolution). They can differ for scaling.
Common Patterns
Gradient Fill
rust
use vello_common::peniko::{Gradient, LinearGradientPosition, ColorStop, ColorStops, Extend};
let gradient = Gradient {
kind: LinearGradientPosition { start, end }.into(),
stops: ColorStops::from([
ColorStop::from((0.0, color1)),
ColorStop::from((1.0, color2)),
].as_slice()),
extend: Extend::Pad,
..Default::default()
};
scene.set_paint(gradient);
Image Drawing
rust
use vello_hybrid::{Renderer, Pixmap};
use vello_common::paint::{Image, ImageSource};
use vello_common::peniko::ImageSampler;
// Upload image to atlas (once) - requires encoder
let image_id = renderer.upload_image(&device, &queue, &mut encoder, &pixmap);
// Draw (per frame)
let image = Image {
image: ImageSource::OpaqueId(image_id),
sampler: ImageSampler::default(),
};
scene.set_paint(image);
scene.fill_rect(&rect);
// Cleanup when done - also requires encoder
renderer.destroy_image(&device, &queue, &mut encoder, image_id);
AtlasWriter types: Pixmap, Arc<Pixmap>, or wgpu::Texture implement AtlasWriter.
Pitfalls
| Issue | Cause | Fix |
|---|---|---|
| State bleeds between frames | Missing reset() | Call scene.reset() before each frame |
| Nothing renders | Paint alpha = 0 | Solid colors with alpha=0 are skipped as optimization |
SlotsExhausted error | Too many nested clip layers | Reduce nesting or use push_clip_path() instead |
| Filter effects panic | Not implemented | push_layer() with filter and set_filter_effect() are unimplemented |
| GPU memory leak | Forgot destroy_image() | Always destroy images when no longer needed |
Imports
rust
// Scene and rendering
use vello_hybrid::{Scene, Renderer, RenderTargetConfig, RenderSize};
// Geometry (from kurbo via vello_common)
use vello_common::kurbo::{Affine, BezPath, Circle, Point, Rect, Shape};
// Paint types (from peniko via vello_common)
use vello_common::peniko::{
BlendMode, Color, Fill, Gradient, Image, Stroke,
ColorStop, ColorStops, Extend, LinearGradientPosition, RadialGradientPosition,
};
use vello_common::peniko::color::palette::css::*; // Named colors
WebGL Backend (WASM only)
rust
#[cfg(target_arch = "wasm32")] use vello_hybrid::WebGlRenderer; let mut renderer = WebGlRenderer::new(canvas_element); renderer.render(&scene, &render_size)?;