refactor(render): de-Qt oakrender and wrap it in a pure C ABI

- copy engine/render to src/render/src (sunk param types excluded),
  de-Qt in five parallel groups: core machinery (tickets/worker pool/
  jobs), caches, color/texture, preview/IPC, GPU backends
- replace Qt GL/Vulkan wrappers with native context abstractions
  (CGL/EGL/WGL, raw vulkan.h), QProcess with POSIX WorkerProcess,
  QJsonObject with a minimal NDJSON-compatible workerjson (wire
  protocol unchanged), QDataStream disk state with a byte-compatible
  BinaryStream
- signals become single std::function callbacks or facade-triggered
  calls per the documented signal/slot strategy
- pure C ABI in include/render + src/render/c_api (renderer/cache/
  color/manager families, OAKRENDER_E_* codes), 37 gtest cases
- bridge src/node/transition/render/* stubs to the real oakrender
  headers, closing the node<->render cycle: liboaknode links
  liboakrender, zero dangling symbols
- docs: M7 implementation status + oakrender semantic-change notes
This commit is contained in:
2026-08-06 03:21:26 +08:00
parent d77348ad9f
commit edbd3913af
170 changed files with 818511 additions and 358 deletions
+96
View File
@@ -126,3 +126,99 @@ nm -D oaknode 构建产物 | grep -c " U _ZN5olive.*render" # 必须 0
```
node→render 的 47 次引用此时应全部经 oakrender C ABIM3 遗留的
"暂不断链"在此结清)。
## 实施现状(2026-08-05
M7 已落地:oakrender 整库编译通过、纯 C ABI 与测试就位、独立构建
全绿(37 个用例:33 通过 + 4 个 GTEST_SKIP0 失败),oaknode 回归
96/96 不变红。以下为与上文计划的实际差异。
### 最终目录结构
- `src/render/src/` — 去 Qt 化 C++ 实现(`olive::` 命名空间),target
`oakrender`SHARED+ 动态后端 `oakgl`/`oakvulkan`(各自由
`*backend_c.cpp` 单个 TU 编成,`oak_renderer_*` C ABI,运行时由
DynamicRenderer dlopen);平铺结构,`src/render/src` 为 include 根。
- `src/render/c_api/` — 纯 C ABI 包装(renderer/cache/color/manager
共 4 个 .cpp + 内部头 `alivecount.h`/`internalhandles.h`),经
`target_sources` 合并进 `oakrender`,不单独成库。
- `src/render/tests/` — gtest,单一 target `oakrender-gtest`
cache/color/manager/renderer 4 个 _test.cpp),
`gtest_discover_tests``DISCOVERY_MODE PRE_TEST`)。
- `include/render/`(仓库根)— 公共 C 头:`error.h` + renderer.h
display/纹理/帧/blit + 后端管理)、cache.hPlaybackCache/
FrameHashCache + `oakrender_debug_alive_count()`)、color.h
ColorProcessor + ColorManager 静态函数)、manager.h
RenderManager/PreviewAutoCacher/DiskManager + 异步帧请求)。
- `src/render/standalone/CMakeLists.txt` — 独立构建 driver(见下)。
- `src/render/transition/` — 过渡 stub/桥接头(render/ 前缀的桥接头
转发到 `src/render/src` 真身;codec/audio/task/config/pluginSupport
为 stub),供 oaknode 与 oakrender 共用(须置于
`src/node/transition` 之前)。
### 独立构建与测试
```sh
cmake -S src/render/standalone -B build-oakrender
cmake --build build-oakrender -j
ctest --test-dir build-oakrender --output-on-failure
```
测试数字:oakrender **37/37**33 通过,4 个 skipGL 相关的
renderer init/纹理生命周期、blit_color_managed 2 例按 §4 的
GTEST_SKIP 模式;manager_init、request_frame 实跑 2 例因
RenderManager 构造读取 config 悬置符号而无法在 standalone 跑,
可跑的 E_STATE/E_INVALID/E_NOT_FOUND 路径已覆盖,含用 oaknode
factory 真建 ViewerOutput 验证)。oaknode 回归 **96/96**
OCIO 配置照 oaknode 做法经 ctest `ENVIRONMENT OCIO=` 注入
`engine/render/ocioconf/config.ocio`color 测试对
sRGB OETF→Linear 做已知值抽样断言(0.5 → 0.214041,容差 1e-3)。
oakrender-gtest 照 oaknode-gtest 配方 `-Wl,-force_load` libOfxHost
并复用 `src/node/standalone/oakengine_ipc_shim.cpp`
oakengine_ipc_* 悬置符号。
### 实际依赖与链接形态
- Oak 内部:oaknode、oakcommon、oakundo、olivecore、ffmpeg_bridge
(真实 target`add_subdirectory` 引入)。
- 第三方:OpenColorIO、OpenImageIO、Imath/OpenEXR(头)、OpenGL/
CoreVideo/Metal/QuartzCore framework、GTest(仅测试)。
- liboakrender + liboakgl/liboakvulkan 均以 `-undefined dynamic_lookup`
悬置 codec/audio/task/pluginSupport/config 等未拆分模块符号;
后端库在加载时从 liboakrender 解析大部分符号。
- 帧缓存 save/load 往返与 `codec_frame_set/get_params` 的存储断言
留待 M5oakcodec):`codec/frame.h` 仍是 transition stubFrame
无法 allocate,本批只覆盖错误路径(save 不崩、load 未命中返回
E_NOT_FOUND)。
### 与计划的主要差异
- **§5 闭环的实现方式:oaknode 直接链接 oakrender 的 C++ 库,而不
是经 oakrender C ABI。** `src/node/transition/render/*` 已从 stub
改为桥接头(转发到 `src/render/src` 真身),oaknode 源里的
`#include "render/..."` 原样保留、解析到真身类;oaknode-gtest
链接 liboakrendernode→render 引用在链接期由 C++ 符号直接结清。
这是 02 §4 裁决 A 的变通执行(裁决原文要求"统一改成经 oakrender
C ABI"):OakRenderCache/ColorProcessor 等的纯 C ABI 已在
`include/render/` 就位供后续消费者(Rust 化)使用,但 oaknode
自身未改写为 C ABI 调用方。
- §5 的 grep/nm 判据按此口径重新表述(实测值,2026-08-05):
- `grep -rn '#include "render/' src/node/src | wc -l` = **38**
(非 0;全部经桥接头指向真身,无 stub 残留语义);
- `nm` 口径改为「liboaknode 的 `U __ZN5olive*` 未解析符号
**56** 个,**0 个悬置**」:25 个由 liboakrender 解析
PlaybackCache/FrameHashCache/DiskManager/RenderManager/
ColorProcessor/PreviewAutoCacher/LUTLibrary 等),其余 31 个由
oakcommonVideoParams/XmlStream*/SubtitleParams/QtUtils)、
oakundoUndoCommand/UndoStack/MultiUndoCommand vtable)解析。
- 公共头位于 `include/render/`(非 §1 的 `include/oakrender/`),
函数前缀 `oakrender_`,与 oaknode/oakcommon 的既有契约一致
(§1 目标形态中的 `oakrender/include/oakrender/` 未采用)。
- C API 命名照 R7-A §A.2 的 display.h 重写版改前缀
`oakrender_display_*`/`oakrender_codec_frame_*``OakCodecFrame`
在 renderer.h 定义(M5 未落地,按 §2.2 注释在 oakrender 侧先写)。
- 已知坑(已解,记录给后续模块):`src/render/transition/render/`
桥接头占用 `"render/renderer.h"` 等拼写,与公共头
`include/render/renderer.h` 撞名——公共头内部互相同目录
quoted includec_api 源用相对路径包含公共头,测试目标
`BEFORE PRIVATE``include/` 提到最前。
+33
View File
@@ -213,3 +213,36 @@ ColorManager)去Qt化过程中的删除与语义变化,迁移调用方时需
`src/node/DEQT.md` §7(如 `Sequence::update_track_cache()`
`Footage::check_footage()/default_color_space_changed()/
proxy_ready()/proxy_finished()`、5 条 invalidate_from_keyframe_*)。
## oakrender 去Qt化的删除与语义变更(2026-08-05)
- `RenderTicket::finished` 不再跨线程补发:回调在调用 finish() 的
线程上触发;未决状态由 facade 自查 `is_running()`
- PreviewAutoCacher 延迟重排队改显式标志:单次 QTimer 重排队删除,
`try_render()``delayed_requeue_pending_`facade 在
`requeue_delay_ms()` 后重调 `try_render()`
- DiskCacheFolder 周期存盘由 GUI 线程 QTimer 改后台线程,数据保护
`std::recursive_mutex`(原靠 QObject 线程亲和串行化)。
- PlaybackCache 的 Qt 信号改单回调注册:`set_invalidated_callback`/
`set_validated_callback`/`set_requested_callback`/
`set_cancel_all_callback`;跨层 invalidated/validated 通知由 facade
在命令后重发(M7 §2.2:oakrender 不持有上层回调)。
- `DiskManager::instance()` 惰性自建(原 app 启动时显式
create_instance;库消费者不经 facade 也能用)。
- FrameHashCache 帧缓存 JPEG 读写 QImage→OIIO/OpenEXR。
- AudioWaveformCache/PlaybackCache 的 QPainter 绘制归 app 层;
缓存指示条高度固化为常量 4`oakrender_cache_indicator_height()`
`QFontMetrics(QFont()).height()/4`)。
- 离屏 GL 上下文共享组需 app 显式传入(原 QOpenGLContext
globalShareContext 隐式共享)。
- OpenGLContext/Vulkan 上下文抽象层(OpenGLContextProvider 等)替代
QOpenGLContext 直用。
- WorkerProcess 仅 POSIX 实现(Windows 占位未做)。
- worker IPC 的 NDJSON 协议未变,workerjson 为本地(去 Qt)实现。
- `:/shaders` qrc 资源缺口:着色器源码的 Qt 资源路径在库形态下
不可用,需 app 侧提供文件映射。
- 删除 ipc/ipcmessage.cpp 等 3 个过期 .cpp(对应头已自包含 inline
.cpp 内容失效)。
- displayinternal.h 分层违规(render→src/capi)并入 texturehandle.h。
- Renderer 线程亲和由 QObject::thread() 改显式 owner thread
`set_owner_thread_to_current()`/`called_on_owner_thread()`)。