docs: sync builtin forward pipeline docs

This commit is contained in:
2026-04-03 13:51:27 +08:00
parent 62e0d8b46d
commit 73821ff73f
13 changed files with 483 additions and 116 deletions

View File

@@ -0,0 +1,53 @@
# BuiltinForwardPipeline::BuildInputLayout
**命名空间**: `XCEngine::Rendering::Pipelines`
**类型**: `method`
**头文件**: `XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h`
返回这条前向管线当前硬编码使用的静态网格顶点布局。
```cpp
static RHI::InputLayoutDesc BuildInputLayout();
```
## 当前实现返回值
当前固定返回 3 个顶点元素:
1. `POSITION`
- 格式: `R32G32B32_Float`
- `semanticIndex = 0`
- `inputSlot = 0`
- `alignedByteOffset = 0`
2. `NORMAL`
- 格式: `R32G32B32_Float`
- offset: `offsetof(Resources::StaticMeshVertex, normal)`
3. `TEXCOORD`
- 格式: `R32G32_Float`
- offset: `offsetof(Resources::StaticMeshVertex, uv0)`
最需要注意的一点是:
- 位置当前是 `float3`,不是旧实现或旧文档里写过的 `float4`
这已经由 `tests/Rendering/unit/test_builtin_forward_pipeline.cpp` 明确校验。
## 当前语义
这个方法定义的不是“通用顶点布局建议”,而是 `BuiltinForwardPipeline` 当前真正依赖的 mesh 输入契约。
换句话说:
- 只要你还在用这条 builtin forward pipeline就必须保证顶点数据与 `StaticMeshVertex` 的布局兼容
- 如果你需要不同的顶点流或额外属性,更合理的做法通常是创建新的 pipeline而不是继续复用这条 builtin 管线
## 返回值
- `RHI::InputLayoutDesc` - 可直接写入图形管线描述的输入布局
## 相关文档
- [BuiltinForwardPipeline](BuiltinForwardPipeline.md)
- [Render](Render.md)

View File

