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

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