Open source

active

One accelerator contract, three kinds of silicon.

virtio-accel

A guest asks for an accelerator. virtio-accel decides what it gets — contexts, buffers, programs, queues, events — and ships the no_std Rust layers behind that answer, along with host backends that run the same TOSA artifact on Apple's Neural Engine, Intel NPUs, and Qualcomm's Hexagon.

Rustv0.4.0Updated Sep 20, 2026crates.ioGitHub
crates
15
host backends
3
protocol, frozen
1.0
forbid unsafe outright
11 / 15

What it is

The object model is small on purpose: contexts, buffers, programs, execution queues, submissions, and events. Everything else is built out of those six.

Most protocol proposals stop at the document. This one ships the guest, device, transport, queue, and TOSA layers as working no_std Rust, and three host backends that put the same artifact on real hardware. You can read the spec, but you can also run it.

The portable layers know nothing about Linux ioctls, macOS frameworks, Windows APIs, guest physical addresses, or vendor command formats — which is the whole point. The part nobody should have to rewrite per platform doesn't get rewritten per platform. Host integrations live in adapter crates the facade never depends on.

This is pre-standardization work and it claims no Virtio device ID. Protocol 1.0 is stable enough to build against and to argue with; it is not an approved Virtio specification.

What it carries

The workload we push hardest through it is not a classifier. It is relativistic ray tracing — Kerr geodesics around a spinning black hole, and light transport through a Dneg traversable wormhole — submitted as TOSA graphs through the same Accelerator contract the Core ML and OpenVINO backends implement.

It is a deliberately awkward workload for a protocol like this, which is why it is useful. A ray tile is thousands of independent lanes, and each one can retire on its own: captured by the horizon, absorbed by the disk, or escaped to infinity. So the graph carries live masks, not just tensors. One step graph is compiled once and resubmitted for every tile, which is exactly the reuse the object model is supposed to make cheap.

It also pins down where precision has to hold. Sensitive determinants, reductions, and the event decisions that retire a lane stay in FP32; bulk nonlinear work drops to FP16. Boolean boundaries cross the ABI as lossless FP32 bridges, so a backend with no Boolean tensor type still keeps mask logic inside the accelerator partition instead of round-tripping to the host every step.

Kerr geodesics · emissive plasma

Three seconds of accretion flow around a spinning black hole, with the background field smeared into arcs by the hole's own gravity. Nothing in the geodesic solve reruns across these frames: the camera and the metric never change, so the traced boundary map is reused and only the plasma volume is resampled. Caching that map is the difference between a still and an animation.

Ray-traced Dneg wormhole: a dark spherical throat rimmed in blue light, showing warm dust lanes from the far side, set against a deep blue nebula and dense starfield.
Dneg wormhole · return

The throat with the far side's dust lanes curling through the mouth and the origin sky wrapped around its rim. Both celestial spheres rotate against a stationary lens map, so an unchanged camera costs shading rather than another geodesic trace.

Ray-traced Dneg wormhole on approach: concentric blue rings of lensed light inside a dark throat, surrounded by a warm brown haze and starfield.
Dneg wormhole · approach

Closer in, where the Einstein rings tighten and the two environments meet at the rim. Step count and samples per pixel are decoupled from raster size, so image quality and window size move independently.

Backends

Three backends run end to end today. Each takes the same device-neutral TOSA 1.0 artifact, lowers it with its own native toolchain, and binds the caller's own allocations — no staging copy on the way in or out.

“Supported” below means the backend admits that program and dtype and runs it on hardware. Parsing a graph is not executing one, and no backend here will quietly dequantize something it cannot run: an unsupported precision is rejected at load, where you can see it.

Apple Core ML / ANE

virtio-accel-coreml

macOS 14+

Lowers TOSA into Core ML and submits ANE-capable predictions against buffers the caller already owns, accepting a result only when Core ML wrote into that same allocation. Core ML places each operation on the ANE or the CPU as it sees fit. Direct INT8 boundaries need macOS 26+ and currently cover identity and zero-point-aware MATMUL; the INT4 facilities Core ML advertises are compressed weight storage, not INT4 tensor execution.

Program dtypes

  • FP32 supported
  • FP16 supported
  • FP8 not supported
  • INT8 supported
  • INT4 not supported

Intel OpenVINO

virtio-accel-openvino

OpenVINO 2026.x

Lowers the same artifact into in-memory OpenVINO IR and compiles per device — NPU first, then GPU, then CPU — under accuracy-preserving execution mode. It reports completion only if the runtime actually wrote into the caller's output allocation, which is a stronger claim than “the call returned”. Its INT8 tier legalizes zero points explicitly in INT32.

Program dtypes

  • FP32 supported
  • FP16 supported
  • FP8 not supported
  • INT8 supported
  • INT4 not supported

Qualcomm Hexagon

virtio-accel-hexagon

Experimental; QAIRT 2.49 on Windows ARM64

Lowers a strict FP16 and INT8 subset to QNN and runs it on Hexagon HTP with direct client buffers. FP16 covers 41 of the 42 operators the other two backends share — ERF has no QAIRT node. FP32 is refused on purpose: the v73 precision probe caught MATMUL rounding to FP16 despite FLOAT_32 tensors, so admitting it would misreport the numerics. Without a complete SDK selected at build time, construction returns RuntimeUnavailable rather than falling back to CPU.

Program dtypes

  • FP32 not supported
  • FP16 supported
  • FP8 not supported
  • INT8 supported
  • INT4 not supported

AMD XDNA

In development

