refactor(rendering): extract default pipeline resolution from camera renderer

This commit is contained in:
2026-04-15 21:55:35 +08:00
parent e23d9710e7
commit cf1d6e1c1a
5 changed files with 133 additions and 42 deletions

View File

@@ -582,6 +582,8 @@ add_library(XCEngine STATIC
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameGraph/State.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameGraph/SurfaceUtils.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameGraph/SurfaceUtils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Internal/RenderPipelineFactory.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Internal/RenderPipelineFactory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/RenderPassGraphContract.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/RenderPipelineStageGraphContract.cpp

View File

@@ -3,8 +3,7 @@
#include "Components/CameraComponent.h"
#include "Rendering/Execution/DirectionalShadowExecutionState.h"
#include "Rendering/Execution/Internal/CameraFrameGraph/Executor.h"
#include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h"
#include "Rendering/Pipelines/ScriptableRenderPipelineHost.h"
#include "Rendering/Internal/RenderPipelineFactory.h"
#include "Rendering/RenderPipelineAsset.h"
#include "Rendering/RenderSurface.h"
#include "Rendering/Shadow/DirectionalShadowRuntime.h"
@@ -13,40 +12,8 @@
namespace XCEngine {
namespace Rendering {
namespace {
std::shared_ptr<const RenderPipelineAsset> CreateDefaultPipelineAsset() {
return Pipelines::CreateManagedOrDefaultScriptableRenderPipelineAsset();
}
std::unique_ptr<RenderPipeline> CreatePipelineFromAsset(
const std::shared_ptr<const RenderPipelineAsset>& pipelineAsset) {
const std::shared_ptr<const RenderPipelineAsset> resolvedAsset =
pipelineAsset != nullptr ? pipelineAsset : CreateDefaultPipelineAsset();
if (resolvedAsset != nullptr) {
std::unique_ptr<RenderPipeline> pipeline = resolvedAsset->CreatePipeline();
if (pipeline != nullptr) {
return pipeline;
}
}
const std::shared_ptr<const RenderPipelineAsset> fallbackAsset =
CreateDefaultPipelineAsset();
if (fallbackAsset != nullptr &&
fallbackAsset != resolvedAsset) {
std::unique_ptr<RenderPipeline> pipeline = fallbackAsset->CreatePipeline();
if (pipeline != nullptr) {
return pipeline;
}
}
return std::make_unique<Pipelines::ScriptableRenderPipelineHost>();
}
} // namespace
CameraRenderer::CameraRenderer()
: CameraRenderer(CreateDefaultPipelineAsset()) {
: CameraRenderer(Internal::CreateDefaultRenderPipelineAsset()) {
}
CameraRenderer::CameraRenderer(std::unique_ptr<RenderPipeline> pipeline)
@@ -56,9 +23,8 @@ CameraRenderer::CameraRenderer(std::unique_ptr<RenderPipeline> pipeline)
}
CameraRenderer::CameraRenderer(std::shared_ptr<const RenderPipelineAsset> pipelineAsset)
: m_pipelineAsset(std::move(pipelineAsset))
, m_directionalShadowRuntime(std::make_unique<DirectionalShadowRuntime>()) {
SetPipelineAsset(m_pipelineAsset);
: m_directionalShadowRuntime(std::make_unique<DirectionalShadowRuntime>()) {
SetPipelineAsset(std::move(pipelineAsset));
}
CameraRenderer::~CameraRenderer() {
@@ -73,8 +39,10 @@ void CameraRenderer::SetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
}
void CameraRenderer::SetPipelineAsset(std::shared_ptr<const RenderPipelineAsset> pipelineAsset) {
m_pipelineAsset = pipelineAsset != nullptr ? std::move(pipelineAsset) : CreateDefaultPipelineAsset();
ResetPipeline(CreatePipelineFromAsset(m_pipelineAsset));
ResetPipeline(
Internal::CreateRenderPipelineOrDefault(
pipelineAsset,
&m_pipelineAsset));
}
void CameraRenderer::ResetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
@@ -84,8 +52,10 @@ void CameraRenderer::ResetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
m_pipeline = std::move(pipeline);
if (m_pipeline == nullptr) {
m_pipelineAsset = CreateDefaultPipelineAsset();
m_pipeline = CreatePipelineFromAsset(m_pipelineAsset);
m_pipeline =
Internal::CreateRenderPipelineOrDefault(
nullptr,
&m_pipelineAsset);
}
}

View File

@@ -0,0 +1,60 @@
#include "Rendering/Internal/RenderPipelineFactory.h"
#include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h"
#include "Rendering/Pipelines/ScriptableRenderPipelineHost.h"
namespace XCEngine {
namespace Rendering {
namespace Internal {
std::shared_ptr<const RenderPipelineAsset> CreateDefaultRenderPipelineAsset() {
return Pipelines::CreateManagedOrDefaultScriptableRenderPipelineAsset();
}
std::shared_ptr<const RenderPipelineAsset> ResolveRenderPipelineAssetOrDefault(
std::shared_ptr<const RenderPipelineAsset> preferredAsset) {
return preferredAsset != nullptr
? std::move(preferredAsset)
: CreateDefaultRenderPipelineAsset();
}
std::unique_ptr<RenderPipeline> CreateRenderPipelineOrDefault(
const std::shared_ptr<const RenderPipelineAsset>& preferredAsset,
std::shared_ptr<const RenderPipelineAsset>* outResolvedAsset) {
const std::shared_ptr<const RenderPipelineAsset> resolvedAsset =
ResolveRenderPipelineAssetOrDefault(preferredAsset);
if (resolvedAsset != nullptr) {
if (std::unique_ptr<RenderPipeline> pipeline =
resolvedAsset->CreatePipeline()) {
if (outResolvedAsset != nullptr) {
*outResolvedAsset = resolvedAsset;
}
return pipeline;
}
}
const std::shared_ptr<const RenderPipelineAsset> fallbackAsset =
CreateDefaultRenderPipelineAsset();
if (fallbackAsset != nullptr &&
fallbackAsset != resolvedAsset) {
if (std::unique_ptr<RenderPipeline> pipeline =
fallbackAsset->CreatePipeline()) {
if (outResolvedAsset != nullptr) {
*outResolvedAsset = fallbackAsset;
}
return pipeline;
}
}
if (outResolvedAsset != nullptr) {
*outResolvedAsset =
fallbackAsset != nullptr
? fallbackAsset
: resolvedAsset;
}
return std::make_unique<Pipelines::ScriptableRenderPipelineHost>();
}
} // namespace Internal
} // namespace Rendering
} // namespace XCEngine

View File

@@ -0,0 +1,24 @@
#pragma once
#include <memory>
namespace XCEngine {
namespace Rendering {
class RenderPipeline;
class RenderPipelineAsset;
namespace Internal {
std::shared_ptr<const RenderPipelineAsset> CreateDefaultRenderPipelineAsset();
std::shared_ptr<const RenderPipelineAsset> ResolveRenderPipelineAssetOrDefault(
std::shared_ptr<const RenderPipelineAsset> preferredAsset);
std::unique_ptr<RenderPipeline> CreateRenderPipelineOrDefault(
const std::shared_ptr<const RenderPipelineAsset>& preferredAsset,
std::shared_ptr<const RenderPipelineAsset>* outResolvedAsset = nullptr);
} // namespace Internal
} // namespace Rendering
} // namespace XCEngine

View File

@@ -421,6 +421,7 @@ public:
struct MockPipelineAssetState {
int createCalls = 0;
int configureCameraFramePlanCalls = 0;
bool createNullPipeline = false;
std::shared_ptr<MockPipelineState> lastCreatedPipelineState;
FinalColorSettings defaultFinalColorSettings = {};
std::function<void(CameraFramePlan&)> configureCameraFramePlan = {};
@@ -691,6 +692,11 @@ public:
std::unique_ptr<RenderPipeline> CreatePipeline() const override {
++m_state->createCalls;
if (m_state->createNullPipeline) {
m_state->lastCreatedPipelineState.reset();
return nullptr;
}
m_state->lastCreatedPipelineState = std::make_shared<MockPipelineState>();
return std::make_unique<MockPipeline>(m_state->lastCreatedPipelineState);
}
@@ -4281,6 +4287,35 @@ TEST(CameraRenderer_Test, DefaultPipelineAssetUsesManagedSelectionWhenPresent) {
Pipelines::ClearManagedRenderPipelineAssetDescriptor();
}
TEST(CameraRenderer_Test, RebindsToResolvedDefaultAssetWhenPreferredAssetCannotCreatePipeline) {
const Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
"GameScripts",
"Gameplay",
"ManagedRenderPipelineProbeAsset"
};
Pipelines::SetManagedRenderPipelineAssetDescriptor(descriptor);
auto failingAssetState = std::make_shared<MockPipelineAssetState>();
failingAssetState->createNullPipeline = true;
CameraRenderer renderer(std::make_shared<MockPipelineAsset>(failingAssetState));
EXPECT_EQ(failingAssetState->createCalls, 1);
EXPECT_NE(renderer.GetPipeline(), nullptr);
EXPECT_NE(
dynamic_cast<Pipelines::ScriptableRenderPipelineHost*>(renderer.GetPipeline()),
nullptr);
auto* asset =
dynamic_cast<const Pipelines::ManagedScriptableRenderPipelineAsset*>(
renderer.GetPipelineAsset());
ASSERT_NE(asset, nullptr);
EXPECT_EQ(asset->GetDescriptor().assemblyName, "GameScripts");
EXPECT_EQ(asset->GetDescriptor().namespaceName, "Gameplay");
EXPECT_EQ(asset->GetDescriptor().className, "ManagedRenderPipelineProbeAsset");
Pipelines::ClearManagedRenderPipelineAssetDescriptor();
}
TEST(SceneRenderer_Test, CreatesPipelineInstancesFromPipelineAssetsAndShutsDownReplacedPipelines) {
Scene scene("SceneRendererAssetScene");