@@ -6,56 +6,82 @@
**头文件**: `XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h`
**描述**: 当前内建的默认前向渲染管线实现基础纹理采样、深度测试和 mesh 绘制
**描述**: 当前内建的前向渲染管线实现。它会按 shader pass 的资源声明动态构建 `PassResourceLayout`、descriptor set 与 `RHIPipelineState`,并通过 `RenderPassSequence` 执行默认的 opaque pass
## 概
## 概
`BuiltinForwardPipeline` 是当前引擎真正能跑起来的默认渲染管线。
`BuiltinForwardPipeline` 已经不再是“固定几套 descriptor set + 单一 pipeline layout”的旧模型。当前实现有三条关键缓存链路
它的工作路径大致是:
- `m_passResourceLayouts`:以 `(shader*, passName)` 为 key缓存每个 shader pass 的资源布局、pipeline layout、静态 descriptor set 和语义位置。
- `m_pipelineStates`:以 `(shader*, passName, material render state)` 为 key缓存真正的图形 pipeline state。
- `m_dynamicDescriptorSets`:以 `(passLayout, setIndex, objectId, material)` 为 key缓存逐物体或逐材质的 descriptor set。
1. 基于 `RenderContext` 创建 pipeline state、descriptor pool、sampler 和 fallback texture
2. 使用 [RenderResourceCache](../../RenderResourceCache/RenderResourceCache.md) 把 `Mesh` / `Texture` 上传成 GPU 资源。
3. 读取 [VisibleRenderObject](../../VisibleRenderObject/VisibleRenderObject.md) 列表。
4. 为每个物体写常量缓冲、绑定纹理和采样器,然后发出 draw call。
构造函数只向 `m_passSequence` 注册一个 `BuiltinForwardOpaquePass`。因此当前仍是一条单 pass 的前向路径,但生命周期已经统一收口到 [RenderPassSequence](../../RenderPass/RenderPass.md)
## 当前实现能力
## 当前资源契约
- 支持 D3D12 与 OpenGL 两套内嵌 shader 路径。
- 支持颜色附件和深度附件。
- 支持 mesh section 绘制。
- 支持从 `Material` 上按若干常见名字查找基础颜色纹理。
- 当材质或纹理缺失时,使用 1x1 白纹理作为 fallback。
`BuiltinForwardPipeline` 会优先读取 shader pass 自己声明的 `resources`。如果该列表为空,则回退到 legacy builtin forward 绑定:
## 当前实现限制
- `set 1 binding 0` -> `PerObject` / `CBV`
- `set 2 binding 0` -> `Material` / `CBV`
- `set 3 binding 0` -> `BaseColorTexture` / `Texture2D`
- `set 4 binding 0` -> `LinearClampSampler` / `Sampler`
- 当前是非常基础的 forward path不包含光照、阴影、法线贴图、后处理或多 pass。
- 只画当前提取结果中的 mesh没有 skybox、UI、粒子或透明物体排序。
- 纹理查找采用名字启发式,当前会依次尝试 `baseColorTexture``_BaseColorTexture``_MainTex` 等键名
- 当前 input layout 把位置声明成 `R32G32B32A32_Float`,而 `StaticMeshVertex::position``Vector3`;现有集成测试能跑通,但这说明顶点布局约定仍需要更严格校准
- 当前 pipeline resource 生命周期完全由这条管线对象自己管理,还没有被更高层渲染框架统一接管
当前可识别的 forward 语义只有四个:
- `PerObject`:必需,且必须是唯一的 constant buffer
- `Material`:可选,且必须是唯一的 constant buffer
- `BaseColorTexture`:可选,且必须是唯一的 `Texture2D``TextureCube`
- `LinearClampSampler`:可选,且必须是唯一的 sampler。
布局构建阶段遇到以下情况会直接记录错误并拒绝创建该 pass layout
- 未知语义。
- 非法 set index。
- 在同一个 set 中混用 sampler 与非 sampler 绑定。
- 在同一个 set 中出现重复 binding。
- 缺少 `PerObject`
如果第一个实际绑定的 set 大于 `0`,并且 `set 0` 为空,实现还会补一个兼容用的 `set 0`,避免某些布局路径要求从 `set 0` 开始。
## 当前渲染流程
1. [Initialize](Initialize.md) 通过 `m_passSequence.Initialize(context)` 进入 pass 生命周期。
2. [Render](Render.md) 把 `RenderContext``RenderSurface``RenderSceneData` 打包成 `RenderPassContext`,再交给 `m_passSequence.Execute(...)`
3. `BuiltinForwardOpaquePass` 内部调用 `ExecuteForwardOpaquePass()`,处理 render target 绑定、viewport/scissor、颜色与深度清理以及前后自动状态切换。
4. 渲染阶段遍历 `RenderSceneData::visibleItems`,筛出 `BuiltinMaterialPass::ForwardLit` 物体。
5. 每个物体都会按当前材质解析 shader/pass获取或创建 pass layout、pipeline state、动态或静态 descriptor set然后写入常量并发出 draw call。
## 当前实现细节
- [BuildInputLayout](BuildInputLayout.md) 现在明确使用 `POSITION=float3``NORMAL=float3``TEXCOORD=float2`,与 `StaticMeshVertex` 对齐。
- 材质贴图解析通过 `ResolveBuiltinBaseColorTexture(material)` 进入 builtin base-color 语义,不再依赖旧文档里的“按若干名字猜测纹理”说法。
- 逐物体常量来自 `PerObjectConstants`;逐材质常量目前只写入 `baseColorFactor`
- 采样器和 1x1 白色 fallback 纹理在初始化后长期复用;具体 `Texture``Mesh` 的 GPU 资源则由 [RenderResourceCache](../../RenderResourceCache/RenderResourceCache.md) 按需上传。
## 当前限制
- 目前只注册了 `BuiltinForwardOpaquePass`,没有透明排序、阴影、延迟渲染或后处理主路径。
- 资源语义是白名单模型,超出 `PerObject / Material / BaseColorTexture / LinearClampSampler` 的声明不会被接受。
- `Render()` 层面不会因为单个物体 `DrawVisibleItem()` 失败而整体返回 `false`;当前调用点仍然以“尽量继续绘制其余物体”为主。
## 公开方法
| 方法 | 说明 |
|------|------|
| [Destructor](Destructor.md) | 析构时关闭管线资源。 |
| [Initialize](Initialize.md) | 初始化这条内建前向管线。 |
| [Shutdown](Shutdown.md) | 释放内部创建的所有 RHI 资源。 |
| [Render](Render.md) | 把 `RenderSceneData` 绘制到目标表面。 |
## 设计说明
即便当前实现很轻量,把默认管线拆成独立类仍然是对的:
- `SceneRenderer` 不必硬编码具体 draw 逻辑。
- 未来想加 deferred、shadow pass 或 editor preview pipeline 时,接口上有扩展空间。
这和商业引擎里保留 builtin pipeline 作为“默认可用实现”的思路是一致的。
| [Constructor](Constructor.md) | 创建管线对象,并注册默认的 opaque pass。 |
| [Destructor](Destructor.md) | 析构时调用 `Shutdown()`。 |
| [BuildInputLayout](BuildInputLayout.md) | 返回 builtin forward 使用的静态网格输入布局。 |
| [Initialize](Initialize.md) | 初始化 pass sequence并在需要时准备共享 GPU 资源。 |
| [Shutdown](Shutdown.md) | 关闭 pass sequence释放 pass layout、descriptor set、pipeline state 与 fallback 资源。 |
| [Render](Render.md) | 把 `RenderSceneData` 绘制到目标 `RenderSurface`。 |
## 相关文档
- [Pipelines](../Pipelines.md)
- [BuiltinForwardPipelineAsset](../BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)
- [RenderPipeline](../../RenderPipeline/RenderPipeline.md)
- [RenderResourceCache](../../RenderResourceCache/RenderResourceCache.md)
- [RenderPipelineAsset](../../RenderPipelineAsset/RenderPipelineAsset.md)
- [CameraRenderer](../../CameraRenderer/CameraRenderer.md)
- [RenderPass](../../RenderPass/RenderPass.md)
- [Scene Extraction And Builtin Forward Pipeline](../../../../_guides/Rendering/Scene-Extraction-And-Builtin-Forward-Pipeline.md)

