- Audio tickets join the process backend: render_audio_batch wire
message, workers mix straight into shm slots (SLOT_FORMAT_AUDIO_F32),
ShmAudio payload with release semantics, crash isolation covers audio
renders; playback audio uses an async 4-chunk prefetch drained on the
UI tick (also fixes the sub-60fps chunk truncation bug); oversized
ranges and dispatcher outages fall back to in-process inline.
- Per-ticket slot formats: force_format is honored (exports request
F32 slots, dropping the BGRA8 round-trip and its 8-bit quantization);
segments grow on demand via worker-idle rebuild with generation
handoff; the scheduler filters over-capacity tickets.
- Adaptive defaults: 128-256MB/worker segment budgets drive slots per
worker, batch size follows workers/slots; bench_process example
measures throughput and adjacent-frame completion deltas
(e.g. 4 workers: 841 fps, 4.6ms mean delta).
With the C ABI facade (oakengine) retired, the frozen-ABI rationale is
gone. UndoCommand now boxes a Send Command trait (new/from_closures/
multi), dropping OakUndoCommandVtable, the userdata trampolines, the
refcount shell, the handle module, and all undostack_* handle exports.
The global facade loses its raw-pointer out-params (can_undo/can_redo
return bool, command_name returns String). oaktimeline/oaknode/
oakplugin/oaktask construct commands directly via UndoCommand::new.
oakundo src is now free of unsafe; behavior (ordering, idempotence,
done flags, groups, observers, 200-row cap) is unchanged and pinned by
the rewritten tests.
- WorkerPool thread pool deleted; RenderManager defaults to the
Processes backend (oak-worker children), Threads kept as a test-only
inline dispatcher; audio tickets stay in-process until S3.
- Onscreen path reads worker shm slots directly: BGRA8 slot format,
RenderedFrame::Shm wrapped into the display buffer (single disclosed
GPU-staging memcpy), scopes analyze BGRA8; the long-lived full-res /
thumbnail paths take the counted slot_to_vec copy and release.
- Playback pre-render window: forward 120 frames (configurable) fed to
the PreviewScheduler at Playback priority, interleaved across
workers, cached in shm slots until the playhead consumes them;
generation-based invalidation cancels and releases on edits.
- oaktask export and oak-cli run on private ProcessDispatchers (fixed
a pump-while-locked self-deadlock in the export loop); facade
get_frame handles ShmFrame payloads.
- Acceptance: preview path main_heap_frame_copies == 0 with spawned
workers, CLI transcode/render verified end to end.
Proxy: preview-path proxy substitution (global UseProxyMedia AND
per-footage enabled AND on-disk ready; export always uses originals),
proxy generate/delete/reveal/enable actions, ProxyDialog with global
and per-footage custom params, Tools menu + context-menu Proxy
submenus, progress in the status bar, OVE serialization of proxy
metadata and source_start_time.
Sync: timeline context-menu Synchronize by Source Time / by Waveform /
by Waveform (Adjust Speed) with ctrl-shift-w, cache-envelope
extraction with validity masks, reference/anchor selection and
single multi-undo application (replace-with-gap, speed adjust,
re-place) mirroring timelinewidget.cpp semantics.
Module-internal object references are Rust types now (values, Arc,
Mutex); CHandle remains only at the oakengine C-ABI boundary:
- oakundo: the global stack holds UndoStack/UndoCommand values
directly (stack token is the static's address)
- oaktimeline: marker/workarea boxes carry Arc<Mutex<T>>; commands
share the same allocation through Arc clones (readers in oakengine
stubs and the app's graphops updated to lock)
- oaktask/oakstorage: sessions, write-through bindings and the
database backend pass ProjectArc; the Session drops its manual
release bookkeeping; nodeutil keeps the CHandle<->Arc boundary
conversion (release_project restored for the app)
- oakcodec: handle.rs deleted outright (no facade entry needed it);
texture/block placeholders are unit structs
- oakrender: copier's project handle is an identity u64; alive-count
machinery removed; handle.rs is make_owned/get/get_mut only
- oakplugin: the instance registry is gone (its unregister key never
matched, leaking weak entries); handle.rs is the RefBox boundary type
- oaknode/oakcommon: only dead guard/borrow helpers removed; external
payload handles (texture/processor) documented as the boundary
Flake hunts landed along the way: the audio recording test serializes
on the shared manager lock with a normalized state; the autocacher
cancel test uses a slow producer so cancellation is deterministic.
- facade: oakengine_sequence_set_workarea_undoable (enable+range as one
undo record); marker add/remove/list already existed and are now
covered by it_timeline (10 new tests: markers, workarea, cross-track)
- fixes: stubs workarea_get honored NULL out-params (is_enabled always
failed); export tasks honor custom ranges (export_params_pod dropped
them; oaktask EncodingParams carries has_custom_range)
- app: markers on the ruler (gpui diamond markers), menu
sequence-add/remove marker, set/clear work area (selected-clip bounds
or playhead+1), ruler drag previews live and commits one undoable
record (C++ ruler semantics); export uses the work area when enabled
- cross-track clip moves were already wired; now covered end to end
Single-lib cleanup: the per-crate src/bridge/ and src/ffi.rs layers are
gone (oakundo/oakcommon/oaknode/oaktimeline/oakcodec/oakaudio/
oakrender/oaktask/oakplugin/oakstorage); cross-crate calls are plain
Rust, CHandle marshalling shrinks to the oakengine boundary, and tests
call the Rust APIs directly (pure C-ABI wrapper tests removed where
the domain layer already covers the behavior).
exporter.h family implemented: oakengine_export_render (CLI contract),
oakengine_export_render_with_params (was a stub), last_error and
progress callback; synchronous path reuses task_create_export +
start_sync. Fixes on the way: oaktask video ticket self-deadlock,
audio params dropped on the export path, codec encoder AAC slicing and
H.264 time base. Real-mp4 tests cover both entry points, progress and
the illegal-argument matrix.
Also: oakstorage session maps null project handles to None (version-
info path), configstore test double literal 3.14 -> 3.15 (clippy PI
lint), oakaudio output callback scratch buffer + env-aware P1 test,
cli media round-trip test uses a generated 16-frame clip (no more
minute-long debug runs).
engine:
- oakrender eval footage hook decodes via oakcodec (JobSpec::Footage
carries filename/stream); ticket/ffi/manager wiring, real-media
decode test with programmatically generated MPEG-2
- oakrender bridge/codec.rs + node.rs: direct oakcodec/oaknode calls;
the crate's dlsym module is gone (project_deep_copy/sync_copy remain
documented always-fail stubs — never implemented in oaknode)
- oakaudio waveform/decoder path adjustments for the decode hook
app (gpui + gpui_widgets):
- menu bar scrubbing: hovering another top-level title while a menu is
open switches to it; popup width is content-aware (CJK-aware) instead
of fixed 160px
- density pass: window rem 16 -> 14px, menu rows 26 -> 22px, dock tabs
32 -> 26px, viewer transport tightened
- open/import/save-as use the native platform file dialogs
(prompt_for_paths / prompt_for_new_path; multi-select import);
MockEngine records imported footage for tests
- project explorer Tree/Icons toggle is localized (explorer.tree /
explorer.icons widget keys)
- oakengine_sequence_move_clip implemented for real (oaktimeline
TrackMoveBlockCommand; fixes the graph-ownership/gap-anchor/ripple
trim bugs the stub was hiding); same-track via the frozen C ABI,
cross-track supported by the module command
- oaknode clip blocks now declare a tex_in texture input and set
effect_input to it, so timeline clips can host effect chains; facade
test covers effect insert/remove on a real clip
- oakffmpeg-link: FFMPEG_DIR is now mandatory with a clear panic (a
Homebrew upgrade left the system ffmpeg .pc pointing at a deleted
dav1d Cellar path, breaking links); reads a git-ignored workspace
.env for IDEs that cannot inject env vars (RustRover); links the C++
stdlib for C++ codec libs (svt-av1)
- oakengine re-exports oaknode so tests share one crate instance;
it_node uses the direct instance's value type where it calls the
module FFI (the --workspace dev-dependency feature split builds
oaknode twice)