refactor: route renderer defaults through pipeline assets

This commit is contained in:
2026-04-01 00:56:48 +08:00
parent 3373119eee
commit 618ebed05d
7 changed files with 131 additions and 8 deletions

View File

@@ -14,20 +14,27 @@ class Scene;
namespace Rendering { namespace Rendering {
class RenderSurface; class RenderSurface;
class RenderPipelineAsset;
class CameraRenderer { class CameraRenderer {
public: public:
CameraRenderer(); CameraRenderer();
explicit CameraRenderer(std::unique_ptr<RenderPipeline> pipeline); explicit CameraRenderer(std::unique_ptr<RenderPipeline> pipeline);
explicit CameraRenderer(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
~CameraRenderer(); ~CameraRenderer();
void SetPipeline(std::unique_ptr<RenderPipeline> pipeline); void SetPipeline(std::unique_ptr<RenderPipeline> pipeline);
void SetPipelineAsset(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
RenderPipeline* GetPipeline() const { return m_pipeline.get(); } RenderPipeline* GetPipeline() const { return m_pipeline.get(); }
const RenderPipelineAsset* GetPipelineAsset() const { return m_pipelineAsset.get(); }
bool Render(const CameraRenderRequest& request); bool Render(const CameraRenderRequest& request);
private: private:
void ResetPipeline(std::unique_ptr<RenderPipeline> pipeline);
RenderSceneExtractor m_sceneExtractor; RenderSceneExtractor m_sceneExtractor;
std::shared_ptr<const RenderPipelineAsset> m_pipelineAsset;
std::unique_ptr<RenderPipeline> m_pipeline; std::unique_ptr<RenderPipeline> m_pipeline;
}; };

View File

@@ -3,6 +3,7 @@
#include <XCEngine/Rendering/RenderMaterialUtility.h> #include <XCEngine/Rendering/RenderMaterialUtility.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/RenderResourceCache.h> #include <XCEngine/Rendering/RenderResourceCache.h>
#include <XCEngine/RHI/RHIDescriptorPool.h> #include <XCEngine/RHI/RHIDescriptorPool.h>
@@ -100,6 +101,11 @@ private:
RenderPassSequence m_passSequence; RenderPassSequence m_passSequence;
}; };
class BuiltinForwardPipelineAsset final : public RenderPipelineAsset {
public:
std::unique_ptr<RenderPipeline> CreatePipeline() const override;
};
} // namespace Pipelines } // namespace Pipelines
} // namespace Rendering } // namespace Rendering
} // namespace XCEngine } // namespace XCEngine

View File

