Files
XCEngine/docs/plan/Renderer_C++层第一阶段收口计划_2026-04-13_晚间.md

311 lines
12 KiB
Markdown
Raw Permalink Normal View History

# Renderer C++层第一阶段收口计划
日期: `2026-04-13`
## 1. 文档定位
这份文档是 `Render Graph` 之前的最后一轮 `native render kernel v1` 收口计划。
目标不是继续往当前 `Rendering` 层里塞新功能,而是先把下面几件事彻底做清楚:
- `request -> frame plan -> execution` 三层语义分开。
- `RenderSceneExtractor -> CullingResults -> RendererList -> DrawSettings` 这条数据组织链正式化。
- `BuiltinForwardPipeline` 从“大杂烩渲染器”收成“协调器 + 子能力”。
- `Editor` 注入点、阴影、主场景、后处理之间的边界说清楚。
- 给下一步 `C++ Render Graph` 留出稳定输入,而不是把当前混乱直接 graph 化。
结论先写在前面:
- `Render Graph` 应该做在 `C++ native` 层。
- 现在还不应该直接开做 `Render Graph``Deferred Renderer`
- 当前更优先的是把现有渲染层整理干净,再往 SRP/URP 方向演进。
## 2. 当前阶段已经完成的收口
截至 `2026-04-13` 晚间,已经落地的内容:
- `CameraRenderRequest -> CameraFramePlan` 已经分层,`CameraRenderer` 开始正式消费 plan。
- `CullingResults / RendererList` contract 已经进入 `RenderSceneData`
- `Forward / Depth / ObjectId` 已经优先走 `RendererList`,旧 `visibleItems` 只保留过渡 fallback。
- `RendererListUtils` 已经把可见项遍历规则收口成公共工具。
- `Gaussian / Volumetric` 已经从 `BuiltinForwardPipeline` 中抽成统一 `SceneRenderFeaturePass`
- `FrameExecutionContext / ScenePhase / DrawSettings` 已经引入。
- `RenderPipeline` 已经支持新的 `FrameExecutionContext` 入口,旧三参数入口保留为兼容适配层。
- `BuiltinForwardPipeline` 已经开始按 scene phase 组织主场景执行。
- `CameraRenderer` 主场景阶段已经走新的 execution context而不是继续只传三参数。
本轮验证结果:
- `XCEditor` 已重新编译通过。
- `rendering_unit_tests` 已重新编译通过。
- `editor_tests` 已重新编译通过。
- `editor_tests --gtest_filter=*ViewportRenderFlow*:*SceneViewportRenderPassBundle* --gtest_brief=1` 通过 `14/14`
- `rendering_unit_tests --gtest_filter=*BuiltinForwardPipeline*:*RenderPass*:*CameraSceneRenderer*:*Shadow*:*ObjectId* --gtest_brief=1` 通过 `67/68`
- 唯一失败仍然是既有老问题:
`BuiltinForwardPipeline_Test.OpenGLRuntimeTranspilesForwardShadowVariantToLegacyClipConventions`
## 3. 为什么现在还不能直接上 Render Graph
现在直接上 `Render Graph`,本质上是在 graph 里继续承接当前的隐式耦合,问题只会换个位置存在。
当前还没完全收口的核心问题不是“没有 graph”而是下面这些边界还不够正式
- `CameraRenderer` 和各类 scene pass 之间,谁负责组织阶段,谁负责执行,还没有完全模块化。
- `Shadow` 相关逻辑仍然分散在 planner、camera execution、pipeline、surface cache 几处。
- `BuiltinForwardPipeline` 虽然已经开始瘦身,但还没有彻底收成一个明确的 coordinator。
- `Editor` 的扩展点虽然已可用,但 contract 还偏“约定式”,还不够像以后给 `C# SRP` 暴露的正式接口。
- 目录结构仍然在暴露旧历史:一些“子系统”目前还是文件堆,不是真正的模块。
如果这些问题不先解决,`Render Graph` 只会变成一个新的承压层,后面再拆更贵。
## 4. Render Graph 和未来 SRP/URP 的边界
未来的推荐结构仍然是这条线:
`RHI -> Native Render Kernel -> Render Graph -> SRP-like Contract -> Universal Renderer -> C# Custom Pipeline`
其中边界应当明确成这样:
- `C++ native` 保留:
- `Render Graph`
- `CullingResults / RendererList`
- draw / dispatch context
- GPU resource cache
- shadow map / atlas 执行能力
- Gaussian 排序与 working set
- Volume 资源上传与底层执行
- `URP-like` 包层保留:
- feature 编排
- pass 注入顺序
- renderer feature 配置
- 用户级 pipeline 组合
- 未来的 `C#` 自定义渲染管线 API
这意味着:
- 阴影、Gaussian、Volumetric 不是整块搬去包层。
- 包层更像 Unity 的 `URP renderer``renderer feature`
- native 层更像 Unity 没公开给用户、但真正负责执行和图资源生命周期的内核。
## 5. 第一阶段还差哪些工作才能收口
### 5.1 Shadow 子系统正式化
这是当前最值得先做的一块。
现状问题:
- 阴影规划在 `Planning`
- 阴影 surface/cache 在 `Execution/Caches`
- 阴影执行又是 standalone pass。
- 主场景采样阴影的状态切换仍在 `BuiltinForwardPipeline`
这说明阴影现在“能跑”,但还不是一个正式子系统。
收口目标:
- 明确 `shadow planning / shadow resources / shadow execution / shadow sampling contract` 四层边界。
- 把方向光阴影相关共享数据收成一组正式类型,而不是散落在多个调用点上。
- 为以后扩展 `cascades / shadow atlas / additional light shadows / baked shadowmask` 留出位置。
### 5.2 Editor 注入点正式化
现状问题:
- 当前有 `pre scene / post scene / overlay / object id / outline / grid` 多种 editor 路径。
- 这些能力已经能工作,但还没有统一成“正式 stage 注入 contract”。
收口目标:
- 明确哪些注入点属于 runtime 正式阶段,哪些属于 editor-only extension。
-`CameraFramePlan` 对这些阶段的描述更加稳定。
- 给以后 `C# renderer feature` 的注入点设计提供 native 对照物。
### 5.3 BuiltinForwardPipeline 继续瘦身
本轮已经完成第一刀,但还没收完。
还需要继续做的事情:
- 把 forward scene phase 执行和底层 draw/resource 逻辑彻底分开。
- 把 forward renderer 自己的内部资源、skybox、feature 协调代码进一步收拢。
- 保证 `BuiltinForwardPipeline` 自己只表达“阶段顺序和协调”,不再继续膨胀。
### 5.4 旧 fallback 的裁边
当前有一些过渡兼容层是故意保留的:
- `RenderPipeline::Render(context, surface, sceneData)` 旧入口
- `visibleItems` fallback
- `BuildRenderRequests` 旧习惯入口
这些现在不该硬删,因为会影响现有 tests 和 editor 链路。
但第一阶段收口前,至少要做到:
- 新主链默认只走正式 contract。
- 旧入口只作为 adapter不再新增依赖。
- 每个 fallback 都有明确退出条件。
### 5.5 测试和文档补齐
当前已有回归还不够系统。
还需要补的重点测试:
- `FrameExecutionContext` 是否完整透传 source surface / source color view / state。
- `BuiltinForwardPipeline` scene phase 顺序是否稳定。
- feature pass 的 `Prepare -> Execute` 顺序是否稳定。
- editor 注入点在有后处理和无后处理两种情况下是否仍能保持正确 source/destination surface。
- shadow planning 和 main scene shadow sampling 之间的契约测试。
## 6. 下一步最优先该做什么
下一步最优先建议做:
`Shadow 子系统收口`
原因很直接:
- 它横跨 `Planning / Execution / Pipeline / Resources / Sampling`
- 它是以后 `Deferred / Light Baking / ShadowMask / Additional Light Shadows` 的共同基础。
- 它也是未来 `Render Graph` 最敏感的一类资源依赖链。
- 如果阴影先不收,后面 graph 化时 barrier、resource lifetime、pass dependency 都会更乱。
建议顺序:
1. 先把方向光阴影的 plan/data/resource/execute contract 固化。
2. 再把 editor 注入 contract 固化。
3. 然后做第一轮目录收拢。
4. 最后判断这一阶段是否可以正式收口,进入 `Render Graph` 设计。
## 7. 当前 Rendering 目录结构存在的问题
### 7.1 `FrameData` 目录太杂
现在 `FrameData` 里同时混着:
- camera/environment 数据
- scene snapshot
- visible item
- culling results
- renderer list utils
这说明它不是一个明确模块,而是“跟帧有关的先放这”。
建议方向:
- `FrameData` 保留纯只读帧快照类型。
-`CullingResults / RendererList / Filtering / Sorting / DrawSettings` 逐步收进更明确的 `Execution``Culling` 子域。
- `RendererListUtils` 这种执行辅助逻辑,不适合长期留在 `FrameData`
### 7.2 `Passes` 目录混合了三类东西
现在 `Passes` 里同时有:
- 主场景 pass
- fullscreen/post-process pass
- editor pass
这会让“runtime 正式渲染能力”和“editor 辅助渲染能力”继续混在一起。
建议方向:
- `Passes/Scene`
- `Passes/Fullscreen`
- `Passes/Editor`
- `Passes/Shadow`
不一定要一次性全搬,但后面新增文件不应继续平铺。
### 7.3 `BuiltinForwardPipeline` 还没形成真正子模块
当前 forward 相关代码已经分散在:
- `BuiltinForwardPipeline.h/.cpp`
- `BuiltinForwardPipelineSkybox.cpp`
- `Internal/BuiltinForwardPipelineResources.cpp`
这已经具备“应该单独成目录”的条件。
建议方向:
- `Rendering/Pipelines/BuiltinForward/`
- `BuiltinForwardPipeline.h`
- `BuiltinForwardPipeline.cpp`
- `BuiltinForwardPipelineScene.cpp`
- `BuiltinForwardPipelineResources.cpp`
- `BuiltinForwardPipelineSkybox.cpp`
这样后面 forward / deferred / universal renderer 才能并列演进。
### 7.4 `Shadow` 目录还不算真正的 shadow 子系统
目前虽然已经有 `Rendering/Shadow`,但从全链路看,阴影的责任仍然散在其他目录。
建议方向:
- `Shadow` 目录最终至少容纳:
- planning types
- shared frame data
- runtime resources / caches
- shadow executor or shadow renderer
### 7.5 `Internal` 边界不稳定
现在 `src/Rendering/Internal` 更像历史遗留缓冲区。
长期风险:
- 真正属于 forward 的内部实现放在全局 `Internal`
- 真正属于 volume / splat / shadow 的内部实现也可能继续堆进去
建议方向:
- 全局 `Internal` 只保留跨模块公共 helper。
- 各子系统自己的内部文件放回各自目录。
## 8. 建议的第一轮目录收拢动作
这一轮只做低风险收拢,不做大搬家。
建议动作:
-`BuiltinForwardPipeline*` 相关实现收成 `Pipelines/BuiltinForward/` 子目录。
-`Passes` 至少先分出 `Editor``Fullscreen` 两个子目录。
-`Shadow` 补一组正式 shared types再决定是否移动更多实现文件。
- 暂时不大动 `include` 层 public 路径,先保证编译和引用稳定。
原则:
- 先按职责拆,再按目录搬。
- 不为了“好看”做纯目录手术。
- 每次收拢都必须带编译和回归。
## 9. 第一阶段收口完成的判定标准
满足下面这些条件,就可以认为 `Render Graph` 之前这一阶段基本收口:
- `CameraFramePlan` 成为主执行入口,旧 request 入口只保留兼容壳。
- `FrameExecutionContext / ScenePhase / DrawSettings` 成为主场景执行正式 contract。
- `CullingResults / RendererList` 成为主要 draw organization contract。
- `BuiltinForwardPipeline` 被收成 coordinator而不是继续长成总垃圾堆。
- `Shadow` 成为清晰子系统,而不是散点逻辑。
- `Editor` 注入点形成稳定 contract。
- 目录结构不再继续鼓励“新逻辑直接往老文件里塞”。
- 相关 tests 和编译链稳定。
到这一步,再开始 `C++ Render Graph`,代价才是可控的。
## 10. 当前建议
当前最佳路线不变:
- 短期:继续按 Unity 的 `SRP + URP` 方向做 native 基座。
- 中期:先在 `C++` 做出稳定的 `Render Graph + RendererList + Feature Injection` 内核。
- 中长期:再暴露 `C#` 自定义渲染管线接口,做你自己的 `URP-like` 包层。
眼下最正确的动作不是“赶紧补 deferred”也不是“先把所有特效搬去包层”而是
`先把当前 native rendering layer 整理成一个真正可扩展的内核。`