feat(rust): first green Rust crates — oakcore-rs, oakundo, oakcommon, oaktimeline, oakaudio
- oakcore-rs: Rational/TimeRange/TimeRangeList/PixelFormat/SampleFormat mirroring oakcore C++ semantics (91.6% coverage) - oakundo: UndoCommand/UndoStack with vtable commands (99.6%) - oakcommon: config/XML/VideoParams/logging etc. (89.8%, 516 tests); XML via quick-xml, logging via the log facade - oaktimeline: markers/workarea/edit commands (95.4%) - oakaudio: processor/manager/sync/waveform/levelmeter (88.4%) - unified -MMCCCC error codes across all C ABI headers (registry in include/common/error.h; pass-through rule) - olive::Variant moved node -> common (cross-module value type) - oakcommon_videoparams_set_is_3d added to the C ABI - M11 (oakplugin Rust rewrite) plan + notes.md freeze line for the inter-module C ABI wiring
This commit is contained in:
@@ -46,6 +46,7 @@
|
||||
| M7 | oakrender | `render/`(Renderer/PlaybackCache/ColorManager/帧缓存/job) | render→node 38、render→codec 9、render→task 2、render→undo 1、render→src 1(违规) |
|
||||
| M8 | oaktask | `task/`(Task/TaskManager/项目任务编排/cache 任务;**工程文件 IO 已划给 oakstorage,M3a**) | task→node 38、task→codec 4、task→render 4、task→storage(load/save 委托) |
|
||||
| M9 | oakplugin | `pluginSupport/`(OpenFX host) | plugin→node 6、plugin→render 6、plugin→undo 2、plugin→coreengine 2 |
|
||||
| M11 | oakplugin Rust 重写 | 整个模块换 Rust(含自研 OFX host 取代 HostSupport;0-2 期已立项:golden master、crate 落地、GL+ofxColour+render 驱动收编) | 手册 M11;项目 Rust 化滩头模块,完成后 node/render→plugin C++ 引用归零 |
|
||||
| — | liboakengine | `src/capi` + `coreengine` + `tool/` + `ui/` 残余 | 纯装配层:facade 内部调用改经各模块 C ABI(或保持现状直接链,见 M9 §4 裁决) |
|
||||
|
||||
**M3.5(伴随 M3 的类型下沉)**:`render/videoparams.h`、
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
# M11:oakplugin Rust 重写(含自研 OFX Host)
|
||||
|
||||
> 前置:M9(oakplugin 拆分)已完成,模块边界已是纯 C ABI
|
||||
> (`include/plugin/*.h`,引用计数句柄)。本计划把 oakplugin 的
|
||||
> **整个实现**换成 Rust:自研 OFX 宿主取代 openfx HostSupport
|
||||
> (third_party/openfx/HostSupport,vendored 1.3 万行 C++),六个
|
||||
> C++ 类(4485 行)语义级移植;pluginrenderer(oakrender 内,
|
||||
> 1857 行)在第 2 期收编。
|
||||
>
|
||||
> 这是项目全量 Rust 化的滩头模块:第一张 Rust crate 模板
|
||||
> (构建、测试、FFI 纪律、泄漏断言)在此确立。
|
||||
>
|
||||
> 本文档覆盖已立项的 0-2 期;OpenCL(3 期)与 UI 类 suite
|
||||
> (Interact/Dialog/Draw,4 期)届时评审再立项。
|
||||
|
||||
## 0. 形态决策(2026-08,已定)
|
||||
|
||||
- **单一 Rust crate 收编整个模块**,不自起独立 host 库。crate
|
||||
内部 host 核心与实例/参数/纹理桥之间是普通 Rust 模块调用
|
||||
(safe,编译器查所有权),只有两条 FFI 边界:
|
||||
1. 对 OFX 插件:fetchSuite/action,规范定义的 C ABI;
|
||||
2. 对 oak 其余模块:`include/plugin/*.h`,M9 已冻结。
|
||||
- 上游零感知:oaknode 的 PluginNode、facade、oakrender 都只认
|
||||
C ABI,不关心实现语言。
|
||||
- HostSupport 删除后,liboaknode/liboakrender 对 liboakplugin 的
|
||||
C++ 符号引用(PluginCache、Property::Set 等 30+ 个)归零。
|
||||
- unsafe 收敛在两层:suite trampoline(插件调入)与 C ABI 导出
|
||||
(oak 调入)。其余全部 safe Rust。
|
||||
- 每个 FFI 入口必须 `catch_unwind` 兜底并映射为负错误码(01 §0),
|
||||
构建保持 `panic = "unwind"`。
|
||||
|
||||
## 1. 保留与消耗的资产
|
||||
|
||||
- `include/plugin/{error,host,instance}.h`:公共契约,不变。
|
||||
- 六个 C++ 类的语义(olivehost/oliveplugininstance/oliveclip/
|
||||
paraminstance/image/pluginprogressreporter):移植,不重新设计。
|
||||
- pluginrenderer.cpp 的渲染流程语义:2 期收编时逐段对照。
|
||||
- HostSupport:仅作行为参照系,不进构建。
|
||||
|
||||
## 2. 第 0 期:Golden master 与测试基建(约 1 周)
|
||||
|
||||
不改实现,产出验收门槛。
|
||||
|
||||
### 2.1 插件内省 C ABI(include/plugin/instance.h 新增,约 15 函数)
|
||||
|
||||
参数枚举(名称/OFX 类型/标签/hint/父组/坐标系/secret/
|
||||
display min-max/choice labels-values-order/按类型默认值)、clip
|
||||
枚举(名称/标签/可选性/分量/位深)、描述符(标识/label/描述/
|
||||
上下文集)。PluginNode 同期改走该 C ABI,node→plugin C++ 引用
|
||||
归零。行为必须逐行不变。
|
||||
|
||||
### 2.2 描述符快照
|
||||
|
||||
系统三 bundle(CImg/Misc/Shadertoy)全量 dump 成 JSON 入库
|
||||
(tests/ofx/snapshots/):标识、上下文、参数矩阵(默认值与
|
||||
choice 排序结果)、clip 描述、**getClipPreferences 协商后结果**
|
||||
(分量/位深/像素比——隐式行为主要来源)。后续每期 diff 必须为空。
|
||||
|
||||
### 2.3 渲染 golden master
|
||||
|
||||
代表性效果集(CImg invert/blur、一个 2D 变换、一个 Shadertoy、
|
||||
一个 generator):固定输入帧,CPU 与 GL 两路径,全链路
|
||||
**F32 + ACEScg**,存 EXR + SHA256。CPU 路径要求 bit 级一致,
|
||||
GL 允许 1e-4 容差;GL 用例仅本机,CI 跳过。
|
||||
|
||||
### 2.4 最小测试插件
|
||||
|
||||
~300 行 C 测试插件(filter 上下文,覆盖常用参数类型与双 clip),
|
||||
供 suite round-trip 单测与 1 期首测。
|
||||
|
||||
## 3. 第 1 期:Rust crate 落地(约 4-5 周)
|
||||
|
||||
### 3.1 范围
|
||||
|
||||
- host 核心:Property/Memory/ImageEffect v1/Parameter(12 种类型)/
|
||||
Message v1v2/Progress v1v2/TimeLine v1/MultiThread v1 suite;
|
||||
filter/generator/transition 上下文;describe/describeInContext/
|
||||
createInstance/destroyInstance/getClipPreferences/getRoD/getRoI/
|
||||
isIdentity/render(CPU)/begin-endSequenceRender 动作。
|
||||
- 六类移植:host 单例(扫描/缓存)、instance 包装、clip↔纹理桥
|
||||
(经 oakrender C ABI)、param↔node 桥(经 oaknode/oakundo C
|
||||
ABI)、image 包装、progress reporter。
|
||||
- 语义重灾区(逐条对照 HostSupport 并注释):clip 分量/位深/
|
||||
像素比协商顺序;RoD/RoI;isIdentity 短路;field 透传。
|
||||
|
||||
### 3.2 crate 结构(src/plugin/rust/)
|
||||
|
||||
声明底稿已入库,见该目录。模块划分:ffi(C ABI 导出)、handle
|
||||
(句柄脚手架)、host(扫描/缓存/suite 注册)、descriptor、
|
||||
instance、clip、image、param、property、suites/*(八张函数表)、
|
||||
bridge/{node,render,undo}(oak C ABI 导入)。
|
||||
|
||||
### 3.3 构建
|
||||
|
||||
crate 出 staticlib;CMake 经 corrosion(或自定义 target)链成
|
||||
liboakplugin;standalone 树接线不变;CI 加 rust toolchain(版本
|
||||
pin 在 rust-toolchain.toml)。
|
||||
|
||||
### 3.4 明确不做
|
||||
|
||||
GL 路径、ofxColour(均 2 期);OpenCL(3 期评审);
|
||||
Interact/Dialog/Draw(4 期);Parametric(按需)。公共 C ABI 不变。
|
||||
|
||||
### 3.5 验收
|
||||
|
||||
- 0 期 golden master 全绿(描述符 diff 空、CPU 渲染 bit 一致)。
|
||||
- 测试插件 round-trip + CImg 全量插件 describe/协商冒烟。
|
||||
- 生命周期:createInstance/destroyInstance 配对、重复 scan、
|
||||
render 中途 cancel;alive 计数无泄漏。
|
||||
- nm:liboaknode/liboakrender→liboakplugin C++ 符号为 0;
|
||||
HostSupport 移出构建。
|
||||
- cargo test(host 内部单测)+ ctest(C ABI 层)双绿。
|
||||
|
||||
## 4. 第 2 期:GL 路径 + ofxColour + pluginrenderer 收编(约 2-3 周)
|
||||
|
||||
- OpenGLRender suite v1(clipLoadTexture/clipFreeTexture/
|
||||
flushResources)与像素深度协商;纹理桥沿用 M9 的
|
||||
wrap_native/readback 机制。
|
||||
- ofxColour:属性族 + GetOutputColourspace action;ACEScg 工作
|
||||
空间经 OCIO config 属性告知插件。
|
||||
- pluginrenderer.cpp 语义收编进 crate(render driver 模块),
|
||||
oakrender 的 PluginJob 退化为一次 C ABI 调用;oakrender 彻底
|
||||
不碰 OFX。
|
||||
- 验收:GL golden master 本机绿;ofxColour 属性 round-trip 单测 +
|
||||
支持插件端到端用例;F32+ACEScg 链路保持绿。
|
||||
|
||||
## 5. 依赖与顺序
|
||||
|
||||
- 开始前:③ 剩余机械部分(render→node、→common、transition
|
||||
清理)收尾。
|
||||
- 2.1 完成后 ③ 的 node→plugin 依赖清零;render→plugin 的 12 个
|
||||
符号随 1 期 HostSupport 删除消失。
|
||||
- 每期结束独立评审再进下一期。
|
||||
|
||||
## 6. 风险
|
||||
|
||||
- **语义边角**:HostSupport 隐式行为无法全覆盖;缓解:快照含
|
||||
协商后结果 + CImg 全量协商冒烟。
|
||||
- **FFI 纪律**:panic 越界/回调线程模型是新坑;缓解:catch_unwind
|
||||
全入口覆盖、共享状态全部 Mutex、回调线程注册表。
|
||||
- **GL 本机依赖**:GL 验收需人工本机确认。
|
||||
- **首个 Rust 模块**:构建模板(corrosion、双测试层、alive 计数)
|
||||
要为后续模块立好,宁慢勿滥。
|
||||
@@ -395,3 +395,122 @@ ColorManager)去Qt化过程中的删除与语义变化,迁移调用方时需
|
||||
oaknode 的 35 个 TU,析构引用 olive::Texture::~Texture——值系统
|
||||
载荷问题,与 UndoCommand 跨模块继承同类,留待值系统重做。
|
||||
除此之外 liboaknode→liboakrender 的 C++ 符号引用为 0。
|
||||
|
||||
## ③ C ABI 接线冻结线(2026-08-07)
|
||||
|
||||
③(模块间调用切 C ABI)完成两整块后冻结,剩余部分改由各模块的
|
||||
Rust 重写驱动(RIIR 后调用方只能走 C ABI,接线自动发生且被类型
|
||||
强制做对):
|
||||
|
||||
- 已切:oaknode→oaktimeline(81431d180)、oaknode→oakrender
|
||||
(5a564f30c,缓存体系/色彩/单例全部 C ABI 化)。
|
||||
- olive::Variant 从 oaknode 下沉到 oakcommon(src/common/src/
|
||||
variant.{h,cpp})——它本是跨模块值类型。
|
||||
- 冻结时点的残留(nm 可查):
|
||||
- render→node 41 个 C++ 符号:ProjectCopier 深拷贝族、
|
||||
NodeTraverser(RenderProcessor 跨模块继承)、ColorManager、
|
||||
Footage/MultiCam/ViewerOutput 常量、oaknode_c_api::alive_*。
|
||||
→ 在 oaknode/oakrender Rust 重写中消解(架构底稿:
|
||||
src/node/rust、src/render/rust;ProjectCopier 反转为
|
||||
oaknode_project_deep_copy/sync_copy,traverser 改 hook 制)。
|
||||
- node/render→plugin 的 OFX C++ 符号:随 M11(DeepSeek 实现中)
|
||||
落地消解。
|
||||
- 各模块→oakcommon 的 XmlStreamReader/FileFunctions/VideoParams
|
||||
C++ 调用:随 oakcommon Rust 化消解。
|
||||
- 文档化例外:Texture 的 Variant 载荷(Rust 侧不存在此问题)、
|
||||
UndoCommand 跨模块继承、oakgl2/oakvulkan 后端插件接口。
|
||||
- ④(隐藏 C++ API)同步搁置:模块 Rust 化后 C++ 符号自然消失。
|
||||
|
||||
## oakcommon Rust 测试:ffmpeg_bridge 符号依赖(2026-08-08)
|
||||
|
||||
`oakcommon_ffmpegutils_get_compatible_bridge_pixel_format` 在非测试构建
|
||||
中会经 `find_best_pix_fmt_of_list` 引用 ffmpeg_bridge 的
|
||||
`fb_find_best_pix_fmt_of_list` 符号。集成测试二进制不链接 libffmpeg_bridge,
|
||||
实验证实直接调用该 FFI 导出会在链接期报 `_fb_find_best_pix_fmt_of_list`
|
||||
undefined symbol(cargo test --test link_exp 复现,随后已删)。
|
||||
|
||||
因此该函数不能走普通集成测试。处理方式(与 oakplugin/oaktimeline 的
|
||||
test-stubs 约定一致):
|
||||
|
||||
- `src/common/rust/Cargo.toml` 新增 `test-stubs` feature;
|
||||
- `find_best_pix_fmt_of_list` 的 extern 声明/调用改为
|
||||
`#[cfg(all(not(test), not(feature = "test-stubs")))]`,桩改为
|
||||
`#[cfg(any(test, feature = "test-stubs"))]`——`cargo test --lib`
|
||||
无需 flag 仍走桩,集成测试 `cargo test --features test-stubs` 也可链接;
|
||||
- `tests/ffi_ffmpegutils.rs` 覆盖 ffmpegutils 全部 6 个 FFI 导出
|
||||
(成功路径 + null out-param 的 E_INVALID 路径),需带
|
||||
`--features test-stubs` 运行;不带 flag 时该文件整体为空(cfg 门控)。
|
||||
|
||||
## oakcommon Rust:ocioutils/oiioutils 吸收 oakoci(2026-08-08 接手笔记)
|
||||
|
||||
### 基线
|
||||
|
||||
`src/common/rust` 全量测试:`cargo test --features test-stubs` **497 个全部通过**
|
||||
(314 lib + 12 contract + 8 ffi_colortransform + 61 ffi_commandlineparser +
|
||||
24 ffi_config + 8 ffi_ffmpegutils + 21 ffi_misc + 12 ffi_subtitleparams +
|
||||
15 ffi_videoparams + 22 ffi_xmlutils + 集成 real_ocio 等)。TODO 中旧快照
|
||||
"476"已过时;后续验收以"保持 497+ 全绿"为准。
|
||||
|
||||
### oakoci shim crate 的拆解去向
|
||||
|
||||
`src/bindings/oakoci/`(untracked,纯 Rust shim,曾用于给
|
||||
oakrender Rust 提供 OCIO/图像能力)内容已全部内收进
|
||||
`src/common/rust`,然后整目录删除:
|
||||
|
||||
| oakoci 内容 | 去向 | 落点 |
|
||||
|---|---|---|
|
||||
| `oci.rs` OcioConfig / OcioProcessor(包 `ocio_rs::Config`/`CPUProcessor`) | 重写为 `ocioutils.rs` 的 `OcioConfig`/`OcioProcessor`,错误从消息包装 `Error` 改为 `crate::error::Error::Failed`(新增 `From<ocio_rs::OcioError>`) | `src/common/rust/src/ocioutils.rs` |
|
||||
| `image.rs` F32Image + read/write_image_f32(image 0.25 tiff) | 原样并入 `oiioutils.rs`,错误统一走 `Error::Failed` | `src/common/rust/src/oiioutils.rs` |
|
||||
| `error.rs` 消息包装 Error | 并入 `error.rs`(`Error::new` 便捷构造) | `src/common/rust/src/error.rs` |
|
||||
| `tests/smoke.rs`(5 OCIO + 1 TIF round-trip) | 移植为 `tests/real_ocio.rs`,config 用 `env!("CARGO_MANIFEST_DIR")/../../../engine/render/ocioconf/config.ocio`,断言改为 `Error::Failed(_)` | `src/common/rust/tests/real_ocio.rs` |
|
||||
|
||||
### 位深判别值(已验证)
|
||||
|
||||
`ocio_rs::BitDepth` 是 `#[repr(i32)]`,判别值即 OCIO 码:Unknown=0,
|
||||
Uint8=1, Uint10=2, Uint16=5, F16=7, F32=8。`ocioutils.rs` 直接
|
||||
`depth as i32`,单测锁死 1/2/5/7/8/0,与 C++ 的
|
||||
`OCIOUtils::get_ocio_bit_depth_from_pixel_format`(CPP-PARITY)一致。
|
||||
|
||||
### 决策:不引入 ffmpeg-next(偏差,已落定)
|
||||
|
||||
TODO 原计划用 `ffmpeg-next` 的 `av_d2q` 做 aspect-ratio 换算。复查发现
|
||||
C++ 侧 `Rational::from_double`(`core/src/util/rational.cpp:39`)本身就是
|
||||
**av_d2q 的移植**(文件内注释 "ported from FFmpeg's av_d2q"),oakcore-rs
|
||||
的 `Rational::from_double` 与之对等,且现有 12 个单测已锁死行为
|
||||
(NaN/超界→(0,0)、0.0→(0,1)、约分)。因此**保留手写移植,走
|
||||
`oakcore_rs::Rational::from_double`**,不把 ffmpeg-sys-next(bindgen +
|
||||
系统 FFmpeg)拖进叶子 crate——守住 README 的 "narrow extern C" 纪律。
|
||||
`oiioutils.rs` 的实现已如此;文档残留的 "via ffmpeg-next" 说法待清。
|
||||
|
||||
### OCIO 环境依赖
|
||||
|
||||
`ocio-sys` 不自探测系统 OCIO:无配置时构建的是 stub bridge(调用全失败)。
|
||||
`src/common/rust/.cargo/config.toml`(从 oakoci 抄入)固定三个变量:
|
||||
`OCIO_RS_ENABLE_REAL=1`、`OCIO_INSTALL_DIR=/opt/homebrew`、
|
||||
`OCIO_RS_LINK=dynamic`。机器上 OpenColorIO 2.5.2(Homebrew)、
|
||||
libavutil 60.26.102、~/.cargo/registry 已缓存 ocio-rs/ocio-sys/
|
||||
image/ffmpeg-next 全套。
|
||||
|
||||
### 待办(后续会话)
|
||||
|
||||
1. 全量验证:`cargo test --features test-stubs` ≥497 绿;`cargo build --release`。
|
||||
2. 清文档残留:`oiioutils.rs` 模块注释与 `README.md` 依赖表/决策 6 的
|
||||
"ffmpeg-next" 说法改为 oakcore-rs 手写移植。
|
||||
3. `rm -rf src/bindings/oakoci`(已确认无 CMake/workspace/源码引用,仅
|
||||
oakotio/oakaudioout 两个 sibling README 提到,删前先改)。
|
||||
4. `cargo tarpaulin --features test-stubs` 覆盖率 ≥80%(tarpaulin 默认只
|
||||
跑 lib 单测,新并入代码已带模块内单测,见 ocioutils.rs/oiioutils.rs)。
|
||||
5. 不做任何 git 提交;分支 refactor/split-oakengine 上的既有暂存改动
|
||||
(variant.cpp/h 移动、include/*/error.h)不触碰。
|
||||
|
||||
## 技术债登记(2026-08-09)
|
||||
|
||||
- **oaktask 渲染循环同步化**:src/task/rust/src/render.rs 目前是
|
||||
"一帧一 ticket、wait 到底"的同步循环(C++ 原版是最多
|
||||
hardware_concurrency 个 ticket 并发 + 完成队列 + condvar)。
|
||||
可观察契约不变但导出/预缓存吞吐下降。修复方案:oakrender
|
||||
ticket arena 本就支持多 ticket 在飞 + 回调,改为 N 并发 +
|
||||
按序交付,并发度参数照 C++。待 render crate 落定后立即派代理
|
||||
补上(测试已就绪)。
|
||||
- **oaktask 导出缺口**:临时文件重命名(失败不留半成品)与
|
||||
sidecar 字幕编码器未实现;precache 缺项目深拷贝。
|
||||
|
||||
Reference in New Issue
Block a user