@@ -13,14 +13,19 @@ class Scene;
namespace Rendering { namespace Rendering {
class RenderPipelineAsset;
class SceneRenderer { class SceneRenderer {
public: public:
SceneRenderer(); SceneRenderer();
explicit SceneRenderer(std::unique_ptr<RenderPipeline> pipeline); explicit SceneRenderer(std::unique_ptr<RenderPipeline> pipeline);
explicit SceneRenderer(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
~SceneRenderer() = default; ~SceneRenderer() = default;
void SetPipeline(std::unique_ptr<RenderPipeline> pipeline); void SetPipeline(std::unique_ptr<RenderPipeline> pipeline);
void SetPipelineAsset(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
RenderPipeline* GetPipeline() const { return m_cameraRenderer.GetPipeline(); } RenderPipeline* GetPipeline() const { return m_cameraRenderer.GetPipeline(); }
const RenderPipelineAsset* GetPipelineAsset() const { return m_cameraRenderer.GetPipelineAsset(); }
std::vector<CameraRenderRequest> BuildRenderRequests( std::vector<CameraRenderRequest> BuildRenderRequests(
const Components::Scene& scene, const Components::Scene& scene,

View File

@@ -1,6 +1,7 @@
#include "Rendering/CameraRenderer.h" #include "Rendering/CameraRenderer.h"
#include "Rendering/Pipelines/BuiltinForwardPipeline.h" #include "Rendering/Pipelines/BuiltinForwardPipeline.h"
#include "Rendering/RenderPipelineAsset.h"
#include "Rendering/RenderSurface.h" #include "Rendering/RenderSurface.h"
#include "Scene/Scene.h" #include "Scene/Scene.h"
@@ -32,17 +33,38 @@ void ShutdownPassSequence(RenderPassSequence* sequence, bool initialized) {
} }
} }
std::shared_ptr<const RenderPipelineAsset> CreateDefaultPipelineAsset() {
static const std::shared_ptr<const RenderPipelineAsset> s_defaultPipelineAsset =
std::make_shared<Pipelines::BuiltinForwardPipelineAsset>();
return s_defaultPipelineAsset;
}
std::unique_ptr<RenderPipeline> CreatePipelineFromAsset(
const std::shared_ptr<const RenderPipelineAsset>& pipelineAsset) {
if (pipelineAsset != nullptr) {
std::unique_ptr<RenderPipeline> pipeline = pipelineAsset->CreatePipeline();
if (pipeline != nullptr) {
return pipeline;
}
}
return std::make_unique<Pipelines::BuiltinForwardPipeline>();
}
} // namespace } // namespace
CameraRenderer::CameraRenderer() CameraRenderer::CameraRenderer()
: m_pipeline(std::make_unique<Pipelines::BuiltinForwardPipeline>()) { : CameraRenderer(CreateDefaultPipelineAsset()) {
} }
CameraRenderer::CameraRenderer(std::unique_ptr<RenderPipeline> pipeline) CameraRenderer::CameraRenderer(std::unique_ptr<RenderPipeline> pipeline)
: m_pipeline(std::move(pipeline)) { : m_pipelineAsset(nullptr) {
if (!m_pipeline) { ResetPipeline(std::move(pipeline));
m_pipeline = std::make_unique<Pipelines::BuiltinForwardPipeline>(); }
}
CameraRenderer::CameraRenderer(std::shared_ptr<const RenderPipelineAsset> pipelineAsset)
: m_pipelineAsset(std::move(pipelineAsset)) {
SetPipelineAsset(m_pipelineAsset);
} }
CameraRenderer::~CameraRenderer() { CameraRenderer::~CameraRenderer() {
@@ -52,13 +74,24 @@ CameraRenderer::~CameraRenderer() {
} }
void CameraRenderer::SetPipeline(std::unique_ptr<RenderPipeline> pipeline) { void CameraRenderer::SetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
if (m_pipeline) { m_pipelineAsset.reset();
ResetPipeline(std::move(pipeline));
}
void CameraRenderer::SetPipelineAsset(std::shared_ptr<const RenderPipelineAsset> pipelineAsset) {
m_pipelineAsset = pipelineAsset != nullptr ? std::move(pipelineAsset) : CreateDefaultPipelineAsset();
ResetPipeline(CreatePipelineFromAsset(m_pipelineAsset));
}
void CameraRenderer::ResetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
if (m_pipeline != nullptr) {
m_pipeline->Shutdown(); m_pipeline->Shutdown();
} }
m_pipeline = std::move(pipeline); m_pipeline = std::move(pipeline);
if (!m_pipeline) { if (m_pipeline == nullptr) {
m_pipeline = std::make_unique<Pipelines::BuiltinForwardPipeline>(); m_pipelineAsset = CreateDefaultPipelineAsset();
m_pipeline = CreatePipelineFromAsset(m_pipelineAsset);
} }
} }

View File

@@ -236,6 +236,10 @@ BuiltinForwardPipeline::~BuiltinForwardPipeline() {
Shutdown(); Shutdown();
} }
std::unique_ptr<RenderPipeline> BuiltinForwardPipelineAsset::CreatePipeline() const {
return std::make_unique<BuiltinForwardPipeline>();
}
RHI::InputLayoutDesc BuiltinForwardPipeline::BuildInputLayout() { RHI::InputLayoutDesc BuiltinForwardPipeline::BuildInputLayout() {
RHI::InputLayoutDesc inputLayout = {}; RHI::InputLayoutDesc inputLayout = {};

View File

@@ -25,10 +25,18 @@ SceneRenderer::SceneRenderer(std::unique_ptr<RenderPipeline> pipeline)
: m_cameraRenderer(std::move(pipeline)) { : m_cameraRenderer(std::move(pipeline)) {
} }
SceneRenderer::SceneRenderer(std::shared_ptr<const RenderPipelineAsset> pipelineAsset)
: m_cameraRenderer(std::move(pipelineAsset)) {
}
void SceneRenderer::SetPipeline(std::unique_ptr<RenderPipeline> pipeline) { void SceneRenderer::SetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
m_cameraRenderer.SetPipeline(std::move(pipeline)); m_cameraRenderer.SetPipeline(std::move(pipeline));
} }
void SceneRenderer::SetPipelineAsset(std::shared_ptr<const RenderPipelineAsset> pipelineAsset) {
m_cameraRenderer.SetPipelineAsset(std::move(pipelineAsset));
}
std::vector<CameraRenderRequest> SceneRenderer::BuildRenderRequests( std::vector<CameraRenderRequest> SceneRenderer::BuildRenderRequests(
const Components::Scene& scene, const Components::Scene& scene,
Components::CameraComponent* overrideCamera, Components::CameraComponent* overrideCamera,

View File

@@ -2,6 +2,7 @@
#include <XCEngine/Components/CameraComponent.h> #include <XCEngine/Components/CameraComponent.h>
#include <XCEngine/Rendering/CameraRenderer.h> #include <XCEngine/Rendering/CameraRenderer.h>
#include <XCEngine/Rendering/RenderPipelineAsset.h>
#include <XCEngine/Rendering/RenderSurface.h> #include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/Rendering/SceneRenderer.h> #include <XCEngine/Rendering/SceneRenderer.h>
#include <XCEngine/Scene/Scene.h> #include <XCEngine/Scene/Scene.h>
@@ -30,6 +31,11 @@ struct MockPipelineState {
std::vector<std::string> eventLog; std::vector<std::string> eventLog;
}; };
struct MockPipelineAssetState {
int createCalls = 0;
std::shared_ptr<MockPipelineState> lastCreatedPipelineState;
};
class MockPipeline final : public RenderPipeline { class MockPipeline final : public RenderPipeline {
public: public:
explicit MockPipeline(std::shared_ptr<MockPipelineState> state) explicit MockPipeline(std::shared_ptr<MockPipelineState> state)
@@ -65,6 +71,22 @@ private:
std::shared_ptr<MockPipelineState> m_state; std::shared_ptr<MockPipelineState> m_state;
}; };
class MockPipelineAsset final : public RenderPipelineAsset {
public:
explicit MockPipelineAsset(std::shared_ptr<MockPipelineAssetState> state)
: m_state(std::move(state)) {
}
std::unique_ptr<RenderPipeline> CreatePipeline() const override {
++m_state->createCalls;
m_state->lastCreatedPipelineState = std::make_shared<MockPipelineState>();
return std::make_unique<MockPipeline>(m_state->lastCreatedPipelineState);
}
private:
std::shared_ptr<MockPipelineAssetState> m_state;
};
class TrackingPass final : public RenderPass { class TrackingPass final : public RenderPass {
public: public:
TrackingPass( TrackingPass(
@@ -321,6 +343,44 @@ TEST(SceneRenderer_Test, ForwardsPipelineLifetimeAndRenderCallsToCameraRenderer)
EXPECT_EQ(replacementState->shutdownCalls, 1); EXPECT_EQ(replacementState->shutdownCalls, 1);
} }
TEST(SceneRenderer_Test, CreatesPipelineInstancesFromPipelineAssetsAndShutsDownReplacedPipelines) {
Scene scene("SceneRendererAssetScene");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
camera->SetDepth(2.0f);
auto initialAssetState = std::make_shared<MockPipelineAssetState>();
auto replacementAssetState = std::make_shared<MockPipelineAssetState>();
{
SceneRenderer renderer(std::make_shared<MockPipelineAsset>(initialAssetState));
ASSERT_NE(renderer.GetPipeline(), nullptr);
ASSERT_NE(renderer.GetPipelineAsset(), nullptr);
EXPECT_EQ(initialAssetState->createCalls, 1);
const RenderSurface surface(800, 600);
ASSERT_TRUE(renderer.Render(scene, nullptr, CreateValidContext(), surface));
ASSERT_NE(initialAssetState->lastCreatedPipelineState, nullptr);
EXPECT_EQ(initialAssetState->lastCreatedPipelineState->renderCalls, 1);
EXPECT_EQ(initialAssetState->lastCreatedPipelineState->lastCamera, camera);
renderer.SetPipelineAsset(std::make_shared<MockPipelineAsset>(replacementAssetState));
ASSERT_NE(initialAssetState->lastCreatedPipelineState, nullptr);
EXPECT_EQ(initialAssetState->lastCreatedPipelineState->shutdownCalls, 1);
EXPECT_EQ(replacementAssetState->createCalls, 1);
ASSERT_TRUE(renderer.Render(scene, nullptr, CreateValidContext(), surface));
ASSERT_NE(replacementAssetState->lastCreatedPipelineState, nullptr);
EXPECT_EQ(replacementAssetState->lastCreatedPipelineState->renderCalls, 1);
EXPECT_EQ(replacementAssetState->lastCreatedPipelineState->lastCamera, camera);
}
ASSERT_NE(replacementAssetState->lastCreatedPipelineState, nullptr);
EXPECT_EQ(replacementAssetState->lastCreatedPipelineState->shutdownCalls, 1);
}
TEST(SceneRenderer_Test, SortsManualCameraRequestsByDepthBeforeRendering) { TEST(SceneRenderer_Test, SortsManualCameraRequestsByDepthBeforeRendering) {
Scene scene("SceneRendererManualRequests"); Scene scene("SceneRendererManualRequests");