View File

@@ -0,0 +1,42 @@
# BuiltinForwardPipeline::BuiltinForwardPipeline
**命名空间**: `XCEngine::Rendering::Pipelines`
**类型**: `method`
**头文件**: `XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h`
创建一条新的内建前向渲染管线对象。
```cpp
BuiltinForwardPipeline();
```
## 当前实现行为
构造函数当前只做一件事:
- 向内部 `m_passSequence` 注册一个 `Detail::BuiltinForwardOpaquePass`
它不会在构造时立刻创建任何设备相关资源。下面这些对象都留到 [Initialize](Initialize.md) 或首次 [Render](Render.md) 时再按需创建:
- builtin `ForwardLit` shader 句柄
- 线性 clamp sampler
- fallback 白色纹理和 SRV
- `PassResourceLayout`
- `RHIPipelineState`
- 静态 / 动态 descriptor set
## 设计说明
把“对象构造”和“设备资源初始化”拆开,是渲染系统里很常见也很合理的设计:
- 构造函数不依赖 `RenderContext`
- 上层可以先把 pipeline 对象组装进 `CameraRenderer`
- 真正拿到设备和命令列表后,再决定是否初始化、重建或销毁资源
## 相关文档
- [BuiltinForwardPipeline](BuiltinForwardPipeline.md)
- [Initialize](Initialize.md)
- [Render](Render.md)

View File

@@ -1,16 +1,14 @@
# BuiltinForwardPipeline::~BuiltinForwardPipeline
销毁内建前向管线对象。
```cpp
~BuiltinForwardPipeline() override;
```
## 行为说明
当前析构函数会调用 [Shutdown](Shutdown.md)。
析构函数会直接调用 [Shutdown](Shutdown.md),把内部 pass sequence 和 builtin forward 共享资源完整释放掉
## 相关文档
- [返回类型总览](BuiltinForwardPipeline.md)
- [BuiltinForwardPipeline](BuiltinForwardPipeline.md)
- [Shutdown](Shutdown.md)

View File

@@ -1,31 +1,37 @@
# BuiltinForwardPipeline::Initialize
初始化内建前向管线。
```cpp
bool Initialize(const RenderContext& context) override;
```
## 行为说明
当前实现直接转发到内部 `EnsureInitialized(context)`
当前实现不再直接调用管线自身的 `EnsureInitialized()`,而是把生命周期交给内部的 `m_passSequence`
```cpp
return m_passSequence.Initialize(context);
```
由于构造函数只注册了一个 `BuiltinForwardOpaquePass`,这里的真实初始化工作会进入该 pass 的 `Initialize()`,再由它调用 `BuiltinForwardPipeline::EnsureInitialized(context)`
## 参数
- `context` - 当前渲染上下文。
- `context` - 当前渲染上下文,必须提供有效的 device、command list 与 backend
## 返回值
- 初始化成功返回 `true`
- 否则返回 `false`
- 成功返回 `true`
- `context` 无效,或共享 GPU 资源准备失败时返回 `false`
## 当前实现说明
## 当前初始化内容
- 若当前设备与 backend 和已初始化状态匹配,内部会复用现有资源。
- 若上下文变化,会先销毁旧资源,再重新创建。
- 复用同一个 device/backend 时,`EnsureInitialized()` 会直接返回,不重复构建共享资源。
- device 或 backend 变化,会先销毁旧资源,再重新创建 builtin forward shader、线性 clamp sampler、1x1 白色 fallback 纹理和对应 SRV
- `PassResourceLayout``RHIPipelineState` 与动态 descriptor set 不会在这里一次性全部建立,而是在后续真正渲染某个 shader pass / 材质时按需创建。
## 相关文档
- [返回类型总览](BuiltinForwardPipeline.md)
- [BuiltinForwardPipeline](BuiltinForwardPipeline.md)
- [Render](Render.md)
- [Shutdown](Shutdown.md)
- [RenderPass](../../RenderPass/RenderPass.md)

View File

