Software renderer
raylib 6.0 adds rlsw, a software renderer backend that renders into an
in-memory framebuffer with no GPU or window required. raylib-rs exposes it
via the software_renderer Cargo feature and the test_harness module
(source)
— a set of helpers that initialise a windowless context, draw a frame,
read the framebuffer back, and let you probe pixel values. Note: test_harness
is gated on #[cfg(feature = "software_renderer")] and does not appear on
docs.rs (docs.rs builds with only the nobuild feature).
This is the mechanism behind raylib-rs’s Tier-2 render tests: the CI
software-render job runs on all three platforms (ubuntu/macOS/windows)
without a display server.
API surface
software_rendererCargo feature — enables the rlsw backend. Addfeatures = ["software_renderer"]to yourCargo.tomldependency.with_headless(w, h, body)— initialise aw × hwindowless context, runbody(rl, thread), then tear down. Call at most once per test process (raylib is single-init per process).render_frame(rl, thread, draw)— draw one frame via thedrawclosure and return a normalized top-left RGBAImage. Coordinates and colors match what you drew:Color::REDat screen(x, y)reads back as red at(x, y).render_frame_raw(rl, thread, draw)— raw readback: BGRA bytes, Y-inverted. Use only when you need the unprocessed rlsw output.pixel_at(img, x, y)— read the pixel at(x, y)as aPxvalue withr/g/b/afields.assert_pixel(img, x, y, expected, tol)— assert the RGB channels at(x, y)matchexpectedwithin a per-channel tolerancetol. Alpha is intentionally ignored (the Memory platform readback does not guarantee alpha fidelity).
Example
The example below is rust,ignore because raylib’s CI build of the rlib that
backs mdbook test uses the full feature, which falls through to
PLATFORM=Desktop with the OpenGL backend. test_harness lives under
#[cfg(feature = "software_renderer")], so it isn’t compiled into that rlib.
To actually run a software-renderer test, compile the crate with
--no-default-features --features software_renderer,SUPPORT_MODULE_RTEXTURES,SUPPORT_MODULE_RSHAPES,SUPPORT_MODULE_RTEXT,SUPPORT_MODULE_RMODELS,SUPPORT_IMAGE_GENERATION,raygui
(this is what check.yml/test.yml do for the Tier-2 render tests). The WS9
showcase pipeline is the eventual home for runnable demos.
extern crate raylib;
use raylib::prelude::*;
use raylib::test_harness::{with_headless, render_frame, assert_pixel};
#[test]
fn red_rectangle_center_pixel() {
with_headless(256, 256, |rl, thread| {
let img = render_frame(rl, thread, |d| {
d.clear_background(Color::BLACK);
d.draw_rectangle(64, 64, 128, 128, Color::RED);
});
// Center of the rectangle should be red.
assert_pixel(&img, 128, 128, Color::RED, 0);
// A corner well outside the rectangle should be black.
assert_pixel(&img, 4, 4, Color::BLACK, 0);
});
}
Gotchas
software_rendereris not enabled by thefullfeature alias. Thefullalias explicitly excludes mutually-exclusive backend selectors (opengl_*,sdl,wayland,drm,software_renderer) perraylib/Cargo.toml. A--features fullbuild therefore defaults toPLATFORM=Desktopwith OpenGL —test_harnesswon’t be compiled in. To use the software renderer, build with--no-default-features --features software_renderer,...(see the canonical command below). Thecompile_error!inraylib-sys/build.rsonly fires when an explicitopengl_*(ordrm) feature is combined withsoftware_renderer;fullalone does not trigger it.software_rendereris mutually exclusive withwasm32-unknown-emscripten(tracked-deferred). rlsw-on-Emscripten is not yet supported; seedocs/superpowers/notes/ws6b-complete.md.- All required raylib modules must be linked.
The harness requires
SUPPORT_MODULE_RSHAPES,SUPPORT_MODULE_RTEXTURES,SUPPORT_MODULE_RTEXT,SUPPORT_MODULE_RMODELS,SUPPORT_MODULE_RAUDIO, plusSUPPORT_IMAGE_GENERATION(the safegen_image_*family is currently ungated; MSVC link fails without it). Therayguifeature is also enabled in CI sorender_guitests link cleanly. Disabling any required module causes a link error; see the memory notesoftware-renderer-headless-testing. with_headlessis single-init. raylib can only be initialised once per process. Run software-renderer tests with:cargo test -p raylib --no-default-features \ --features software_renderer,SUPPORT_MODULE_RTEXTURES,SUPPORT_MODULE_RSHAPES,SUPPORT_MODULE_RTEXT,SUPPORT_MODULE_RMODELS,SUPPORT_IMAGE_GENERATION,raygui \ -- --test-threads=1--test-threads=1is required because the harness initialises raylib’s platform layer once per process. In a test suite, wrap all headless tests inside a singlewith_headlesscall or use a process-global init strategy (e.g.,std::sync::OnceLock).
See also
- Features and platforms — feature flag reference.
test_harnesssource — module is cfg-gated onsoftware_renderer; not surfaced on docs.rs.docs/superpowers/notes/ws4b-complete.md— WS4b harness design rationale.docs/superpowers/notes/ws5-complete.md— readback normalization details.