From 648de07b00cab694fd98f6591f53cdee64a3a18b Mon Sep 17 00:00:00 2001 From: Mike Solar Date: Sat, 17 Jan 2026 16:53:54 +0800 Subject: [PATCH] Add LRU TODO --- TODO-zh.md | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ TODO.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 TODO-zh.md create mode 100644 TODO.md diff --git a/TODO-zh.md b/TODO-zh.md new file mode 100644 index 000000000..a04b1a792 --- /dev/null +++ b/TODO-zh.md @@ -0,0 +1,90 @@ +# TODO + +## 目标 +- 实现 2–3 秒预渲染的 LRU 缓存和代理剪辑功能,并以“小步快跑”的方式在现有架构中逐步落地,确保每一步都可编译。 + +## 现有架构中的落点 +- 播放/渲染调度:`app/render/renderprocessor.cpp`, `app/render/plugin/pluginrenderer.cpp`, `app/node/traverser.cpp` +- 插件节点输入/默认值:`app/node/plugins/Plugin.cpp` +- Clip 图像/纹理获取:`app/pluginSupport/OliveClip.cpp`, `app/pluginSupport/OliveClip.h` +- 节点与值系统:`app/node/node.h`, `app/node/node.cpp`, `app/node/value.h` +- 工程序列化:`app/node/project/serializer/*` + +## LRU 缓存计划(代码改动 + 集成点) + +### 步骤 1(可编译):新增缓存类型但不接入逻辑 +- 新增缓存模块,例如 `app/render/cache/framecache.h/.cpp`。 +- 定义: + - `FrameCacheKey`(图哈希/版本、时间、参数、代理模式、渲染缩放)。 + - `FrameCacheEntry`(AVFrame 或 Texture + 元信息 + 字节数 + 最近访问时间)。 + - `FrameCache` API:`get(key)`、`put(key, entry)`、`invalidateByVersion(version)`。 +- 先只编译通过,不改变行为。 + +### 步骤 2(可编译):图版本号/失效机制 +- 在 `Node` 或渲染入口维护图版本号。 +- 当参数变化、连线变化时递增。 +- 渲染侧可读取版本号用于缓存失效。 + +### 步骤 3(小行为):仅缓存当前帧 +- 在 `renderprocessor.cpp` 播放路径上: + - 先查缓存,命中则直接显示。 + - 未命中则正常渲染,并写入缓存。 +- 缓存预算先设很小,风险低。 + +### 步骤 4(小行为):预渲染窗口 +- 增加队列,渲染 [now, now+N],N=2–3 秒。 +- 并发限制(例如 2–3 个任务),避免抢 UI。 +- 优先级:当前帧 > 近未来。 +- Seek 时取消/丢弃过期任务。 + +### 步骤 5(行为):LRU 淘汰 +- 按内存预算/帧数上限淘汰最久未使用。 + +### 步骤 6(行为):CPU/GPU 策略 +- 默认缓存 CPU 帧,播放时再上传 GPU。 +- GPU 缓存可作为后续优化开关。 + +### 步骤 7(可观测性) +- 统计命中率、平均渲染耗时、掉帧。 +- Debug 构建下输出日志。 + +## 代理剪辑计划(代码改动 + 集成点) + +### 步骤 1(可编译):数据模型与序列化 +- 在 clip 元数据里增加: + - `proxy_path`、`proxy_width`、`proxy_height`、`proxy_codec`、`proxy_fps`。 +- 在 `app/node/project/serializer/*` 写入/读取。 + +### 步骤 2(小行为):代理选择策略 +- 增加全局/每 clip 的代理模式: + - `Auto`、`ForceProxy`、`ForceOriginal`。 +- 在媒体解析层根据模式决定用原片还是代理。 + +### 步骤 3(行为):代理生成 +- 新增后台转码任务(复用现有渲染/导出流程)。 +- 生成完成后更新元数据。 + +### 步骤 4(行为):UI 接入 +- 增加“生成代理”“重链接代理”入口。 +- 在剪辑或预览上显示代理标识。 + +### 步骤 5(验证) +- 对比代理与原片的时间精度、音画同步。 +- 导出默认使用原片。 + +## 小步快跑执行顺序(每步可编译) +1) 新增缓存模块/类型(不接入)。 +2) 增加图版本号与失效接口。 +3) 播放路径只缓存当前帧。 +4) 预渲染 2–3 秒窗口 + 并发限制。 +5) LRU 淘汰策略。 +6) 图版本变更触发失效。 +7) 统计与日志。 +8) 代理元数据字段 + 序列化。 +9) 代理选择策略(Auto/Force)。 +10) 代理生成任务 + UI 入口。 + +## 待确认问题 +- 缓存预算默认值(按硬件分级)。 +- 代理文件默认存储路径。 +- 是否做 GPU 纹理缓存。 diff --git a/TODO.md b/TODO.md new file mode 100644 index 000000000..8700308b8 --- /dev/null +++ b/TODO.md @@ -0,0 +1,92 @@ +# TODO + +## Goal +- Add an LRU prerender cache (2–3 seconds ahead) and proxy clip support, implemented as incremental, compile-safe steps within the current architecture. + +## Where the Changes Live (Current Architecture) +- Playback/render scheduling: `app/render/renderprocessor.cpp`, `app/render/plugin/pluginrenderer.cpp`, `app/node/traverser.cpp` +- Plugin node inputs/defaults: `app/node/plugins/Plugin.cpp` +- Clip image/texture fetch: `app/pluginSupport/OliveClip.cpp`, `app/pluginSupport/OliveClip.h` +- Node graph and values: `app/node/node.h`, `app/node/node.cpp`, `app/node/value.h` +- Project/serialization: `app/node/project/serializer/*` + +## LRU Cache Plan (Code Changes + Integration Points) + +### Step 1 (compile-safe): Introduce cache data types (no behavior yet) +- Add a small cache module, e.g. `app/render/cache/framecache.h/.cpp`. +- Define: + - `FrameCacheKey` (graph version/hash, time, params, proxy mode, render scale). + - `FrameCacheEntry` (AVFrame or Texture + metadata + byte size + last-used). + - `FrameCache` API: `get(key)`, `put(key, entry)`, `invalidateByVersion(version)`. +- Wire in a compile-only stub with no runtime usage. + +### Step 2 (compile-safe): Define graph/version invalidation hook +- Add a lightweight “graph version” counter to `Node` or a render pipeline owner. +- Increment on param changes and graph edits. +- Expose a read-only version getter for the render pipeline. + +### Step 3 (small behavior): Cache current frame only +- In `renderprocessor.cpp` playback path, check cache before rendering: + - If hit, present cached frame. + - If miss, render normally and `put` into cache. +- Keep budget small (few frames) to minimize risk. + +### Step 4 (small behavior): Pre-render window scheduling +- Add a render queue for time range [now, now+N] (N = 2–3s). +- Limit worker count (e.g., 2–3 tasks) to avoid UI starvation. +- Prioritize current frame > near future. +- On seek, cancel or drop stale tasks. + +### Step 5 (behavior): LRU eviction policy +- Enforce memory budget and frame count cap. +- Evict least-recently-used entries. + +### Step 6 (behavior): GPU/CPU policy +- Cache CPU frames by default for safety. +- For GL outputs, upload from cached CPU frame when displayed. +- Optionally add GPU caching later behind a feature flag. + +### Step 7 (observability) +- Add counters for hit rate, average render time, and drops. +- Log only in debug builds. + +## Proxy Clip Plan (Code Changes + Integration Points) + +### Step 1 (compile-safe): Data model + serialization +- Extend clip metadata with: + - `proxy_path`, `proxy_width`, `proxy_height`, `proxy_codec`, `proxy_fps`. +- Add read/write in `app/node/project/serializer/*`. + +### Step 2 (small behavior): Proxy selection policy +- Add project-level and clip-level proxy mode: + - `Auto`, `ForceProxy`, `ForceOriginal`. +- Add a simple resolver in clip/media source code that picks proxy if enabled. + +### Step 3 (behavior): Proxy generation pipeline +- Add a background task to build proxies (using existing render/export tasks). +- Store output path and metadata on success. + +### Step 4 (behavior): UI wiring +- Add “Generate Proxy” action + proxy indicator. +- Add “Relink Proxy” dialog. + +### Step 5 (validation) +- Compare proxy vs original for timing and sync. +- Ensure proxies are ignored for export unless explicitly enabled. + +## Small-Step Implementation Plan (Each Step Builds) +1) Add cache module + types (no references). +2) Add graph version counter (increment on changes). +3) Wire cache lookup for current frame only. +4) Add prerender queue (2–3 seconds) with limited concurrency. +5) Add LRU eviction + memory budget. +6) Add cache invalidation on graph version change. +7) Add basic metrics/logging. +8) Add proxy metadata fields + serialization. +9) Add proxy selection policy (Auto/Force modes). +10) Add proxy generation task + UI entry points. + +## Open Questions +- Default cache size per hardware tier. +- Where to store proxy files on disk. +- Whether to cache GPU textures or CPU frames only.