Refactor rendering frame execution contracts

This commit is contained in:
2026-04-13 22:16:04 +08:00
parent 48daaa1bd0
commit 712f99e723
30 changed files with 1398 additions and 247 deletions

View File

@@ -0,0 +1,310 @@
# 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 整理成一个真正可扩展的内核。`

View File

@@ -0,0 +1,179 @@
#pragma once
#include <XCEngine/Rendering/Planning/CameraRenderRequest.h>
namespace XCEngine {
namespace Rendering {
struct CameraFramePlan {
CameraRenderRequest request = {};
ShadowCasterRenderRequest shadowCaster = {};
DirectionalShadowRenderPlan directionalShadow = {};
PostProcessRenderRequest postProcess = {};
FinalOutputRenderRequest finalOutput = {};
ResolvedFinalColorPolicy finalColorPolicy = {};
RenderPassSequence* preScenePasses = nullptr;
RenderPassSequence* postScenePasses = nullptr;
RenderPassSequence* overlayPasses = nullptr;
static CameraFramePlan FromRequest(const CameraRenderRequest& request) {
CameraFramePlan plan = {};
plan.request = request;
plan.shadowCaster = request.shadowCaster;
plan.directionalShadow = request.directionalShadow;
plan.postProcess = request.postProcess;
plan.finalOutput = request.finalOutput;
plan.finalColorPolicy = request.finalColorPolicy;
plan.preScenePasses = request.preScenePasses;
plan.postScenePasses = request.postScenePasses;
plan.overlayPasses = request.overlayPasses;
return plan;
}
bool IsValid() const {
return request.IsValid();
}
bool HasFrameStage(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PreScenePasses:
return preScenePasses != nullptr;
case CameraFrameStage::ShadowCaster:
return shadowCaster.IsRequested() || directionalShadow.IsValid();
case CameraFrameStage::DepthOnly:
return request.depthOnly.IsRequested();
case CameraFrameStage::MainScene:
return true;
case CameraFrameStage::PostProcess:
return postProcess.IsRequested();
case CameraFrameStage::FinalOutput:
return finalOutput.IsRequested();
case CameraFrameStage::ObjectId:
return request.objectId.IsRequested();
case CameraFrameStage::PostScenePasses:
return postScenePasses != nullptr;
case CameraFrameStage::OverlayPasses:
return overlayPasses != nullptr;
default:
return false;
}
}
RenderPassSequence* GetPassSequence(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PreScenePasses:
return preScenePasses;
case CameraFrameStage::PostProcess:
return postProcess.passes;
case CameraFrameStage::FinalOutput:
return finalOutput.passes;
case CameraFrameStage::PostScenePasses:
return postScenePasses;
case CameraFrameStage::OverlayPasses:
return overlayPasses;
default:
return nullptr;
}
}
const RenderSurface& GetMainSceneSurface() const {
if (postProcess.IsRequested()) {
return postProcess.sourceSurface;
}
if (finalOutput.IsRequested()) {
return finalOutput.sourceSurface;
}
return request.surface;
}
const RenderSurface& GetFinalCompositedSurface() const {
if (finalOutput.IsRequested()) {
return finalOutput.destinationSurface;
}
if (postProcess.IsRequested()) {
return postProcess.destinationSurface;
}
return request.surface;
}
const RenderSurface* GetOutputSurface(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PreScenePasses:
case CameraFrameStage::MainScene:
return &GetMainSceneSurface();
case CameraFrameStage::ShadowCaster:
return shadowCaster.IsRequested() ? &shadowCaster.surface : nullptr;
case CameraFrameStage::DepthOnly:
return request.depthOnly.IsRequested() ? &request.depthOnly.surface : nullptr;
case CameraFrameStage::PostProcess:
return postProcess.IsRequested() ? &postProcess.destinationSurface : nullptr;
case CameraFrameStage::FinalOutput:
return finalOutput.IsRequested() ? &finalOutput.destinationSurface : nullptr;
case CameraFrameStage::ObjectId:
return request.objectId.IsRequested() ? &request.objectId.surface : nullptr;
case CameraFrameStage::PostScenePasses:
case CameraFrameStage::OverlayPasses:
return &GetFinalCompositedSurface();
default:
return nullptr;
}
}
const RenderSurface* GetSourceSurface(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PostProcess:
return postProcess.IsRequested() ? &postProcess.sourceSurface : nullptr;
case CameraFrameStage::FinalOutput:
return finalOutput.IsRequested() ? &finalOutput.sourceSurface : nullptr;
default:
return nullptr;
}
}
RHI::RHIResourceView* GetSourceColorView(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PostProcess:
return postProcess.IsRequested() ? postProcess.sourceColorView : nullptr;
case CameraFrameStage::FinalOutput:
return finalOutput.IsRequested() ? finalOutput.sourceColorView : nullptr;
default:
return nullptr;
}
}
RHI::ResourceStates GetSourceColorState(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PostProcess:
return postProcess.IsRequested() ? postProcess.sourceColorState : RHI::ResourceStates::Common;
case CameraFrameStage::FinalOutput:
return finalOutput.IsRequested() ? finalOutput.sourceColorState : RHI::ResourceStates::Common;
default:
return RHI::ResourceStates::Common;
}
}
bool RequiresIntermediateSceneColor() const {
return postProcess.IsRequested() || finalOutput.IsRequested();
}
};
inline CameraRenderRequest BuildLegacyCameraRenderRequest(
const CameraFramePlan& plan) {
CameraRenderRequest request = plan.request;
request.shadowCaster = plan.shadowCaster;
request.directionalShadow = plan.directionalShadow;
request.postProcess = plan.postProcess;
request.finalOutput = plan.finalOutput;
request.finalColorPolicy = plan.finalColorPolicy;
request.preScenePasses = plan.preScenePasses;
request.postScenePasses = plan.postScenePasses;
request.overlayPasses = plan.overlayPasses;
return request;
}
} // namespace Rendering
} // namespace XCEngine

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <XCEngine/Rendering/Execution/CameraFramePlan.h>
#include <XCEngine/Rendering/Extraction/RenderSceneExtractor.h> #include <XCEngine/Rendering/Extraction/RenderSceneExtractor.h>
#include <XCEngine/Rendering/Planning/CameraRenderRequest.h> #include <XCEngine/Rendering/Planning/CameraRenderRequest.h>
#include <XCEngine/Rendering/RenderPass.h> #include <XCEngine/Rendering/RenderPass.h>
@@ -49,19 +50,20 @@ public:
RenderPass* GetShadowCasterPass() const { return m_shadowCasterPass.get(); } RenderPass* GetShadowCasterPass() const { return m_shadowCasterPass.get(); }
bool Render(const CameraRenderRequest& request); bool Render(const CameraRenderRequest& request);
bool Render(const CameraFramePlan& plan);
private: private:
void ResetPipeline(std::unique_ptr<RenderPipeline> pipeline); void ResetPipeline(std::unique_ptr<RenderPipeline> pipeline);
bool ResolveShadowCasterRequest( bool ResolveShadowCasterRequest(
const CameraRenderRequest& request, const CameraFramePlan& plan,
ShadowCasterRenderRequest& outResolvedShadowCaster, ShadowCasterRenderRequest& outResolvedShadowCaster,
RHI::RHIResourceView*& outShadowMapView); RHI::RHIResourceView*& outShadowMapView);
bool BuildSceneDataForRequest( bool BuildSceneDataForPlan(
const CameraRenderRequest& request, const CameraFramePlan& plan,
RHI::RHIResourceView* shadowMapView, RHI::RHIResourceView* shadowMapView,
RenderSceneData& outSceneData); RenderSceneData& outSceneData);
bool ExecuteRenderPlan( bool ExecuteRenderPlan(
const CameraRenderRequest& request, const CameraFramePlan& plan,
const ShadowCasterRenderRequest& resolvedShadowCaster, const ShadowCasterRenderRequest& resolvedShadowCaster,
const RenderSceneData& sceneData); const RenderSceneData& sceneData);

View File

@@ -0,0 +1,15 @@
#pragma once
#include <XCEngine/Rendering/Execution/ScenePhase.h>
#include <XCEngine/Rendering/FrameData/CullingResults.h>
namespace XCEngine {
namespace Rendering {
struct DrawSettings {
ScenePhase scenePhase = ScenePhase::Opaque;
RendererListType rendererListType = RendererListType::AllVisible;
};
} // namespace Rendering
} // namespace XCEngine

View File

@@ -0,0 +1,56 @@
#pragma once
#include <XCEngine/Rendering/Execution/ScenePhase.h>
#include <XCEngine/Rendering/RenderContext.h>
namespace XCEngine {
namespace RHI {
class RHIResourceView;
} // namespace RHI
namespace Rendering {
struct RenderSceneData;
class RenderSurface;
struct FrameExecutionContext {
FrameExecutionContext(
const RenderContext& inRenderContext,
const RenderSurface& inSurface,
const RenderSceneData& inSceneData,
const RenderSurface* inSourceSurface = nullptr,
RHI::RHIResourceView* inSourceColorView = nullptr,
RHI::ResourceStates inSourceColorState = RHI::ResourceStates::Common)
: renderContext(inRenderContext)
, surface(inSurface)
, sceneData(inSceneData)
, sourceSurface(inSourceSurface)
, sourceColorView(inSourceColorView)
, sourceColorState(inSourceColorState) {
}
const RenderContext& renderContext;
const RenderSurface& surface;
const RenderSceneData& sceneData;
const RenderSurface* sourceSurface = nullptr;
RHI::RHIResourceView* sourceColorView = nullptr;
RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common;
};
struct ScenePhaseExecutionContext {
ScenePhaseExecutionContext(
const FrameExecutionContext& inFrameContext,
ScenePhase inScenePhase,
bool inSampledDirectionalShadow = false)
: frameContext(inFrameContext)
, scenePhase(inScenePhase)
, sampledDirectionalShadow(inSampledDirectionalShadow) {
}
FrameExecutionContext frameContext;
ScenePhase scenePhase = ScenePhase::Opaque;
bool sampledDirectionalShadow = false;
};
} // namespace Rendering
} // namespace XCEngine

View File

