waterui-graphics
High-performance GPU rendering primitives for WaterUI applications.
Overview
waterui-graphics provides three distinct APIs for GPU-accelerated rendering, each targeting different levels of abstraction and use cases:
- Canvas - Beginner-friendly 2D vector graphics using Vello (shapes, paths, fills, strokes)
- ShaderSurface - Intermediate shader-based rendering with automatic pipeline setup
- GpuSurface - Advanced low-level wgpu access for custom GPU rendering
All three APIs render at display refresh rates (60-120fps+) and support HDR surfaces when available. The crate automatically handles surface format selection, preferring Rgba16Float for HDR displays and falling back to sRGB formats on SDR displays.
Installation
Add to your Cargo.toml:
[]
= "0.1.0"
Or via the main waterui crate:
[]
= "0.2"
Quick Start
Canvas - Draw 2D Shapes
The simplest way to draw vector graphics:
use Canvas;
use ;
use Color;
use *;
ShaderSurface - WGSL Shaders Made Easy
Load and render fragment shaders with automatic uniform management:
use shader;
use *;
The shader automatically receives these uniforms:
struct Uniforms {
time: f32, // Elapsed time in seconds
resolution: vec2<f32>, // Surface size in pixels
_padding: f32,
}
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
@fragment
fn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
let t = uniforms.time;
return vec4<f32>(uv.x, uv.y, sin(t), 1.0);
}
GpuSurface - Full wgpu Control
For advanced rendering pipelines, implement the GpuRenderer trait:
use ;
use *;
Core Concepts
Canvas Drawing API
Canvas provides a callback-based API where you receive a DrawingContext each frame:
- Shapes - Fill and stroke circles, rectangles, lines, and arbitrary paths using
kurbogeometry primitives - Styling - Apply solid colors or gradients using
penikobrushes - Layers - Push clip layers and alpha layers for compositing effects
- Performance - Renders via Vello at full GPU speed with anti-aliasing
The DrawingContext provides helper methods:
ctx.size // Canvas dimensions as kurbo::Size
ctx.center // Center point
ctx.fill // Fill a shape with solid color
ctx.fill_brush // Fill with gradient/pattern
ctx.stroke // Stroke a shape outline
ctx.push_clip // Begin clipping region
ctx.push_alpha // Begin alpha layer
ctx.pop_layer // End layer
ctx.scene // Access underlying Vello scene
ShaderSurface Uniforms
ShaderSurface automatically injects a uniform buffer accessible via @group(0) @binding(0):
time: f32- Elapsed seconds since shader creation (for animations)resolution: vec2<f32>- Current surface size in pixels- Fragment input
uv: vec2<f32>- Normalized coordinates (0.0 to 1.0)
GpuRenderer Lifecycle
The GpuRenderer trait defines three lifecycle methods:
setup()- Called once when GPU resources are ready; create pipelines, buffers, bind groupsresize()- Called when surface size changes (before render); recreate size-dependent resourcesrender()- Called each frame withGpuFramecontaining device, queue, texture, and dimensions
HDR Support
All three APIs automatically detect and utilize HDR surfaces:
// In setup()
if ctx.is_hdr
// In render()
if frame.is_hdr
HDR surfaces use Rgba16Float format when available, allowing color values beyond 1.0 for highlights and bloom effects.
Examples
Drawing with Gradients
use Canvas;
use Circle;
use ;
new
Inline Shader
use ShaderSurface;
new
Custom Render Pipeline
See /Users/lexoliu/Coding/waterui/examples/flame/src/lib.rs for a complete example implementing:
- Multi-pass HDR rendering
- Procedural flame shader with fractal noise
- Bloom post-processing with separable Gaussian blur
- ACES tonemapping with vignette and film grain
API Overview
Canvas Module
Canvas::new(draw_fn)- Create canvas with drawing callbackDrawingContext- Frame-by-frame drawing context with shape rendering methods- Re-exports:
kurbo(2D geometry),peniko(colors, brushes, gradients)
ShaderSurface Module
ShaderSurface::new(wgsl_source)- Create surface from WGSL fragment shader stringshader!(path)- Macro to load shader from file at compile time- Automatic uniforms:
time,resolution
GpuSurface Module
GpuSurface::new(renderer)- Create surface with customGpuRendererGpuRenderertrait - Implement for custom GPU rendering logicGpuContext- GPU resources during setup (device, queue, surface format)GpuFrame- Frame data during render (device, queue, texture, view, dimensions)preferred_surface_format(caps)- Helper to select best surface format (HDR preferred)
Re-exported Dependencies
wgpu- Direct access to wgpu types forGpuRendererimplementationsbytemuck- Safe byte conversions for uniform bufferskurbo- 2D geometry (viavello::kurbo)peniko- Styling primitives (viavello::peniko)
Features
Default Features
canvas- Enables Canvas API (depends onwgpuandvello)
Optional Features
wgpu- Enables GpuSurface and ShaderSurface (no Canvas)
All features are enabled by default. To use only lower-level GPU APIs without Vello:
[]
= { = "0.1.0", = false, = ["wgpu"] }
Performance Notes
- Canvas uses Vello's GPU-accelerated vector renderer with area-based anti-aliasing
- All rendering stretches to fill available space by default (
StretchAxis::Both) - Use
.size(width, height)modifier to constrain dimensions - ShaderSurface compiles WGSL at setup time; compilation errors appear in logs
- GpuSurface provides zero-cost abstraction over raw wgpu rendering
Platform Support
Graphics rendering requires a platform backend that supports wgpu:
- Apple (iOS, macOS) - Metal backend
- Android - Vulkan backend
- Hydrolysis - CPU rendering via Vello/tiny-skia (experimental)
Terminal UI backend (tui) does not support GPU rendering.