fix(rendering): refresh managed pipelines on srp environment changes
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <XCEngine/Rendering/Extraction/RenderSceneExtractor.h>
|
||||
#include <XCEngine/Rendering/RenderPipeline.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -33,12 +34,14 @@ public:
|
||||
|
||||
void SetPipeline(std::unique_ptr<RenderPipeline> pipeline);
|
||||
void SetPipelineAsset(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
|
||||
RenderPipeline* GetPipeline() const { return m_pipeline.get(); }
|
||||
const RenderPipelineAsset* GetPipelineAsset() const { return m_pipelineAsset.get(); }
|
||||
RenderPipeline* GetPipeline() const;
|
||||
const RenderPipelineAsset* GetPipelineAsset() const;
|
||||
|
||||
bool Render(const CameraFramePlan& plan);
|
||||
|
||||
private:
|
||||
bool UsesManagedPipelineBinding() const;
|
||||
void RefreshManagedPipelineBindingIfNeeded();
|
||||
void ResetPipeline(std::unique_ptr<RenderPipeline> pipeline);
|
||||
bool BuildSceneDataForPlan(
|
||||
const CameraFramePlan& plan,
|
||||
@@ -53,6 +56,8 @@ private:
|
||||
std::shared_ptr<const RenderPipelineAsset> m_pipelineAsset;
|
||||
std::unique_ptr<RenderPipeline> m_pipeline;
|
||||
std::unique_ptr<DirectionalShadowRuntime> m_directionalShadowRuntime;
|
||||
bool m_usesDefaultPipelineAssetSelection = false;
|
||||
size_t m_managedPipelineEnvironmentGeneration = 0u;
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -96,6 +96,7 @@ void SetManagedRenderPipelineBridge(
|
||||
void ClearManagedRenderPipelineBridge();
|
||||
std::shared_ptr<const ManagedRenderPipelineBridge>
|
||||
GetManagedRenderPipelineBridge();
|
||||
size_t GetManagedRenderPipelineEnvironmentGeneration();
|
||||
|
||||
void SetManagedRenderPipelineAssetDescriptor(
|
||||
const ManagedRenderPipelineAssetDescriptor& descriptor);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Rendering/Execution/DirectionalShadowExecutionState.h"
|
||||
#include "Rendering/Execution/Internal/CameraFrameGraph/Executor.h"
|
||||
#include "Rendering/Internal/RenderPipelineFactory.h"
|
||||
#include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h"
|
||||
#include "Rendering/RenderPipelineAsset.h"
|
||||
#include "Rendering/RenderSurface.h"
|
||||
#include "Rendering/Shadow/DirectionalShadowRuntime.h"
|
||||
@@ -21,10 +22,17 @@ bool RequiresPipelineStageRecording(
|
||||
plan.GetPassSequence(stage) == nullptr;
|
||||
}
|
||||
|
||||
bool IsManagedPipelineAsset(
|
||||
const std::shared_ptr<const RenderPipelineAsset>& pipelineAsset) {
|
||||
return dynamic_cast<const Pipelines::ManagedScriptableRenderPipelineAsset*>(
|
||||
pipelineAsset.get()) != nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CameraRenderer::CameraRenderer()
|
||||
: CameraRenderer(Internal::CreateDefaultRenderPipelineAsset()) {
|
||||
: m_directionalShadowRuntime(std::make_unique<DirectionalShadowRuntime>()) {
|
||||
SetPipelineAsset(nullptr);
|
||||
}
|
||||
|
||||
CameraRenderer::CameraRenderer(std::unique_ptr<RenderPipeline> pipeline)
|
||||
@@ -46,16 +54,53 @@ CameraRenderer::~CameraRenderer() {
|
||||
|
||||
void CameraRenderer::SetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
|
||||
m_pipelineAsset.reset();
|
||||
m_usesDefaultPipelineAssetSelection = false;
|
||||
m_managedPipelineEnvironmentGeneration = 0u;
|
||||
ResetPipeline(std::move(pipeline));
|
||||
}
|
||||
|
||||
void CameraRenderer::SetPipelineAsset(std::shared_ptr<const RenderPipelineAsset> pipelineAsset) {
|
||||
m_usesDefaultPipelineAssetSelection = pipelineAsset == nullptr;
|
||||
ResetPipeline(
|
||||
Internal::CreateRenderPipelineOrDefault(
|
||||
pipelineAsset,
|
||||
&m_pipelineAsset));
|
||||
}
|
||||
|
||||
RenderPipeline* CameraRenderer::GetPipeline() const {
|
||||
const_cast<CameraRenderer*>(this)->RefreshManagedPipelineBindingIfNeeded();
|
||||
return m_pipeline.get();
|
||||
}
|
||||
|
||||
const RenderPipelineAsset* CameraRenderer::GetPipelineAsset() const {
|
||||
const_cast<CameraRenderer*>(this)->RefreshManagedPipelineBindingIfNeeded();
|
||||
return m_pipelineAsset.get();
|
||||
}
|
||||
|
||||
bool CameraRenderer::UsesManagedPipelineBinding() const {
|
||||
return m_usesDefaultPipelineAssetSelection ||
|
||||
IsManagedPipelineAsset(m_pipelineAsset);
|
||||
}
|
||||
|
||||
void CameraRenderer::RefreshManagedPipelineBindingIfNeeded() {
|
||||
if (!UsesManagedPipelineBinding()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t currentGeneration =
|
||||
Pipelines::GetManagedRenderPipelineEnvironmentGeneration();
|
||||
if (currentGeneration == m_managedPipelineEnvironmentGeneration) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_usesDefaultPipelineAssetSelection) {
|
||||
SetPipelineAsset(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
SetPipelineAsset(m_pipelineAsset);
|
||||
}
|
||||
|
||||
void CameraRenderer::ResetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
|
||||
if (m_pipeline != nullptr) {
|
||||
m_pipeline->Shutdown();
|
||||
@@ -63,11 +108,17 @@ void CameraRenderer::ResetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
|
||||
|
||||
m_pipeline = std::move(pipeline);
|
||||
if (m_pipeline == nullptr) {
|
||||
m_usesDefaultPipelineAssetSelection = true;
|
||||
m_pipeline =
|
||||
Internal::CreateRenderPipelineOrDefault(
|
||||
nullptr,
|
||||
&m_pipelineAsset);
|
||||
}
|
||||
|
||||
m_managedPipelineEnvironmentGeneration =
|
||||
UsesManagedPipelineBinding()
|
||||
? Pipelines::GetManagedRenderPipelineEnvironmentGeneration()
|
||||
: 0u;
|
||||
}
|
||||
|
||||
bool CameraRenderer::BuildSceneDataForPlan(
|
||||
@@ -109,6 +160,8 @@ bool CameraRenderer::ExecuteRenderPlan(
|
||||
|
||||
bool CameraRenderer::Render(
|
||||
const CameraFramePlan& plan) {
|
||||
RefreshManagedPipelineBindingIfNeeded();
|
||||
|
||||
if (!plan.IsValid() || m_pipeline == nullptr) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
|
||||
@@ -23,6 +23,11 @@ size_t& GetManagedRenderPipelineBridgeGenerationStorage() {
|
||||
return s_generation;
|
||||
}
|
||||
|
||||
size_t& GetManagedRenderPipelineEnvironmentGenerationStorage() {
|
||||
static size_t s_generation = 1u;
|
||||
return s_generation;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ManagedScriptableRenderPipelineAsset::ManagedScriptableRenderPipelineAsset(
|
||||
@@ -109,11 +114,13 @@ void SetManagedRenderPipelineBridge(
|
||||
std::shared_ptr<const ManagedRenderPipelineBridge> bridge) {
|
||||
GetManagedRenderPipelineBridgeStorage() = std::move(bridge);
|
||||
++GetManagedRenderPipelineBridgeGenerationStorage();
|
||||
++GetManagedRenderPipelineEnvironmentGenerationStorage();
|
||||
}
|
||||
|
||||
void ClearManagedRenderPipelineBridge() {
|
||||
GetManagedRenderPipelineBridgeStorage().reset();
|
||||
++GetManagedRenderPipelineBridgeGenerationStorage();
|
||||
++GetManagedRenderPipelineEnvironmentGenerationStorage();
|
||||
}
|
||||
|
||||
std::shared_ptr<const ManagedRenderPipelineBridge>
|
||||
@@ -121,13 +128,19 @@ GetManagedRenderPipelineBridge() {
|
||||
return GetManagedRenderPipelineBridgeStorage();
|
||||
}
|
||||
|
||||
size_t GetManagedRenderPipelineEnvironmentGeneration() {
|
||||
return GetManagedRenderPipelineEnvironmentGenerationStorage();
|
||||
}
|
||||
|
||||
void SetManagedRenderPipelineAssetDescriptor(
|
||||
const ManagedRenderPipelineAssetDescriptor& descriptor) {
|
||||
GetManagedRenderPipelineAssetDescriptorStorage() = descriptor;
|
||||
++GetManagedRenderPipelineEnvironmentGenerationStorage();
|
||||
}
|
||||
|
||||
void ClearManagedRenderPipelineAssetDescriptor() {
|
||||
GetManagedRenderPipelineAssetDescriptorStorage() = {};
|
||||
++GetManagedRenderPipelineEnvironmentGenerationStorage();
|
||||
}
|
||||
|
||||
ManagedRenderPipelineAssetDescriptor GetManagedRenderPipelineAssetDescriptor() {
|
||||
|
||||
@@ -4912,6 +4912,37 @@ TEST(CameraRenderer_Test, DefaultPipelineAssetUsesManagedSelectionWhenPresent) {
|
||||
Pipelines::ClearManagedRenderPipelineAssetDescriptor();
|
||||
}
|
||||
|
||||
TEST(CameraRenderer_Test, DefaultPipelineAssetRefreshesWhenManagedSelectionChanges) {
|
||||
Pipelines::ClearManagedRenderPipelineAssetDescriptor();
|
||||
|
||||
CameraRenderer renderer;
|
||||
EXPECT_EQ(
|
||||
dynamic_cast<const Pipelines::ManagedScriptableRenderPipelineAsset*>(
|
||||
renderer.GetPipelineAsset()),
|
||||
nullptr);
|
||||
|
||||
const Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
|
||||
"GameScripts",
|
||||
"Gameplay",
|
||||
"ManagedRenderPipelineProbeAsset"
|
||||
};
|
||||
Pipelines::SetManagedRenderPipelineAssetDescriptor(descriptor);
|
||||
|
||||
auto* managedAsset =
|
||||
dynamic_cast<const Pipelines::ManagedScriptableRenderPipelineAsset*>(
|
||||
renderer.GetPipelineAsset());
|
||||
ASSERT_NE(managedAsset, nullptr);
|
||||
EXPECT_EQ(managedAsset->GetDescriptor().assemblyName, "GameScripts");
|
||||
EXPECT_EQ(managedAsset->GetDescriptor().namespaceName, "Gameplay");
|
||||
EXPECT_EQ(managedAsset->GetDescriptor().className, "ManagedRenderPipelineProbeAsset");
|
||||
|
||||
Pipelines::ClearManagedRenderPipelineAssetDescriptor();
|
||||
EXPECT_EQ(
|
||||
dynamic_cast<const Pipelines::ManagedScriptableRenderPipelineAsset*>(
|
||||
renderer.GetPipelineAsset()),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
TEST(CameraRenderer_Test, RebindsToResolvedDefaultAssetWhenPreferredAssetCannotCreatePipeline) {
|
||||
const Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
|
||||
"GameScripts",
|
||||
@@ -4941,6 +4972,40 @@ TEST(CameraRenderer_Test, RebindsToResolvedDefaultAssetWhenPreferredAssetCannotC
|
||||
Pipelines::ClearManagedRenderPipelineAssetDescriptor();
|
||||
}
|
||||
|
||||
TEST(CameraRenderer_Test, RecreatesManagedPipelineWhenBridgeChanges) {
|
||||
Pipelines::ClearManagedRenderPipelineBridge();
|
||||
|
||||
const Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
|
||||
"GameScripts",
|
||||
"Gameplay",
|
||||
"ManagedRenderPipelineProbeAsset"
|
||||
};
|
||||
|
||||
auto firstBridgeState = std::make_shared<MockManagedRenderPipelineBridgeState>();
|
||||
Pipelines::SetManagedRenderPipelineBridge(
|
||||
std::make_shared<MockManagedRenderPipelineBridge>(firstBridgeState));
|
||||
|
||||
CameraRenderer renderer(
|
||||
std::make_shared<Pipelines::ManagedScriptableRenderPipelineAsset>(
|
||||
descriptor));
|
||||
ASSERT_NE(
|
||||
dynamic_cast<Pipelines::ScriptableRenderPipelineHost*>(renderer.GetPipeline()),
|
||||
nullptr);
|
||||
EXPECT_EQ(firstBridgeState->createAssetRuntimeCalls, 1);
|
||||
|
||||
auto secondBridgeState = std::make_shared<MockManagedRenderPipelineBridgeState>();
|
||||
Pipelines::SetManagedRenderPipelineBridge(
|
||||
std::make_shared<MockManagedRenderPipelineBridge>(secondBridgeState));
|
||||
|
||||
auto* host =
|
||||
dynamic_cast<Pipelines::ScriptableRenderPipelineHost*>(renderer.GetPipeline());
|
||||
ASSERT_NE(host, nullptr);
|
||||
EXPECT_NE(host->GetStageRecorder(), nullptr);
|
||||
EXPECT_EQ(secondBridgeState->createAssetRuntimeCalls, 1);
|
||||
|
||||
Pipelines::ClearManagedRenderPipelineBridge();
|
||||
}
|
||||
|
||||
TEST(SceneRenderer_Test, CreatesPipelineInstancesFromPipelineAssetsAndShutsDownReplacedPipelines) {
|
||||
Scene scene("SceneRendererAssetScene");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user