Rust GUI frameworks
2019 Rendering 2026: The default GPU layer
08

wgpu: the shared GPU layer

One GPU API for Vulkan, Metal, D3D and the browser.

wgpu is a Rust implementation of the WebGPU API that runs on Metal, Vulkan, Direct3D 12, OpenGL and, in a browser, the real WebGPU. Application code is the same everywhere. The first step is always the same: create an instance, ask for an adapter (a physical GPU), then open a device and a queue. The output below is from the Mac that built this book.

wgpu-device/src/bin/one.rs ✔ compiled · pollster 0.4, wgpu 30 · rustc 1.95.0
use book_error::Result;

fn main() -> Result<()> {
    let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());

    // Ask for the best GPU the OS and drivers will give us. Having no GPU is a
    // normal condition, so this is an error value and not a panic.
    let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions::default()))?;
    let info = adapter.get_info();
    println!("{} via {:?}", info.name, info.backend);

    // A device is the logical connection; the queue submits work to it.
    let (_device, _queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor::default()))?;
    Ok(())
}
output
Intel(R) Iris(TM) Plus Graphics via Metal

The adapter reports which backend it used: here an Intel GPU through Metal. Note the constructor: in wgpu 30 an InstanceDescriptor has no Default; you pick new_without_display_handle() or new_with_display_handle(), so that the OpenGL backend can be told whether a display exists. This is the sort of change that shows up in every major version.

wgpu-device/src/bin/two.rs ✔ compiled · pollster 0.4, wgpu 30 · rustc 1.95.0
fn main() {
    // Metal on macOS, Vulkan/GL on Linux, D3D12 on Windows, WebGPU in a browser.
    let mut desc = wgpu::InstanceDescriptor::new_without_display_handle();
    desc.backends = wgpu::Backends::PRIMARY;
    let instance = wgpu::Instance::new(desc);

    // No usable GPU? Ask for a software adapter instead: the route a
    // "software rendering" fallback takes.
    let options = wgpu::RequestAdapterOptions {
        force_fallback_adapter: true,
        ..Default::default()
    };
    match pollster::block_on(instance.request_adapter(&options)) {
        Ok(a) => println!("fallback: {}", a.get_info().name),
        Err(e) => println!("no software adapter here: {e}"),
    }
}
output
no software adapter here: No suitable graphics adapter found; noop not requested, vulkan support not compiled in, metal had no fallback adapters, dx12 support not compiled in, gl not requested, webgpu support not compiled in

force_fallback_adapter asks for a software implementation, the route a "no GPU available" mode would take. On this Mac none exists and wgpu says exactly why. That is the reason several frameworks keep a CPU renderer (Floem's README describes one built on tiny-skia, and Slint has a software renderer) and a reason software paths keep appearing in this ecosystem. wgpu is now the common GPU layer under egui, Slint, Vello and Floem, and versions 29 and 30 shipped in 2026.

crates.io first publish.