@@ -0,0 +1,40 @@
#pragma once
#include <XCEngine/Core/Types.h>
namespace XCEngine {
namespace Rendering {
enum class ScenePhase : Core::uint32 {
Opaque = 0,
Skybox = 1,
Feature = 2,
Transparent = 3,
EditorExtension = 4,
PostProcess = 5,
FinalOutput = 6
};
inline const char* ToString(ScenePhase scenePhase) {
switch (scenePhase) {
case ScenePhase::Opaque:
return "Opaque";
case ScenePhase::Skybox:
return "Skybox";
case ScenePhase::Feature:
return "Feature";
case ScenePhase::Transparent:
return "Transparent";
case ScenePhase::EditorExtension:
return "EditorExtension";
case ScenePhase::PostProcess:
return "PostProcess";
case ScenePhase::FinalOutput:
return "FinalOutput";
}
return "Unknown";
}
} // namespace Rendering
} // namespace XCEngine

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <XCEngine/Rendering/Execution/CameraFramePlan.h>
#include <XCEngine/Rendering/Execution/CameraRenderer.h> #include <XCEngine/Rendering/Execution/CameraRenderer.h>
#include <XCEngine/Rendering/Planning/CameraRenderRequest.h> #include <XCEngine/Rendering/Planning/CameraRenderRequest.h>
#include <XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h> #include <XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h>
@@ -35,9 +36,16 @@ public:
Components::CameraComponent* overrideCamera, Components::CameraComponent* overrideCamera,
const RenderContext& context, const RenderContext& context,
const RenderSurface& surface); const RenderSurface& surface);
std::vector<CameraFramePlan> BuildFramePlans(
const Components::Scene& scene,
Components::CameraComponent* overrideCamera,
const RenderContext& context,
const RenderSurface& surface);
bool Render(const CameraRenderRequest& request); bool Render(const CameraRenderRequest& request);
bool Render(const std::vector<CameraRenderRequest>& requests); bool Render(const std::vector<CameraRenderRequest>& requests);
bool Render(const CameraFramePlan& plan);
bool Render(const std::vector<CameraFramePlan>& plans);
bool Render( bool Render(
const Components::Scene& scene, const Components::Scene& scene,
Components::CameraComponent* overrideCamera, Components::CameraComponent* overrideCamera,
@@ -45,12 +53,14 @@ public:
const RenderSurface& surface); const RenderSurface& surface);
private: private:
std::vector<CameraFramePlan> CreateFramePlansFromRequests(
const std::vector<CameraRenderRequest>& requests) const;
void PrepareOwnedFullscreenStageState(size_t requestCount); void PrepareOwnedFullscreenStageState(size_t requestCount);
void ResolveCameraFinalColorPolicies( void ResolveCameraFinalColorPolicies(
std::vector<CameraRenderRequest>& requests) const; std::vector<CameraFramePlan>& plans) const;
void AttachFullscreenStageRequests( void AttachFullscreenStageRequests(
const RenderContext& context, const RenderContext& context,
std::vector<CameraRenderRequest>& requests); std::vector<CameraFramePlan>& plans);
SceneRenderRequestPlanner m_requestPlanner; SceneRenderRequestPlanner m_requestPlanner;
CameraRenderer m_cameraRenderer; CameraRenderer m_cameraRenderer;

View File

@@ -0,0 +1,85 @@
#pragma once
#include <XCEngine/Core/Types.h>
#include <cstddef>
#include <limits>
#include <vector>
namespace XCEngine {
namespace Rendering {
enum class RendererListType : Core::uint32 {
AllVisible = 0,
Opaque = 1,
Transparent = 2,
ShadowCaster = 3,
ObjectId = 4
};
enum class RendererSortMode : Core::uint32 {
None = 0,
FrontToBack = 1,
BackToFront = 2
};
struct FilteringSettings {
Core::int32 renderQueueMin = std::numeric_limits<Core::int32>::lowest();
Core::int32 renderQueueMax = std::numeric_limits<Core::int32>::max();
bool requireShadowCasting = false;
bool requireRenderObjectId = false;
};
struct SortingSettings {
RendererSortMode sortMode = RendererSortMode::None;
};
struct RendererListDesc {
RendererListType type = RendererListType::AllVisible;
FilteringSettings filtering = {};
SortingSettings sorting = {};
};
struct RendererList {
RendererListDesc desc = {};
std::vector<Core::uint32> visibleRenderItemIndices;
bool Empty() const {
return visibleRenderItemIndices.empty();
}
size_t Size() const {
return visibleRenderItemIndices.size();
}
};
struct CullingResults {
std::vector<RendererList> rendererLists;
void Clear() {
rendererLists.clear();
}
RendererList* FindRendererList(RendererListType type) {
for (RendererList& rendererList : rendererLists) {
if (rendererList.desc.type == type) {
return &rendererList;
}
}
return nullptr;
}
const RendererList* FindRendererList(RendererListType type) const {
for (const RendererList& rendererList : rendererLists) {
if (rendererList.desc.type == type) {
return &rendererList;
}
}
return nullptr;
}
};
} // namespace Rendering
} // namespace XCEngine

View File

@@ -3,6 +3,7 @@
#include <XCEngine/Core/Math/Vector2.h> #include <XCEngine/Core/Math/Vector2.h>
#include <XCEngine/Core/Math/Vector3.h> #include <XCEngine/Core/Math/Vector3.h>
#include <XCEngine/Core/Math/Vector4.h> #include <XCEngine/Core/Math/Vector4.h>
#include <XCEngine/Rendering/FrameData/CullingResults.h>
#include <XCEngine/Rendering/FrameData/RenderCameraData.h> #include <XCEngine/Rendering/FrameData/RenderCameraData.h>
#include <XCEngine/Rendering/FrameData/RenderEnvironmentData.h> #include <XCEngine/Rendering/FrameData/RenderEnvironmentData.h>
#include <XCEngine/Rendering/Shadow/DirectionalShadowSettings.h> #include <XCEngine/Rendering/Shadow/DirectionalShadowSettings.h>
@@ -115,6 +116,7 @@ struct RenderSceneData {
RenderEnvironmentData environment; RenderEnvironmentData environment;
RenderLightingData lighting; RenderLightingData lighting;
Resources::ShaderKeywordSet globalShaderKeywords; Resources::ShaderKeywordSet globalShaderKeywords;
CullingResults cullingResults;
std::vector<VisibleRenderItem> visibleItems; std::vector<VisibleRenderItem> visibleItems;
std::vector<VisibleGaussianSplatItem> visibleGaussianSplats; std::vector<VisibleGaussianSplatItem> visibleGaussianSplats;
std::vector<VisibleVolumeItem> visibleVolumes; std::vector<VisibleVolumeItem> visibleVolumes;
@@ -122,6 +124,22 @@ struct RenderSceneData {
bool HasCamera() const { bool HasCamera() const {
return camera != nullptr; return camera != nullptr;
} }
RendererList* FindRendererList(RendererListType type) {
return cullingResults.FindRendererList(type);
}
const RendererList* FindRendererList(RendererListType type) const {
return cullingResults.FindRendererList(type);
}
const VisibleRenderItem* TryGetVisibleRenderItem(Core::uint32 index) const {
if (index >= visibleItems.size()) {
return nullptr;
}
return &visibleItems[index];
}
}; };
} // namespace Rendering } // namespace Rendering

View File

@@ -0,0 +1,145 @@
#pragma once
#include <XCEngine/Components/MeshRendererComponent.h>
#include <XCEngine/Rendering/FrameData/RenderSceneData.h>
#include <XCEngine/Resources/Material/Material.h>
#include <utility>
namespace XCEngine {
namespace Rendering {
inline FilteringSettings BuildDefaultFilteringSettings(RendererListType type) {
FilteringSettings filtering = {};
switch (type) {
case RendererListType::AllVisible:
break;
case RendererListType::Opaque:
filtering.renderQueueMax =
static_cast<Core::int32>(Resources::MaterialRenderQueue::Transparent) - 1;
break;
case RendererListType::Transparent:
filtering.renderQueueMin =
static_cast<Core::int32>(Resources::MaterialRenderQueue::Transparent);
break;
case RendererListType::ShadowCaster:
filtering.requireShadowCasting = true;
break;
case RendererListType::ObjectId:
filtering.requireRenderObjectId = true;
break;
}
return filtering;
}
inline SortingSettings BuildDefaultSortingSettings(RendererListType type) {
SortingSettings sorting = {};
switch (type) {
case RendererListType::Opaque:
case RendererListType::ShadowCaster:
case RendererListType::ObjectId:
sorting.sortMode = RendererSortMode::FrontToBack;
break;
case RendererListType::Transparent:
sorting.sortMode = RendererSortMode::BackToFront;
break;
case RendererListType::AllVisible:
sorting.sortMode = RendererSortMode::None;
break;
}
return sorting;
}
inline RendererListDesc BuildDefaultRendererListDesc(RendererListType type) {
RendererListDesc desc = {};
desc.type = type;
desc.filtering = BuildDefaultFilteringSettings(type);
desc.sorting = BuildDefaultSortingSettings(type);
return desc;
}
inline bool MatchesFilteringSettings(
const VisibleRenderItem& visibleItem,
const FilteringSettings& filtering) {
if (visibleItem.renderQueue < filtering.renderQueueMin ||
visibleItem.renderQueue > filtering.renderQueueMax) {
return false;
}
if (filtering.requireShadowCasting &&
visibleItem.meshRenderer != nullptr &&
!visibleItem.meshRenderer->GetCastShadows()) {
return false;
}
if (filtering.requireRenderObjectId &&
!IsValidRenderObjectId(visibleItem.renderObjectId)) {
return false;
}
return true;
}
inline bool MatchesRendererListDesc(
const VisibleRenderItem& visibleItem,
const RendererListDesc& desc) {
return MatchesFilteringSettings(visibleItem, desc.filtering);
}
inline RendererList BuildRendererList(
RendererListType type,
const std::vector<VisibleRenderItem>& visibleItems) {
RendererList rendererList = {};
rendererList.desc = BuildDefaultRendererListDesc(type);
rendererList.visibleRenderItemIndices.reserve(visibleItems.size());
for (Core::uint32 visibleItemIndex = 0;
visibleItemIndex < static_cast<Core::uint32>(visibleItems.size());
++visibleItemIndex) {
if (!MatchesRendererListDesc(
visibleItems[visibleItemIndex],
rendererList.desc)) {
continue;
}
rendererList.visibleRenderItemIndices.push_back(visibleItemIndex);
}
return rendererList;
}
template <typename Visitor>
inline void VisitRendererListVisibleItems(
const RenderSceneData& sceneData,
RendererListType rendererListType,
Visitor&& visitor) {
const RendererList* rendererList = sceneData.FindRendererList(rendererListType);
if (rendererList != nullptr) {
for (Core::uint32 visibleItemIndex : rendererList->visibleRenderItemIndices) {
const VisibleRenderItem* visibleItem =
sceneData.TryGetVisibleRenderItem(visibleItemIndex);
if (visibleItem == nullptr) {
continue;
}
visitor(*visibleItem);
}
return;
}
const RendererListDesc fallbackDesc = BuildDefaultRendererListDesc(rendererListType);
for (const VisibleRenderItem& visibleItem : sceneData.visibleItems) {
if (!MatchesRendererListDesc(visibleItem, fallbackDesc)) {
continue;
}
visitor(visibleItem);
}
}
} // namespace Rendering
} // namespace XCEngine

View File

@@ -3,6 +3,7 @@
#include <XCEngine/Core/Asset/ResourceHandle.h> #include <XCEngine/Core/Asset/ResourceHandle.h>
#include <XCEngine/Core/Math/Matrix4.h> #include <XCEngine/Core/Math/Matrix4.h>
#include <XCEngine/Rendering/Builtin/BuiltinPassTypes.h> #include <XCEngine/Rendering/Builtin/BuiltinPassTypes.h>
#include <XCEngine/Rendering/FrameData/CullingResults.h>
#include <XCEngine/Rendering/Materials/RenderMaterialResolve.h> #include <XCEngine/Rendering/Materials/RenderMaterialResolve.h>
#include <XCEngine/Rendering/RenderPass.h> #include <XCEngine/Rendering/RenderPass.h>
#include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h> #include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h>
@@ -46,6 +47,7 @@ protected:
BuiltinMaterialPass passType, BuiltinMaterialPass passType,
Containers::String builtinShaderPath); Containers::String builtinShaderPath);
virtual RendererListType GetRendererListType() const;
virtual bool ShouldRenderVisibleItem(const VisibleRenderItem& visibleItem) const; virtual bool ShouldRenderVisibleItem(const VisibleRenderItem& visibleItem) const;
private: private:

