- oaknode Rust crate: full implementation (core engine, sequence/ track/block/footage, traverser, serializer, 43 node behaviors; 493 tests green) - oakrender Rust crate: full implementation incl. wgpu backend skeleton, ticket arena, worker pool (136 tests green; fixed lost-wakeup and ticket ordering races) - src/facade/rust (oakfacade): 222 oakengine_* exports over the module C ABIs (61 tests green); worker_main + real POSIX shm frame-slot transport (SpscRingBuffer/FrameSlotPool, wire-compatible with engine/render/ipc) - cli/rust + worker/rust binaries (29 + 29 tests green) - oakotio: FCPXML import/export (49 tests green) - oaktask: OTIO/FCPXML format dispatch (90 tests green) - app/rust: gpui app skeleton — dock panels (viewers/timeline/ explorer/inspector/node editor), transport, olive themes, i18n (en/zh), 37 tests green - gpui submodule: menu checkmarks, dock ratios, vertical meter, CPU-frame viewer surface, drop-frame timecode
oak-worker (Rust)
Headless render worker process — the Rust rewrite of worker/workermain.cpp
(contract: engine/include/oakengine/worker.h and
engine/include/oakengine/ipc.h).
Build and test
cargo build --release # binary: target/release/oak-worker
cargo test # unit + integration tests (29 tests)
The worker is a thin shell over the facade, exactly like the C++
worker/workermain.cpp is a thin shell over liboakengine:
oakfacade::worker::worker_main(the port ofengine/src/capi/worker.cppoakengine_worker_main()) owns the whole runtime: render backend selection through the oakrender module C ABI (dynamic → OpenGL fallback), the startup handshake and the NDJSON control loop.src/main.rsonly parses--backend(clap) and forwards.oakfacade::ipcowns the shared-memory frame-slot transport (the realSpscRingBuffer+FrameSlotPoolover POSIXshm_open/mmap);src/transport.rsattaches through it.
The oakrender module crate (../../src/render/rust) is linked so the
facade's renderer imports resolve; oakrender depends on ocio-rs with the
bundled feature, whose first-time build fetches a vendored OpenColorIO
dependency (sse2neon) from github.com. On networks without github access,
build with a shared target directory that already contains a completed
oakrender build tree, e.g.:
CARGO_TARGET_DIR=/path/to/oak/src/render/rust/target cargo build --release
What the worker does
Same flow as the C++ main, in the same order:
- parse
--backend <name>(clap; defaultopengl;noneskips renderer creation and the process exits 1, like the C++ main). - initialize the render backend (inside
oakfacade::worker): the oakrender module C ABIoakrender_display_renderer_create_dynamic+_init, falling back to the direct OpenGL renderer exactly like the C++create_renderer()fallback chain. - write the startup handshake (protocol version 1, empty shared-memory geometry — same as the C++ worker's startup handshake; the parent creates the segments and announces their geometry in its reply).
- serve the NDJSON control loop on stdin/stdout until a
shutdownmessage or EOF:handshakeattaches the announced shared-memory frame-slot pools through the real transport;load_graph/render_frame/cancel/shutdownare dispatched by the facade session. Responses are one compact JSON line per message.
Implemented vs stubbed (nothing is faked)
Real: argument parsing, render backend initialization (real wgpu
renderer, dynamic → OpenGL fallback), startup handshake, NDJSON framing,
message validation (protocol version, handshake geometry, load_graph
file existence/size — the same messages the C++ worker emits), the
shared-memory frame-slot transport (oakfacade::ipc — POSIX
shm_open/mmap/munmap/shm_unlink, the SPSC ring buffer and the
frame-slot pool with the exact version-1 shared layout; a handshake
genuinely attaches the output and input pools), unknown-type/
malformed-message errors, shutdown/EOF termination.
Stubbed (documented in src/transport.rs):
| area | reason |
|---|---|
node-graph deserialization (load_graph beyond the file checks) |
the oaknode crate is a todo!() skeleton |
frame rendering (render_frame) |
no graph/render-pipeline backing (the shm frame-slot transport is attached, but there is no graph to render) |
Stubbed requests answer with a clear {"type":"error","message":…} that
names the missing piece (a render_frame error also carries the ticket,
mirroring the C++ error_message() shape). A real load_graph on a
non-existent/empty file produces the C++-identical error before reaching
the stub.
Deviation from the C++: the startup handshake omits gl_major/
gl_minor — the oakrender module C ABI exposes no GL context version (the
C++ worker reads them off its QOpenGLContext).
Layout
src/
main.rs clap entry; thin shell forwarding to oakfacade::worker
(renderer init, handshake, NDJSON loop all live there)
ipc.rs control-plane message structs + NDJSON framing (serde)
session.rs in-process session mirror (message dispatch + real shm
handshake attach), exercised by the unit tests
transport.rs real shared-memory frame-slot transport over oakfacade::ipc
tests/worker.rs binary-level tests (help, clap errors, --backend none exit 1)
The NDJSON control-loop behavior is exercised in-process in src/session.rs
against the facade's real shared memory (no GPU needed via --backend none
sessions); a binary-level loop test would require a working GPU backend and
is deliberately not part of the unit suite. Run the binary against a
created segment to see the real attach path:
target/release/oak-worker --backend opengl <<< '{"type":"shutdown"}'