Add LRU TODO

This commit is contained in:
2026-01-17 16:53:54 +08:00
parent c1bcfeb78b
commit 648de07b00
2 changed files with 182 additions and 0 deletions
+90
View File
@@ -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=23 秒。
- 并发限制(例如 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 纹理缓存。
+92
View File
@@ -0,0 +1,92 @@
# TODO
## Goal
- Add an LRU prerender cache (23 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 = 23s).
- Limit worker count (e.g., 23 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 (23 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.