下面这份直接作为 Codex 的完整执行计划使用。所有条目都按强制要求执行,不保留旧实现,不增加兼容层,不引入独立 PerfTrace 库。 # Renderive Kernel Render DAG 完整改造执行计划 ## 0. 总目标 将 Plot 内部渲染执行统一改造成: ```text Renderable 状态 + Renderable 数据依赖 + Renderable 图层依赖 + prepare_buffer 状态 + paint_buffer 状态 + Renderable 内部任务 DAG │ ▼ render_plan compiler │ ▼ ONE Render DAG │ ▼ ONE Taskflow │ ▼ Frame 执行 │ ├── 普通运行:不记录详细性能 │ └── Capture:直接写 Frame execution slots │ ▼ 三缓冲完成交换 │ ▼ immutable frame_snapshot │ ┌─────┴────────┐ ▼ ▼ frame_analysis node_statistics │ │ └──────┬───────┘ ▼ 后端 API │ ▼ 前端 DAG + Worker Timeline + 多帧统计 ``` Kernel Render DAG 必须同时成为: ```text 执行依赖的唯一事实来源 Taskflow 编译的唯一事实来源 单帧性能分析的唯一事实来源 前端 DAG 展示的唯一事实来源 ``` --- # 1. 锁死 Renderable 三阶段语义 Renderable 的执行语义必须明确分成: ```text prepare ↓ paint ↓ composite ``` 这三个阶段不是全局阶段,不允许建立全局 barrier。 它们是每个 Renderable 以及 Renderable 内部任务自己的局部依赖关系。 必须严格执行以下语义。 ### `prepare` `prepare` 必须完成: ```text 读取自身业务数据 读取其他 Renderable 提供的数据 处理所有跨 Renderable dependency 坐标转换 数据转换 几何计算 可见范围计算 裁剪信息计算 布局结果准备 分片 索引生成 raster 前置数据生成 paint 所需全部输入生成 ``` `prepare` 最终必须只产生当前 Renderable 自己的: ```text prepare_buffer ``` ### `paint` `paint` 必须满足: ```text 禁止读取其他 Renderable 禁止解析 dependency 禁止查询其他 Renderable 当前状态 禁止重新执行跨 Renderable 数据计算 禁止临时从 Axis/Series/其他对象读取绘制输入 ``` `paint` 只能读取: ```text 自身 prepare_buffer 自身 paint-only 配置 自身 paint target ``` `paint` 只能写: ```text 自身 paint_buffer ``` 必须满足这个验证原则: > 将其他 Renderable 全部从 `paint` 的可访问环境中移除,只保留当前 Renderable 的 `prepare_buffer`,`paint` 仍必须能够完整正确执行。 ### `composite` `composite` 必须: ```text 只读取已经完成的 paint_buffer 按照 layer 关系完成图层组合 不读取 Renderable 原始业务数据 不执行 prepare 计算 ``` --- # 2. 建立强类型 `prepare_buffer` 每一个需要 prepare 数据的 Renderable 必须拥有自己的强类型 Prepare Buffer。 禁止实现: ```cpp std::unordered_map ``` 禁止通过通用字符串字段传递 Renderable 绘制输入。 例如: ```text Axis └── axis_prepare_buffer Spectrum └── spectrum_prepare_buffer Waterfall └── waterfall_prepare_buffer Afterglow └── afterglow_prepare_buffer ``` 具体字段由各 Renderable 自己定义。 例如 Waterfall: ```text waterfall_prepare_buffer ├── transformed_data ├── visible_range ├── partition_description ├── chunk_metadata ├── raster_parameters └── 其他 paint 必需数据 ``` Paint 不得绕过这些结构重新访问数据源。 --- # 3. 审计并拆除所有混合 Prepare/Paint 实现 逐个审计所有 Renderable。 重点处理: ```text Waterfall Spectrum Afterglow ``` 同时扫描其他 Renderable 中: ```text paint() build_paint_task_graph() render() raster() ``` 内部是否仍包含: ```text 数据变换 跨 Renderable 查询 坐标计算 布局计算 分片 输入数据准备 ``` 全部迁移到 Prepare。 原来的混合实现直接删除。 不得保留: ```text 旧 paint path + 新 prepare path ``` 两套兼容逻辑。 绘制结果必须保持一致。 --- # 4. Prepare Buffer 与 Paint Buffer 完全独立缓存 每个 Renderable 必须独立维护: ```text prepare_buffer validity paint_buffer validity ``` 不得继续使用一个 Renderable 整体缓存状态同时代表两者。 缓存关系必须严格满足: ```text prepare invalid ↓ paint 必须 invalid ``` 但: ```text paint invalid ``` 不得无条件导致: ```text prepare invalid ``` --- # 5. 建立独立 Prepare/Paint Revision 现有 revision/cache revision 体系必须拆到能够分别回答: ```text 当前 prepare_buffer 是否仍有效 当前 paint_buffer 是否仍有效 ``` 至少在语义上存在: ```text prepare input revision prepare output revision paint input revision paint output revision ``` 具体字段名称保持现有项目命名风格。 ### Prepare 有效性必须依赖 ```text 自身数据 revision 依赖 Renderable 提供的数据 revision 会影响 prepare 的尺寸/范围/坐标参数 prepare-only properties ``` ### Paint 有效性必须依赖 ```text 当前 prepare_buffer revision paint-only properties 影响 raster/output 的尺寸和配置 ``` 例如: ```text 仅颜色变化 ``` 必须能够得到: ```text prepare cache = valid paint cache = invalid ``` 例如: ```text 依赖 Axis 范围变化 ``` 必须得到: ```text prepare cache = invalid paint cache = invalid ``` --- # 6. 修正 Dependency Invalidations 跨 Renderable dependency 必须只描述 Prepare 数据依赖。 例如: ```text Series depends on Axis ``` 必须编译成: ```text Axis Prepare ↓ Series Prepare ``` 不得编译成: ```text Axis Paint ↓ Series Prepare ``` 不得继续使用: ```text 整个 Renderable A ↓ 整个 Renderable B ``` 这种粗粒度执行约束。 Prepare 数据变化向 dependency 后继传播: ```text A prepare invalid ↓ B prepare invalid ↓ B paint invalid ``` Paint-only 状态变化不得传播到其他 Renderable 的 Prepare: ```text A paint invalid ``` 不得导致: ```text B prepare invalid ``` --- # 7. 建立 Renderable DAG Builder 接口 Renderable 必须正式提供建图能力。 保留运行时多态。 建立与现有类体系匹配的虚函数,语义必须等价于: ```cpp virtual void build_prepare_graph(render_graph_builder &builder); virtual void build_paint_graph(render_graph_builder &builder); ``` 两个函数必须写入同一个: ```text render_graph_builder ``` 不得分别生成两张最终 Graph。 简单 Renderable: ```text Prepare ↓ Paint ``` 复杂 Renderable 可以展开自己的内部 DAG。 --- # 8. Waterfall 必须展开真实内部 DAG Waterfall 分片必须全部成为正式 Node。 不得把分片隐藏为一个 Waterfall Task 内部的匿名并行执行。 例如: ```text Waterfall Prepare │ ├── Chunk 0 Prepare -> Chunk 0 Paint ─┐ ├── Chunk 1 Prepare -> Chunk 1 Paint ─┤ ├── Chunk 2 Prepare -> Chunk 2 Paint ─┤ └── Chunk N Prepare -> Chunk N Paint ─┤ ▼ Merge ``` 如果某些分片只需要单独的 Prepare 或单独 Paint,则按真实依赖建立节点。 不得为了统一结构制造不存在的任务。 动态 Chunk 必须拥有稳定逻辑 Node ID。 --- # 9. `prepare -> paint` 只能是局部依赖 禁止建立: ```text 所有 Prepare 完成 ↓ 所有 Paint 开始 ``` 这种全局 Barrier。 必须形成流水式 DAG: ```text Prepare A -> Paint A Prepare B -------------> Paint B Prepare C -> Paint C ``` 因此实际运行允许: ```text Prepare A 完成 ↓ Paint A 开始 ``` 同时: ```text Prepare B Prepare C ``` 仍在执行。 这条必须通过并发测试明确验证。 --- # 10. Paint 必须最大程度并行 所有 Renderable 的 Paint 必须只写自己的独立: ```text paint_buffer ``` 因此: ```text Axis Paint Series Paint Waterfall Paint Legend Paint ``` 在不存在真实 Paint 依赖的情况下必须允许完全并行。 不得直接将: ```text layer_node_ ``` 转换为: ```text Paint A -> Paint B ``` 从而人为串行化 Paint。 --- # 11. Layer 关系必须编译到 Composite 图层顺序必须主要落实到 Composite DAG。 例如: ```text Background Paint Series Paint Axis Paint ``` 可以并行。 最终: ```text Background Paint ↓ Composite Background │ Series Paint └────> Composite Series │ Axis Paint └────> Composite Axis ``` 具体依赖按照现有 Layer Graph 的真实顺序生成。 必须保持最终像素结果与原实现一致。 --- # 12. 最终只有一张 Render DAG 最终 Compiler 输入必须为: ```text Renderable internal graph + dependency_node_ + layer_node_ + prepare_buffer validity + paint_buffer validity + Renderable 当前状态 ``` 输出必须只有: ```text render_plan └── graph ``` Graph 内统一存在: ```text prepare node paint node composite node ``` 不得生成: ```text prepare_graph paint_graph ``` 两张最终执行图。 --- # 13. Buffer 必须在建图阶段裁剪任务 缓存命中的工作必须直接从本帧有效 DAG 中删除。 禁止继续生成: ```text cache_hit ``` 空 Task。 完整路径: ```text Prepare ↓ Paint ↓ Composite ``` ### Prepare Cache Hit 本帧必须生成: ```text Paint ↓ Composite ``` Paint 直接读取已有 Prepare Buffer。 ### Paint Cache Hit 本帧必须生成: ```text Composite ``` Composite 直接读取已有 Paint Buffer。 ### Prepare/Paint 均失效 生成: ```text Prepare ↓ Paint ↓ Composite ``` --- # 14. 建立稳定 `node_id` Kernel/Plot 必须统一分配 DAG Node 身份。 所有逻辑任务必须拥有: ```text node_id ``` 包括: ```text Prepare Paint Composite Waterfall dynamic chunks 内部 merge 内部 geometry task ``` 规则严格保持: ```text 逻辑任务身份不变 => node_id 不变 ``` ```text 逻辑任务语义改变 => 分配新 node_id ``` ```text node 退休 => node_id 永不复用 ``` --- # 15. Node 必须带最小元数据 每个 Render Node 至少包含: ```text node_id owner/renderable id name kind execution_index ``` `kind` 至少有: ```text prepare paint composite ``` 不提前添加无实际使用场景的分类。 --- # 16. 建立单一 `render_plan` 建立: ```text render_plan ├── version └── graph ├── nodes └── edges ``` `render_plan` 必须代表: > 当前 Plot 在当前 Renderable、Dependency、Layer、Prepare Cache、Paint Cache 状态下真正会执行的完整 Render DAG。 --- # 17. 建立 `render_plan_version` 以下任一情况发生时必须产生新 Version: ```text active node set 改变 Node 增加 Node 删除 Edge 改变 Waterfall 分片拓扑变化 dependency topology 变化 layer/composite topology 变化 prepare cache 裁剪结果变化 paint cache 裁剪结果变化 ``` 仅以下变化不得产生新 Version: ```text Task 实际耗时变化 Task Worker 改变 调度顺序不同 实际并行程度不同 ``` --- # 18. Render Plan 编译成一个 Taskflow 必须满足: ```text 1 Render Node = 1 Taskflow Task ``` 以及: ```text 1 Render Edge = 1 Taskflow dependency ``` 最终: ```text render_plan.graph ↓ Taskflow ↓ Taskflow Executor ``` 不得生成两个前后 Taskflow。 --- # 19. Taskflow 只遵守偏序关系 DAG Edge 只表示: ```text B 不能在 A 完成以前执行 ``` 没有 Edge 的 Node 必须交由 Taskflow 自由调度。 不得写: ```text 固定 Worker 固定执行次序 手工串行队列 ``` 除非任务本身存在真实依赖。 --- # 20. 性能采集必须请求式开启 正常运行: ```text capture = disabled ``` 不得常驻记录完整 Node 时序。 必须实现: ```text capture_next_frame() ``` 以及: ```text capture_frames(count) ``` 例如: ```text capture_frames(20) ``` 必须从后续完整 Render Frame 开始连续捕获 20 帧,然后自动停止。 --- # 21. Capture Controller 必须保持极简 Plot/Kernel 内维护: ```text capture enabled remaining frame count capture session id ``` 使用必要的原子状态实现。 不得增加: ```text Event system Record system MPSC performance queue TLS trace system collector thread ``` --- # 22. Frame 必须持有 Capture 状态 每个正在 Render 的 Frame 在开始执行时必须确定: ```text capture_this_frame ``` 该状态在本 Frame 生命周期内保持不变。 不得执行到一半再打开 Capture。 --- # 23. Frame 性能数据使用预分配 List 不得在 Task 热路径使用: ```text map unordered_map ``` Render Plan 编译时给每个 Node 分配: ```text execution_index ``` 例如: ```text Node #100 -> slot 0 Node #101 -> slot 1 Node #203 -> slot 2 ``` Capture Frame 创建: ```text node_execution[] ``` 长度直接根据 Plan 确定。 --- # 24. `node_execution` 必须记录真实时序 至少记录: ```text node_id start_time end_time worker_id status ``` `duration` 不重复存储: ```text duration = end_time - start_time ``` 时间源必须保持单调并能在 Worker 间比较。 --- # 25. Taskflow Worker 只能写自己的 Execution Slot 编译 Taskflow 时将: ```text Task ``` 直接绑定: ```text execution_index ``` Capture 开启: ```text execution.start = now execution.worker = worker 执行真实任务 execution.end = now execution.status = complete ``` 不同 Task 不得写同一个 slot。 热路径不得用 mutex 保护整个性能数据结构。 --- # 26. Capture 关闭时不得采集详细时间 Capture 关闭时 Task 必须直接进入正常执行路径。 不得仍然执行: ```text now() start record end record statistics aggregation ``` 只保留最小 capture branch。 --- # 27. Renderable 自定义指标直接写 Execution Slot Renderable 实现允许对自己当前 Node 补充固定性能指标。 例如 Waterfall Prepare: ```text input_count chunk_size prepared_cells ``` Paint: ```text pixel_count primitive_count ``` 不得在 Worker 热路径实现: ```cpp unordered_map ``` 使用固定结构或固定 metric slot。 --- # 28. Frame Snapshot 必须绑定 `render_plan_version` Capture Frame 至少包含: ```text frame_id render_plan_version render_start render_end node_execution[] ``` 不再创建: ```text Trace Span Record Event ``` 等额外运行层。 一帧自己的执行数据就是唯一运行快照。 --- # 29. 三缓冲交换必须成为 Snapshot 发布边界 运行阶段: ```text working frame │ Taskflow 写 execution slots │ render complete │ triple-buffer exchange │ completed frame ``` 进入 Completed 后: ```text frame performance ``` 必须不可再修改。 外部读取 Completed Frame 时不得需要锁住 Taskflow Worker。 --- # 30. 建立 Capture Repository 三缓冲不负责保存历史性能帧。 Capture 请求的 Completed Frame 必须在冷路径复制/移动到: ```text capture_repository ``` 结构: ```text capture_session ├── session_id ├── requested_count ├── captured_count ├── active └── frame_snapshots[] ``` 抓取达到请求数量以后必须自动结束 Session。 --- # 31. 保存 Render Plan 历史结构 必须能够: ```text render_plan_version ↓ 找到当时对应的 Render DAG ``` 连续 20 帧过程中允许: ```text Frame 100 -> Plan 30 Frame 101 -> Plan 30 Frame 102 -> Plan 31 Frame 103 -> Plan 32 ``` 每帧必须绑定自己真实执行的 Plan Version。 不得假定一个 Capture Session 只有一个 DAG Version。 --- # 32. 实现 `frame_analysis` 所有重分析必须发生在 Render 热路径之外。 输入: ```text render_plan + frame_snapshot ``` 输出: ```text frame_analysis ``` 至少计算: ```text total_render_duration node_duration node_start_offset node_end_offset dependency_ready_time scheduler_wait critical_path critical_path_duration critical_path_contribution total_work_duration peak_parallelism average_parallelism parallel_overlap worker utilization bottleneck nodes ``` --- # 33. Scheduler Wait 必须从 DAG 和实际时间推导 对于: ```text A ─┐ ├──> C B ─┘ ``` 计算: ```text dependency_ready(C) = max(A.end, B.end) ``` 然后: ```text scheduler_wait(C) = C.start - dependency_ready(C) ``` Source Node: ```text dependency_ready = render_start ``` 不得为了获得 Wait 再增加事件采集系统。 --- # 34. 正确处理并行节点的耗时占比 不得简单计算: ```text node_duration / sum(all node durations) ``` 作为“帧耗时占比”。 必须明确输出不同指标: ```text work_contribution critical_path_contribution ``` 并行节点允许 Work Duration 总和远大于 Wall Duration。 --- # 35. 实现 `node_statistics` 按稳定: ```text node_id ``` 聚合多帧数据。 至少维护: ```text execution_count average moving_average p50 p95 p99 min max critical_path_frequency average_scheduler_wait ``` 短生命周期 Waterfall Node 同样统计。 --- # 36. 支持按 `render_plan_version` 聚合 必须支持: ```text Plan v30 ├── frame... └── statistics Plan v31 ├── frame... └── statistics ``` 用于直接比较 DAG 编译策略变化后的性能。 例如: ```text Plan v30 P95 render = 8.4 ms Plan v31 P95 render = 6.1 ms ``` --- # 37. 后端增加 Capture API 按照当前后端/Adminive API 风格接入。 必须提供等价能力: ```text 请求下一帧 请求连续 N 帧 查看 capture 状态 查看 capture session 查看 captured frame 列表 读取单帧 snapshot 读取单帧 analysis 读取 render plan topology 读取 node statistics 读取 plan version statistics ``` 禁止为了这些 API 重新实时读取 Worker 数据。 接口只读取: ```text completed snapshots analysis statistics ``` --- # 38. 前端增加 Performance Capture 页面 前端必须提供: ```text Capture next frame Capture N frames ``` 默认 N 可输入: ```text 20 ``` Capture 时显示: ```text captured 7 / 20 ``` 完成后显示捕获到的 Frame 列表。 --- # 39. Frame 列表必须显示 Version 例如: ```text Frame #10381 Plan v57 6.81 ms Frame #10382 Plan v57 7.02 ms Frame #10383 Plan v58 5.93 ms ``` 点击 Frame 后必须加载: ```text frame_snapshot + 对应 render_plan_version + frame_analysis ``` --- # 40. 前端主视图必须是一张完整 Render DAG 不得拆成: ```text Prepare DAG Paint DAG ``` 两个主图。 必须显示完整: ```text Prepare ↓ Paint ↓ Composite ``` 以及跨 Renderable 数据依赖。 例如: ```text Axis Prepare ────────────────┐ │ │ ▼ ▼ Axis Paint Series Prepare │ │ │ ▼ │ Series Paint │ │ │ ▼ │ Composite Series │ │ └──────────────────────┼──> Composite Axis ``` Waterfall 内部 Chunk 必须可以展开。 --- # 41. 前端 DAG Node 必须按 `kind` 区分 至少区分: ```text prepare paint composite ``` 节点上直接显示: ```text 当前 duration scheduler_wait worker critical contribution historical p95 ``` 不得只有一个模糊的百分比字段。 --- # 42. 前端必须显示 Prepare/Paint Cache 独立状态 Renderable Detail 必须显示: ```text prepare cache: HIT/MISS paint cache: HIT/MISS ``` 例如: ```text Spectrum prepare cache: HIT paint cache: MISS ``` 用户必须能够直接理解为什么本 Frame DAG 中: ```text Spectrum Prepare ``` 不存在,而: ```text Spectrum Paint ``` 存在。 --- # 43. 前端必须实现真实 Worker Timeline 同一个 Frame 必须能够按真实时间显示: ```text time ─────────────────────────────────────────> Worker 0 [Axis Prepare][Axis Paint ] Worker 1 [Series Prepare ][Series Paint] Worker 2 [WF Prepare][Chunk0 Prep][Chunk0 Paint] Worker 3 [Chunk1 Prep][Chunk1 Paint] Worker 4 [Composite] ``` 这张 Timeline 使用: ```text start_time end_time worker_id ``` 直接生成。 --- # 44. DAG 与 Timeline 必须双向联动 点击 DAG Node: ```text Chunk 7 Paint ``` 必须在 Timeline 高亮它的真实执行区间。 点击 Timeline 区间: ```text Worker 3 / 2.3ms ~ 3.7ms ``` 必须高亮对应 DAG Node。 --- # 45. 前端 Node Detail 必须展示当前与历史对比 例如: ```text Waterfall / Chunk 7 / Paint current duration 1.42 ms scheduler wait 0.18 ms worker 3 moving average 1.13 ms p95 1.67 ms p99 2.10 ms critical contribution 12.4% critical path frequency 14 / 20 ``` Renderable 自定义指标同时显示。 --- # 46. 连续 N 帧必须提供统计视图 Capture 20 帧以后必须提供: ```text total render avg p50 p95 max parallelism average peak scheduler wait average p95 critical path node frequency ``` 不得只提供 20 个单帧链接。 --- # 47. 不同 Plan Version 必须支持直接比较 如果 Capture 中存在: ```text Plan v57 Plan v58 ``` 必须能够比较: ```text frame count render avg render p95 peak parallelism average parallelism scheduler wait critical path nodes ``` 并展示拓扑变化: ```text 新增 node 删除 node 新增 edge 删除 edge 缓存裁剪变化 ``` --- # 48. 测试执行顺序 所有阶段必须遵守: ```text 先补测试 ↓ 确认测试失败 ↓ 修改实现 ↓ 相关测试通过 ↓ 全量测试通过 ↓ 再进入下一阶段 ``` 不得先整体改完再补测试。 --- # 49. 必须增加的核心测试 覆盖: ```text prepare 禁止依赖 paint 结果 paint 不访问其他 Renderable prepare_buffer 独立有效 paint_buffer 独立有效 prepare invalid -> paint invalid paint invalid 不反向 invalid prepare dependency 只约束 prepare prepare 完成后对应 paint 可立即执行 不存在全局 prepare barrier 无依赖 Renderable prepare 真并行 独立 paint_buffer 的 paint 真并行 layer 顺序只正确约束 composite cache hit 节点真正不进入 DAG node_id 跨 plan version 稳定 retired node_id 不复用 Waterfall 动态分片 node 正确 render_plan_version 正确变化 一张 DAG 正确编译一个 Taskflow Capture off 不生成 execution timing Capture next frame 只抓一帧 Capture 20 frames 正好抓 20 帧 多 worker 写不同 execution slot 无竞争 Frame A/B 不串 performance 数据 三缓冲交换以后 snapshot 不再变化 Plan version 与 Frame 正确绑定 scheduler_wait 推导正确 critical path 正确 并行时间重叠计算正确 前端 API 返回 Plan + Frame 完整数据 ``` --- # 50. 并发与 Sanitizer 验证 必须执行: ```text 高并发 Taskflow 测试 Waterfall 大量动态 Chunk 持续 Render Capture 连续多帧 Capture 开关反复操作 Plan 高频变化 缓存高频命中/失效 ``` 并运行项目当前环境可用的: ```text ASan UBSan TSan ``` TSan 重点检查: ```text Frame execution slots capture controller triple-buffer publish capture repository plan history ``` --- # 51. 性能回归验证 必须单独比较: ```text Capture OFF ``` 情况下改造前后的 Render 性能。 Capture OFF 不得因为性能分析系统引入明显: ```text 锁竞争 动态内存分配 hash lookup 时间采样 队列 push observer 聚合 ``` Capture ON 的开销单独测量。 --- # 52. 清理旧性能统计路径 当 Frame Capture + `node_statistics` 完成以后,审计现有 Renderable Task Observer / Task Execution Snapshot / Rolling Statistics 等机制。 如果职责已经完全被新结构替换: ```text 直接删除旧实现 ``` 不得保留双统计路径。 仅保留仍有独立语义、没有被新系统替代的统计能力。 --- # 53. 最终代码结构必须满足 ```text Plot │ ├── Renderable graph relationships │ ├── render_plan compiler │ └── ONE Render DAG │ ├── Taskflow executor │ ├── frame buffers │ ├── prepare_buffer state │ ├── paint_buffer state │ └── optional performance snapshot │ ├── capture controller │ ├── capture repository │ ├── frame_analysis │ └── node_statistics ``` 前端: ```text Performance │ ├── Capture Control ├── Captured Frames ├── Render DAG ├── Worker Timeline ├── Node Detail ├── Multi-frame Statistics └── Plan Version Comparison ``` --- # 54. 最终不可破坏的设计规则 这部分直接放到 Codex 任务最顶部: > **所有跨 Renderable 数据访问必须在 `prepare` 完成。** > > **`paint` 禁止访问其他 Renderable,只能消费自身 `prepare_buffer`。** > > **`prepare_buffer` 与 `paint_buffer` 必须是完全独立的两层缓存。** > > **`prepare` 缓存失效必须使 `paint` 缓存失效;`paint` 缓存失效不得反向污染 `prepare`。** > > **Prepare、Paint、Composite 最终必须构成同一张 Render DAG。** > > **禁止建立全局 Prepare→Paint Barrier。** > > **某个 Prepare 完成后,只要其真实依赖已经满足,对应 Paint 必须立即允许进入 Taskflow 调度。** > > **独立 `paint_buffer` 的 Paint 必须尽可能并行,Layer 顺序落实到 Composite。** > > **缓存命中的工作必须在 Render DAG 构建阶段直接裁剪。** > > **Kernel Render DAG 是执行、Taskflow 编译和性能分析的唯一拓扑事实来源。** > > **性能时序完全绑定 Frame,不建立 Trace/Event/Record/MPSC 性能事件体系。** > > **Capture 必须请求式开启,支持下一帧和连续 N 帧。** > > **Capture 开启时 Taskflow Task 直接写 Frame 预分配 Execution Slot。** > > **三缓冲交换完成后 Frame Snapshot 必须不可变。** > > **性能分析必须在完成帧冷路径执行。** > > **前端必须同时展示 Render DAG 偏序关系和本 Frame 的真实 Worker 时序。** > > **不得触碰 git。** > > **所有代码保持 K&R 风格,不增加无意义空行。** > > **被替换的旧实现直接删除,不做兼容实现。** 执行完成后的最终数据流必须严格为: ```text Renderable / Dependency / Layer / Cache │ ▼ render_plan compiler │ ▼ ONE Render DAG │ ▼ Taskflow │ ┌──────┴──────┐ │ │ Capture OFF Capture ON │ │ 正常执行 Frame slots │ ▼ completed Frame │ ▼ triple-buffer publish │ ▼ immutable snapshot │ ┌──────────┴──────────┐ ▼ ▼ frame_analysis node_statistics │ │ └──────────┬──────────┘ ▼ Backend API │ ▼ DAG + Worker Timeline + Multi-frame Analysis + Plan Version Compare ``` 这份计划直接从 Renderable 边界改造一直执行到最终前端性能分析页面。