oxiui-render-soft — Pure-Rust software (CPU) render backend for OxiUI

oxiui-render-soft is the Pure-Rust software renderer for OxiUI. It rasterizes a [oxiui_core::paint::DrawList] entirely on the CPU into an in-memory 0xAARRGGBB framebuffer — no GPU, no window, and no display connection required. Every pixel is produced by Rust code in this crate (with png for PNG export and the optional oxiui-text pipeline for glyph rasterization), making it the canonical backend for headless rendering, CI smoke tests, ffi-audit containers, and embedded targets.
The crate is built around a clip-correct [Canvas] that replays draw commands through a [ClipStack], plus a [SoftBackend] that implements [oxiui_core::paint::RenderBackend]. It includes a full 2-D rasterization stack — scanline polygon fill with anti-aliasing, Bézier paths, gradients, box shadows via Gaussian blur, ordered dithering, and a tile iterator for (optionally rayon-parallel) rendering. #![forbid(unsafe_code)] is enforced crate-wide.
Installation
[dependencies]
oxiui-render-soft = "0.2.1"
To build the GPU-free audit configuration explicitly, disable default features:
[dependencies]
oxiui-render-soft = { version = "0.2.1", default-features = false }
Quick Start
Render a scene headlessly and export it as a PNG — no display needed:
use oxiui_core::Color;
use oxiui_render_soft::headless::render_headless_scene;
# fn main() -> Result<(), oxiui_render_soft::SoftRenderError> {
let buffer = render_headless_scene(128, 96, |canvas| {
canvas.fill_rect(16.0, 16.0, 64.0, 48.0, Color(255, 0, 0, 255));
canvas.fill_circle(96.0, 48.0, 20.0, Color(0, 128, 255, 255));
});
assert_eq!(buffer.width, 128);
assert!(buffer.has_content());
buffer.save_png(std::path::Path::new("/tmp/scene.png"))?;
# Ok(())
# }
Replaying a DrawList through SoftBackend
use oxiui_core::paint::{DrawList, RenderBackend};
use oxiui_core::{geometry::Rect, Color};
use oxiui_render_soft::{SoftBackend, headless::PixelFormat};
# fn main() -> Result<(), oxiui_core::UiError> {
let mut backend = SoftBackend::with_background(64, 64, Color(26, 27, 38, 255));
let mut list = DrawList::new();
list.push_rect(Rect::new(8.0, 8.0, 48.0, 48.0), Color(255, 255, 255, 255));
backend.execute(&list)?;
let bytes = backend.to_bytes(PixelFormat::Bgra8);
assert_eq!(bytes.len(), 4 * 64 * 64);
# Ok(())
# }
API Overview
Top-level renderer types
| Item |
Kind |
Description |
SoftRenderer |
struct |
Stateless software renderer. new(), with_size(w, h), clear_frame(w, h, color) -> Result<Vec<u32>, UiError>, render(w, h, bg, draw_fn) -> Framebuffer |
SoftBackend |
struct |
CPU [RenderBackend] that replays a DrawList onto a Framebuffer |
AaMode |
enum |
Anti-aliasing strategy: None, Msaa4x, Supersampling |
ShadowQuality |
enum |
Shadow fidelity: Off, Low, High |
SoftRenderQuality |
struct |
Combined preset (aa_mode, shadow_quality); low(), balanced(), high() |
SoftRenderError |
enum |
Crate error type (see below) |
SoftBackend methods
SoftBackend implements [oxiui_core::paint::RenderBackend].
| Method |
Description |
SoftBackend::new(w, h) |
Backend with a transparent framebuffer |
SoftBackend::with_background(w, h, bg) |
Backend pre-filled with a solid colour |
SoftBackend::with_quality(w, h, quality) |
Backend pre-configured with a [SoftRenderQuality] preset |
set_quality(quality) / quality() |
Set / borrow the active quality preset |
frame() |
Borrow the underlying [Framebuffer] |
into_framebuffer() |
Consume the backend, returning the [Framebuffer] |
clear(color) |
Fill the framebuffer with a solid colour |
width() / height() |
Framebuffer dimensions in pixels |
to_bytes(format) |
Export pixels as a flat byte vector in a [PixelFormat] |
apply_shadow_spec(rect, spec) |
Apply an [oxiui_theme::ShadowSpec] (requires theme feature) |
execute(&list) |
(RenderBackend) replay a DrawList clip-correctly |
surface_size() |
(RenderBackend) target size as Size |
supports_blur/gradients/paths/images() |
(RenderBackend) all return true |
supports_text() |
(RenderBackend) true when the text feature loaded a font |
headless module
Display-free rendering helpers for CI / ffi-audit.
| Item |
Description |
render_headless_once(w, h) -> RgbaBuffer |
Fill a buffer with the COOLJAPAN dark-theme background |
render_headless_scene(w, h, draw_fn) -> RgbaBuffer |
Paint a custom scene via a [Canvas] callback |
RgbaBuffer |
RGBA pixel buffer (width, height, data); has_content(), save_png(path) |
PixelFormat |
Output byte layout: Argb32, Bgra8, Rgb565 |
HEADLESS_BG_COLOR |
[u8; 4] default background (#1A1B26, Tokyo Night) |
framebuffer module
| Item |
Description |
Framebuffer |
CPU pixel buffer (0xAARRGGBB, row-major) |
Framebuffer::new(w, h) / with_fill(w, h, color) |
Allocate transparent / pre-filled |
pixels() / pixels_mut() |
Borrow the raw u32 pixel slice |
width() / height() / clear(color) |
Dimensions and full-buffer fill |
pack(&Color) / pack_rgba(r,g,b,a) / unpack(u32) |
Free functions for 0xAARRGGBB conversion |
draw module — Canvas
Canvas borrows a Framebuffer and owns a [ClipStack]; all drawing is clipped to the current effective clip with straight-alpha source-over compositing.
| Method group |
Methods |
| Construction / state |
new(fb), set_aa(bool), aa field, framebuffer() |
| Clipping |
push_clip(x, y, w, h), pop_clip() |
| Rectangles |
fill_rect, stroke_rect, fill_rounded_rect, fill_rounded_rect_per_corner |
| Circles / ellipses |
fill_circle, fill_ellipse (analytical coverage AA) |
| Lines |
draw_line, draw_line_wu (Wu AA), draw_line_thick, draw_line_dashed |
| Paths |
fill_path, stroke_path |
| Gradients |
fill_linear_gradient_cmd, fill_radial_gradient_cmd |
| Bézier |
draw_quad_bezier, draw_cubic_bezier |
| Images |
blit_rgba, blit_bilinear, blit_nine_slice |
| Shadows |
box_shadow_cmd |
| Supporting types |
SrcImage<'a> (borrowed RGBA view; new, is_valid), DashPattern (new(dash_len, gap_len)) |
Glyph blitting helper: blit_glyph_bitmap(fb, x, y, w, h, pixels, color) (re-exported at crate root).
clip module
| Item |
Description |
ClipRect |
Integer clip rectangle with contains, from_rect, full, intersection |
ClipStack |
Stack of intersected clip rects; push, pop, current |
scanline module
| Item |
Description |
fill_polygon |
Active-Edge-Table scanline fill with vertical-supersample coverage AA; row and span ranges are clamped to the framebuffer's own dimensions, so out-of-range vertex coordinates cannot force unbounded loop iteration |
fill_polygon_clipped |
Same as fill_polygon, additionally clipped to a ClipRect |
fill_triangle |
Triangle fill convenience |
FillRule |
Winding rule: even-odd / non-zero |
Rasterizer / RasterizerScratch |
Reusable scratch-buffer rasterizer (fill_polygon/fill_polygon_clipped methods) that avoids per-polygon heap allocation in tight loops |
path module
| Item |
Description |
Path / PathBuilder |
2-D paths with Bézier flattening |
StrokeStyle |
Stroke configuration |
Cap / Join |
Line-cap and line-join styles |
gradient module
| Item |
Description |
LinearGradient / RadialGradient |
Gradient fills with sRGB colour interpolation |
GradientStop |
Colour stop |
lerp_color |
sRGB colour interpolation helper |
blend module
| Item |
Description |
BlendMode |
Extended blend modes: multiply / screen / overlay / darken / lighten |
RgbaUnit |
Premultiplied-alpha unit helper |
blend_mode / blend_pixel / composite_into |
Blend / composite functions. composite_into's bounds-check guard computes w * h * 4 with checked usize arithmetic (rather than raw u32 math) so an oversized caller-supplied w/h is rejected outright instead of silently wrapping past the real buffer length |
shadow module
| Item |
Description |
box_shadow |
Box shadow via separable 1-D Gaussian blur |
gaussian_blur_alpha |
Alpha-channel Gaussian blur |
gaussian_kernel(blur_radius) |
Build a half-width 1-D Gaussian kernel for a given blur radius |
GaussianCache |
Cache of precomputed Gaussian kernels |
fft_blur module (fft-blur feature)
FFT-accelerated alternative to shadow::gaussian_blur_alpha for large blur kernels (radius ≥ 32px), using oxifft::convolve_mode.
| Item |
Description |
gaussian_blur_alpha_fft(alpha, w, h, kernel) |
Separable Gaussian blur via FFT convolution when fft-blur is enabled; when the feature is off, this same function forwards to shadow::gaussian_blur_alpha (direct convolution) so callers always get a real blur — the feature only changes performance, never behaviour |
should_use_fft_blur(blur_radius) -> bool |
true once blur_radius >= FFT_BLUR_MIN_RADIUS |
FFT_BLUR_MIN_RADIUS |
Threshold (32.0) above which FFT convolution outperforms direct convolution |
simd_fill module
Pure-Rust SIMD (wide crate) bulk pixel operations behind the simd feature; every function also has a scalar fallback compiled in, so call sites never need to feature-gate.
| Item |
Description |
fill_solid(pixels, color) |
8-lane SIMD solid fill over a &mut [u32] buffer |
alpha_blend_row(src, dst) |
Premultiplied source-over alpha blend of one pixel row |
gradient_row_horizontal(..) |
8-lane interpolated horizontal gradient row fill |
backend_switch module (wgpu-compat feature)
Runtime CPU/GPU backend switching over the shared DrawList format.
| Item |
Description |
DynBackend |
Enum wrapping either SoftBackend or oxiui-render-wgpu's WgpuBackend, implementing RenderBackend |
DynBackend::soft(w, h) / DynBackend::wgpu(backend) |
Construct from either backend |
kind() / is_soft() / is_wgpu() |
Inspect which backend is active |
as_soft() / as_soft_mut() |
Borrow the inner SoftBackend when active |
BackendKind |
Discriminant enum (Soft, Wgpu) |
canvas_upload module (canvas-2d feature)
Canvas 2D pixel upload path for wasm32 targets; native builds get no-op stubs that always return Ok(()).
| Item |
Description |
upload_framebuffer(fb, canvas_id) |
Upload a Framebuffer to an HTML canvas via putImageData (wasm32) |
upload_rgba(data, w, h, canvas_id) |
Upload a raw RGBA byte buffer to an HTML canvas |
framebuffer_to_rgba8(fb) -> Vec<u8> |
Convert a Framebuffer to a flat RGBA8 byte buffer |
dither module
| Item |
Description |
ordered_dither_rgba |
Bayer-matrix ordered dithering for reduced-bit output |
BayerMatrix |
Ordered-dither threshold matrix |
tile module
| Item |
Description |
Tile / TileIter |
64×64 render-tile iteration |
tiles_for / collect_tiles / render_tiles |
Tile enumeration and serial driver |
render_parallel |
rayon-parallel tile driver (requires parallel feature) |
DirtyRegion |
Dirty-rectangle tracking |
DEFAULT_TILE_SIZE |
Default tile edge length |
Re-exports
When the theme feature is active, [oxiui_theme::ShadowSpec] is re-exported as oxiui_render_soft::ShadowSpec.
Feature Flags
| Feature |
Default |
Description |
text |
yes |
Enable glyph shaping / rasterization via oxiui-text; DrawText commands are rendered instead of skipped |
theme |
no |
Enable oxiui-theme integration (apply_shadow_spec, ShadowSpec re-export) |
parallel |
no |
Enable the rayon-backed parallel tile driver (render_parallel) |
simd |
no |
Enable wide-backed 8-lane SIMD paths in the simd_fill module (fill_solid, alpha_blend_row, gradient_row_horizontal); scalar fallbacks are always compiled in |
fft-blur |
no |
Route large-kernel (blur_radius >= 32px) Gaussian blur through oxifft::convolve_mode instead of direct convolution; without it, gaussian_blur_alpha_fft still blurs correctly by forwarding to the direct-convolution path — the feature only changes performance, never correctness |
wgpu-compat |
no |
Enable the backend_switch module's DynBackend enum for runtime switching between SoftBackend and oxiui-render-wgpu's WgpuBackend |
canvas-2d |
no |
Enable the canvas_upload module's wasm32 Canvas-2D putImageData pixel upload path (native builds get no-op stubs) |
Disable default features (default-features = false) for the GPU- and text-pipeline-free audit build.
Error Variants
SoftRenderError implements std::error::Error and Display.
| Variant |
Description |
Io(String) |
An I/O error (e.g. cannot create or write the PNG output file) |
Png(String) |
A PNG encoding / decoding error |
SoftBackend::execute returns [oxiui_core::UiError] (the shared OxiUI error type).
Related Crates
oxiui — the OxiUI facade crate.
oxiui-core — RenderBackend, DrawList, DrawCommand, Color, UiError, geometry types.
oxiui-render-wgpu — the GPU render path (wgpu) for comparison.
oxiui-text — the text-shaping pipeline used by the text feature.
oxiui-theme — design tokens and ShadowSpec used by the theme feature.
License
Apache-2.0 — COOLJAPAN OU (Team Kitasan)