Align rendering orchestration with camera stack plans

This commit is contained in:
2026-04-28 02:42:42 +08:00
parent be0d244372
commit 3bc0cfcf08
20 changed files with 616 additions and 13 deletions

View File

@@ -507,6 +507,7 @@ add_library(XCEngine STATIC
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Builtin/BuiltinPassMetadataUtils.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Builtin/BuiltinPassLayoutUtils.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/CameraFramePlan.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/CameraStackFramePlan.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/CameraFrameStage.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/CameraRenderer.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/DirectionalShadowExecutionState.h
@@ -575,6 +576,7 @@ add_library(XCEngine STATIC
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/CameraFramePlan.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/CameraStackFramePlan.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/CameraRenderer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/RenderPipelineHost.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/SceneRenderSequence.cpp

View File

@@ -62,6 +62,9 @@ Unity 兼容的公开命名、对象所有权和扩展点。
具体后端头。
- 新增 camera-stack、renderer-index、shadow、depth、post-process 或 final output 行为时,不要绕过
`CameraFramePlanBuilder``SceneRenderRequestPlanner`
- 修改 camera stack 行为时,要保持 `CameraRenderRequest.cameraStackId``CameraStackFramePlan`
`RenderPipelineHost::BuildStackFramePlans``SceneRenderer::BuildStackFramePlans` 同步。
`CameraFramePlan` 是每个 camera 的叶子计划;`CameraStackFramePlan` 是顶层渲染生命周期根。
- 不要在 native 长生命周期对象里保存 raw managed object pointers 或 managed context handles。
需要持久化时,通过现有 external managed object handle 系统 retain。
- Managed URP public APIs 不要依赖 `CameraFrameGraph``NativeSceneRecorder` 这类 native
@@ -97,8 +100,9 @@ Unity 兼容的公开命名、对象所有权和扩展点。
built-in forward pipeline policy而不是作为 URP-declared work 的 backend executor。
- 目标所有权模型是URP 决定渲染什么、何时渲染、哪些 renderer lists/passes/features 激活,以及
哪些 stages 存在native 只执行这些声明,不夹带 built-in pipeline policy。
- `CameraFramePlanBuilder` 现在负责从 request 构造 `CameraFramePlan` 并委托所选
`RenderPipelineAsset::ConfigureCameraFramePlan`。它不再在 asset hook 之后追加通用 legacy
- `CameraFramePlanBuilder` 现在负责从 request 构造 per-camera `CameraFramePlan`,再按
`CameraRenderRequest.cameraStackId` 收口为 `CameraStackFramePlan`。它委托所选
`RenderPipelineAsset::ConfigureCameraFramePlan` 配置叶子计划,不再在 asset hook 之后追加通用 legacy
fullscreen stage heuristic默认 native fullscreen/final-output 行为应留在 native asset policy 内部。
- Hidden fallback 很危险。如果 managed URP stage 声明支持但无法 record失败必须可见。不要静默用
default built-in path 画同一个 stage然后称之为 URP。
@@ -132,10 +136,12 @@ Native renderer 现在是 camera frame planner 加 RenderGraph executormanage
叠在 native scene draw backend 之上。
- `SceneRenderer` 是 scene-level convenience entry point。它的公开管线选择根是 `RenderPipelineAsset`
它通过 `SceneRenderRequestPlanner` 收集 camera requests通过 `RenderPipelineHost` 构建 frame plans
然后渲染排序后的 camera plans。
它通过 `SceneRenderRequestPlanner` 收集 camera requests通过 `RenderPipelineHost` 构建
`CameraStackFramePlan`,然后以 camera stack 为根渲染。旧的 `BuildFramePlans`/flat-plan `Render`
API 只是兼容包装。
- `RenderPipelineHost` 拥有一个 `CameraFramePlanBuilder` 和一个 `CameraRenderer`。它是从
`CameraRenderRequest``CameraFramePlan` 的常规 native bridge并沿用同一个 asset selection root。
`CameraRenderRequest``CameraStackFramePlan` 的常规 native bridge并沿用同一个 asset selection root。
Stack 渲染完成后由所选 `RenderPipeline` 接收 `FinishCameraStackRendering`,用于 URP stack 生命周期收尾。
- `CameraRenderer` 拥有 asset 创建出的所选 `RenderPipeline`,提取 `RenderSceneData`,解析 directional
shadow execution把全部 frame stages 记录进 native `RenderGraph`,编译 graph 并执行。
- `RenderPipelineAsset` 是 native asset contract。它创建 pipeline配置 pipeline 实例,配置 request
@@ -265,6 +271,9 @@ package。
- `RendererFramePlan` 不得只是 pass 对象引用列表。`ScriptableRenderPass.CreateFramePlanSnapshot` 是冻结
pass 状态的边界;新增 mutable pass state 时必须确认它能被 frame-plan snapshot 捕获,避免后续 camera
planning 改写前一个 camera 的 recording。
- `OnFinishCameraStackRendering` 是 camera-stack 生命周期回调,不是 per-stage 或 per-camera-frame 回调。
`ScriptableRenderer` 可以在 `RecordRendererFromFramePlan` 时登记待收尾的 `RendererFramePlan`,但只能由
native `CameraStackFramePlan` 渲染完成后的 `FinishCameraStackRendering` 触发实际回调。
- URP features 的 `AddRenderPasses` 是 per-camera 声明点,不是 per-stage 回调。不要通过
stage 数据分阶段重复 enqueue`AddRenderPasses`/`SetupRenderPasses` 必须使用 `RendererPassQueueData`
而不是 recording 阶段的 `RenderingData`。pass 所属 stage 应由 `RenderPassEvent -> RendererBlock`
@@ -377,6 +386,8 @@ Scene data 每个 camera frame 提取一次,然后由 pipeline 调整。
authoring 还未公开。
- `UniversalPostProcessBlock` 仍保留 post-process source promotion helper实际 post-process stage 由
active pass queue 中的 features/passes 声明。
- 当前 camera stack 归属仍来自 `SceneRenderRequestPlanner` 对 base/overlay 请求流的 `cameraStackId`
分组;引擎相机数据模型还没有 Unity `cameraStack` 那种显式 per-base overlay 列表。
- Render-pipeline selection 已切到 `AssetRef` 作为根身份,并且 managed SRP descriptor 已保存
ScriptableObject graph snapshot完整 editor/importer `.asset` 持久化和 sub-asset authoring 仍未完成。
- 当前 shadow support 是单个 main directional shadow path没有 cascades。
@@ -411,6 +422,10 @@ Scene data 每个 camera frame 提取一次,然后由 pipeline 调整。
- URP stage planning 已收口到 renderer active pass queue 派生的 per-`framePlanId` `RendererFramePlan`
stage manifest。Stage support 和 stage recording 现在消费 planning 阶段保存的同一份冻结 plan
关闭了 feature planning hook、support probe、recording 和各 stage 分别重建 pass queue 的重复事实源。
- 顶层 native orchestration 已从 flat camera frame list 收口为 `CameraStackFramePlan``SceneRenderer`
`RenderPipelineHost` 的真实渲染入口以 camera stack 为根flat `CameraFramePlan` APIs 保留为兼容包装。
- URP `OnFinishCameraStackRendering` 已改为 stack-end 语义recording 阶段只登记待收尾 passnative
`CameraStackFramePlan` 渲染完成后再通过 pipeline/stage-recorder bridge 触发。
- `CameraFramePlanBuilder` 已移除对 fullscreen stages 的通用尾部自动补齐selected
`RenderPipelineAsset` 现在是 native plan policy 的唯一入口managed URP path 不再保留第二个
fullscreen stage planner。

View File

@@ -0,0 +1,28 @@
#pragma once
#include <XCEngine/Rendering/Execution/CameraFramePlan.h>
#include <cstdint>
#include <vector>
namespace XCEngine {
namespace Rendering {
struct CameraStackFramePlan {
uint64_t stackPlanId = 0u;
uint64_t cameraStackId = 0u;
std::vector<CameraFramePlan> cameraPlans = {};
static CameraStackFramePlan FromCameraPlans(
uint64_t cameraStackId,
std::vector<CameraFramePlan> cameraPlans);
bool IsValid() const;
bool HasBaseCamera() const;
bool IsOverlayOnly() const;
const CameraFramePlan* GetBaseCameraPlan() const;
const CameraFramePlan* GetSortKeyPlan() const;
};
} // namespace Rendering
} // namespace XCEngine

View File

@@ -1,5 +1,6 @@
#pragma once
#include <XCEngine/Rendering/Execution/CameraStackFramePlan.h>
#include <XCEngine/Rendering/Execution/CameraRenderer.h>
#include <memory>
@@ -22,9 +23,13 @@ public:
std::vector<CameraFramePlan> BuildFramePlans(
const std::vector<CameraRenderRequest>& requests);
std::vector<CameraStackFramePlan> BuildStackFramePlans(
const std::vector<CameraRenderRequest>& requests);
bool Render(const CameraFramePlan& plan);
bool Render(const std::vector<CameraFramePlan>& plans);
bool Render(const CameraStackFramePlan& stackPlan);
bool Render(const std::vector<CameraStackFramePlan>& stackPlans);
private:
CameraRenderer m_cameraRenderer;

View File

@@ -1,5 +1,6 @@
#pragma once
#include <XCEngine/Rendering/Execution/CameraStackFramePlan.h>
#include <XCEngine/Rendering/Execution/RenderPipelineHost.h>
#include <XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h>
@@ -28,9 +29,16 @@ public:
Components::CameraComponent* overrideCamera,
const RenderContext& context,
const RenderSurface& surface);
std::vector<CameraStackFramePlan> BuildStackFramePlans(
const Components::Scene& scene,
Components::CameraComponent* overrideCamera,
const RenderContext& context,
const RenderSurface& surface);
bool Render(const CameraFramePlan& plan);
bool Render(const std::vector<CameraFramePlan>& plans);
bool Render(const CameraStackFramePlan& stackPlan);
bool Render(const std::vector<CameraStackFramePlan>& stackPlans);
bool Render(
const Components::Scene& scene,
Components::CameraComponent* overrideCamera,

View File

@@ -60,6 +60,8 @@ public:
const RenderContext& context,
const RenderSurface& surface,
const RenderSceneData& sceneData) override;
void FinishCameraStackRendering(
const CameraStackFramePlan& stackPlan) override;
void ConfigureRenderSceneData(
const CameraFramePlan& plan,
RenderSceneData& sceneData) const override;

View File

@@ -27,6 +27,7 @@ struct CameraRenderRequest {
FinalOutputRenderRequest finalOutput;
ResolvedFinalColorPolicy finalColorPolicy = {};
ObjectIdRenderRequest objectId;
uint64_t cameraStackId = 0u;
float cameraDepth = 0.0f;
uint8_t cameraStackOrder = 0;
int32_t rendererIndex = -1;

View File

@@ -23,6 +23,7 @@ namespace Rendering {
class RenderGraphBuilder;
struct CameraFramePlan;
struct CameraStackFramePlan;
struct DirectionalShadowExecutionState;
struct DirectionalShadowSurfaceAllocation;
@@ -91,6 +92,8 @@ public:
const RenderPipelineStageRenderGraphContext&) {
return false;
}
virtual void FinishCameraStackRendering(
const CameraStackFramePlan&) {}
};
class RenderPipelineBackend {
@@ -142,6 +145,8 @@ public:
const CameraFramePlan& plan,
const DirectionalShadowSurfaceAllocation& shadowAllocation,
DirectionalShadowExecutionState& shadowState) const;
virtual void FinishCameraStackRendering(
const CameraStackFramePlan&) {}
void SetCameraFrameStandalonePass(
CameraFrameStage stage,

View File

@@ -0,0 +1,89 @@
#include <XCEngine/Rendering/Execution/CameraStackFramePlan.h>
#include <atomic>
#include <utility>
namespace XCEngine {
namespace Rendering {
namespace {
uint64_t AllocateCameraStackFramePlanId() {
static std::atomic<uint64_t> s_nextStackPlanId{ 1u };
uint64_t stackPlanId =
s_nextStackPlanId.fetch_add(
1u,
std::memory_order_relaxed);
if (stackPlanId == 0u) {
stackPlanId =
s_nextStackPlanId.fetch_add(
1u,
std::memory_order_relaxed);
}
return stackPlanId;
}
bool IsBaseCameraPlan(const CameraFramePlan& plan) {
return plan.request.cameraStackOrder == 0u;
}
} // namespace
CameraStackFramePlan CameraStackFramePlan::FromCameraPlans(
uint64_t cameraStackId,
std::vector<CameraFramePlan> cameraPlans) {
CameraStackFramePlan stackPlan = {};
stackPlan.stackPlanId = AllocateCameraStackFramePlanId();
stackPlan.cameraStackId = cameraStackId;
stackPlan.cameraPlans = std::move(cameraPlans);
return stackPlan;
}
bool CameraStackFramePlan::IsValid() const {
if (stackPlanId == 0u ||
cameraPlans.empty()) {
return false;
}
for (const CameraFramePlan& plan : cameraPlans) {
if (!plan.IsValid()) {
return false;
}
}
return true;
}
bool CameraStackFramePlan::HasBaseCamera() const {
return GetBaseCameraPlan() != nullptr;
}
bool CameraStackFramePlan::IsOverlayOnly() const {
return !cameraPlans.empty() &&
!HasBaseCamera();
}
const CameraFramePlan* CameraStackFramePlan::GetBaseCameraPlan() const {
for (const CameraFramePlan& plan : cameraPlans) {
if (IsBaseCameraPlan(plan)) {
return &plan;
}
}
return nullptr;
}
const CameraFramePlan* CameraStackFramePlan::GetSortKeyPlan() const {
if (const CameraFramePlan* const basePlan = GetBaseCameraPlan();
basePlan != nullptr) {
return basePlan;
}
return cameraPlans.empty()
? nullptr
: &cameraPlans.front();
}
} // namespace Rendering
} // namespace XCEngine

View File

@@ -3,6 +3,9 @@
#include "Rendering/Planning/CameraFramePlanBuilder.h"
#include "Rendering/Planning/SceneRenderRequestUtils.h"
#include <algorithm>
#include <utility>
namespace XCEngine {
namespace Rendering {
@@ -16,6 +19,23 @@ bool CompareCameraFramePlans(
rhs.request);
}
bool CompareCameraStackFramePlans(
const CameraStackFramePlan& lhs,
const CameraStackFramePlan& rhs) {
const CameraFramePlan* const lhsSortKeyPlan =
lhs.GetSortKeyPlan();
const CameraFramePlan* const rhsSortKeyPlan =
rhs.GetSortKeyPlan();
if (lhsSortKeyPlan == nullptr ||
rhsSortKeyPlan == nullptr) {
return false;
}
return CompareCameraFramePlans(
*lhsSortKeyPlan,
*rhsSortKeyPlan);
}
} // namespace
RenderPipelineHost::RenderPipelineHost()
@@ -42,8 +62,22 @@ std::vector<CameraFramePlan> RenderPipelineHost::BuildFramePlans(
: std::vector<CameraFramePlan>();
}
std::vector<CameraStackFramePlan> RenderPipelineHost::BuildStackFramePlans(
const std::vector<CameraRenderRequest>& requests) {
return m_framePlanBuilder != nullptr
? m_framePlanBuilder->BuildStackPlans(
requests,
GetPipelineAsset())
: std::vector<CameraStackFramePlan>();
}
bool RenderPipelineHost::Render(const CameraFramePlan& plan) {
return m_cameraRenderer.Render(plan);
std::vector<CameraFramePlan> plans = {};
plans.push_back(plan);
return Render(
CameraStackFramePlan::FromCameraPlans(
plan.request.cameraStackId,
std::move(plans)));
}
bool RenderPipelineHost::Render(const std::vector<CameraFramePlan>& plans) {
@@ -63,8 +97,20 @@ bool RenderPipelineHost::Render(const std::vector<CameraFramePlan>& plans) {
sortedPlans.end(),
CompareCameraFramePlans);
return Render(
m_framePlanBuilder != nullptr
? m_framePlanBuilder->BuildStackPlansFromFramePlans(
std::move(sortedPlans))
: std::vector<CameraStackFramePlan>());
}
bool RenderPipelineHost::Render(const CameraStackFramePlan& stackPlan) {
if (!stackPlan.IsValid()) {
return false;
}
bool rendered = false;
for (const CameraFramePlan& plan : sortedPlans) {
for (const CameraFramePlan& plan : stackPlan.cameraPlans) {
if (!m_cameraRenderer.Render(plan)) {
return false;
}
@@ -72,6 +118,44 @@ bool RenderPipelineHost::Render(const std::vector<CameraFramePlan>& plans) {
rendered = true;
}
if (rendered) {
if (RenderPipeline* const pipeline = GetPipeline();
pipeline != nullptr) {
pipeline->FinishCameraStackRendering(stackPlan);
}
}
return rendered;
}
bool RenderPipelineHost::Render(const std::vector<CameraStackFramePlan>& stackPlans) {
if (stackPlans.empty()) {
return false;
}
for (const CameraStackFramePlan& stackPlan : stackPlans) {
if (!stackPlan.IsValid()) {
return false;
}
}
std::vector<CameraStackFramePlan> sortedStackPlans =
stackPlans;
std::stable_sort(
sortedStackPlans.begin(),
sortedStackPlans.end(),
CompareCameraStackFramePlans);
bool rendered = false;
for (const CameraStackFramePlan& stackPlan :
sortedStackPlans) {
if (!Render(stackPlan)) {
return false;
}
rendered = true;
}
return rendered;
}

View File

@@ -34,6 +34,21 @@ std::vector<CameraFramePlan> SceneRenderer::BuildFramePlans(
return m_pipelineHost.BuildFramePlans(requests);
}
std::vector<CameraStackFramePlan> SceneRenderer::BuildStackFramePlans(
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,
m_pipelineHost.GetPipelineAsset());
return m_pipelineHost.BuildStackFramePlans(requests);
}
bool SceneRenderer::Render(const CameraFramePlan& plan) {
return m_pipelineHost.Render(plan);
}
@@ -42,12 +57,20 @@ bool SceneRenderer::Render(const std::vector<CameraFramePlan>& plans) {
return m_pipelineHost.Render(plans);
}
bool SceneRenderer::Render(const CameraStackFramePlan& stackPlan) {
return m_pipelineHost.Render(stackPlan);
}
bool SceneRenderer::Render(const std::vector<CameraStackFramePlan>& stackPlans) {
return m_pipelineHost.Render(stackPlans);
}
bool SceneRenderer::Render(
const Components::Scene& scene,
Components::CameraComponent* overrideCamera,
const RenderContext& context,
const RenderSurface& surface) {
return Render(BuildFramePlans(scene, overrideCamera, context, surface));
return Render(BuildStackFramePlans(scene, overrideCamera, context, surface));
}
} // namespace Rendering

View File

@@ -193,6 +193,13 @@ bool ScriptableRenderPipelineHost::Render(
m_pipelineBackend->Render(context, surface, sceneData);
}
void ScriptableRenderPipelineHost::FinishCameraStackRendering(
const CameraStackFramePlan& stackPlan) {
if (m_stageRecorder != nullptr) {
m_stageRecorder->FinishCameraStackRendering(stackPlan);
}
}
void ScriptableRenderPipelineHost::ConfigureRenderSceneData(
const CameraFramePlan& plan,
RenderSceneData& sceneData) const {

View File

@@ -2,6 +2,8 @@
#include "Rendering/RenderPipelineAsset.h"
#include <utility>
namespace XCEngine {
namespace Rendering {
@@ -13,6 +15,19 @@ std::vector<CameraFramePlan> CameraFramePlanBuilder::BuildPlans(
return plans;
}
std::vector<CameraStackFramePlan> CameraFramePlanBuilder::BuildStackPlans(
const std::vector<CameraRenderRequest>& requests,
const RenderPipelineAsset* pipelineAsset) {
std::vector<CameraFramePlan> plans = CreatePlansFromRequests(requests);
ConfigurePlans(plans, pipelineAsset);
return CreateStackPlansFromPlans(std::move(plans));
}
std::vector<CameraStackFramePlan> CameraFramePlanBuilder::BuildStackPlansFromFramePlans(
std::vector<CameraFramePlan> plans) const {
return CreateStackPlansFromPlans(std::move(plans));
}
std::vector<CameraFramePlan> CameraFramePlanBuilder::CreatePlansFromRequests(
const std::vector<CameraRenderRequest>& requests) const {
std::vector<CameraFramePlan> plans = {};
@@ -24,6 +39,43 @@ std::vector<CameraFramePlan> CameraFramePlanBuilder::CreatePlansFromRequests(
return plans;
}
std::vector<CameraStackFramePlan> CameraFramePlanBuilder::CreateStackPlansFromPlans(
std::vector<CameraFramePlan> plans) const {
std::vector<CameraStackFramePlan> stackPlans = {};
if (plans.empty()) {
return stackPlans;
}
stackPlans.reserve(plans.size());
for (CameraFramePlan& plan : plans) {
const uint64_t cameraStackId = plan.request.cameraStackId;
if (cameraStackId != 0u) {
bool appendedToExistingStack = false;
for (CameraStackFramePlan& stackPlan : stackPlans) {
if (stackPlan.cameraStackId == cameraStackId) {
stackPlan.cameraPlans.push_back(std::move(plan));
appendedToExistingStack = true;
break;
}
}
if (appendedToExistingStack) {
continue;
}
}
std::vector<CameraFramePlan> stackCameraPlans = {};
stackCameraPlans.push_back(std::move(plan));
stackPlans.push_back(
CameraStackFramePlan::FromCameraPlans(
cameraStackId,
std::move(stackCameraPlans)));
}
return stackPlans;
}
void CameraFramePlanBuilder::ConfigurePlans(
std::vector<CameraFramePlan>& plans,
const RenderPipelineAsset* pipelineAsset) const {

View File

@@ -1,6 +1,7 @@
#pragma once
#include <XCEngine/Rendering/Execution/CameraFramePlan.h>
#include <XCEngine/Rendering/Execution/CameraStackFramePlan.h>
#include <vector>
@@ -19,10 +20,17 @@ public:
std::vector<CameraFramePlan> BuildPlans(
const std::vector<CameraRenderRequest>& requests,
const RenderPipelineAsset* pipelineAsset);
std::vector<CameraStackFramePlan> BuildStackPlans(
const std::vector<CameraRenderRequest>& requests,
const RenderPipelineAsset* pipelineAsset);
std::vector<CameraStackFramePlan> BuildStackPlansFromFramePlans(
std::vector<CameraFramePlan> plans) const;
private:
std::vector<CameraFramePlan> CreatePlansFromRequests(
const std::vector<CameraRenderRequest>& requests) const;
std::vector<CameraStackFramePlan> CreateStackPlansFromPlans(
std::vector<CameraFramePlan> plans) const;
void ConfigurePlans(
std::vector<CameraFramePlan>& plans,
const RenderPipelineAsset* pipelineAsset) const;

View File

@@ -56,6 +56,8 @@ std::vector<CameraRenderRequest> SceneRenderRequestPlanner::BuildRequests(
CollectCameras(scene, overrideCamera);
size_t renderedBaseCameraCount = 0;
uint64_t nextCameraStackId = 1u;
uint64_t activeCameraStackId = 0u;
for (Components::CameraComponent* camera : cameras) {
CameraRenderRequest request;
if (!SceneRenderRequestUtils::BuildCameraRenderRequest(
@@ -69,6 +71,12 @@ std::vector<CameraRenderRequest> SceneRenderRequestPlanner::BuildRequests(
continue;
}
if (camera->GetStackType() == Components::CameraStackType::Base ||
activeCameraStackId == 0u) {
activeCameraStackId = nextCameraStackId++;
}
request.cameraStackId = activeCameraStackId;
if (pipelineAsset != nullptr) {
pipelineAsset->ConfigureCameraRenderRequest(
request,

View File

@@ -12,6 +12,7 @@
#include "Physics/PhysicsWorld.h"
#include "Rendering/Caches/DirectionalShadowSurfaceCache.h"
#include "Rendering/Execution/CameraFramePlan.h"
#include "Rendering/Execution/CameraStackFramePlan.h"
#include "Rendering/Execution/DirectionalShadowExecutionState.h"
#include "Rendering/Execution/CameraFrameRenderGraphFrameData.h"
#include "Rendering/Execution/Internal/CameraFrameGraph/SurfaceUtils.h"
@@ -2134,6 +2135,7 @@ public:
m_supportsStageContextualMethod = nullptr;
m_supportsStageMethod = nullptr;
m_recordStageMethod = nullptr;
m_finishCameraStackRenderingMethod = nullptr;
m_resolvedPipelineHandle = 0;
m_boundSceneDrawBackend = nullptr;
}
@@ -2322,6 +2324,35 @@ public:
return flushed;
}
void FinishCameraStackRendering(
const Rendering::CameraStackFramePlan& stackPlan) override {
if (!IsRuntimeAlive()) {
return;
}
MonoObject* const pipelineObject = GetManagedPipelineObject();
MonoMethod* const method =
ResolveFinishCameraStackRenderingMethod(pipelineObject);
if (pipelineObject == nullptr ||
method == nullptr) {
return;
}
for (const Rendering::CameraFramePlan& plan :
stackPlan.cameraPlans) {
int32_t rendererIndex = plan.request.rendererIndex;
uint64_t framePlanId = plan.framePlanId;
void* args[2] = {
&rendererIndex,
&framePlanId };
m_runtime->InvokeManagedMethod(
pipelineObject,
method,
args,
nullptr);
}
}
private:
struct ManagedRenderFuncExecutionState {
std::shared_ptr<const MonoManagedRenderPipelineAssetRuntime>
@@ -2415,6 +2446,7 @@ private:
m_supportsStageContextualMethod = nullptr;
m_supportsStageMethod = nullptr;
m_recordStageMethod = nullptr;
m_finishCameraStackRenderingMethod = nullptr;
m_resolvedPipelineHandle = pipelineHandle;
}
@@ -2471,6 +2503,19 @@ private:
return m_recordStageMethod;
}
MonoMethod* ResolveFinishCameraStackRenderingMethod(
MonoObject* pipelineObject) const {
if (m_finishCameraStackRenderingMethod == nullptr) {
m_finishCameraStackRenderingMethod =
m_runtime->ResolveManagedMethod(
pipelineObject,
"FinishCameraStackRenderingInstance",
2);
}
return m_finishCameraStackRenderingMethod;
}
bool FlushManagedRasterPasses(
const Rendering::RenderPipelineStageRenderGraphContext& context,
ManagedScriptableRenderContextState& managedContextState) {
@@ -2653,6 +2698,7 @@ private:
mutable MonoMethod* m_supportsStageContextualMethod = nullptr;
mutable MonoMethod* m_supportsStageMethod = nullptr;
mutable MonoMethod* m_recordStageMethod = nullptr;
mutable MonoMethod* m_finishCameraStackRenderingMethod = nullptr;
mutable uint32_t m_resolvedPipelineHandle = 0;
std::vector<std::unique_ptr<Rendering::RenderPass>> m_fullscreenPassPool = {};
Rendering::SceneDrawBackend* m_boundSceneDrawBackend = nullptr;