@@ -1,7 +1,5 @@
# BuiltinForwardPipeline::Render
执行一次内建前向渲染。
```cpp
bool Render(
const RenderContext& context,
@@ -11,36 +9,58 @@ bool Render(
## 行为说明
当前实现会
当前 `Render()` 本身很薄,只做两件事
1. 确保管线资源已初始化
2. 检查颜色附件是否存在
3. 在需要时把颜色附件从 `stateBefore` 转成 `RenderTarget`
4. 绑定 render target、viewport 和 scissor
5. 清颜色和深度。
6. 设置 pipeline state 与 primitive topology。
7. 遍历 `sceneData.visibleObjects`,逐个发出 draw call。
8. 在需要时把颜色附件从 `RenderTarget` 转回 `stateAfter`
1. 调用 `Initialize(context)`,确保 pass sequence 与共享资源已经可用
2. 组装 `RenderPassContext { context, surface, sceneData }`,再执行 `m_passSequence.Execute(passContext)`
由于当前 sequence 里只包含 `BuiltinForwardOpaquePass`,真正的绘制逻辑发生在 `ExecuteForwardOpaquePass()`
## 当前 opaque pass 流程
1. 校验 `surface.GetColorAttachments()` 非空
2. 如启用了自动状态切换,把颜色附件从 `surface.GetColorStateBefore()` 转成 `RenderTarget`
3. 绑定 render target、depth attachment、viewport 与 scissor。
4.`RenderSurface` 的 clear-color override 和 `sceneData.cameraData.clearFlags` 决定是否清颜色/深度。
5. 设置 `TriangleList` 拓扑。
6. 遍历 `RenderSceneData::visibleItems`,只处理匹配 `BuiltinMaterialPass::ForwardLit` 的可见项。
7. 对每个物体复用或创建匹配的 pipeline state并调用内部 `DrawVisibleItem(...)`
8. 结束时如启用了自动状态切换,再把颜色附件从 `RenderTarget` 切回 `surface.GetColorStateAfter()`
## `DrawVisibleItem()` 当前行为
单个可见项的绘制链路为:
1. 通过 `RenderResourceCache` 取得 mesh 的 GPU 缓存。
2. 写入 `PerObjectConstants`,其中包含投影矩阵、视图矩阵、`localToWorld`、逆矩阵和主方向光数据。
3. 基于材质解析实际要使用的 shader/pass。
4. 获取或创建该 `(shader*, passName)` 对应的 `PassResourceLayout`
5. 解析 base-color 纹理视图与逐材质常量。
6. 逐 set 绑定 descriptor
-`PerObject / Material / Texture` 的 set 走动态 descriptor set 缓存。
- 只含 sampler 的 set 走静态 descriptor set 缓存。
7. 调用 `SetGraphicsDescriptorSets(...)`,并按 section 或整 mesh 发出 `DrawIndexed` / `Draw`
## 参数
- `context` - 当前渲染上下文。
- `surface` - 当前目标表面
- `sceneData` - 提取好的相机和可见对象数据。
- `surface` - 当前输出目标。
- `sceneData` - `RenderSceneExtractor` 产出的相机、光照与 `visibleItems` 数据。
## 返回值
- 成功返回 `true`
- 初始化失败或没有颜色附件时返回 `false`
- 整个 pass sequence 成功执行时返回 `true`
- 初始化失败、缺少颜色附件、render area 非法,或 pass sequence 中某个 pass 明确失败时返回 `false`
## 当前实现限制
## 当前限制
- 当前不会因为某个单独物体绘制失败而整体返回 `false`;内部 `DrawVisibleObject()` 的失败结果并没有汇总成整帧失败
- 当前没有多 pass 结构
- 当前默认总会清颜色;没有“只加载不清除”的 load/store 策略配置
- 当前 sequence 只有一个 opaque pass还没有透明排序、shadow pass 或 deferred path
- 调用点目前不会把单个 `DrawVisibleItem()` 的失败汇总成整体失败;它更偏向“跳过当前物体,继续绘制其余物体”
- `Render()` 只处理一个 `RenderSurface` 和一份 `RenderSceneData`,不是 render graph
## 相关文档
- [返回类型总览](BuiltinForwardPipeline.md)
- [BuiltinForwardPipeline](BuiltinForwardPipeline.md)
- [RenderSurface](../../RenderSurface/RenderSurface.md)
- [VisibleRenderObject](../../VisibleRenderObject/VisibleRenderObject.md)
- [RenderPass](../../RenderPass/RenderPass.md)
- [Scene Extraction And Builtin Forward Pipeline](../../../../_guides/Rendering/Scene-Extraction-And-Builtin-Forward-Pipeline.md)

View File

@@ -1,23 +1,38 @@
# BuiltinForwardPipeline::Shutdown
关闭内建前向管线并释放其资源。
```cpp
void Shutdown() override;
```
## 行为说明
当前实现直接调用内部 `DestroyPipelineResources()`,释放
当前 `Shutdown()` 已经统一走 pass sequence
- resource cache
- fallback texture / view
- sampler
- pipeline state
- pipeline layout
- descriptor set / descriptor pool
```cpp
m_passSequence.Shutdown();
```
真正的资源释放发生在 `BuiltinForwardOpaquePass::Shutdown()` 中。该 pass 会回调 `BuiltinForwardPipeline::DestroyPipelineResources()`,把 builtin forward 相关的共享缓存全部清掉。
## 当前释放内容
- `RenderResourceCache`
- `m_pipelineStates`
- `m_dynamicDescriptorSets`
- `m_passResourceLayouts`
- fallback 纹理与 SRV
- 线性 clamp sampler
这里释放的是“按 pass layout 分组的 pipeline layout / descriptor set / descriptor pool”而不是旧文档里描述的单一全局 pipeline layout。
## 当前语义
- 多次调用是安全的;资源被清空后成员会回到空状态。
- 下次 `Render()``Initialize()` 再次进入时,会按当前 device/backend 重新建立共享资源。
## 相关文档
- [返回类型总览](BuiltinForwardPipeline.md)
- [BuiltinForwardPipeline](BuiltinForwardPipeline.md)
- [Destructor](Destructor.md)
- [RenderResourceCache](../../RenderResourceCache/RenderResourceCache.md)
- [RenderPass](../../RenderPass/RenderPass.md)

View File

@@ -0,0 +1,49 @@
# BuiltinForwardPipelineAsset
**命名空间**: `XCEngine::Rendering::Pipelines`
**类型**: `class final`
**头文件**: `XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h`
**描述**: 当前默认的具体 `RenderPipelineAsset`,负责生成新的 [BuiltinForwardPipeline](../BuiltinForwardPipeline/BuiltinForwardPipeline.md) 实例。
## 概览
`BuiltinForwardPipelineAsset` 是当前渲染模块里唯一公开的 concrete pipeline asset。它的职责很简单
- 作为默认主管线工厂存在
- 在需要时返回一条新的 `BuiltinForwardPipeline`
`engine/src/Rendering/CameraRenderer.cpp` 的当前接线:
- `CameraRenderer` 的默认构造路径会使用静态共享的 `BuiltinForwardPipelineAsset`
- `SetPipelineAsset()` 也会通过这类 asset 重建当前主管线实例
- 如果外部传入空 asset当前仍会回退到默认 `BuiltinForwardPipelineAsset`
## 生命周期与所有权
- asset 自身通常以 `std::shared_ptr<const RenderPipelineAsset>` 共享持有
- 它创建出来的 pipeline 以 `std::unique_ptr<RenderPipeline>` 返回
- runtime pipeline 的生命周期最终由 `CameraRenderer` 或调用方接管,而不是由 asset 自己保留
这就是“共享工厂对象 + 独占运行时实例”的典型渲染系统分层。
## 当前实现边界
- 当前没有任何可配置字段
- 不能通过它选择不同 shader、不同 pass 序列或不同渲染路径
- 它还不是项目资源数据库里的可序列化 renderer asset只是 C++ 工厂对象
## 公开方法
| 方法 | 说明 |
|------|------|
| [CreatePipeline](CreatePipeline.md) | 创建一条新的 `BuiltinForwardPipeline` 实例。 |
## 相关文档
- [BuiltinForwardPipeline](../BuiltinForwardPipeline/BuiltinForwardPipeline.md)
- [Pipelines](../Pipelines.md)
- [RenderPipelineAsset](../../RenderPipelineAsset/RenderPipelineAsset.md)
- [CameraRenderer](../../CameraRenderer/CameraRenderer.md)

View File

@@ -0,0 +1,47 @@
# BuiltinForwardPipelineAsset::CreatePipeline
**命名空间**: `XCEngine::Rendering::Pipelines`
**类型**: `method`
**头文件**: `XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h`
创建一条新的 builtin forward runtime pipeline。
```cpp
std::unique_ptr<RenderPipeline> CreatePipeline() const override;
```
## 当前实现行为
当前实现直接返回:
```cpp
std::make_unique<BuiltinForwardPipeline>()
```
这意味着:
- 每次调用都会生成一条新的 `BuiltinForwardPipeline`
- 当前不会复用已有 runtime pipeline
- 当前也不会返回 `nullptr`
## 当前调用位置
`CameraRenderer` 通过内部 `CreatePipelineFromAsset()` 使用这个方法:
1. 若当前有 `pipelineAsset`,先执行 `asset->CreatePipeline()`
2. 若拿到有效实例,就接管这条新管线
3. 若 asset 为空或返回空指针,再回退到直接 `std::make_unique<BuiltinForwardPipeline>()`
`BuiltinForwardPipelineAsset` 来说,第 3 步当前基本不会触发。
## 返回值
- `std::unique_ptr<RenderPipeline>` - 指向一条全新的 `BuiltinForwardPipeline`
## 相关文档
- [BuiltinForwardPipelineAsset](BuiltinForwardPipelineAsset.md)
- [BuiltinForwardPipeline](../BuiltinForwardPipeline/BuiltinForwardPipeline.md)
- [RenderPipelineAsset::CreatePipeline](../../RenderPipelineAsset/CreatePipeline.md)

View File

@@ -4,27 +4,54 @@
**类型**: `submodule`
**描述**: 承载具体渲染管线实现,当前公开的是内建前向渲染管线
**描述**: 提供当前公开的具体渲染管线实现,以及与之配套的 pipeline asset 工厂
## 概
## 概
把具体渲染实现放在 `Rendering::Pipelines` 子命名空间,而不是直接塞进 `SceneRenderer`,是很合理的架构选择:
`Rendering::Pipelines` 子命名空间承载的不是“渲染总流程”,而是“真正把场景数据画到目标表面的 runtime pipeline 实现”。
- `SceneRenderer` 只负责组织渲染流程。
- 具体怎么画,由管线对象决定。
当前这层已经明确分成两类对象:
这和商业引擎里“renderer 负责 orchestrationpipeline 负责 actual rendering”的分层是相通的。
- runtime pipeline
负责解析 shader pass、构建 pipeline layout、缓存 descriptor set并发出 draw call。
- pipeline asset
负责决定该创建哪一条 runtime pipeline并把实例交给 `CameraRenderer`
## 当前实现
这和商业引擎里常见的 `RenderPipelineAsset -> RenderPipeline` 分层是一致的。当前功能还不算多,但架构边界已经建立起来了。
当前公开的具体管线只有一个:
## 当前公开类型
- [BuiltinForwardPipeline](BuiltinForwardPipeline/BuiltinForwardPipeline.md)
- `BuiltinForwardPipeline.h`
- 当前默认的主场景前向管线实现。
- [BuiltinForwardPipelineAsset](BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)
- `BuiltinForwardPipeline.h`
- 当前默认的 concrete `RenderPipelineAsset`,负责创建新的 `BuiltinForwardPipeline`
它承担的角色更像“默认可跑通的内建前向管线”,而不是覆盖完整 PBR、光照、阴影和后处理的成熟渲染框架。
## 默认接线关系
当前默认路径是:
1. `CameraRenderer` 拿到 `BuiltinForwardPipelineAsset`
2. asset 创建 `BuiltinForwardPipeline`
3. runtime pipeline 执行主场景绘制
这样做的价值在于:
- `CameraRenderer` 不需要知道 builtin forward 的内部细节
- future custom pipeline 的扩展位已经存在
- pipeline 工厂和 pipeline 实例的生命周期可以分开管理
## 当前边界
- 目前公开的 concrete runtime pipeline 仍然只有 builtin forward 一条
- `BuiltinForwardPipelineAsset` 还只是 C++ 工厂对象,不是项目资源数据库里的 renderer asset
- deferred、多主管线配置、render graph 和复杂 frame orchestration 还没有在这一层落地
## 相关文档
- [当前模块](../Rendering.md)
- [Rendering](../Rendering.md)
- [RenderPipeline](../RenderPipeline/RenderPipeline.md)
- [RenderPipelineAsset](../RenderPipelineAsset/RenderPipelineAsset.md)
- [CameraRenderer](../CameraRenderer/CameraRenderer.md)
- [Scene Extraction And Builtin Forward Pipeline](../../../_guides/Rendering/Scene-Extraction-And-Builtin-Forward-Pipeline.md)

View File

@@ -1,24 +1,59 @@
# RenderPipelineAsset::CreatePipeline
创建一个新的渲染管线实例。
**命名空间**: `XCEngine::Rendering`
**类型**: `method`
**头文件**: `XCEngine/Rendering/RenderPipelineAsset.h`
由具体 asset 创建一条新的 runtime 渲染管线实例。
```cpp
virtual std::unique_ptr<RenderPipeline> CreatePipeline() const = 0;
```
## 行为说明
## 接口契约
派生类应根据自身配置返回一个具体 `RenderPipeline` 实例。
从接口形状上,调用方可以依赖这几点:
- 返回值拥有独占所有权
- 返回对象是 `RenderPipeline` 派生实例
- 这是一个 `const` 工厂方法asset 自己不需要暴露可变运行时状态
## 当前调用链
当前最主要的消费方是 `CameraRenderer` 内部的 `CreatePipelineFromAsset()`
1. 若存在 `pipelineAsset`,先调用 `asset->CreatePipeline()`
2. 若拿到有效实例,就把它作为当前主管线
3. 若 asset 为空或返回空指针,再回退到 `BuiltinForwardPipeline`
因此派生类最好遵守一个明确的工程约定:
- 返回一条新的、可独立 `Shutdown()` / `Render()` 的 runtime pipeline
- 不要把某条活动中的共享 pipeline 实例直接借给调用方
## 返回值
- 一个拥有独占所有权的 `RenderPipeline` 对象。
- `std::unique_ptr<RenderPipeline>` - 新创建的运行时管线;允许派生类返回 `nullptr`,但当前默认调用方会把这视为失败并继续走 fallback
## 当前公开实现示例
- [BuiltinForwardPipelineAsset::CreatePipeline](../Pipelines/BuiltinForwardPipelineAsset/CreatePipeline.md)
## 设计说明
把返回值设计成 `std::unique_ptr` 是合理的,因为渲染管线往往具有明确的独占生命周期,不适合共享所有权。
这里使用 `std::unique_ptr` 很关键,因为 runtime pipeline 往往持有:
- 设备指针
- pipeline state
- descriptor set
- 缓存和临时 GPU 资源
这类对象通常应当具备清晰的唯一生命周期,而不是被多处共享。
## 相关文档
- [返回类型总览](RenderPipelineAsset.md)
- [RenderPipelineAsset](RenderPipelineAsset.md)
- [RenderPipeline](../RenderPipeline/RenderPipeline.md)
- [BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)

View File

@@ -6,34 +6,70 @@
**头文件**: `XCEngine/Rendering/RenderPipelineAsset.h`
**描述**: 定义渲染管线工厂接口,用于创建具体 `RenderPipeline` 实例。
**描述**: 渲染管线工厂接口,用于按需创建新的 runtime [RenderPipeline](../RenderPipeline/RenderPipeline.md) 实例。
## 概
## 概
`RenderPipelineAsset` 体现的是“数据/配置对象负责生成运行时管线实例”的设计方向。
`RenderPipelineAsset` 的职责不是自己渲染,而是回答一个更高层的问题:
这和商业引擎里常见的 pipeline asset / renderer asset 思路很接近:
- 当前这台 `CameraRenderer` 应该创建哪一种主管线实例?
- asset 负责描述“要创建哪条渲染管线”
- runtime pipeline 负责真正执行渲染
这和商业引擎里常见的 `RenderPipelineAsset -> RenderPipeline` 分层很接近。好处是:
- 上层编排器只依赖抽象接口,不直接硬编码具体管线类型
- runtime pipeline 可以被重建、替换或按不同入口注入
- 工厂对象和运行时实例可以采用不同所有权模型
## 当前真实接线
当前最直接的消费方是 [CameraRenderer](../CameraRenderer/CameraRenderer.md)
- 默认构造时会拿到一份默认 pipeline asset
- [SetPipelineAsset](../CameraRenderer/SetPipelineAsset.md) 会通过 asset 重建主管线
- `GetPipelineAsset()` 返回的是当前工厂对象,而不是 runtime pipeline
按当前源码,默认 concrete asset 是 [Pipelines::BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)。
## 当前公开实现
当前公开的 concrete 实现有:
- [BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)
它会创建 [BuiltinForwardPipeline](../Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md)。
## 生命周期与所有权
- `RenderPipelineAsset` 通常以 `std::shared_ptr<const RenderPipelineAsset>` 共享持有
- [CreatePipeline](CreatePipeline.md) 返回新的 `std::unique_ptr<RenderPipeline>`
- asset 不保留运行时实例;实例生命周期由 `CameraRenderer` 或调用方接管
这种“共享工厂 + 独占运行体”的组合很适合渲染系统,因为 runtime pipeline 往往持有设备、pipeline state 和 descriptor set不适合被多方共享所有权。
## 当前实现边界
- 当前它只是抽象接口。
- 当前公开 API 里没有看到对应的具体 asset 派生类型。
- `SceneRenderer` 目前也没有直接接入这个抽象,而是默认直接创建 [BuiltinForwardPipeline](../Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md)。
这说明接口方向已经铺好,但 asset-driven pipeline 切换还没有完全接上。
- 当前它仍然只是纯 C++ 工厂接口,不是项目资源数据库里的可序列化资产类型
- 还没有 renderer asset inspector、热重载或多 profile 配置
- 当前 fallback 策略很保守,目标是“即使 asset 路径出问题,也尽量总有 builtin pipeline 可跑”
## 公开方法
| 方法 | 说明 |
|------|------|
| [Destructor](Destructor.md) | 虚析构函数。 |
| [CreatePipeline](CreatePipeline.md) | 创建一个具体渲染管线实例。 |
| [Destructor](Destructor.md) | 虚析构函数,保证经由基类销毁派生 asset 时行为正确。 |
| [CreatePipeline](CreatePipeline.md) | 创建一条新的 runtime 管线实例。 |
## 设计说明
这一层的重要性,不在于“多包一层接口”,而在于把“选择哪种主管线”和“真正执行绘制”分开:
- `CameraRenderer` 不需要知道 builtin forward 的内部细节
- 不同 asset 后续可以创建完全不同的 runtime pipeline 类型
- 如果未来要把主管线选择接入项目设置或 viewport 模式,不必重写 camera submission 主流程
## 相关文档
- [当前模块](../Rendering.md)
- [Rendering](../Rendering.md)
- [RenderPipeline](../RenderPipeline/RenderPipeline.md)
- [SceneRenderer](../SceneRenderer/SceneRenderer.md)
- [BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)
- [Scene Extraction And Builtin Forward Pipeline](../../../_guides/Rendering/Scene-Extraction-And-Builtin-Forward-Pipeline.md)

View File

@@ -14,12 +14,15 @@
2. [CameraRenderRequest](CameraRenderRequest/CameraRenderRequest.md) 把单次提交的主表面、object-id 输出和 builtin 后处理需求打包起来。
3. [CameraRenderer](CameraRenderer/CameraRenderer.md) 执行单个请求。
4. [RenderSceneExtractor](RenderSceneExtractor/RenderSceneExtractor.md) 依据相机和 render area 提取 `RenderSceneData`
5. [RenderPipeline](RenderPipeline/RenderPipeline.md) 负责主场景绘制
6. `ObjectIdPass` 与 [Passes](Passes/Passes.md) 子模块在主场景之后补上 object-id、grid 和 selection outline 等额外结果
7. [RenderMaterialUtility](RenderMaterialUtility/RenderMaterialUtility.md) 把材质元数据与 render state 翻译成这条链路能消费的规则
5. [RenderPipelineAsset](RenderPipelineAsset/RenderPipelineAsset.md) 决定创建哪条 runtime 主场景管线;默认实现是 [Pipelines::BuiltinForwardPipelineAsset](Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)
6. [RenderPipeline](RenderPipeline/RenderPipeline.md) 负责主场景绘制;当前默认 runtime 实现是 [Pipelines::BuiltinForwardPipeline](Pipelines/BuiltinForwardPipeline/BuiltinForwardPipeline.md)
7. `ObjectIdPass` 与 [Passes](Passes/Passes.md) 子模块在主场景之后补上 object-id、grid 和 selection outline 等额外结果
8. [RenderMaterialUtility](RenderMaterialUtility/RenderMaterialUtility.md) 把材质元数据与 render state 翻译成这条链路能消费的规则。
这意味着当前渲染模块已经不只是“scene -> pipeline”两段式结构而是包含了主场景、辅助缓冲和 builtin post-process 的完整相机提交流程。
更底层的基础协议则由 [SceneRenderRequestPlanner](SceneRenderRequestPlanner/SceneRenderRequestPlanner.md)、[SceneRenderRequestUtils](SceneRenderRequestUtils/SceneRenderRequestUtils.md)、[RenderSceneUtility](RenderSceneUtility/RenderSceneUtility.md)、[RenderPass](RenderPass/RenderPass.md)、[ObjectIdPass](ObjectIdPass/ObjectIdPass.md) 和 [ObjectIdEncoding](ObjectIdEncoding/ObjectIdEncoding.md) 补齐。它们分别负责请求规划、排序规则、场景提取 helper、通用 pass 生命周期以及 object-id 编解码约定。
## 当前主流程
对一台相机,当前主流程大致是:
@@ -27,9 +30,10 @@
1. `SceneRenderer` 生成并排序 `CameraRenderRequest`
2. `CameraRenderer` 校验请求
3. `RenderSceneExtractor` 提取可见物体与相机数据
4. `RenderPipeline` 绘制主颜色目标
5. 如有需要,执行 object-id pass生成辅助 object-id 纹理
6. 执行调用方注入的 post pass、builtin post-process 和 overlay pass
4. 通过 `RenderPipelineAsset` 创建或替换主管线实例
5. `RenderPipeline` 绘制主颜色目标
6. 如有需要,执行 object-id pass生成辅助 object-id 纹理
7. 执行调用方注入的 post pass、builtin post-process 和 overlay pass
scene viewport 的无限网格和选中轮廓,就是通过这条 object-id + builtin post-process 链路接入的。
@@ -48,9 +52,12 @@ scene viewport 的无限网格和选中轮廓,就是通过这条 object-id + b
- 不透明 / 透明排序语义
- 剔除、混合和深度状态如何写进图形管线描述
在当前默认 builtin forward 路径里shader pass 的 `resources` 声明还会进一步参与 `PassResourceLayout` 构建,因为 `BuiltinForwardPipeline` 已经开始按资源契约生成 descriptor set layout。
## 当前实现边界
- 当前默认路径仍然是内建前向渲染,而不是完整 SRP / render graph。
- `RenderPipelineAsset` 已经接入默认主链路,但当前还不是项目资源系统里的完整 renderer asset。
- object-id 和 builtin post-process 主要服务于编辑器视口与调试链路。
- builtin selection outline 当前依赖单独的 object-id SRV而不是从主颜色结果反推。
- 多相机排序由 `SceneRenderer` 处理,`CameraRenderer` 本身只执行单请求。
@@ -59,15 +66,21 @@ scene viewport 的无限网格和选中轮廓,就是通过这条 object-id + b
- [CameraRenderRequest](CameraRenderRequest/CameraRenderRequest.md) - `CameraRenderRequest.h`
- [CameraRenderer](CameraRenderer/CameraRenderer.md) - `CameraRenderer.h`
- [ObjectIdEncoding](ObjectIdEncoding/ObjectIdEncoding.md) - `ObjectIdEncoding.h`
- [ObjectIdPass](ObjectIdPass/ObjectIdPass.md) - `ObjectIdPass.h`
- [Passes](Passes/Passes.md) - `Passes/`
- [RenderCameraData](RenderCameraData/RenderCameraData.md) - `RenderCameraData.h`
- [RenderContext](RenderContext/RenderContext.md) - `RenderContext.h`
- [RenderMaterialUtility](RenderMaterialUtility/RenderMaterialUtility.md) - `RenderMaterialUtility.h`
- [RenderPass](RenderPass/RenderPass.md) - `RenderPass.h`
- [RenderPipeline](RenderPipeline/RenderPipeline.md) - `RenderPipeline.h`
- [RenderPipelineAsset](RenderPipelineAsset/RenderPipelineAsset.md) - `RenderPipelineAsset.h`
- [RenderResourceCache](RenderResourceCache/RenderResourceCache.md) - `RenderResourceCache.h`
- [RenderSceneExtractor](RenderSceneExtractor/RenderSceneExtractor.md) - `RenderSceneExtractor.h`
- [RenderSceneUtility](RenderSceneUtility/RenderSceneUtility.md) - `RenderSceneUtility.h`
- [RenderSurface](RenderSurface/RenderSurface.md) - `RenderSurface.h`
- [SceneRenderRequestPlanner](SceneRenderRequestPlanner/SceneRenderRequestPlanner.md) - `SceneRenderRequestPlanner.h`
- [SceneRenderRequestUtils](SceneRenderRequestUtils/SceneRenderRequestUtils.md) - `SceneRenderRequestUtils.h`
- [SceneRenderer](SceneRenderer/SceneRenderer.md) - `SceneRenderer.h`
- [VisibleRenderObject](VisibleRenderObject/VisibleRenderObject.md) - `VisibleRenderObject.h`
- [Pipelines](Pipelines/Pipelines.md) - `Pipelines/`