feat(srp): lock project-side pipeline lifecycle contracts
Add project asset probes for renderer invalidation, asset invalidation, and runtime release through the public SRP API surface. Cover the project/Assets bridge path with lifecycle scripting tests and archive the completed project-side SRP bridge plan.
This commit is contained in:
@@ -1,9 +1,38 @@
|
||||
using System.Reflection;
|
||||
using XCEngine;
|
||||
using XCEngine.Rendering;
|
||||
using XCEngine.Rendering.Universal;
|
||||
|
||||
namespace ProjectScripts
|
||||
{
|
||||
internal static class ProjectProbeRuntimeVersionUtility
|
||||
{
|
||||
private static readonly MethodInfo s_getRuntimeResourceVersionMethod =
|
||||
typeof(ScriptableRenderPipelineAsset)
|
||||
.GetMethod(
|
||||
"GetRuntimeResourceVersionInstance",
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.NonPublic);
|
||||
|
||||
public static int GetRuntimeResourceVersion(
|
||||
ScriptableRenderPipelineAsset asset)
|
||||
{
|
||||
if (asset == null ||
|
||||
s_getRuntimeResourceVersionMethod == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
object version =
|
||||
s_getRuntimeResourceVersionMethod.Invoke(
|
||||
asset,
|
||||
null);
|
||||
return version is int resolvedVersion
|
||||
? resolvedVersion
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectPostProcessColorScalePass
|
||||
: ScriptableRenderPass
|
||||
{
|
||||
@@ -154,4 +183,549 @@ namespace ProjectScripts
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ProjectRendererInvalidationProbeState
|
||||
{
|
||||
public static int CreatePipelineCallCount;
|
||||
public static int DisposePipelineCallCount;
|
||||
public static int CreateRendererCallCount;
|
||||
public static int SetupRendererCallCount;
|
||||
public static int CreateFeatureCallCount;
|
||||
public static int DisposeRendererCallCount;
|
||||
public static int DisposeFeatureCallCount;
|
||||
public static int InvalidateRendererCallCount;
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
CreatePipelineCallCount = 0;
|
||||
DisposePipelineCallCount = 0;
|
||||
CreateRendererCallCount = 0;
|
||||
SetupRendererCallCount = 0;
|
||||
CreateFeatureCallCount = 0;
|
||||
DisposeRendererCallCount = 0;
|
||||
DisposeFeatureCallCount = 0;
|
||||
InvalidateRendererCallCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectRendererInvalidationProbePipeline
|
||||
: RendererBackedRenderPipeline
|
||||
{
|
||||
public ProjectRendererInvalidationProbePipeline(
|
||||
RendererBackedRenderPipelineAsset asset)
|
||||
: base(asset)
|
||||
{
|
||||
ProjectRendererInvalidationProbeState
|
||||
.CreatePipelineCallCount++;
|
||||
}
|
||||
|
||||
protected override void Dispose(
|
||||
bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
ProjectRendererInvalidationProbeState
|
||||
.DisposePipelineCallCount++;
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectRendererInvalidationProbeFeature
|
||||
: ScriptableRendererFeature
|
||||
{
|
||||
protected override void ReleaseRuntimeResources()
|
||||
{
|
||||
ProjectRendererInvalidationProbeState
|
||||
.DisposeFeatureCallCount++;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectRendererInvalidationProbeRenderer
|
||||
: ScriptableRenderer
|
||||
{
|
||||
protected override bool SupportsRendererRecording(
|
||||
RendererRecordingContext context)
|
||||
{
|
||||
return context != null &&
|
||||
context.stage == CameraFrameStage.MainScene;
|
||||
}
|
||||
|
||||
protected override bool RecordRenderer(
|
||||
RendererRecordingContext context)
|
||||
{
|
||||
return context != null;
|
||||
}
|
||||
|
||||
protected override void ReleaseRuntimeResources()
|
||||
{
|
||||
ProjectRendererInvalidationProbeState
|
||||
.DisposeRendererCallCount++;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectRendererInvalidationProbeRendererData
|
||||
: ScriptableRendererData
|
||||
{
|
||||
protected override ScriptableRenderer CreateRenderer()
|
||||
{
|
||||
ProjectRendererInvalidationProbeState
|
||||
.CreateRendererCallCount++;
|
||||
return new ProjectRendererInvalidationProbeRenderer();
|
||||
}
|
||||
|
||||
protected override void SetupRenderer(
|
||||
ScriptableRenderer renderer)
|
||||
{
|
||||
ProjectRendererInvalidationProbeState
|
||||
.SetupRendererCallCount++;
|
||||
base.SetupRenderer(renderer);
|
||||
}
|
||||
|
||||
protected override ScriptableRendererFeature[]
|
||||
CreateRendererFeatures()
|
||||
{
|
||||
ProjectRendererInvalidationProbeState
|
||||
.CreateFeatureCallCount++;
|
||||
return new ScriptableRendererFeature[]
|
||||
{
|
||||
new ProjectRendererInvalidationProbeFeature()
|
||||
};
|
||||
}
|
||||
|
||||
protected override string GetPipelineRendererAssetKey()
|
||||
{
|
||||
return "BuiltinForward";
|
||||
}
|
||||
|
||||
public void InvalidateForTest()
|
||||
{
|
||||
ProjectRendererInvalidationProbeState
|
||||
.InvalidateRendererCallCount++;
|
||||
SetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectRendererInvalidationProbeAsset
|
||||
: RendererBackedRenderPipelineAsset
|
||||
{
|
||||
private readonly ProjectRendererInvalidationProbeRendererData
|
||||
m_rendererData;
|
||||
|
||||
public ProjectRendererInvalidationProbeAsset()
|
||||
{
|
||||
ProjectRendererInvalidationProbeState.Reset();
|
||||
m_rendererData =
|
||||
new ProjectRendererInvalidationProbeRendererData();
|
||||
rendererDataList = new ScriptableRendererData[]
|
||||
{
|
||||
m_rendererData
|
||||
};
|
||||
}
|
||||
|
||||
protected override ScriptableRenderPipeline
|
||||
CreateRendererBackedPipeline()
|
||||
{
|
||||
return new ProjectRendererInvalidationProbePipeline(
|
||||
this);
|
||||
}
|
||||
|
||||
public void InvalidateDefaultRendererForTest()
|
||||
{
|
||||
if (m_rendererData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_rendererData.InvalidateForTest();
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ProjectPersistentFeatureProbeState
|
||||
{
|
||||
public static int CreateRendererCallCount;
|
||||
public static int CreateFeatureRuntimeCallCount;
|
||||
public static int DisposeRendererCallCount;
|
||||
public static int DisposeFeatureCallCount;
|
||||
public static int InvalidateRendererCallCount;
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
CreateRendererCallCount = 0;
|
||||
CreateFeatureRuntimeCallCount = 0;
|
||||
DisposeRendererCallCount = 0;
|
||||
DisposeFeatureCallCount = 0;
|
||||
InvalidateRendererCallCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectPersistentFeatureProbeRendererFeature
|
||||
: ScriptableRendererFeature
|
||||
{
|
||||
public override void Create()
|
||||
{
|
||||
ProjectPersistentFeatureProbeState
|
||||
.CreateFeatureRuntimeCallCount++;
|
||||
}
|
||||
|
||||
protected override void ReleaseRuntimeResources()
|
||||
{
|
||||
ProjectPersistentFeatureProbeState
|
||||
.DisposeFeatureCallCount++;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectPersistentFeatureProbeRenderer
|
||||
: ScriptableRenderer
|
||||
{
|
||||
protected override bool SupportsRendererRecording(
|
||||
RendererRecordingContext context)
|
||||
{
|
||||
return context != null &&
|
||||
context.stage == CameraFrameStage.MainScene;
|
||||
}
|
||||
|
||||
protected override bool RecordRenderer(
|
||||
RendererRecordingContext context)
|
||||
{
|
||||
return context != null;
|
||||
}
|
||||
|
||||
protected override void ReleaseRuntimeResources()
|
||||
{
|
||||
ProjectPersistentFeatureProbeState
|
||||
.DisposeRendererCallCount++;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectPersistentFeatureProbeRendererData
|
||||
: ScriptableRendererData
|
||||
{
|
||||
private readonly ProjectPersistentFeatureProbeRendererFeature
|
||||
m_feature =
|
||||
new ProjectPersistentFeatureProbeRendererFeature();
|
||||
|
||||
protected override ScriptableRenderer CreateRenderer()
|
||||
{
|
||||
ProjectPersistentFeatureProbeState
|
||||
.CreateRendererCallCount++;
|
||||
return new ProjectPersistentFeatureProbeRenderer();
|
||||
}
|
||||
|
||||
protected override ScriptableRendererFeature[]
|
||||
CreateRendererFeatures()
|
||||
{
|
||||
return new ScriptableRendererFeature[]
|
||||
{
|
||||
m_feature
|
||||
};
|
||||
}
|
||||
|
||||
protected override string GetPipelineRendererAssetKey()
|
||||
{
|
||||
return "BuiltinForward";
|
||||
}
|
||||
|
||||
public void InvalidateForTest()
|
||||
{
|
||||
ProjectPersistentFeatureProbeState
|
||||
.InvalidateRendererCallCount++;
|
||||
SetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectPersistentFeatureProbeAsset
|
||||
: RendererBackedRenderPipelineAsset
|
||||
{
|
||||
private readonly ProjectPersistentFeatureProbeRendererData
|
||||
m_rendererData;
|
||||
|
||||
public ProjectPersistentFeatureProbeAsset()
|
||||
{
|
||||
ProjectPersistentFeatureProbeState.Reset();
|
||||
m_rendererData =
|
||||
new ProjectPersistentFeatureProbeRendererData();
|
||||
rendererDataList = new ScriptableRendererData[]
|
||||
{
|
||||
m_rendererData
|
||||
};
|
||||
}
|
||||
|
||||
public void InvalidateDefaultRendererForTest()
|
||||
{
|
||||
if (m_rendererData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_rendererData.InvalidateForTest();
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ProjectAssetInvalidationProbeState
|
||||
{
|
||||
public static int CreatePipelineCallCount;
|
||||
public static int DisposePipelineCallCount;
|
||||
public static int InvalidateAssetCallCount;
|
||||
public static int LastCreatedSupportedStage;
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
CreatePipelineCallCount = 0;
|
||||
DisposePipelineCallCount = 0;
|
||||
InvalidateAssetCallCount = 0;
|
||||
LastCreatedSupportedStage =
|
||||
(int)CameraFrameStage.MainScene;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectAssetInvalidationProbePipeline
|
||||
: ScriptableRenderPipeline
|
||||
{
|
||||
private readonly CameraFrameStage m_supportedStage;
|
||||
|
||||
public ProjectAssetInvalidationProbePipeline(
|
||||
CameraFrameStage supportedStage)
|
||||
{
|
||||
m_supportedStage = supportedStage;
|
||||
ProjectAssetInvalidationProbeState
|
||||
.LastCreatedSupportedStage =
|
||||
(int)supportedStage;
|
||||
}
|
||||
|
||||
protected override bool SupportsStageRenderGraph(
|
||||
CameraFrameStage stage)
|
||||
{
|
||||
return stage == m_supportedStage;
|
||||
}
|
||||
|
||||
protected override bool RecordStageRenderGraph(
|
||||
ScriptableRenderContext context)
|
||||
{
|
||||
return context != null;
|
||||
}
|
||||
|
||||
protected override void Dispose(
|
||||
bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
ProjectAssetInvalidationProbeState
|
||||
.DisposePipelineCallCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectAssetInvalidationProbeAsset
|
||||
: ScriptableRenderPipelineAsset
|
||||
{
|
||||
private CameraFrameStage m_supportedStage =
|
||||
CameraFrameStage.MainScene;
|
||||
|
||||
public ProjectAssetInvalidationProbeAsset()
|
||||
{
|
||||
ProjectAssetInvalidationProbeState.Reset();
|
||||
}
|
||||
|
||||
protected override ScriptableRenderPipeline CreatePipeline()
|
||||
{
|
||||
ProjectAssetInvalidationProbeState
|
||||
.CreatePipelineCallCount++;
|
||||
return new ProjectAssetInvalidationProbePipeline(
|
||||
m_supportedStage);
|
||||
}
|
||||
|
||||
public void InvalidatePipelineForTest(
|
||||
CameraFrameStage supportedStage)
|
||||
{
|
||||
if (m_supportedStage == supportedStage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_supportedStage = supportedStage;
|
||||
ProjectAssetInvalidationProbeState
|
||||
.InvalidateAssetCallCount++;
|
||||
SetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectRendererInvalidationRuntimeSelectionProbe
|
||||
: MonoBehaviour
|
||||
{
|
||||
public void Start()
|
||||
{
|
||||
GraphicsSettings.renderPipelineAsset =
|
||||
new ProjectRendererInvalidationProbeAsset();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectRendererInvalidationObservationProbe
|
||||
: MonoBehaviour
|
||||
{
|
||||
public int ObservedCreatePipelineCallCount;
|
||||
public int ObservedDisposePipelineCallCount;
|
||||
public int ObservedCreateRendererCallCount;
|
||||
public int ObservedSetupRendererCallCount;
|
||||
public int ObservedCreateFeatureCallCount;
|
||||
public int ObservedDisposeRendererCallCount;
|
||||
public int ObservedDisposeFeatureCallCount;
|
||||
public int ObservedInvalidateRendererCallCount;
|
||||
public int ObservedRuntimeResourceVersionBeforeInvalidation;
|
||||
public int ObservedRuntimeResourceVersionAfterInvalidation;
|
||||
|
||||
private bool m_requestedInvalidation;
|
||||
|
||||
public void Update()
|
||||
{
|
||||
ProjectRendererInvalidationProbeAsset selectedAsset =
|
||||
GraphicsSettings.renderPipelineAsset
|
||||
as ProjectRendererInvalidationProbeAsset;
|
||||
if (!m_requestedInvalidation &&
|
||||
selectedAsset != null &&
|
||||
ProjectRendererInvalidationProbeState
|
||||
.CreateRendererCallCount > 0)
|
||||
{
|
||||
ObservedRuntimeResourceVersionBeforeInvalidation =
|
||||
ProjectProbeRuntimeVersionUtility
|
||||
.GetRuntimeResourceVersion(
|
||||
selectedAsset);
|
||||
selectedAsset.InvalidateDefaultRendererForTest();
|
||||
ObservedRuntimeResourceVersionAfterInvalidation =
|
||||
ProjectProbeRuntimeVersionUtility
|
||||
.GetRuntimeResourceVersion(
|
||||
selectedAsset);
|
||||
m_requestedInvalidation = true;
|
||||
}
|
||||
|
||||
ObservedCreatePipelineCallCount =
|
||||
ProjectRendererInvalidationProbeState
|
||||
.CreatePipelineCallCount;
|
||||
ObservedDisposePipelineCallCount =
|
||||
ProjectRendererInvalidationProbeState
|
||||
.DisposePipelineCallCount;
|
||||
ObservedCreateRendererCallCount =
|
||||
ProjectRendererInvalidationProbeState
|
||||
.CreateRendererCallCount;
|
||||
ObservedSetupRendererCallCount =
|
||||
ProjectRendererInvalidationProbeState
|
||||
.SetupRendererCallCount;
|
||||
ObservedCreateFeatureCallCount =
|
||||
ProjectRendererInvalidationProbeState
|
||||
.CreateFeatureCallCount;
|
||||
ObservedDisposeRendererCallCount =
|
||||
ProjectRendererInvalidationProbeState
|
||||
.DisposeRendererCallCount;
|
||||
ObservedDisposeFeatureCallCount =
|
||||
ProjectRendererInvalidationProbeState
|
||||
.DisposeFeatureCallCount;
|
||||
ObservedInvalidateRendererCallCount =
|
||||
ProjectRendererInvalidationProbeState
|
||||
.InvalidateRendererCallCount;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectPersistentFeatureRuntimeSelectionProbe
|
||||
: MonoBehaviour
|
||||
{
|
||||
public void Start()
|
||||
{
|
||||
GraphicsSettings.renderPipelineAsset =
|
||||
new ProjectPersistentFeatureProbeAsset();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectPersistentFeatureObservationProbe
|
||||
: MonoBehaviour
|
||||
{
|
||||
public int ObservedCreateRendererCallCount;
|
||||
public int ObservedCreateFeatureRuntimeCallCount;
|
||||
public int ObservedDisposeRendererCallCount;
|
||||
public int ObservedDisposeFeatureCallCount;
|
||||
public int ObservedInvalidateRendererCallCount;
|
||||
|
||||
private bool m_requestedInvalidation;
|
||||
|
||||
public void Update()
|
||||
{
|
||||
ProjectPersistentFeatureProbeAsset selectedAsset =
|
||||
GraphicsSettings.renderPipelineAsset
|
||||
as ProjectPersistentFeatureProbeAsset;
|
||||
if (!m_requestedInvalidation &&
|
||||
selectedAsset != null &&
|
||||
ProjectPersistentFeatureProbeState
|
||||
.CreateFeatureRuntimeCallCount > 0)
|
||||
{
|
||||
selectedAsset.InvalidateDefaultRendererForTest();
|
||||
m_requestedInvalidation = true;
|
||||
}
|
||||
|
||||
ObservedCreateRendererCallCount =
|
||||
ProjectPersistentFeatureProbeState
|
||||
.CreateRendererCallCount;
|
||||
ObservedCreateFeatureRuntimeCallCount =
|
||||
ProjectPersistentFeatureProbeState
|
||||
.CreateFeatureRuntimeCallCount;
|
||||
ObservedDisposeRendererCallCount =
|
||||
ProjectPersistentFeatureProbeState
|
||||
.DisposeRendererCallCount;
|
||||
ObservedDisposeFeatureCallCount =
|
||||
ProjectPersistentFeatureProbeState
|
||||
.DisposeFeatureCallCount;
|
||||
ObservedInvalidateRendererCallCount =
|
||||
ProjectPersistentFeatureProbeState
|
||||
.InvalidateRendererCallCount;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectAssetInvalidationRuntimeSelectionProbe
|
||||
: MonoBehaviour
|
||||
{
|
||||
public void Start()
|
||||
{
|
||||
GraphicsSettings.renderPipelineAsset =
|
||||
new ProjectAssetInvalidationProbeAsset();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProjectAssetInvalidationObservationProbe
|
||||
: MonoBehaviour
|
||||
{
|
||||
public int ObservedCreatePipelineCallCount;
|
||||
public int ObservedDisposePipelineCallCount;
|
||||
public int ObservedInvalidateAssetCallCount;
|
||||
public int ObservedLastCreatedSupportedStage;
|
||||
|
||||
private bool m_requestedInvalidation;
|
||||
|
||||
public void Update()
|
||||
{
|
||||
ProjectAssetInvalidationProbeAsset selectedAsset =
|
||||
GraphicsSettings.renderPipelineAsset
|
||||
as ProjectAssetInvalidationProbeAsset;
|
||||
if (!m_requestedInvalidation &&
|
||||
selectedAsset != null &&
|
||||
ProjectAssetInvalidationProbeState
|
||||
.CreatePipelineCallCount > 0)
|
||||
{
|
||||
selectedAsset.InvalidatePipelineForTest(
|
||||
CameraFrameStage.PostProcess);
|
||||
m_requestedInvalidation = true;
|
||||
}
|
||||
|
||||
ObservedCreatePipelineCallCount =
|
||||
ProjectAssetInvalidationProbeState
|
||||
.CreatePipelineCallCount;
|
||||
ObservedDisposePipelineCallCount =
|
||||
ProjectAssetInvalidationProbeState
|
||||
.DisposePipelineCallCount;
|
||||
ObservedInvalidateAssetCallCount =
|
||||
ProjectAssetInvalidationProbeState
|
||||
.InvalidateAssetCallCount;
|
||||
ObservedLastCreatedSupportedStage =
|
||||
ProjectAssetInvalidationProbeState
|
||||
.LastCreatedSupportedStage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||
#include <XCEngine/Input/InputManager.h>
|
||||
#include <XCEngine/Rendering/Execution/CameraFrameRenderGraphFrameData.h>
|
||||
#include <XCEngine/Rendering/Graph/RenderGraph.h>
|
||||
#include <XCEngine/Rendering/Graph/RenderGraphCompiler.h>
|
||||
#include <XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h>
|
||||
#include <XCEngine/Rendering/RenderSurface.h>
|
||||
#include <XCEngine/RHI/RHIResourceView.h>
|
||||
#include <XCEngine/Scene/Scene.h>
|
||||
#include <XCEngine/Scripting/Mono/MonoScriptRuntime.h>
|
||||
#include <XCEngine/Scripting/ScriptComponent.h>
|
||||
#include <XCEngine/Scripting/ScriptEngine.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
@@ -19,6 +24,7 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
using namespace XCEngine::Components;
|
||||
using namespace XCEngine::Scripting;
|
||||
|
||||
namespace {
|
||||
@@ -77,6 +83,15 @@ MonoScriptRuntime::Settings CreateProjectMonoSettings() {
|
||||
class ProjectScriptAssemblyTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
engine = &ScriptEngine::Get();
|
||||
engine->OnRuntimeStop();
|
||||
engine->SetRuntimeFixedDeltaTime(
|
||||
ScriptEngine::DefaultFixedDeltaTime);
|
||||
XCEngine::Input::InputManager::Get().Shutdown();
|
||||
XCEngine::Resources::ResourceManager::Get().Shutdown();
|
||||
XCEngine::Rendering::Pipelines::
|
||||
ClearConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
|
||||
ASSERT_TRUE(std::filesystem::exists(ResolveProjectScriptCoreDllPath()));
|
||||
ASSERT_TRUE(std::filesystem::exists(ResolveProjectGameScriptsDllPath()));
|
||||
|
||||
@@ -97,9 +112,43 @@ protected:
|
||||
|
||||
runtime = std::make_unique<MonoScriptRuntime>(std::move(settings));
|
||||
ASSERT_TRUE(runtime->Initialize()) << runtime->GetLastError();
|
||||
engine->SetRuntime(runtime.get());
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
if (engine != nullptr) {
|
||||
engine->OnRuntimeStop();
|
||||
engine->SetRuntime(nullptr);
|
||||
}
|
||||
|
||||
XCEngine::Input::InputManager::Get().Shutdown();
|
||||
XCEngine::Rendering::Pipelines::
|
||||
ClearConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
runtime.reset();
|
||||
scene.reset();
|
||||
XCEngine::Resources::ResourceManager::Get().Shutdown();
|
||||
}
|
||||
|
||||
Scene* CreateScene(const std::string& sceneName) {
|
||||
scene = std::make_unique<Scene>(sceneName);
|
||||
return scene.get();
|
||||
}
|
||||
|
||||
ScriptComponent* AddProjectScript(
|
||||
GameObject* gameObject,
|
||||
const std::string& className) {
|
||||
ScriptComponent* component =
|
||||
gameObject->AddComponent<ScriptComponent>();
|
||||
component->SetScriptClass(
|
||||
"GameScripts",
|
||||
"ProjectScripts",
|
||||
className);
|
||||
return component;
|
||||
}
|
||||
|
||||
ScriptEngine* engine = nullptr;
|
||||
std::unique_ptr<MonoScriptRuntime> runtime;
|
||||
std::unique_ptr<Scene> scene;
|
||||
};
|
||||
|
||||
TEST_F(ProjectScriptAssemblyTest, InitializesFromProjectScriptAssemblyDirectory) {
|
||||
@@ -360,4 +409,338 @@ TEST_F(
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ProjectScriptAssemblyTest,
|
||||
ProjectManagedBridgeRebuildsRendererAfterProjectRendererDataInvalidation) {
|
||||
Scene* runtimeScene =
|
||||
CreateScene("ProjectRendererInvalidationScene");
|
||||
GameObject* selectionObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectRendererInvalidationSelection");
|
||||
ScriptComponent* selectionScript =
|
||||
AddProjectScript(
|
||||
selectionObject,
|
||||
"ProjectRendererInvalidationRuntimeSelectionProbe");
|
||||
ASSERT_NE(selectionScript, nullptr);
|
||||
GameObject* observationObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectRendererInvalidationObservation");
|
||||
ScriptComponent* observationScript =
|
||||
AddProjectScript(
|
||||
observationObject,
|
||||
"ProjectRendererInvalidationObservationProbe");
|
||||
ASSERT_NE(observationScript, nullptr);
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor
|
||||
descriptor =
|
||||
XCEngine::Rendering::Pipelines::
|
||||
GetConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
ASSERT_TRUE(descriptor.IsValid());
|
||||
ASSERT_NE(descriptor.managedAssetHandle, 0u);
|
||||
EXPECT_EQ(descriptor.assemblyName, "GameScripts");
|
||||
EXPECT_EQ(descriptor.namespaceName, "ProjectScripts");
|
||||
EXPECT_EQ(
|
||||
descriptor.className,
|
||||
"ProjectRendererInvalidationProbeAsset");
|
||||
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
std::unique_ptr<XCEngine::Rendering::RenderPipelineStageRecorder>
|
||||
recorder = assetRuntime->CreateStageRecorder();
|
||||
ASSERT_NE(recorder, nullptr);
|
||||
|
||||
const XCEngine::Rendering::RenderContext context = {};
|
||||
ASSERT_TRUE(recorder->Initialize(context));
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
EXPECT_TRUE(runtime->GetLastError().empty()) << runtime->GetLastError();
|
||||
|
||||
int observedCreatePipelineCallCount = 0;
|
||||
int observedDisposePipelineCallCount = 0;
|
||||
int observedCreateRendererCallCount = 0;
|
||||
int observedSetupRendererCallCount = 0;
|
||||
int observedCreateFeatureCallCount = 0;
|
||||
int observedDisposeRendererCallCount = 0;
|
||||
int observedDisposeFeatureCallCount = 0;
|
||||
int observedInvalidateRendererCallCount = 0;
|
||||
int observedRuntimeResourceVersionBeforeInvalidation = 0;
|
||||
int observedRuntimeResourceVersionAfterInvalidation = 0;
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreatePipelineCallCount",
|
||||
observedCreatePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposePipelineCallCount",
|
||||
observedDisposePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreateRendererCallCount",
|
||||
observedCreateRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedSetupRendererCallCount",
|
||||
observedSetupRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreateFeatureCallCount",
|
||||
observedCreateFeatureCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposeRendererCallCount",
|
||||
observedDisposeRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposeFeatureCallCount",
|
||||
observedDisposeFeatureCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedInvalidateRendererCallCount",
|
||||
observedInvalidateRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedRuntimeResourceVersionBeforeInvalidation",
|
||||
observedRuntimeResourceVersionBeforeInvalidation));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedRuntimeResourceVersionAfterInvalidation",
|
||||
observedRuntimeResourceVersionAfterInvalidation));
|
||||
|
||||
EXPECT_EQ(observedCreatePipelineCallCount, 2);
|
||||
EXPECT_EQ(observedDisposePipelineCallCount, 1);
|
||||
EXPECT_EQ(observedCreateRendererCallCount, 2);
|
||||
EXPECT_EQ(observedSetupRendererCallCount, 2);
|
||||
EXPECT_EQ(observedCreateFeatureCallCount, 2);
|
||||
EXPECT_EQ(observedDisposeRendererCallCount, 1);
|
||||
EXPECT_EQ(observedDisposeFeatureCallCount, 1);
|
||||
EXPECT_EQ(observedInvalidateRendererCallCount, 1);
|
||||
EXPECT_GT(observedRuntimeResourceVersionBeforeInvalidation, 0);
|
||||
EXPECT_EQ(
|
||||
observedRuntimeResourceVersionAfterInvalidation,
|
||||
observedRuntimeResourceVersionBeforeInvalidation + 1);
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ProjectScriptAssemblyTest,
|
||||
ProjectManagedBridgeReleasesProjectRendererCachesAcrossInvalidationAndAssetRuntimeRelease) {
|
||||
Scene* runtimeScene =
|
||||
CreateScene("ProjectPersistentFeatureLifecycleScene");
|
||||
GameObject* selectionObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectPersistentFeatureSelection");
|
||||
ScriptComponent* selectionScript =
|
||||
AddProjectScript(
|
||||
selectionObject,
|
||||
"ProjectPersistentFeatureRuntimeSelectionProbe");
|
||||
ASSERT_NE(selectionScript, nullptr);
|
||||
GameObject* observationObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectPersistentFeatureObservation");
|
||||
ScriptComponent* observationScript =
|
||||
AddProjectScript(
|
||||
observationObject,
|
||||
"ProjectPersistentFeatureObservationProbe");
|
||||
ASSERT_NE(observationScript, nullptr);
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor
|
||||
descriptor =
|
||||
XCEngine::Rendering::Pipelines::
|
||||
GetConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
ASSERT_TRUE(descriptor.IsValid());
|
||||
ASSERT_NE(descriptor.managedAssetHandle, 0u);
|
||||
EXPECT_EQ(descriptor.assemblyName, "GameScripts");
|
||||
EXPECT_EQ(descriptor.namespaceName, "ProjectScripts");
|
||||
EXPECT_EQ(
|
||||
descriptor.className,
|
||||
"ProjectPersistentFeatureProbeAsset");
|
||||
|
||||
{
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
std::unique_ptr<XCEngine::Rendering::RenderPipelineStageRecorder>
|
||||
recorder = assetRuntime->CreateStageRecorder();
|
||||
ASSERT_NE(recorder, nullptr);
|
||||
|
||||
const XCEngine::Rendering::RenderContext context = {};
|
||||
ASSERT_TRUE(recorder->Initialize(context));
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
EXPECT_TRUE(runtime->GetLastError().empty()) << runtime->GetLastError();
|
||||
|
||||
int observedCreateRendererCallCount = 0;
|
||||
int observedCreateFeatureRuntimeCallCount = 0;
|
||||
int observedDisposeRendererCallCount = 0;
|
||||
int observedDisposeFeatureCallCount = 0;
|
||||
int observedInvalidateRendererCallCount = 0;
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreateRendererCallCount",
|
||||
observedCreateRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreateFeatureRuntimeCallCount",
|
||||
observedCreateFeatureRuntimeCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposeRendererCallCount",
|
||||
observedDisposeRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposeFeatureCallCount",
|
||||
observedDisposeFeatureCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedInvalidateRendererCallCount",
|
||||
observedInvalidateRendererCallCount));
|
||||
|
||||
EXPECT_EQ(observedCreateRendererCallCount, 2);
|
||||
EXPECT_EQ(observedCreateFeatureRuntimeCallCount, 2);
|
||||
EXPECT_EQ(observedDisposeRendererCallCount, 2);
|
||||
EXPECT_EQ(observedDisposeFeatureCallCount, 2);
|
||||
EXPECT_EQ(observedInvalidateRendererCallCount, 1);
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ProjectScriptAssemblyTest,
|
||||
ProjectManagedBridgeRebuildsPipelineAfterProjectAssetInvalidation) {
|
||||
Scene* runtimeScene =
|
||||
CreateScene("ProjectAssetInvalidationScene");
|
||||
GameObject* selectionObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectAssetInvalidationSelection");
|
||||
ScriptComponent* selectionScript =
|
||||
AddProjectScript(
|
||||
selectionObject,
|
||||
"ProjectAssetInvalidationRuntimeSelectionProbe");
|
||||
ASSERT_NE(selectionScript, nullptr);
|
||||
GameObject* observationObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectAssetInvalidationObservation");
|
||||
ScriptComponent* observationScript =
|
||||
AddProjectScript(
|
||||
observationObject,
|
||||
"ProjectAssetInvalidationObservationProbe");
|
||||
ASSERT_NE(observationScript, nullptr);
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor
|
||||
descriptor =
|
||||
XCEngine::Rendering::Pipelines::
|
||||
GetConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
ASSERT_TRUE(descriptor.IsValid());
|
||||
ASSERT_NE(descriptor.managedAssetHandle, 0u);
|
||||
EXPECT_EQ(descriptor.assemblyName, "GameScripts");
|
||||
EXPECT_EQ(descriptor.namespaceName, "ProjectScripts");
|
||||
EXPECT_EQ(
|
||||
descriptor.className,
|
||||
"ProjectAssetInvalidationProbeAsset");
|
||||
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
std::unique_ptr<XCEngine::Rendering::RenderPipelineStageRecorder>
|
||||
recorder = assetRuntime->CreateStageRecorder();
|
||||
ASSERT_NE(recorder, nullptr);
|
||||
|
||||
const XCEngine::Rendering::RenderContext context = {};
|
||||
ASSERT_TRUE(recorder->Initialize(context));
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
ASSERT_FALSE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess));
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
ASSERT_FALSE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess));
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
EXPECT_TRUE(runtime->GetLastError().empty()) << runtime->GetLastError();
|
||||
|
||||
int observedCreatePipelineCallCount = 0;
|
||||
int observedDisposePipelineCallCount = 0;
|
||||
int observedInvalidateAssetCallCount = 0;
|
||||
int observedLastCreatedSupportedStage = 0;
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreatePipelineCallCount",
|
||||
observedCreatePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposePipelineCallCount",
|
||||
observedDisposePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedInvalidateAssetCallCount",
|
||||
observedInvalidateAssetCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedLastCreatedSupportedStage",
|
||||
observedLastCreatedSupportedStage));
|
||||
|
||||
EXPECT_EQ(observedCreatePipelineCallCount, 2);
|
||||
EXPECT_EQ(observedDisposePipelineCallCount, 1);
|
||||
EXPECT_EQ(observedInvalidateAssetCallCount, 1);
|
||||
EXPECT_EQ(
|
||||
observedLastCreatedSupportedStage,
|
||||
static_cast<int>(
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess));
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user