View File

@@ -6,7 +6,7 @@
#include <XCEngine/Rendering/Caches/RenderResourceCache.h> #include <XCEngine/Rendering/Caches/RenderResourceCache.h>
#include <XCEngine/Rendering/Materials/RenderMaterialResolve.h> #include <XCEngine/Rendering/Materials/RenderMaterialResolve.h>
#include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h> #include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h>
#include <XCEngine/Rendering/RenderPass.h> #include <XCEngine/Rendering/SceneRenderFeaturePass.h>
#include <XCEngine/RHI/RHIDescriptorPool.h> #include <XCEngine/RHI/RHIDescriptorPool.h>
#include <XCEngine/RHI/RHIDescriptorSet.h> #include <XCEngine/RHI/RHIDescriptorSet.h>
#include <XCEngine/RHI/RHIPipelineLayout.h> #include <XCEngine/RHI/RHIPipelineLayout.h>
@@ -40,12 +40,16 @@ class BuiltinGaussianSplatPassResources;
namespace Passes { namespace Passes {
class BuiltinGaussianSplatPass final : public RenderPass { class BuiltinGaussianSplatPass final : public SceneRenderFeaturePass {
public: public:
~BuiltinGaussianSplatPass() override; ~BuiltinGaussianSplatPass() override;
const char* GetName() const override; const char* GetName() const override;
bool Initialize(const RenderContext& context) override; bool Initialize(const RenderContext& context) override;
bool IsActive(const RenderSceneData& sceneData) const override;
bool Prepare(
const RenderContext& context,
const RenderSceneData& sceneData) override;
bool PrepareGaussianSplatResources( bool PrepareGaussianSplatResources(
const RenderContext& context, const RenderContext& context,
const RenderSceneData& sceneData); const RenderSceneData& sceneData);

View File

@@ -16,6 +16,7 @@ public:
const char* GetName() const override; const char* GetName() const override;
protected: protected:
RendererListType GetRendererListType() const override;
bool ShouldRenderVisibleItem(const VisibleRenderItem& visibleItem) const override; bool ShouldRenderVisibleItem(const VisibleRenderItem& visibleItem) const override;
}; };

View File

@@ -6,7 +6,7 @@
#include <XCEngine/Rendering/Caches/RenderResourceCache.h> #include <XCEngine/Rendering/Caches/RenderResourceCache.h>
#include <XCEngine/Rendering/Materials/RenderMaterialResolve.h> #include <XCEngine/Rendering/Materials/RenderMaterialResolve.h>
#include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h> #include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h>
#include <XCEngine/Rendering/RenderPass.h> #include <XCEngine/Rendering/SceneRenderFeaturePass.h>
#include <XCEngine/RHI/RHIDescriptorPool.h> #include <XCEngine/RHI/RHIDescriptorPool.h>
#include <XCEngine/RHI/RHIDescriptorSet.h> #include <XCEngine/RHI/RHIDescriptorSet.h>
#include <XCEngine/RHI/RHIPipelineLayout.h> #include <XCEngine/RHI/RHIPipelineLayout.h>
@@ -33,7 +33,7 @@ struct RenderLightingData;
namespace Passes { namespace Passes {
class BuiltinVolumetricPass final : public RenderPass { class BuiltinVolumetricPass final : public SceneRenderFeaturePass {
public: public:
~BuiltinVolumetricPass() override; ~BuiltinVolumetricPass() override;
@@ -41,6 +41,10 @@ public:
const char* GetName() const override; const char* GetName() const override;
bool Initialize(const RenderContext& context) override; bool Initialize(const RenderContext& context) override;
bool IsActive(const RenderSceneData& sceneData) const override;
bool Prepare(
const RenderContext& context,
const RenderSceneData& sceneData) override;
bool PrepareVolumeResources( bool PrepareVolumeResources(
const RenderContext& context, const RenderContext& context,
const RenderSceneData& sceneData); const RenderSceneData& sceneData);

View File

@@ -1,11 +1,14 @@
#pragma once #pragma once
#include <XCEngine/Rendering/Execution/DrawSettings.h>
#include <XCEngine/Rendering/Execution/FrameExecutionContext.h>
#include <XCEngine/Rendering/Builtin/BuiltinPassTypes.h> #include <XCEngine/Rendering/Builtin/BuiltinPassTypes.h>
#include <XCEngine/Rendering/Materials/RenderMaterialResolve.h> #include <XCEngine/Rendering/Materials/RenderMaterialResolve.h>
#include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h> #include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h>
#include <XCEngine/Rendering/RenderPass.h> #include <XCEngine/Rendering/RenderPass.h>
#include <XCEngine/Rendering/RenderPipeline.h> #include <XCEngine/Rendering/RenderPipeline.h>
#include <XCEngine/Rendering/RenderPipelineAsset.h> #include <XCEngine/Rendering/RenderPipelineAsset.h>
#include <XCEngine/Rendering/SceneRenderFeaturePass.h>
#include <XCEngine/Rendering/Caches/RenderResourceCache.h> #include <XCEngine/Rendering/Caches/RenderResourceCache.h>
#include <XCEngine/RHI/RHIDescriptorPool.h> #include <XCEngine/RHI/RHIDescriptorPool.h>
@@ -50,16 +53,21 @@ public:
BuiltinForwardPipeline(); BuiltinForwardPipeline();
~BuiltinForwardPipeline() override; ~BuiltinForwardPipeline() override;
using RenderPipeline::Render;
static RHI::InputLayoutDesc BuildInputLayout(); static RHI::InputLayoutDesc BuildInputLayout();
bool Initialize(const RenderContext& context) override; bool Initialize(const RenderContext& context) override;
void Shutdown() override; void Shutdown() override;
bool Render(const FrameExecutionContext& executionContext) override;
bool Render( bool Render(
const RenderContext& context, const RenderContext& context,
const RenderSurface& surface, const RenderSurface& surface,
const RenderSceneData& sceneData) override; const RenderSceneData& sceneData) override;
private: private:
using ForwardSceneFeaturePassArray = std::array<SceneRenderFeaturePass*, 2>;
struct OwnedDescriptorSet { struct OwnedDescriptorSet {
RHI::RHIDescriptorPool* pool = nullptr; RHI::RHIDescriptorPool* pool = nullptr;
RHI::RHIDescriptorSet* set = nullptr; RHI::RHIDescriptorSet* set = nullptr;
@@ -263,6 +271,19 @@ private:
}; };
bool EnsureInitialized(const RenderContext& context); bool EnsureInitialized(const RenderContext& context);
ForwardSceneFeaturePassArray CollectForwardSceneFeaturePasses() const;
bool InitializeForwardSceneFeaturePasses(const RenderContext& context);
void ShutdownForwardSceneFeaturePasses();
bool PrepareForwardSceneFeaturePasses(
const FrameExecutionContext& executionContext) const;
bool ExecuteForwardSceneFeaturePasses(
const ScenePhaseExecutionContext& executionContext) const;
ScenePhaseExecutionContext BuildScenePhaseExecutionContext(
const FrameExecutionContext& executionContext,
ScenePhase scenePhase) const;
DrawSettings BuildDrawSettings(ScenePhase scenePhase) const;
bool ExecuteForwardScene(const FrameExecutionContext& executionContext);
bool ExecuteScenePhase(const ScenePhaseExecutionContext& executionContext);
bool CreatePipelineResources(const RenderContext& context); bool CreatePipelineResources(const RenderContext& context);
void DestroyPipelineResources(); void DestroyPipelineResources();
static bool TryResolveSurfacePassType( static bool TryResolveSurfacePassType(
@@ -315,18 +336,14 @@ private:
bool HasProceduralSkybox(const RenderSceneData& sceneData) const; bool HasProceduralSkybox(const RenderSceneData& sceneData) const;
bool BeginForwardScenePass(const RenderPassContext& context); bool BeginForwardScenePass(const RenderPassContext& context);
void EndForwardScenePass(const RenderPassContext& context); void EndForwardScenePass(const RenderPassContext& context);
bool ExecuteForwardOpaquePass(const RenderPassContext& context); bool ExecuteForwardOpaquePass(const ScenePhaseExecutionContext& context);
bool ExecuteForwardSkyboxPass(const RenderPassContext& context); bool ExecuteForwardSkyboxPass(const RenderPassContext& context);
bool ExecuteForwardTransparentPass(const RenderPassContext& context); bool ExecuteForwardTransparentPass(const ScenePhaseExecutionContext& context);
bool DrawVisibleItems( bool DrawVisibleItems(
const RenderContext& context, const FrameExecutionContext& executionContext,
const RenderSurface& surface, const DrawSettings& drawSettings);
const RenderSceneData& sceneData,
bool drawTransparentItems);
bool DrawVisibleItem( bool DrawVisibleItem(
const RenderContext& context, const FrameExecutionContext& executionContext,
const RenderSurface& surface,
const RenderSceneData& sceneData,
const VisibleRenderItem& visibleItem); const VisibleRenderItem& visibleItem);
bool EnsureSkyboxResources(const RenderContext& context); bool EnsureSkyboxResources(const RenderContext& context);
bool CreateSkyboxResources(const RenderContext& context); bool CreateSkyboxResources(const RenderContext& context);

View File

@@ -24,7 +24,7 @@ struct DirectionalShadowPlanningSettings {
float perspectiveFocusFactor = 1.0f; float perspectiveFocusFactor = 1.0f;
float orthographicFocusFactor = 2.0f; float orthographicFocusFactor = 2.0f;
float minDepthRange = 20.0f; float minDepthRange = 20.0f;
float boundsPadding = 1.0f; float boundsPadding = 0.5f;
float minDepthPadding = 2.0f; float minDepthPadding = 2.0f;
DirectionalShadowSamplingSettings sampling = {}; DirectionalShadowSamplingSettings sampling = {};
DirectionalShadowCasterBiasSettings casterBias = {}; DirectionalShadowCasterBiasSettings casterBias = {};

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <XCEngine/Rendering/Execution/FrameExecutionContext.h>
#include <XCEngine/Rendering/RenderContext.h> #include <XCEngine/Rendering/RenderContext.h>
#include <cstddef> #include <cstddef>
@@ -25,6 +26,23 @@ struct RenderPassContext {
RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common; RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common;
}; };
inline RenderPassContext BuildRenderPassContext(
const FrameExecutionContext& executionContext) {
return {
executionContext.renderContext,
executionContext.surface,
executionContext.sceneData,
executionContext.sourceSurface,
executionContext.sourceColorView,
executionContext.sourceColorState
};
}
inline RenderPassContext BuildRenderPassContext(
const ScenePhaseExecutionContext& executionContext) {
return BuildRenderPassContext(executionContext.frameContext);
}
class RenderPass { class RenderPass {
public: public:
virtual ~RenderPass() = default; virtual ~RenderPass() = default;

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <XCEngine/Rendering/Execution/FrameExecutionContext.h>
#include <XCEngine/Rendering/FrameData/RenderSceneData.h> #include <XCEngine/Rendering/FrameData/RenderSceneData.h>
#include <XCEngine/Rendering/RenderContext.h> #include <XCEngine/Rendering/RenderContext.h>
@@ -14,6 +15,12 @@ public:
virtual bool Initialize(const RenderContext& context) = 0; virtual bool Initialize(const RenderContext& context) = 0;
virtual void Shutdown() = 0; virtual void Shutdown() = 0;
virtual bool Render(const FrameExecutionContext& executionContext) {
return Render(
executionContext.renderContext,
executionContext.surface,
executionContext.sceneData);
}
virtual bool Render( virtual bool Render(
const RenderContext& context, const RenderContext& context,
const RenderSurface& surface, const RenderSurface& surface,

View File

@@ -0,0 +1,24 @@
#pragma once
#include <XCEngine/Rendering/RenderPass.h>
namespace XCEngine {
namespace Rendering {
class SceneRenderFeaturePass : public RenderPass {
public:
~SceneRenderFeaturePass() override = default;
virtual bool IsActive(const RenderSceneData& sceneData) const = 0;
virtual bool Prepare(
const RenderContext& renderContext,
const RenderSceneData& sceneData) {
(void)renderContext;
(void)sceneData;
return true;
}
};
} // namespace Rendering
} // namespace XCEngine

View File

@@ -289,81 +289,88 @@ bool ExecuteFullscreenPassSequenceStage(
RenderPassContext BuildFrameStagePassContext( RenderPassContext BuildFrameStagePassContext(
CameraFrameStage stage, CameraFrameStage stage,
const CameraRenderRequest& request, const CameraFramePlan& plan,
const RenderSceneData& sceneData) { const RenderSceneData& sceneData) {
const RenderSurface* outputSurface = request.GetOutputSurface(stage); const RenderSurface* outputSurface = plan.GetOutputSurface(stage);
return { return {
request.context, plan.request.context,
outputSurface != nullptr ? *outputSurface : request.surface, outputSurface != nullptr ? *outputSurface : plan.request.surface,
sceneData, sceneData,
request.GetSourceSurface(stage), plan.GetSourceSurface(stage),
request.GetSourceColorView(stage), plan.GetSourceColorView(stage),
request.GetSourceColorState(stage) plan.GetSourceColorState(stage)
}; };
} }
bool ExecuteFrameStage( bool ExecuteFrameStage(
CameraFrameStage stage, CameraFrameStage stage,
const CameraRenderRequest& request, const CameraFramePlan& plan,
const ShadowCasterRenderRequest& resolvedShadowCaster, const ShadowCasterRenderRequest& resolvedShadowCaster,
const RenderSceneData& sceneData, const RenderSceneData& sceneData,
CameraFrameExecutionState& executionState) { CameraFrameExecutionState& executionState) {
const RenderPassContext passContext = BuildFrameStagePassContext(stage, request, sceneData); const RenderPassContext passContext = BuildFrameStagePassContext(stage, plan, sceneData);
switch (stage) { switch (stage) {
case CameraFrameStage::PreScenePasses: case CameraFrameStage::PreScenePasses:
return ExecutePassSequenceStage( return ExecutePassSequenceStage(
executionState.preScenePasses, executionState.preScenePasses,
request.GetPassSequence(stage), plan.GetPassSequence(stage),
request.context, plan.request.context,
passContext); passContext);
case CameraFrameStage::ShadowCaster: case CameraFrameStage::ShadowCaster:
return ExecuteScenePassRequest( return ExecuteScenePassRequest(
executionState.shadowCasterPass, executionState.shadowCasterPass,
resolvedShadowCaster, resolvedShadowCaster,
request.context, plan.request.context,
sceneData); sceneData);
case CameraFrameStage::DepthOnly: case CameraFrameStage::DepthOnly:
return ExecuteScenePassRequest( return ExecuteScenePassRequest(
executionState.depthOnlyPass, executionState.depthOnlyPass,
request.depthOnly, plan.request.depthOnly,
request.context, plan.request.context,
sceneData); sceneData);
case CameraFrameStage::MainScene: case CameraFrameStage::MainScene:
return executionState.pipeline != nullptr && return executionState.pipeline != nullptr &&
executionState.pipeline->Render(request.context, passContext.surface, sceneData); executionState.pipeline->Render(
FrameExecutionContext(
plan.request.context,
passContext.surface,
sceneData,
passContext.sourceSurface,
passContext.sourceColorView,
passContext.sourceColorState));
case CameraFrameStage::PostProcess: case CameraFrameStage::PostProcess:
return ExecuteFullscreenPassSequenceStage( return ExecuteFullscreenPassSequenceStage(
executionState.postProcessPasses, executionState.postProcessPasses,
request.GetPassSequence(stage), plan.GetPassSequence(stage),
request.context, plan.request.context,
passContext, passContext,
executionState.postProcessSurfaceCache); executionState.postProcessSurfaceCache);
case CameraFrameStage::FinalOutput: case CameraFrameStage::FinalOutput:
return ExecuteFullscreenPassSequenceStage( return ExecuteFullscreenPassSequenceStage(
executionState.finalOutputPasses, executionState.finalOutputPasses,
request.GetPassSequence(stage), plan.GetPassSequence(stage),
request.context, plan.request.context,
passContext, passContext,
executionState.finalOutputSurfaceCache); executionState.finalOutputSurfaceCache);
case CameraFrameStage::ObjectId: case CameraFrameStage::ObjectId:
return !request.objectId.IsRequested() || return !plan.request.objectId.IsRequested() ||
ExecuteStandalonePass( ExecuteStandalonePass(
executionState.objectIdPass, executionState.objectIdPass,
request.context, plan.request.context,
request.objectId.surface, plan.request.objectId.surface,
sceneData); sceneData);
case CameraFrameStage::PostScenePasses: case CameraFrameStage::PostScenePasses:
return ExecutePassSequenceStage( return ExecutePassSequenceStage(
executionState.postScenePasses, executionState.postScenePasses,
request.GetPassSequence(stage), plan.GetPassSequence(stage),
request.context, plan.request.context,
passContext); passContext);
case CameraFrameStage::OverlayPasses: case CameraFrameStage::OverlayPasses:
return ExecutePassSequenceStage( return ExecutePassSequenceStage(
executionState.overlayPasses, executionState.overlayPasses,
request.GetPassSequence(stage), plan.GetPassSequence(stage),
request.context, plan.request.context,
passContext); passContext);
default: default:
return false; return false;
@@ -396,27 +403,27 @@ RenderDirectionalShadowData BuildDirectionalShadowData(
return shadowData; return shadowData;
} }
RenderEnvironmentData BuildEnvironmentData(const CameraRenderRequest& request) { RenderEnvironmentData BuildEnvironmentData(const CameraFramePlan& plan) {
RenderEnvironmentData environment = {}; RenderEnvironmentData environment = {};
const RenderSurface& mainSceneSurface = request.GetMainSceneSurface(); const RenderSurface& mainSceneSurface = plan.GetMainSceneSurface();
if (request.camera == nullptr || if (plan.request.camera == nullptr ||
mainSceneSurface.GetDepthAttachment() == nullptr || mainSceneSurface.GetDepthAttachment() == nullptr ||
!HasRenderClearFlag(request.clearFlags, RenderClearFlags::Color) || !HasRenderClearFlag(plan.request.clearFlags, RenderClearFlags::Color) ||
!request.camera->IsSkyboxEnabled() || !plan.request.camera->IsSkyboxEnabled() ||
request.camera->GetProjectionType() != Components::CameraProjectionType::Perspective) { plan.request.camera->GetProjectionType() != Components::CameraProjectionType::Perspective) {
return environment; return environment;
} }
if (const Resources::Material* skyboxMaterial = request.camera->GetSkyboxMaterial()) { if (const Resources::Material* skyboxMaterial = plan.request.camera->GetSkyboxMaterial()) {
environment.mode = RenderEnvironmentMode::MaterialSkybox; environment.mode = RenderEnvironmentMode::MaterialSkybox;
environment.materialSkybox.material = skyboxMaterial; environment.materialSkybox.material = skyboxMaterial;
return environment; return environment;
} }
environment.mode = RenderEnvironmentMode::ProceduralSkybox; environment.mode = RenderEnvironmentMode::ProceduralSkybox;
environment.skybox.topColor = request.camera->GetSkyboxTopColor(); environment.skybox.topColor = plan.request.camera->GetSkyboxTopColor();
environment.skybox.horizonColor = request.camera->GetSkyboxHorizonColor(); environment.skybox.horizonColor = plan.request.camera->GetSkyboxHorizonColor();
environment.skybox.bottomColor = request.camera->GetSkyboxBottomColor(); environment.skybox.bottomColor = plan.request.camera->GetSkyboxBottomColor();
return environment; return environment;
} }
@@ -538,17 +545,17 @@ void CameraRenderer::ResetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
} }
bool CameraRenderer::ResolveShadowCasterRequest( bool CameraRenderer::ResolveShadowCasterRequest(
const CameraRenderRequest& request, const CameraFramePlan& plan,
ShadowCasterRenderRequest& outResolvedShadowCaster, ShadowCasterRenderRequest& outResolvedShadowCaster,
RHI::RHIResourceView*& outShadowMapView) { RHI::RHIResourceView*& outShadowMapView) {
outResolvedShadowCaster = request.shadowCaster; outResolvedShadowCaster = plan.shadowCaster;
outShadowMapView = nullptr; outShadowMapView = nullptr;
if (outResolvedShadowCaster.IsRequested()) { if (outResolvedShadowCaster.IsRequested()) {
return outResolvedShadowCaster.IsValid(); return outResolvedShadowCaster.IsValid();
} }
if (!request.directionalShadow.IsValid()) { if (!plan.directionalShadow.IsValid()) {
return true; return true;
} }
@@ -556,7 +563,7 @@ bool CameraRenderer::ResolveShadowCasterRequest(
m_directionalShadowSurface = std::make_unique<DirectionalShadowSurfaceCache>(); m_directionalShadowSurface = std::make_unique<DirectionalShadowSurfaceCache>();
} }
if (!m_directionalShadowSurface->EnsureSurface(request.context, request.directionalShadow)) { if (!m_directionalShadowSurface->EnsureSurface(plan.request.context, plan.directionalShadow)) {
return false; return false;
} }
@@ -564,44 +571,44 @@ bool CameraRenderer::ResolveShadowCasterRequest(
outResolvedShadowCaster.clearFlags = RenderClearFlags::Depth; outResolvedShadowCaster.clearFlags = RenderClearFlags::Depth;
if (!outResolvedShadowCaster.hasCameraDataOverride) { if (!outResolvedShadowCaster.hasCameraDataOverride) {
outResolvedShadowCaster.hasCameraDataOverride = true; outResolvedShadowCaster.hasCameraDataOverride = true;
outResolvedShadowCaster.cameraDataOverride = request.directionalShadow.cameraData; outResolvedShadowCaster.cameraDataOverride = plan.directionalShadow.cameraData;
} }
outShadowMapView = m_directionalShadowSurface->GetDepthShaderView(); outShadowMapView = m_directionalShadowSurface->GetDepthShaderView();
return true; return true;
} }
bool CameraRenderer::BuildSceneDataForRequest( bool CameraRenderer::BuildSceneDataForPlan(
const CameraRenderRequest& request, const CameraFramePlan& plan,
RHI::RHIResourceView* shadowMapView, RHI::RHIResourceView* shadowMapView,
RenderSceneData& outSceneData) { RenderSceneData& outSceneData) {
const RenderSurface& mainSceneSurface = request.GetMainSceneSurface(); const RenderSurface& mainSceneSurface = plan.GetMainSceneSurface();
outSceneData = m_sceneExtractor.ExtractForCamera( outSceneData = m_sceneExtractor.ExtractForCamera(
*request.scene, *plan.request.scene,
*request.camera, *plan.request.camera,
mainSceneSurface.GetRenderAreaWidth(), mainSceneSurface.GetRenderAreaWidth(),
mainSceneSurface.GetRenderAreaHeight()); mainSceneSurface.GetRenderAreaHeight());
if (!outSceneData.HasCamera()) { if (!outSceneData.HasCamera()) {
return false; return false;
} }
if (request.directionalShadow.IsValid()) { if (plan.directionalShadow.IsValid()) {
outSceneData.lighting.mainDirectionalShadow = outSceneData.lighting.mainDirectionalShadow =
BuildDirectionalShadowData(request.directionalShadow, shadowMapView); BuildDirectionalShadowData(plan.directionalShadow, shadowMapView);
} }
outSceneData.globalShaderKeywords = BuildSceneGlobalShaderKeywords(outSceneData); outSceneData.globalShaderKeywords = BuildSceneGlobalShaderKeywords(outSceneData);
outSceneData.cameraData.clearFlags = request.clearFlags; outSceneData.cameraData.clearFlags = plan.request.clearFlags;
outSceneData.environment = BuildEnvironmentData(request); outSceneData.environment = BuildEnvironmentData(plan);
if (request.hasClearColorOverride) { if (plan.request.hasClearColorOverride) {
outSceneData.cameraData.clearColor = request.clearColorOverride; outSceneData.cameraData.clearColor = plan.request.clearColorOverride;
} }
return true; return true;
} }
bool CameraRenderer::ExecuteRenderPlan( bool CameraRenderer::ExecuteRenderPlan(
const CameraRenderRequest& request, const CameraFramePlan& plan,
const ShadowCasterRenderRequest& resolvedShadowCaster, const ShadowCasterRenderRequest& resolvedShadowCaster,
const RenderSceneData& sceneData) { const RenderSceneData& sceneData) {
CameraFrameExecutionState executionState = {}; CameraFrameExecutionState executionState = {};
@@ -613,14 +620,14 @@ bool CameraRenderer::ExecuteRenderPlan(
executionState.finalOutputSurfaceCache = m_finalOutputSurfaceCache.get(); executionState.finalOutputSurfaceCache = m_finalOutputSurfaceCache.get();
for (const CameraFrameStageInfo& stageInfo : kOrderedCameraFrameStages) { for (const CameraFrameStageInfo& stageInfo : kOrderedCameraFrameStages) {
if (!request.HasFrameStage(stageInfo.stage) && if (!plan.HasFrameStage(stageInfo.stage) &&
stageInfo.stage != CameraFrameStage::MainScene) { stageInfo.stage != CameraFrameStage::MainScene) {
continue; continue;
} }
if (!ExecuteFrameStage( if (!ExecuteFrameStage(
stageInfo.stage, stageInfo.stage,
request, plan,
resolvedShadowCaster, resolvedShadowCaster,
sceneData, sceneData,
executionState)) { executionState)) {
@@ -633,14 +640,19 @@ bool CameraRenderer::ExecuteRenderPlan(
bool CameraRenderer::Render( bool CameraRenderer::Render(
const CameraRenderRequest& request) { const CameraRenderRequest& request) {
if (!request.IsValid() || m_pipeline == nullptr) { return Render(CameraFramePlan::FromRequest(request));
}
bool CameraRenderer::Render(
const CameraFramePlan& plan) {
if (!plan.IsValid() || m_pipeline == nullptr) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"CameraRenderer::Render failed: request invalid or pipeline missing"); "CameraRenderer::Render failed: plan invalid or pipeline missing");
return false; return false;
} }
const RenderSurface& mainSceneSurface = request.GetMainSceneSurface(); const RenderSurface& mainSceneSurface = plan.GetMainSceneSurface();
if (mainSceneSurface.GetRenderAreaWidth() == 0 || if (mainSceneSurface.GetRenderAreaWidth() == 0 ||
mainSceneSurface.GetRenderAreaHeight() == 0) { mainSceneSurface.GetRenderAreaHeight() == 0) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
@@ -648,29 +660,29 @@ bool CameraRenderer::Render(
"CameraRenderer::Render failed: main scene surface render area is empty"); "CameraRenderer::Render failed: main scene surface render area is empty");
return false; return false;
} }
if (request.depthOnly.IsRequested() && if (plan.request.depthOnly.IsRequested() &&
!request.depthOnly.IsValid()) { !plan.request.depthOnly.IsValid()) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"CameraRenderer::Render failed: depth-only request invalid"); "CameraRenderer::Render failed: depth-only request invalid");
return false; return false;
} }
if (request.postProcess.IsRequested() && if (plan.postProcess.IsRequested() &&
!request.postProcess.IsValid()) { !plan.postProcess.IsValid()) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"CameraRenderer::Render failed: post-process request invalid"); "CameraRenderer::Render failed: post-process request invalid");
return false; return false;
} }
if (request.finalOutput.IsRequested() && if (plan.finalOutput.IsRequested() &&
!request.finalOutput.IsValid()) { !plan.finalOutput.IsValid()) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"CameraRenderer::Render failed: final-output request invalid"); "CameraRenderer::Render failed: final-output request invalid");
return false; return false;
} }
if (request.objectId.IsRequested() && if (plan.request.objectId.IsRequested() &&
!request.objectId.IsValid()) { !plan.request.objectId.IsValid()) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"CameraRenderer::Render failed: object-id request invalid"); "CameraRenderer::Render failed: object-id request invalid");
@@ -679,7 +691,7 @@ bool CameraRenderer::Render(
ShadowCasterRenderRequest resolvedShadowCaster = {}; ShadowCasterRenderRequest resolvedShadowCaster = {};
RHI::RHIResourceView* shadowMapView = nullptr; RHI::RHIResourceView* shadowMapView = nullptr;
if (!ResolveShadowCasterRequest(request, resolvedShadowCaster, shadowMapView)) { if (!ResolveShadowCasterRequest(plan, resolvedShadowCaster, shadowMapView)) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"CameraRenderer::Render failed: ResolveShadowCasterRequest returned false"); "CameraRenderer::Render failed: ResolveShadowCasterRequest returned false");
@@ -687,14 +699,14 @@ bool CameraRenderer::Render(
} }
RenderSceneData sceneData = {}; RenderSceneData sceneData = {};
if (!BuildSceneDataForRequest(request, shadowMapView, sceneData)) { if (!BuildSceneDataForPlan(plan, shadowMapView, sceneData)) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"CameraRenderer::Render failed: BuildSceneDataForRequest returned false"); "CameraRenderer::Render failed: BuildSceneDataForPlan returned false");
return false; return false;
} }
if (!ExecuteRenderPlan(request, resolvedShadowCaster, sceneData)) { if (!ExecuteRenderPlan(plan, resolvedShadowCaster, sceneData)) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"CameraRenderer::Render failed: ExecuteRenderPlan returned false"); "CameraRenderer::Render failed: ExecuteRenderPlan returned false");

View File

@@ -13,6 +13,14 @@ namespace Rendering {
namespace { namespace {
bool CompareCameraFramePlans(
const CameraFramePlan& lhs,
const CameraFramePlan& rhs) {
return SceneRenderRequestUtils::CompareCameraRenderRequests(
lhs.request,
rhs.request);
}
RenderSurface ConfigureFullscreenStageSurface( RenderSurface ConfigureFullscreenStageSurface(
const FullscreenPassSurfaceCache::SurfaceEntry& entry, const FullscreenPassSurfaceCache::SurfaceEntry& entry,
const RenderSurface& templateSurface, const RenderSurface& templateSurface,
@@ -94,44 +102,72 @@ std::vector<CameraRenderRequest> SceneRenderer::BuildRenderRequests(
Components::CameraComponent* overrideCamera, Components::CameraComponent* overrideCamera,
const RenderContext& context, const RenderContext& context,
const RenderSurface& surface) { const RenderSurface& surface) {
std::vector<CameraRenderRequest> requests = const std::vector<CameraFramePlan> plans =
m_requestPlanner.BuildRequests(scene, overrideCamera, context, surface); BuildFramePlans(scene, overrideCamera, context, surface);
ResolveCameraFinalColorPolicies(requests); std::vector<CameraRenderRequest> requests = {};
AttachFullscreenStageRequests(context, requests); requests.reserve(plans.size());
for (const CameraFramePlan& plan : plans) {
requests.push_back(BuildLegacyCameraRenderRequest(plan));
}
return requests; return requests;
} }
std::vector<CameraFramePlan> SceneRenderer::BuildFramePlans(
const Components::Scene& scene,
Components::CameraComponent* overrideCamera,
const RenderContext& context,
const RenderSurface& surface) {
const std::vector<CameraRenderRequest> requests =
m_requestPlanner.BuildRequests(scene, overrideCamera, context, surface);
std::vector<CameraFramePlan> plans = CreateFramePlansFromRequests(requests);
ResolveCameraFinalColorPolicies(plans);
AttachFullscreenStageRequests(context, plans);
return plans;
}
bool SceneRenderer::Render(const CameraRenderRequest& request) { bool SceneRenderer::Render(const CameraRenderRequest& request) {
return m_cameraRenderer.Render(request); return Render(CameraFramePlan::FromRequest(request));
} }
bool SceneRenderer::Render(const std::vector<CameraRenderRequest>& requests) { bool SceneRenderer::Render(const std::vector<CameraRenderRequest>& requests) {
if (requests.empty()) { std::vector<CameraFramePlan> plans = CreateFramePlansFromRequests(requests);
return Render(plans);
}
bool SceneRenderer::Render(const CameraFramePlan& plan) {
return m_cameraRenderer.Render(plan);
}
bool SceneRenderer::Render(const std::vector<CameraFramePlan>& plans) {
if (plans.empty()) {
return false; return false;
} }
for (const CameraRenderRequest& request : requests) { for (const CameraFramePlan& plan : plans) {
if (!request.IsValid()) { if (!plan.IsValid()) {
return false; return false;
} }
} }
std::vector<CameraRenderRequest> sortedRequests = requests; std::vector<CameraFramePlan> sortedPlans = plans;
SceneRenderRequestUtils::SortCameraRenderRequests(sortedRequests); std::stable_sort(
sortedPlans.begin(),
sortedPlans.end(),
CompareCameraFramePlans);
bool rendered = false; bool rendered = false;
for (const CameraRenderRequest& request : sortedRequests) { for (const CameraFramePlan& plan : sortedPlans) {
if (!m_cameraRenderer.Render(request)) { if (!m_cameraRenderer.Render(plan)) {
return false; return false;
} }
UpdateTrackedFullscreenSurfaceState( UpdateTrackedFullscreenSurfaceState(
m_ownedFullscreenStageSurfaces, m_ownedFullscreenStageSurfaces,
&request.GetMainSceneSurface()); &plan.GetMainSceneSurface());
if (request.postProcess.IsRequested()) { if (plan.postProcess.IsRequested()) {
UpdateTrackedFullscreenSurfaceState( UpdateTrackedFullscreenSurfaceState(
m_ownedFullscreenStageSurfaces, m_ownedFullscreenStageSurfaces,
&request.postProcess.destinationSurface); &plan.postProcess.destinationSurface);
} }
rendered = true; rendered = true;
@@ -145,7 +181,18 @@ bool SceneRenderer::Render(
Components::CameraComponent* overrideCamera, Components::CameraComponent* overrideCamera,
const RenderContext& context, const RenderContext& context,
const RenderSurface& surface) { const RenderSurface& surface) {
return Render(BuildRenderRequests(scene, overrideCamera, context, surface)); return Render(BuildFramePlans(scene, overrideCamera, context, surface));
}
std::vector<CameraFramePlan> SceneRenderer::CreateFramePlansFromRequests(
const std::vector<CameraRenderRequest>& requests) const {
std::vector<CameraFramePlan> plans = {};
plans.reserve(requests.size());
for (const CameraRenderRequest& request : requests) {
plans.push_back(CameraFramePlan::FromRequest(request));
}
return plans;
} }
void SceneRenderer::PrepareOwnedFullscreenStageState(size_t requestCount) { void SceneRenderer::PrepareOwnedFullscreenStageState(size_t requestCount) {
@@ -166,39 +213,39 @@ void SceneRenderer::PrepareOwnedFullscreenStageState(size_t requestCount) {
} }
void SceneRenderer::ResolveCameraFinalColorPolicies( void SceneRenderer::ResolveCameraFinalColorPolicies(
std::vector<CameraRenderRequest>& requests) const { std::vector<CameraFramePlan>& plans) const {
const RenderPipelineAsset* pipelineAsset = GetPipelineAsset(); const RenderPipelineAsset* pipelineAsset = GetPipelineAsset();
const FinalColorSettings pipelineDefaults = const FinalColorSettings pipelineDefaults =
pipelineAsset != nullptr ? pipelineAsset->GetDefaultFinalColorSettings() : FinalColorSettings(); pipelineAsset != nullptr ? pipelineAsset->GetDefaultFinalColorSettings() : FinalColorSettings();
for (CameraRenderRequest& request : requests) { for (CameraFramePlan& plan : plans) {
if (request.camera == nullptr) { if (plan.request.camera == nullptr) {
continue; continue;
} }
request.finalColorPolicy = ResolveFinalColorPolicy( plan.finalColorPolicy = ResolveFinalColorPolicy(
pipelineDefaults, pipelineDefaults,
&request.camera->GetFinalColorOverrides()); &plan.request.camera->GetFinalColorOverrides());
} }
} }
void SceneRenderer::AttachFullscreenStageRequests( void SceneRenderer::AttachFullscreenStageRequests(
const RenderContext& context, const RenderContext& context,
std::vector<CameraRenderRequest>& requests) { std::vector<CameraFramePlan>& plans) {
PrepareOwnedFullscreenStageState(requests.size()); PrepareOwnedFullscreenStageState(plans.size());
for (size_t index = 0; index < requests.size(); ++index) { for (size_t index = 0; index < plans.size(); ++index) {
CameraRenderRequest& request = requests[index]; CameraFramePlan& plan = plans[index];
if (request.camera == nullptr || if (plan.request.camera == nullptr ||
request.context.device == nullptr || plan.request.context.device == nullptr ||
!HasValidColorTarget(request.surface)) { !HasValidColorTarget(plan.request.surface)) {
continue; continue;
} }
std::unique_ptr<RenderPassSequence> postProcessSequence = std::unique_ptr<RenderPassSequence> postProcessSequence =
BuildCameraPostProcessPassSequence(request.camera->GetPostProcessPasses()); BuildCameraPostProcessPassSequence(plan.request.camera->GetPostProcessPasses());
std::unique_ptr<RenderPassSequence> finalOutputSequence = std::unique_ptr<RenderPassSequence> finalOutputSequence =
BuildFinalColorPassSequence(request.finalColorPolicy); BuildFinalColorPassSequence(plan.finalColorPolicy);
const bool hasPostProcess = const bool hasPostProcess =
postProcessSequence != nullptr && postProcessSequence->GetPassCount() > 0u; postProcessSequence != nullptr && postProcessSequence->GetPassCount() > 0u;
@@ -208,14 +255,14 @@ void SceneRenderer::AttachFullscreenStageRequests(
continue; continue;
} }
if (request.surface.GetSampleCount() > 1u) { if (plan.request.surface.GetSampleCount() > 1u) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"SceneRenderer fullscreen post-process/final-output chain currently requires a single-sample main scene surface"); "SceneRenderer fullscreen post-process/final-output chain currently requires a single-sample main scene surface");
continue; continue;
} }
const std::vector<RHI::RHIResourceView*>& colorAttachments = request.surface.GetColorAttachments(); const std::vector<RHI::RHIResourceView*>& colorAttachments = plan.request.surface.GetColorAttachments();
const RHI::Format colorFormat = colorAttachments[0]->GetFormat(); const RHI::Format colorFormat = colorAttachments[0]->GetFormat();
if (colorFormat == RHI::Format::Unknown) { if (colorFormat == RHI::Format::Unknown) {
continue; continue;
@@ -226,8 +273,8 @@ void SceneRenderer::AttachFullscreenStageRequests(
if (surfaceCache == nullptr || if (surfaceCache == nullptr ||
!surfaceCache->EnsureSurfaces( !surfaceCache->EnsureSurfaces(
context, context,
request.surface.GetWidth(), plan.request.surface.GetWidth(),
request.surface.GetHeight(), plan.request.surface.GetHeight(),
colorFormat, colorFormat,
fullscreenSurfaceCount)) { fullscreenSurfaceCount)) {
continue; continue;
@@ -246,30 +293,30 @@ void SceneRenderer::AttachFullscreenStageRequests(
} }
if (hasPostProcess) { if (hasPostProcess) {
request.postProcess.sourceSurface = plan.postProcess.sourceSurface =
ConfigureFullscreenStageSurface(*sceneColorEntry, request.surface, true); ConfigureFullscreenStageSurface(*sceneColorEntry, plan.request.surface, true);
request.postProcess.sourceColorView = sceneColorEntry->shaderResourceView; plan.postProcess.sourceColorView = sceneColorEntry->shaderResourceView;
request.postProcess.sourceColorState = request.postProcess.sourceSurface.GetColorStateAfter(); plan.postProcess.sourceColorState = plan.postProcess.sourceSurface.GetColorStateAfter();
request.postProcess.destinationSurface = plan.postProcess.destinationSurface =
hasFinalOutput hasFinalOutput
? ConfigureFullscreenStageSurface(*postProcessOutputEntry, request.surface, false) ? ConfigureFullscreenStageSurface(*postProcessOutputEntry, plan.request.surface, false)
: request.surface; : plan.request.surface;
m_ownedPostProcessSequences[index] = std::move(postProcessSequence); m_ownedPostProcessSequences[index] = std::move(postProcessSequence);
request.postProcess.passes = m_ownedPostProcessSequences[index].get(); plan.postProcess.passes = m_ownedPostProcessSequences[index].get();
} }
if (hasFinalOutput) { if (hasFinalOutput) {
const FullscreenPassSurfaceCache::SurfaceEntry* finalOutputSourceEntry = const FullscreenPassSurfaceCache::SurfaceEntry* finalOutputSourceEntry =
hasPostProcess ? postProcessOutputEntry : sceneColorEntry; hasPostProcess ? postProcessOutputEntry : sceneColorEntry;
request.finalOutput.sourceSurface = plan.finalOutput.sourceSurface =
hasPostProcess hasPostProcess
? request.postProcess.destinationSurface ? plan.postProcess.destinationSurface
: ConfigureFullscreenStageSurface(*sceneColorEntry, request.surface, true); : ConfigureFullscreenStageSurface(*sceneColorEntry, plan.request.surface, true);
request.finalOutput.sourceColorView = finalOutputSourceEntry->shaderResourceView; plan.finalOutput.sourceColorView = finalOutputSourceEntry->shaderResourceView;
request.finalOutput.sourceColorState = request.finalOutput.sourceSurface.GetColorStateAfter(); plan.finalOutput.sourceColorState = plan.finalOutput.sourceSurface.GetColorStateAfter();
request.finalOutput.destinationSurface = request.surface; plan.finalOutput.destinationSurface = plan.request.surface;
m_ownedFinalOutputSequences[index] = std::move(finalOutputSequence); m_ownedFinalOutputSequences[index] = std::move(finalOutputSequence);
request.finalOutput.passes = m_ownedFinalOutputSequences[index].get(); plan.finalOutput.passes = m_ownedFinalOutputSequences[index].get();
} }
} }
} }

View File

@@ -3,6 +3,7 @@
#include "Components/CameraComponent.h" #include "Components/CameraComponent.h"
#include "Components/GameObject.h" #include "Components/GameObject.h"
#include "Components/LightComponent.h" #include "Components/LightComponent.h"
#include "Rendering/FrameData/RendererListUtils.h"
#include "Rendering/Extraction/RenderSceneUtility.h" #include "Rendering/Extraction/RenderSceneUtility.h"
#include "Scene/Scene.h" #include "Scene/Scene.h"
@@ -125,6 +126,21 @@ bool CompareVisibleGaussianSplats(
return CompareVisibleGaussianSplatsStable(lhs, rhs); return CompareVisibleGaussianSplatsStable(lhs, rhs);
} }
void BuildRendererLists(RenderSceneData& sceneData) {
sceneData.cullingResults.Clear();
sceneData.cullingResults.rendererLists.reserve(5u);
sceneData.cullingResults.rendererLists.push_back(
BuildRendererList(RendererListType::AllVisible, sceneData.visibleItems));
sceneData.cullingResults.rendererLists.push_back(
BuildRendererList(RendererListType::Opaque, sceneData.visibleItems));
sceneData.cullingResults.rendererLists.push_back(
BuildRendererList(RendererListType::Transparent, sceneData.visibleItems));
sceneData.cullingResults.rendererLists.push_back(
BuildRendererList(RendererListType::ShadowCaster, sceneData.visibleItems));
sceneData.cullingResults.rendererLists.push_back(
BuildRendererList(RendererListType::ObjectId, sceneData.visibleItems));
}
} // namespace } // namespace
RenderSceneData RenderSceneExtractor::Extract( RenderSceneData RenderSceneExtractor::Extract(
@@ -165,6 +181,7 @@ RenderSceneData RenderSceneExtractor::Extract(
sceneData.visibleVolumes.begin(), sceneData.visibleVolumes.begin(),
sceneData.visibleVolumes.end(), sceneData.visibleVolumes.end(),
CompareVisibleVolumes); CompareVisibleVolumes);
BuildRendererLists(sceneData);
ExtractLighting(scene, cameraPosition, cullingMask, sceneData.lighting); ExtractLighting(scene, cameraPosition, cullingMask, sceneData.lighting);
return sceneData; return sceneData;
@@ -208,6 +225,7 @@ RenderSceneData RenderSceneExtractor::ExtractForCamera(
sceneData.visibleVolumes.begin(), sceneData.visibleVolumes.begin(),
sceneData.visibleVolumes.end(), sceneData.visibleVolumes.end(),
CompareVisibleVolumes); CompareVisibleVolumes);
BuildRendererLists(sceneData);
ExtractLighting(scene, cameraPosition, cullingMask, sceneData.lighting); ExtractLighting(scene, cameraPosition, cullingMask, sceneData.lighting);
return sceneData; return sceneData;

View File

@@ -2,6 +2,7 @@
#include "RHI/RHICommandList.h" #include "RHI/RHICommandList.h"
#include "Rendering/Extraction/RenderSceneExtractor.h" #include "Rendering/Extraction/RenderSceneExtractor.h"
#include "Rendering/FrameData/RendererListUtils.h"
#include "Rendering/Internal/RenderSurfacePipelineUtils.h" #include "Rendering/Internal/RenderSurfacePipelineUtils.h"
#include "Rendering/RenderSurface.h" #include "Rendering/RenderSurface.h"
#include "Resources/Mesh/Mesh.h" #include "Resources/Mesh/Mesh.h"
@@ -139,13 +140,16 @@ bool BuiltinDepthStylePassBase::Execute(const RenderPassContext& context) {
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList); commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
for (const VisibleRenderItem& visibleItem : context.sceneData.visibleItems) { VisitRendererListVisibleItems(
if (!ShouldRenderVisibleItem(visibleItem)) { context.sceneData,
continue; GetRendererListType(),
} [&](const VisibleRenderItem& visibleItem) {
if (!ShouldRenderVisibleItem(visibleItem)) {
return;
}
DrawVisibleItem(context.renderContext, context.surface, context.sceneData, visibleItem); DrawVisibleItem(context.renderContext, context.surface, context.sceneData, visibleItem);
} });
commandList->EndRenderPass(); commandList->EndRenderPass();
@@ -165,6 +169,10 @@ bool BuiltinDepthStylePassBase::Execute(const RenderPassContext& context) {
return true; return true;
} }
RendererListType BuiltinDepthStylePassBase::GetRendererListType() const {
return RendererListType::AllVisible;
}
bool BuiltinDepthStylePassBase::ShouldRenderVisibleItem(const VisibleRenderItem& visibleItem) const { bool BuiltinDepthStylePassBase::ShouldRenderVisibleItem(const VisibleRenderItem& visibleItem) const {
(void)visibleItem; (void)visibleItem;
return true; return true;

View File

@@ -222,6 +222,16 @@ bool BuiltinGaussianSplatPass::Initialize(const RenderContext& context) {
return EnsureInitialized(context); return EnsureInitialized(context);
} }
bool BuiltinGaussianSplatPass::IsActive(const RenderSceneData& sceneData) const {
return !sceneData.visibleGaussianSplats.empty();
}
bool BuiltinGaussianSplatPass::Prepare(
const RenderContext& context,
const RenderSceneData& sceneData) {
return PrepareGaussianSplatResources(context, sceneData);
}
bool BuiltinGaussianSplatPass::PrepareGaussianSplatResources( bool BuiltinGaussianSplatPass::PrepareGaussianSplatResources(
const RenderContext& context, const RenderContext& context,
const RenderSceneData& sceneData) { const RenderSceneData& sceneData) {

View File

@@ -2,6 +2,7 @@
#include "Core/Asset/ResourceManager.h" #include "Core/Asset/ResourceManager.h"
#include "RHI/RHICommandList.h" #include "RHI/RHICommandList.h"
#include "Rendering/FrameData/RendererListUtils.h"
#include "Rendering/Internal/RenderSurfacePipelineUtils.h" #include "Rendering/Internal/RenderSurfacePipelineUtils.h"
#include "Rendering/Extraction/RenderSceneExtractor.h" #include "Rendering/Extraction/RenderSceneExtractor.h"
#include "Rendering/RenderSurface.h" #include "Rendering/RenderSurface.h"
@@ -119,9 +120,12 @@ bool BuiltinObjectIdPass::Execute(const RenderPassContext& context) {
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList); commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
commandList->SetPipelineState(m_pipelineState); commandList->SetPipelineState(m_pipelineState);
for (const VisibleRenderItem& visibleItem : context.sceneData.visibleItems) { VisitRendererListVisibleItems(
DrawVisibleItem(context.renderContext, context.sceneData, visibleItem); context.sceneData,
} RendererListType::ObjectId,
[&](const VisibleRenderItem& visibleItem) {
DrawVisibleItem(context.renderContext, context.sceneData, visibleItem);
});
commandList->EndRenderPass(); commandList->EndRenderPass();

View File

@@ -22,6 +22,10 @@ const char* BuiltinShadowCasterPass::GetName() const {
return "BuiltinShadowCasterPass"; return "BuiltinShadowCasterPass";
} }
RendererListType BuiltinShadowCasterPass::GetRendererListType() const {
return RendererListType::ShadowCaster;
}
bool BuiltinShadowCasterPass::ShouldRenderVisibleItem(const VisibleRenderItem& visibleItem) const { bool BuiltinShadowCasterPass::ShouldRenderVisibleItem(const VisibleRenderItem& visibleItem) const {
return visibleItem.meshRenderer == nullptr || visibleItem.meshRenderer->GetCastShadows(); return visibleItem.meshRenderer == nullptr || visibleItem.meshRenderer->GetCastShadows();
} }

View File

@@ -210,6 +210,16 @@ bool BuiltinVolumetricPass::Initialize(const RenderContext& context) {
return EnsureInitialized(context); return EnsureInitialized(context);
} }
bool BuiltinVolumetricPass::IsActive(const RenderSceneData& sceneData) const {
return !sceneData.visibleVolumes.empty();
}
bool BuiltinVolumetricPass::Prepare(
const RenderContext& context,
const RenderSceneData& sceneData) {
return PrepareVolumeResources(context, sceneData);
}
bool BuiltinVolumetricPass::PrepareVolumeResources( bool BuiltinVolumetricPass::PrepareVolumeResources(
const RenderContext& context, const RenderContext& context,
const RenderSceneData& sceneData) { const RenderSceneData& sceneData) {

View File

@@ -143,58 +143,31 @@ RHI::InputLayoutDesc BuiltinForwardPipeline::BuildInputLayout() {
bool BuiltinForwardPipeline::Initialize(const RenderContext& context) { bool BuiltinForwardPipeline::Initialize(const RenderContext& context) {
return EnsureInitialized(context) && return EnsureInitialized(context) &&
m_gaussianSplatPass != nullptr && InitializeForwardSceneFeaturePasses(context);
m_gaussianSplatPass->Initialize(context) &&
m_volumetricPass != nullptr &&
m_volumetricPass->Initialize(context);
} }
void BuiltinForwardPipeline::Shutdown() { void BuiltinForwardPipeline::Shutdown() {
if (m_gaussianSplatPass != nullptr) { ShutdownForwardSceneFeaturePasses();
m_gaussianSplatPass->Shutdown();
}
if (m_volumetricPass != nullptr) {
m_volumetricPass->Shutdown();
}
DestroyPipelineResources(); DestroyPipelineResources();
} }
bool BuiltinForwardPipeline::Render( bool BuiltinForwardPipeline::Render(
const RenderContext& context, const FrameExecutionContext& executionContext) {
const RenderSurface& surface, if (!Initialize(executionContext.renderContext)) {
const RenderSceneData& sceneData) {
if (!Initialize(context)) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"BuiltinForwardPipeline::Render failed: Initialize returned false"); "BuiltinForwardPipeline::Render failed: Initialize returned false");
return false; return false;
} }
if (m_volumetricPass != nullptr && if (!PrepareForwardSceneFeaturePasses(executionContext)) {
!sceneData.visibleVolumes.empty() &&
!m_volumetricPass->PrepareVolumeResources(context, sceneData)) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"BuiltinForwardPipeline::Render failed: PrepareVolumeResources returned false"); "BuiltinForwardPipeline::Render failed: PrepareForwardSceneFeaturePasses returned false");
return false;
}
if (m_gaussianSplatPass != nullptr &&
!sceneData.visibleGaussianSplats.empty() &&
!m_gaussianSplatPass->PrepareGaussianSplatResources(context, sceneData)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinForwardPipeline::Render failed: PrepareGaussianSplatResources returned false");
return false; return false;
} }
const RenderPassContext passContext = { const RenderPassContext passContext = BuildRenderPassContext(executionContext);
context,
surface,
sceneData,
nullptr,
nullptr,
RHI::ResourceStates::Common
};
if (!BeginForwardScenePass(passContext)) { if (!BeginForwardScenePass(passContext)) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
@@ -203,53 +176,33 @@ bool BuiltinForwardPipeline::Render(
return false; return false;
} }
const bool sampledDirectionalShadow = ShouldSampleMainDirectionalShadowMap(sceneData); const bool sampledDirectionalShadow =
ShouldSampleMainDirectionalShadowMap(executionContext.sceneData);
if (sampledDirectionalShadow) { if (sampledDirectionalShadow) {
TransitionMainDirectionalShadowForSampling(context, sceneData); TransitionMainDirectionalShadowForSampling(
executionContext.renderContext,
executionContext.sceneData);
} }
bool renderResult = ExecuteForwardOpaquePass(passContext); const bool renderResult = ExecuteForwardScene(executionContext);
if (renderResult) {
renderResult = ExecuteForwardSkyboxPass(passContext);
if (!renderResult) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinForwardPipeline::Render failed: ExecuteForwardSkyboxPass returned false");
}
}
if (renderResult && m_gaussianSplatPass != nullptr) {
renderResult = m_gaussianSplatPass->Execute(passContext);
if (!renderResult) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinForwardPipeline::Render failed: BuiltinGaussianSplatPass::Execute returned false");
}
}
if (renderResult && m_volumetricPass != nullptr) {
renderResult = m_volumetricPass->Execute(passContext);
if (!renderResult) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinForwardPipeline::Render failed: BuiltinVolumetricPass::Execute returned false");
}
}
if (renderResult) {
renderResult = ExecuteForwardTransparentPass(passContext);
if (!renderResult) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinForwardPipeline::Render failed: ExecuteForwardTransparentPass returned false");
}
}
if (sampledDirectionalShadow) { if (sampledDirectionalShadow) {
RestoreMainDirectionalShadowAfterSampling(context, sceneData); RestoreMainDirectionalShadowAfterSampling(
executionContext.renderContext,
executionContext.sceneData);
} }
EndForwardScenePass(passContext); EndForwardScenePass(passContext);
return renderResult; return renderResult;
} }
bool BuiltinForwardPipeline::Render(
const RenderContext& context,
const RenderSurface& surface,
const RenderSceneData& sceneData) {
return Render(FrameExecutionContext(context, surface, sceneData));
}
bool BuiltinForwardPipeline::BeginForwardScenePass(const RenderPassContext& passContext) { bool BuiltinForwardPipeline::BeginForwardScenePass(const RenderPassContext& passContext) {
const RenderContext& context = passContext.renderContext; const RenderContext& context = passContext.renderContext;
const RenderSurface& surface = passContext.surface; const RenderSurface& surface = passContext.surface;
@@ -358,20 +311,18 @@ void BuiltinForwardPipeline::EndForwardScenePass(const RenderPassContext& passCo
} }
} }
bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& passContext) { bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(
const RenderContext& context = passContext.renderContext; const ScenePhaseExecutionContext& executionContext) {
const RenderSurface& surface = passContext.surface; return DrawVisibleItems(
const RenderSceneData& sceneData = passContext.sceneData; executionContext.frameContext,
BuildDrawSettings(executionContext.scenePhase));
return DrawVisibleItems(context, surface, sceneData, false);
} }
bool BuiltinForwardPipeline::ExecuteForwardTransparentPass(const RenderPassContext& passContext) { bool BuiltinForwardPipeline::ExecuteForwardTransparentPass(
const RenderContext& context = passContext.renderContext; const ScenePhaseExecutionContext& executionContext) {
const RenderSurface& surface = passContext.surface; return DrawVisibleItems(
const RenderSceneData& sceneData = passContext.sceneData; executionContext.frameContext,
BuildDrawSettings(executionContext.scenePhase));
return DrawVisibleItems(context, surface, sceneData, true);
} }
bool BuiltinForwardPipeline::EnsureInitialized(const RenderContext& context) { bool BuiltinForwardPipeline::EnsureInitialized(const RenderContext& context) {
@@ -392,6 +343,146 @@ bool BuiltinForwardPipeline::EnsureInitialized(const RenderContext& context) {
return m_initialized; return m_initialized;
} }
BuiltinForwardPipeline::ForwardSceneFeaturePassArray
BuiltinForwardPipeline::CollectForwardSceneFeaturePasses() const {
return {
m_gaussianSplatPass.get(),
m_volumetricPass.get()
};
}
bool BuiltinForwardPipeline::InitializeForwardSceneFeaturePasses(const RenderContext& context) {
for (SceneRenderFeaturePass* featurePass : CollectForwardSceneFeaturePasses()) {
if (featurePass == nullptr || !featurePass->Initialize(context)) {
return false;
}
}
return true;
}
void BuiltinForwardPipeline::ShutdownForwardSceneFeaturePasses() {
for (SceneRenderFeaturePass* featurePass : CollectForwardSceneFeaturePasses()) {
if (featurePass != nullptr) {
featurePass->Shutdown();
}
}
}
bool BuiltinForwardPipeline::PrepareForwardSceneFeaturePasses(
const FrameExecutionContext& executionContext) const {
for (SceneRenderFeaturePass* featurePass : CollectForwardSceneFeaturePasses()) {
if (featurePass == nullptr || !featurePass->IsActive(executionContext.sceneData)) {
continue;
}
if (!featurePass->Prepare(
executionContext.renderContext,
executionContext.sceneData)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
(Containers::String("BuiltinForwardPipeline feature prepare failed: ") +
featurePass->GetName()).CStr());
return false;
}
}
return true;
}
bool BuiltinForwardPipeline::ExecuteForwardSceneFeaturePasses(
const ScenePhaseExecutionContext& executionContext) const {
const RenderPassContext passContext = BuildRenderPassContext(executionContext);
for (SceneRenderFeaturePass* featurePass : CollectForwardSceneFeaturePasses()) {
if (featurePass == nullptr ||
!featurePass->IsActive(executionContext.frameContext.sceneData)) {
continue;
}
if (!featurePass->Execute(passContext)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
(Containers::String("BuiltinForwardPipeline feature execute failed: ") +
featurePass->GetName()).CStr());
return false;
}
}
return true;
}
ScenePhaseExecutionContext BuiltinForwardPipeline::BuildScenePhaseExecutionContext(
const FrameExecutionContext& executionContext,
ScenePhase scenePhase) const {
return ScenePhaseExecutionContext(
executionContext,
scenePhase,
ShouldSampleMainDirectionalShadowMap(executionContext.sceneData));
}
DrawSettings BuiltinForwardPipeline::BuildDrawSettings(ScenePhase scenePhase) const {
DrawSettings drawSettings = {};
drawSettings.scenePhase = scenePhase;
switch (scenePhase) {
case ScenePhase::Opaque:
drawSettings.rendererListType = RendererListType::Opaque;
break;
case ScenePhase::Transparent:
drawSettings.rendererListType = RendererListType::Transparent;
break;
default:
drawSettings.rendererListType = RendererListType::AllVisible;
break;
}
return drawSettings;
}
bool BuiltinForwardPipeline::ExecuteScenePhase(
const ScenePhaseExecutionContext& executionContext) {
switch (executionContext.scenePhase) {
case ScenePhase::Opaque:
return ExecuteForwardOpaquePass(executionContext);
case ScenePhase::Skybox:
return ExecuteForwardSkyboxPass(BuildRenderPassContext(executionContext));
case ScenePhase::Feature:
return ExecuteForwardSceneFeaturePasses(executionContext);
case ScenePhase::Transparent:
return ExecuteForwardTransparentPass(executionContext);
default:
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
(Containers::String("BuiltinForwardPipeline::ExecuteScenePhase does not support scene phase: ") +
ToString(executionContext.scenePhase)).CStr());
return false;
}
}
bool BuiltinForwardPipeline::ExecuteForwardScene(
const FrameExecutionContext& executionContext) {
static constexpr ScenePhase kForwardScenePhases[] = {
ScenePhase::Opaque,
ScenePhase::Skybox,
ScenePhase::Feature,
ScenePhase::Transparent
};
for (ScenePhase scenePhase : kForwardScenePhases) {
const ScenePhaseExecutionContext scenePhaseExecutionContext =
BuildScenePhaseExecutionContext(executionContext, scenePhase);
if (!ExecuteScenePhase(scenePhaseExecutionContext)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
(Containers::String("BuiltinForwardPipeline::ExecuteForwardScene failed during phase: ") +
ToString(scenePhase)).CStr());
return false;
}
}
return true;
}
bool BuiltinForwardPipeline::CreatePipelineResources(const RenderContext& context) { bool BuiltinForwardPipeline::CreatePipelineResources(const RenderContext& context) {
m_builtinForwardShader = Resources::ResourceManager::Get().Load<Resources::Shader>( m_builtinForwardShader = Resources::ResourceManager::Get().Load<Resources::Shader>(
Resources::GetBuiltinForwardLitShaderPath()); Resources::GetBuiltinForwardLitShaderPath());

View File

@@ -5,6 +5,7 @@
#include "RHI/RHICommandList.h" #include "RHI/RHICommandList.h"
#include "RHI/RHIDevice.h" #include "RHI/RHIDevice.h"
#include "Rendering/Builtin/BuiltinPassLayoutUtils.h" #include "Rendering/Builtin/BuiltinPassLayoutUtils.h"
#include "Rendering/FrameData/RendererListUtils.h"
#include "Rendering/Internal/RenderSurfacePipelineUtils.h" #include "Rendering/Internal/RenderSurfacePipelineUtils.h"
#include "Rendering/Internal/ShaderVariantUtils.h" #include "Rendering/Internal/ShaderVariantUtils.h"
#include "Rendering/Materials/RenderMaterialResolve.h" #include "Rendering/Materials/RenderMaterialResolve.h"
@@ -687,10 +688,12 @@ BuiltinForwardPipeline::AdditionalLightConstants BuiltinForwardPipeline::BuildAd
} }
bool BuiltinForwardPipeline::DrawVisibleItem( bool BuiltinForwardPipeline::DrawVisibleItem(
const RenderContext& context, const FrameExecutionContext& executionContext,
const RenderSurface& surface,
const RenderSceneData& sceneData,
const VisibleRenderItem& visibleItem) { const VisibleRenderItem& visibleItem) {
const RenderContext& context = executionContext.renderContext;
const RenderSurface& surface = executionContext.surface;
const RenderSceneData& sceneData = executionContext.sceneData;
(void)surface; (void)surface;
const RenderResourceCache::CachedMesh* cachedMesh = m_resourceCache.GetOrCreateMesh(m_device, visibleItem.mesh); const RenderResourceCache::CachedMesh* cachedMesh = m_resourceCache.GetOrCreateMesh(m_device, visibleItem.mesh);
if (cachedMesh == nullptr || cachedMesh->vertexBufferView == nullptr) { if (cachedMesh == nullptr || cachedMesh->vertexBufferView == nullptr) {
@@ -861,36 +864,35 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
} }
bool BuiltinForwardPipeline::DrawVisibleItems( bool BuiltinForwardPipeline::DrawVisibleItems(
const RenderContext& context, const FrameExecutionContext& executionContext,
const RenderSurface& surface, const DrawSettings& drawSettings) {
const RenderSceneData& sceneData, const RenderContext& context = executionContext.renderContext;
bool drawTransparentItems) { const RenderSurface& surface = executionContext.surface;
const RenderSceneData& sceneData = executionContext.sceneData;
RHI::RHICommandList* commandList = context.commandList; RHI::RHICommandList* commandList = context.commandList;
RHI::RHIPipelineState* currentPipelineState = nullptr; RHI::RHIPipelineState* currentPipelineState = nullptr;
for (const VisibleRenderItem& visibleItem : sceneData.visibleItems) {
const bool isTransparentItem = IsTransparentRenderQueue(visibleItem.renderQueue);
if (isTransparentItem != drawTransparentItems) {
continue;
}
auto drawVisibleItem = [&](const VisibleRenderItem& visibleItem) {
const Resources::Material* material = ResolveMaterial(visibleItem); const Resources::Material* material = ResolveMaterial(visibleItem);
BuiltinMaterialPass pass = BuiltinMaterialPass::ForwardLit; BuiltinMaterialPass pass = BuiltinMaterialPass::ForwardLit;
if (!TryResolveSurfacePassType(material, pass)) { if (!TryResolveSurfacePassType(material, pass)) {
continue; return;
} }
RHI::RHIPipelineState* pipelineState = GetOrCreatePipelineState(context, surface, sceneData, material); RHI::RHIPipelineState* pipelineState = GetOrCreatePipelineState(context, surface, sceneData, material);
if (pipelineState == nullptr) { if (pipelineState == nullptr) {
continue; return;
} }
if (pipelineState != currentPipelineState) { if (pipelineState != currentPipelineState) {
commandList->SetPipelineState(pipelineState); commandList->SetPipelineState(pipelineState);
currentPipelineState = pipelineState; currentPipelineState = pipelineState;
} }
DrawVisibleItem(context, surface, sceneData, visibleItem); DrawVisibleItem(executionContext, visibleItem);
} };
VisitRendererListVisibleItems(sceneData, drawSettings.rendererListType, drawVisibleItem);
return true; return true;
} }

View File

@@ -81,11 +81,19 @@ std::vector<CameraRenderRequest> SceneRenderRequestPlanner::BuildRequests(
? static_cast<float>(surface.GetRenderAreaWidth()) / ? static_cast<float>(surface.GetRenderAreaWidth()) /
static_cast<float>(surface.GetRenderAreaHeight()) static_cast<float>(surface.GetRenderAreaHeight())
: 1.0f; : 1.0f;
DirectionalShadowPlanningSettings effectiveShadowSettings =
m_directionalShadowPlanningSettings;
if (mainDirectionalLight->GetOverridesDirectionalShadowSettings()) {
effectiveShadowSettings.sampling =
mainDirectionalLight->GetDirectionalShadowSamplingSettings();
effectiveShadowSettings.casterBias =
mainDirectionalLight->GetDirectionalShadowCasterBiasSettings();
}
request.directionalShadow = Internal::BuildDirectionalShadowRenderPlan( request.directionalShadow = Internal::BuildDirectionalShadowRenderPlan(
scene, scene,
*camera, *camera,
*mainDirectionalLight, *mainDirectionalLight,
m_directionalShadowPlanningSettings, effectiveShadowSettings,
viewportAspect); viewportAspect);
if (request.directionalShadow.IsValid()) { if (request.directionalShadow.IsValid()) {
request.shadowCaster.clearFlags = RenderClearFlags::Depth; request.shadowCaster.clearFlags = RenderClearFlags::Depth;