- nodeparamview: add visited set to get_distance_between_nodes, fixing
unbounded recursion (stack overflow) when the node graph has a cycle
- viewerdisplay: give texture_ a consistent owner via assign_texture();
borrowed queue textures are now retained, created ones freed, fixing
a dangling pointer that corrupted the heap and crashed in the GL driver
- playbackcache: resignal_requests() iterates a copy, handlers may
clear_request_range() while iterating (ASan container-overflow)
- preview C API: preview request ticket lambdas captured the request
state raw; after oakengine_preview_request_free the ticket outlived
the request and the finished callback wrote into freed memory
(heap-use-after-free). The finished flag is now a shared_ptr captured
weakly by the callbacks
- playback: oak_playback_frame regains a timestamp (num/den) filled
from olive::Frame; the viewer queue append no longer uses Rational()
for every frame, which made append_timewise drop all but the first
frame and froze the picture during playback
- mainwindow: open_node_in_viewer refuses sequence nodes; sequences
already have the Sequence Viewer, and saved layouts could otherwise
resurrect a redundant floating Viewer bound to the sequence
R7-A (Qwen 3.8 Max): oakengine/display.h rewritten to the POD contract
from r7-pure-abi-plan.md - oak_video_params everywhere, opaque
texture/frame handles with retain/free protocol (engine-heap control
blocks), OakSharedBuffer refcounted wrapper for the QVariant playback
path. All TexturePtr/FramePtr gone from app (47 sites).
R7-B (Qwen 3.8 Max): liboakengine.so exports 3486 -> 19 C++ symbols
(version script oakengine.ver: oakengine_* plus the documented
oakgl/oakvulkan dlopen plugin ABI). oakengine-obj OBJECT library feeds
both the shared lib and the test binaries (-rdynamic so dlopen'd
backends resolve engine objects).
Fix (Kimi K3): producer/consumer type mismatch - viewerdisplay
unpacks OakSharedBufferPtr but viewer.cpp pushed raw void* handles,
so no frame ever reached the display widget (all 5 vulkan viewer
tests timed out with 'never received a texture'). Producers now wrap
with oak_make_shared_frame / oak_make_shared_texture(retain).
Verified: build 0 errors, ctest 45/45, nm U _ZN5olive = 0 in
oak-editor/oak-render-worker/oak-cli, 19 exported C++ symbols in
liboakengine.so (all documented plugin ABI).
- oakengine/export.h establishes the OAKENGINE_API visibility macros;
include/oakengine/ipc.h is the first pure-C surface (41 functions:
shm, frame slot pool, and the worker IPC messages as POD<->JSON
build/parse), implemented in engine/src/capi/
- the IPC implementations move to engine/src/oliveimpl (namespace
olive::engine::internal::ipc); engine/render/ipc/*.h are rebuilt as
same-name/same-API wrapper classes forwarding across the C boundary
- FrameSlotMeta is shared with the C header verbatim so the app/worker
wire format (v1) is bit-identical; static_asserts pin sizeof and
field offsets
- spscringbuffer.h moves to include/oakengine/ as an inline-only
header (no symbols, not ABI)
- new pure-C test oakengine_ipc_test (make_oakengine_test, no GL)
covers shm, frame pool, message round-trips and the layout asserts;
full gtest suite stays green (1986 tests)
Physical split: app/{audio,cli,codec,common,config,node,pluginSupport,
render,task,timeline,undo,tool,shaders} plus coreengine, version and
ui/icons+colorcoding move to a new top-level engine/ tree, built as
liboakengine.so (shared). The render backends (oakgl/oakvulkan) move
with it and link the engine library instead of embedding a static
render-core subset (libolive-rendercore is gone).
- oak-render-worker now links liboakengine instead of the whole
libolive-editor object set: 336MB -> 2.9MB, no Qt Widgets UI
- the editor links liboakengine for the engine and keeps only UI
objects in libolive-editor
- install/packaging: GNUInstallDirs libdir on Linux, bundle copy on
macOS, oakengine.dll staged for NSIS, AppImage validation entry
- fix backend lookup for the new layout: DynamicRenderer searched
../app but backends now live in engine/; a stale pre-split liboakgl
in the build tree got dlopened instead, re-initialized and later
destroyed the interposed engine statics (full-suite segfault at
DialogSequenceParameterTab, found via gdb watchpoint)