Being built against the same Accelerator contract. The evidence so far shows no native FP32 or FP16 path, so the numeric target for this one is BF16 and block floating point.

Program dtypes

  • FP32 not supported
  • FP16 not supported
  • BF16 supported
  • Block FP/BF16 supported

The workspace

Fifteen crates, published together in dependency order, with dependencies pointing downward only. Each is pinned to a portability tier that CI enforces by building for bare-metal aarch64, riscv64, and wasm32 — so a core crate cannot pick up a host dependency without the build noticing.

Eleven forbid unsafe outright. The three host adapters forbid it everywhere except their own platform, where the FFI stays in a single audited module. The TOSA crate denies rather than forbids, which lets the official generated FlatBuffers accessors live in a private module behind bounded verification instead of hand-rolling a parser for a format someone else already specified.

virtio-accelcore + alloc
Facade re-exporting the portable layers.
virtio-accel-protocore
Pointer-free, little-endian protocol 1.0 wire structures.
virtio-accel-transportcore
Dependency-free descriptor-chain, queue, reset, and notification ports.
virtio-accel-corecore
Backend lifecycle, memory, program, queue, and event contracts.
virtio-accel-tosacore + alloc
Bounded zero-copy TOSA 1.0 validation, lowering analysis, specialization, and packed low-precision utilities.
virtio-accel-vaccelcore
Adapter seam for projecting a native provider — vAccel-style or otherwise — onto the Accelerator contract, with copy-path counters for conformance hooks.
virtio-accel-coremlmacOS std
TOSA-to-Core ML lowering, direct buffers, and asynchronous ANE-capable prediction.
virtio-accel-openvinoLinux std
TOSA-to-OpenVINO IR lowering, direct host-pointer tensors, and asynchronous NPU/GPU/CPU inference.
virtio-accel-hexagonWindows ARM64 std
Strict FP16/INT8 TOSA-to-QNN lowering, direct buffers, and asynchronous Hexagon HTP execution.
virtio-accel-split-queuecore + alloc
Bounded in-memory split-ring reference model.
virtio-accel-guestcore + alloc
Typed reference client with bounded request tracking.
virtio-accel-devicecore + alloc
Device-owned state, including bounded generational IDs.
virtio-accel-mockstd
In-memory backend with deterministic test-only artifacts and scripted faults.
virtio-accel-conformancestd
Transport-free semantic suite and shared FP32/FP16/FP8/INT8/INT4 numerical TOSA corpus.
virtio-accel-cleanroomcore
Independent conformance codec, written without the shared protocol types.

Protocol 1.0

Fixed headers and payloads for device discovery, contexts, buffers, programs, execution queues, submissions, and events. Two decisions shape most of the API.

Unknown values stay raw. Unrecognized opcodes, statuses, and event states remain integers until something validates them, so decoding a hostile byte stream can never construct an invalid Rust enum. And failure still returns an event: a successful submit yields one, and an indeterminate failure must too, because the device still owns those resources and someone has to be able to ask what became of them. Object IDs are opaque, kind-tagged, generational, and never reused once a generation is exhausted.

Two codecs read every canonical frame — the primary zerocopy ABI, and a clean-room implementation written without the shared protocol types. They exchange bytes and nothing else, so the cross-check is genuinely independent and never becomes a production dependency.

The device side doesn't have to be Rust. include/virtio_accel.h is a packed C projection of the wire contract — a projection, not a plugin ABI. CI compiles it as C11 and C++11 and derives its size, alignment, and offset assertions from the same frozen layout manifest the Rust structures are checked against, so neither side can drift on its own.

Writing a backend

Implement the Accelerator contract from virtio-accel-core, then run the semantic suite against it. The suite is transport-free — no wire format, no virtqueue, no OS, no vendor SDK — and it checks the things that are easy to get subtly wrong: memory sharing, transfer permissions, context isolation, cancellation races, resource lifecycle.

There is a fault-injection harness for the paths you cannot reach on purpose, and optional hooks for resource accounting and progress reporting. If you would rather wrap an existing provider than write a backend from scratch, the vAccel adapter crate gives you that seam with the copy-path counters already in place.

Status

Protocol 1.0's opcodes, statuses, and payload layouts are frozen by the final freeze audit. The crate version tracks the Rust API, which is young and will move as adapter authors push on it. A pre-1.0 crate version says nothing about protocol stability — those are two different clocks.

The reserved list is reserved, not forgotten. An implementation that advertises one of those surfaces is not 1.0 conformant, because 1.0 never assigned it negotiation, ownership, or synchronization rules to be conformant to.

In protocol 1.0

  • One command virtqueue at index zero
  • Device discovery and exact compatibility checks
  • Contexts, buffers, opaque programs, queues, submissions, events
  • Bounded explicit buffer transfers
  • Polling, cancellation, release, reset, backend-discard recovery
  • Direct-binding requirements for program-visible buffers
  • Checked finite limits on untrusted counts and retained storage
  • Clean-room codec and transport-free conformance suite

Reserved, unadvertised

  • Multi-queue and event queues
  • External memory import/export
  • Timeline fences
  • Secure contexts
  • Packed virtqueues
  • Negotiation for further VMM, kernel, OS, and vendor integrations
  • A standardized graph IR, compiler, or executable format

Contributing

Disagreement is welcome, including with the frozen decisions — a reasoned objection is worth more than a workaround built on top of one. Wire changes get classified before any code merges.

MSRV is 1.85 on edition 2024, checked in CI. MIT or Apache-2.0, your choice, contributions dual-licensed on the same terms, and no separate CLA.