From 30ee70a4d1bc29e6abfdc96862f293472fa81110 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Sat, 18 Apr 2026 16:41:53 +0800 Subject: [PATCH] feat(rendering): select managed SRP through asset instances --- .../ManagedScriptableRenderPipelineAsset.h | 6 + .../Scripting/Mono/MonoScriptRuntime.h | 4 + .../src/Scripting/Mono/MonoScriptRuntime.cpp | 136 +++++++++++++++--- managed/GameScripts/RenderPipelineApiProbe.cs | 72 ++++++---- .../XCEngine.ScriptCore/GraphicsSettings.cs | 27 +--- managed/XCEngine.ScriptCore/InternalCalls.cs | 6 +- tests/scripting/test_mono_script_runtime.cpp | 68 +++++++-- 7 files changed, 226 insertions(+), 93 deletions(-) diff --git a/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h b/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h index 68fb9c52..869ae521 100644 --- a/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h +++ b/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -19,11 +20,16 @@ struct ManagedRenderPipelineAssetDescriptor { std::string assemblyName; std::string namespaceName; std::string className; + uint32_t managedAssetHandle = 0u; bool IsValid() const { return !assemblyName.empty() && !className.empty(); } + bool HasManagedAssetHandle() const { + return managedAssetHandle != 0u; + } + std::string GetFullName() const { return namespaceName.empty() ? className diff --git a/engine/include/XCEngine/Scripting/Mono/MonoScriptRuntime.h b/engine/include/XCEngine/Scripting/Mono/MonoScriptRuntime.h index 1871405b..4aeafcf2 100644 --- a/engine/include/XCEngine/Scripting/Mono/MonoScriptRuntime.h +++ b/engine/include/XCEngine/Scripting/Mono/MonoScriptRuntime.h @@ -72,6 +72,10 @@ public: MonoObject* GetManagedInstanceObject(const ScriptComponent* component) const; MonoObject* CreateManagedComponentWrapper(MonoClass* componentClass, uint64_t gameObjectUUID); bool DestroyManagedObject(MonoObject* managedObject); + MonoObject* GetExternalManagedObject(uint32_t gcHandle) const; + uint32_t RetainExternalManagedObjectReference(MonoObject* managedObject); + void ReleaseExternalManagedObject(uint32_t gcHandle); + bool IsScriptableRenderPipelineAssetObject(MonoObject* managedObject) const; bool TryGetFieldValue( const ScriptComponent* component, diff --git a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp index 9525fc5e..fd9a5b9e 100644 --- a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp +++ b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp @@ -507,6 +507,7 @@ private: mutable MonoMethod* m_configureCameraRenderRequestMethod = nullptr; mutable MonoMethod* m_configureCameraFramePlanMethod = nullptr; mutable MonoMethod* m_getDefaultFinalColorSettingsMethod = nullptr; + mutable bool m_ownsManagedAssetHandle = false; mutable bool m_assetCreationAttempted = false; }; @@ -899,6 +900,35 @@ bool MonoManagedRenderPipelineAssetRuntime::EnsureManagedAsset() const { m_assetCreationAttempted = true; + if (m_descriptor.HasManagedAssetHandle()) { + MonoObject* const assetObject = + m_runtime->GetExternalManagedObject( + m_descriptor.managedAssetHandle); + MonoClass* const assetClass = + assetObject != nullptr + ? mono_object_get_class(assetObject) + : nullptr; + if (assetClass == nullptr) { + m_runtime->SetError( + "Managed render pipeline asset handle is no longer valid: " + + m_descriptor.GetFullName() + "."); + return false; + } + + if (!IsMonoClassOrSubclass( + assetClass, + m_runtime->m_scriptableRenderPipelineAssetClass)) { + m_runtime->SetError( + "Managed render pipeline asset must derive from ScriptableRenderPipelineAsset: " + + m_descriptor.GetFullName() + "."); + return false; + } + + m_assetHandle = m_descriptor.managedAssetHandle; + m_ownsManagedAssetHandle = false; + return true; + } + MonoClass* assetClass = nullptr; if (!m_runtime->ResolveManagedClass( m_descriptor.assemblyName, @@ -918,8 +948,10 @@ bool MonoManagedRenderPipelineAssetRuntime::EnsureManagedAsset() const { return false; } - return m_runtime->CreateExternalManagedObject(assetClass, m_assetHandle) && - m_assetHandle != 0; + m_ownsManagedAssetHandle = + m_runtime->CreateExternalManagedObject(assetClass, m_assetHandle) && + m_assetHandle != 0; + return m_ownsManagedAssetHandle; } void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const { @@ -927,6 +959,8 @@ void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const { m_configureCameraRenderRequestMethod = nullptr; m_configureCameraFramePlanMethod = nullptr; m_getDefaultFinalColorSettingsMethod = nullptr; + const bool ownsManagedAssetHandle = m_ownsManagedAssetHandle; + m_ownsManagedAssetHandle = false; m_assetCreationAttempted = false; if (!IsRuntimeAlive()) { @@ -934,10 +968,11 @@ void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const { return; } - if (m_assetHandle != 0) { + if (m_assetHandle != 0 && ownsManagedAssetHandle) { m_runtime->DestroyExternalManagedObject(m_assetHandle); - m_assetHandle = 0; } + + m_assetHandle = 0; } MonoObject* MonoManagedRenderPipelineAssetRuntime::GetManagedAssetObject() const { @@ -2683,17 +2718,29 @@ mono_bool InternalCall_Physics_Raycast( return 1; } -void InternalCall_Rendering_SetRenderPipelineAssetType(MonoReflectionType* assetType) { - if (assetType == nullptr) { +void InternalCall_Rendering_SetRenderPipelineAsset(MonoObject* assetObject) { + MonoScriptRuntime* const runtime = GetActiveMonoScriptRuntime(); + const Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor currentDescriptor = + Rendering::Pipelines::GetManagedRenderPipelineAssetDescriptor(); + + if (assetObject == nullptr) { + if (runtime != nullptr && + currentDescriptor.managedAssetHandle != 0u) { + runtime->ReleaseExternalManagedObject( + currentDescriptor.managedAssetHandle); + } + Rendering::Pipelines::ClearManagedRenderPipelineAssetDescriptor(); return; } - MonoType* monoType = mono_reflection_type_get_type(assetType); - MonoClass* monoClass = - monoType != nullptr ? mono_class_from_mono_type(monoType) : nullptr; + MonoClass* const monoClass = mono_object_get_class(assetObject); if (monoClass == nullptr) { - Rendering::Pipelines::ClearManagedRenderPipelineAssetDescriptor(); + return; + } + + if (runtime != nullptr && + !runtime->IsScriptableRenderPipelineAssetObject(assetObject)) { return; } @@ -2703,25 +2750,45 @@ void InternalCall_Rendering_SetRenderPipelineAssetType(MonoReflectionType* asset TrimAssemblyName(SafeString(image != nullptr ? mono_image_get_name(image) : nullptr)); descriptor.namespaceName = SafeString(mono_class_get_namespace(monoClass)); descriptor.className = SafeString(mono_class_get_name(monoClass)); - if (!descriptor.IsValid()) { - Rendering::Pipelines::ClearManagedRenderPipelineAssetDescriptor(); + descriptor.managedAssetHandle = + runtime != nullptr + ? runtime->RetainExternalManagedObjectReference(assetObject) + : 0u; + if (!descriptor.IsValid() || + descriptor.managedAssetHandle == 0u) { + if (runtime != nullptr && + descriptor.managedAssetHandle != 0u) { + runtime->ReleaseExternalManagedObject( + descriptor.managedAssetHandle); + } return; } + if (runtime != nullptr && + currentDescriptor.managedAssetHandle != 0u && + currentDescriptor.managedAssetHandle != descriptor.managedAssetHandle) { + runtime->ReleaseExternalManagedObject( + currentDescriptor.managedAssetHandle); + } + Rendering::Pipelines::SetManagedRenderPipelineAssetDescriptor(descriptor); } -MonoString* InternalCall_Rendering_GetRenderPipelineAssetTypeName() { - const Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = - Rendering::Pipelines::GetManagedRenderPipelineAssetDescriptor(); - if (!descriptor.IsValid()) { - return mono_string_new(mono_domain_get(), ""); +MonoObject* InternalCall_Rendering_GetRenderPipelineAsset() { + MonoScriptRuntime* const runtime = GetActiveMonoScriptRuntime(); + if (runtime == nullptr) { + return nullptr; } - std::string assemblyQualifiedName = descriptor.GetFullName(); - assemblyQualifiedName += ", "; - assemblyQualifiedName += descriptor.assemblyName; - return mono_string_new(mono_domain_get(), assemblyQualifiedName.c_str()); + const Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = + Rendering::Pipelines::GetManagedRenderPipelineAssetDescriptor(); + if (!descriptor.IsValid() || + descriptor.managedAssetHandle == 0u) { + return nullptr; + } + + return runtime->GetExternalManagedObject( + descriptor.managedAssetHandle); } int32_t InternalCall_Rendering_ScriptableRenderContext_GetStage( @@ -3041,8 +3108,8 @@ void RegisterInternalCalls() { mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_AddForce", reinterpret_cast(&InternalCall_Rigidbody_AddForce)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_ClearForces", reinterpret_cast(&InternalCall_Rigidbody_ClearForces)); mono_add_internal_call("XCEngine.InternalCalls::Physics_Raycast", reinterpret_cast(&InternalCall_Physics_Raycast)); - mono_add_internal_call("XCEngine.InternalCalls::Rendering_SetRenderPipelineAssetType", reinterpret_cast(&InternalCall_Rendering_SetRenderPipelineAssetType)); - mono_add_internal_call("XCEngine.InternalCalls::Rendering_GetRenderPipelineAssetTypeName", reinterpret_cast(&InternalCall_Rendering_GetRenderPipelineAssetTypeName)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_SetRenderPipelineAsset", reinterpret_cast(&InternalCall_Rendering_SetRenderPipelineAsset)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_GetRenderPipelineAsset", reinterpret_cast(&InternalCall_Rendering_GetRenderPipelineAsset)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetStage)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordScene", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_RecordScene)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordScenePhase", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_RecordScenePhase)); @@ -3106,6 +3173,7 @@ bool MonoScriptRuntime::Initialize() { void MonoScriptRuntime::Shutdown() { Rendering::Pipelines::ClearManagedRenderPipelineBridge(); + Rendering::Pipelines::ClearManagedRenderPipelineAssetDescriptor(); GetManagedScriptableRenderContextRegistry().clear(); GetManagedScriptableRenderContextNextHandle() = 1; GetManagedScriptableRenderPipelineCameraRequestContextRegistry().clear(); @@ -4206,6 +4274,28 @@ uint32_t MonoScriptRuntime::RetainExternalManagedObject(MonoObject* instance) { return gcHandle; } +MonoObject* MonoScriptRuntime::GetExternalManagedObject(uint32_t gcHandle) const { + return GetManagedObject(gcHandle); +} + +uint32_t MonoScriptRuntime::RetainExternalManagedObjectReference( + MonoObject* managedObject) { + return RetainExternalManagedObject(managedObject); +} + +void MonoScriptRuntime::ReleaseExternalManagedObject(uint32_t gcHandle) { + DestroyExternalManagedObject(gcHandle); +} + +bool MonoScriptRuntime::IsScriptableRenderPipelineAssetObject( + MonoObject* managedObject) const { + return managedObject != nullptr && + m_scriptableRenderPipelineAssetClass != nullptr && + IsMonoClassOrSubclass( + mono_object_get_class(managedObject), + m_scriptableRenderPipelineAssetClass); +} + void MonoScriptRuntime::DestroyExternalManagedObject(uint32_t gcHandle) { if (gcHandle == 0) { return; diff --git a/managed/GameScripts/RenderPipelineApiProbe.cs b/managed/GameScripts/RenderPipelineApiProbe.cs index 5eabee37..4d679763 100644 --- a/managed/GameScripts/RenderPipelineApiProbe.cs +++ b/managed/GameScripts/RenderPipelineApiProbe.cs @@ -39,11 +39,13 @@ namespace Gameplay : ScriptableRenderPipelineAsset { public static int CreatePipelineCallCount; + public Vector4 postProcessScale = new Vector4(1.03f, 0.98f, 0.94f, 1.0f); protected override ScriptableRenderPipeline CreatePipeline() { CreatePipelineCallCount++; - return new ManagedForwardRenderPipelineProbe(); + return new ManagedForwardRenderPipelineProbe( + postProcessScale); } protected override void ConfigureCameraFramePlan( @@ -188,6 +190,15 @@ namespace Gameplay public static int RecordMainSceneCallCount; public static int RecordSceneCallCount; public static int RecordPostProcessCallCount; + public static Vector4 LastPostProcessScale; + + private readonly Vector4 m_postProcessScale; + + public ManagedForwardRenderPipelineProbe( + Vector4 postProcessScale) + { + m_postProcessScale = postProcessScale; + } protected override bool SupportsStageRenderGraph( CameraFrameStage stage) @@ -230,9 +241,10 @@ namespace Gameplay if (context.stage == CameraFrameStage.PostProcess) { RecordPostProcessCallCount++; + LastPostProcessScale = m_postProcessScale; return context.RecordFullscreenPass( FullscreenPassDescriptor.CreateColorScale( - new Vector4(1.03f, 0.98f, 0.94f, 1.0f))); + m_postProcessScale)); } return false; @@ -263,36 +275,28 @@ namespace Gameplay public sealed class RenderPipelineApiProbe : MonoBehaviour { - public bool InitialTypeWasNull; - public bool InvalidSelectionRejected; - public bool InvalidSelectionMentionsScriptableBase; + public bool InitialAssetWasNull; public bool SelectionRoundTripSucceeded; - public string SelectedPipelineTypeName = string.Empty; + public bool SelectionReferencePreserved; + public string SelectedPipelineAssetTypeName = string.Empty; public void Start() { - InitialTypeWasNull = GraphicsSettings.renderPipelineAssetType == null; + InitialAssetWasNull = GraphicsSettings.renderPipelineAsset == null; - try - { - GraphicsSettings.renderPipelineAssetType = - typeof(LegacyRenderPipelineApiProbeAsset); - InvalidSelectionRejected = false; - } - catch (System.ArgumentException ex) - { - InvalidSelectionRejected = true; - InvalidSelectionMentionsScriptableBase = - ex.Message.Contains("ScriptableRenderPipelineAsset"); - } - - GraphicsSettings.renderPipelineAssetType = - typeof(RenderPipelineApiProbeAsset); - System.Type selectedType = GraphicsSettings.renderPipelineAssetType; + RenderPipelineApiProbeAsset selectedAssetInstance = + new RenderPipelineApiProbeAsset(); + GraphicsSettings.renderPipelineAsset = selectedAssetInstance; + ScriptableRenderPipelineAsset selectedAsset = + GraphicsSettings.renderPipelineAsset; SelectionRoundTripSucceeded = - selectedType == typeof(RenderPipelineApiProbeAsset); - SelectedPipelineTypeName = selectedType != null - ? selectedType.FullName ?? string.Empty + selectedAsset is RenderPipelineApiProbeAsset; + SelectionReferencePreserved = + object.ReferenceEquals( + selectedAsset, + selectedAssetInstance); + SelectedPipelineAssetTypeName = selectedAsset != null + ? selectedAsset.GetType().FullName ?? string.Empty : string.Empty; } } @@ -304,8 +308,8 @@ namespace Gameplay ManagedRenderPipelineProbeAsset.CreatePipelineCallCount = 0; ManagedRenderPipelineProbe.SupportsStageCallCount = 0; ManagedRenderPipelineProbe.RecordStageCallCount = 0; - GraphicsSettings.renderPipelineAssetType = - typeof(ManagedRenderPipelineProbeAsset); + GraphicsSettings.renderPipelineAsset = + new ManagedRenderPipelineProbeAsset(); } } @@ -318,6 +322,7 @@ namespace Gameplay public int ObservedRecordMainSceneCallCount; public int ObservedRecordSceneCallCount; public int ObservedRecordPostProcessCallCount; + public Vector4 ObservedPostProcessScale; public void Start() { @@ -327,8 +332,13 @@ namespace Gameplay ManagedForwardRenderPipelineProbe.RecordMainSceneCallCount = 0; ManagedForwardRenderPipelineProbe.RecordSceneCallCount = 0; ManagedForwardRenderPipelineProbe.RecordPostProcessCallCount = 0; - GraphicsSettings.renderPipelineAssetType = - typeof(ManagedForwardRenderPipelineProbeAsset); + ManagedForwardRenderPipelineProbe.LastPostProcessScale = + new Vector4(0.0f, 0.0f, 0.0f, 0.0f); + GraphicsSettings.renderPipelineAsset = + new ManagedForwardRenderPipelineProbeAsset + { + postProcessScale = new Vector4(1.11f, 0.97f, 0.93f, 1.0f) + }; } public void Update() @@ -345,6 +355,8 @@ namespace Gameplay ManagedForwardRenderPipelineProbe.RecordSceneCallCount; ObservedRecordPostProcessCallCount = ManagedForwardRenderPipelineProbe.RecordPostProcessCallCount; + ObservedPostProcessScale = + ManagedForwardRenderPipelineProbe.LastPostProcessScale; } } } diff --git a/managed/XCEngine.ScriptCore/GraphicsSettings.cs b/managed/XCEngine.ScriptCore/GraphicsSettings.cs index 5458c4a3..c3a1a4e7 100644 --- a/managed/XCEngine.ScriptCore/GraphicsSettings.cs +++ b/managed/XCEngine.ScriptCore/GraphicsSettings.cs @@ -4,31 +4,10 @@ namespace XCEngine { public static class GraphicsSettings { - public static Type renderPipelineAssetType + public static ScriptableRenderPipelineAsset renderPipelineAsset { - get - { - string assemblyQualifiedName = - InternalCalls.Rendering_GetRenderPipelineAssetTypeName(); - if (string.IsNullOrEmpty(assemblyQualifiedName)) - { - return null; - } - - return Type.GetType(assemblyQualifiedName, throwOnError: false); - } - set - { - if (value != null && - !typeof(ScriptableRenderPipelineAsset).IsAssignableFrom(value)) - { - throw new ArgumentException( - "GraphicsSettings.renderPipelineAssetType must derive from ScriptableRenderPipelineAsset.", - nameof(value)); - } - - InternalCalls.Rendering_SetRenderPipelineAssetType(value); - } + get => InternalCalls.Rendering_GetRenderPipelineAsset(); + set => InternalCalls.Rendering_SetRenderPipelineAsset(value); } } } diff --git a/managed/XCEngine.ScriptCore/InternalCalls.cs b/managed/XCEngine.ScriptCore/InternalCalls.cs index c29e3bc2..3f3c4a77 100644 --- a/managed/XCEngine.ScriptCore/InternalCalls.cs +++ b/managed/XCEngine.ScriptCore/InternalCalls.cs @@ -377,10 +377,12 @@ namespace XCEngine out int hitIsTrigger); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void Rendering_SetRenderPipelineAssetType(Type assetType); + internal static extern void Rendering_SetRenderPipelineAsset( + ScriptableRenderPipelineAsset asset); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern string Rendering_GetRenderPipelineAssetTypeName(); + internal static extern ScriptableRenderPipelineAsset + Rendering_GetRenderPipelineAsset(); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern int Rendering_ScriptableRenderContext_GetStage( diff --git a/tests/scripting/test_mono_script_runtime.cpp b/tests/scripting/test_mono_script_runtime.cpp index 7d1b8cce..b1a89917 100644 --- a/tests/scripting/test_mono_script_runtime.cpp +++ b/tests/scripting/test_mono_script_runtime.cpp @@ -313,21 +313,17 @@ TEST_F(MonoScriptRuntimeTest, ManagedGraphicsSettingsRoundTripsRenderPipelineAss EXPECT_EQ(descriptor.assemblyName, "GameScripts"); EXPECT_EQ(descriptor.namespaceName, "Gameplay"); EXPECT_EQ(descriptor.className, "RenderPipelineApiProbeAsset"); + EXPECT_NE(descriptor.managedAssetHandle, 0u); - bool invalidSelectionRejected = false; - bool invalidSelectionMentionsScriptableBase = false; + bool initialAssetWasNull = false; bool selectionRoundTripSucceeded = false; - std::string selectedPipelineTypeName; + bool selectionReferencePreserved = false; + std::string selectedPipelineAssetTypeName; EXPECT_TRUE(runtime->TryGetFieldValue( script, - "InvalidSelectionRejected", - invalidSelectionRejected)); - EXPECT_TRUE(invalidSelectionRejected); - EXPECT_TRUE(runtime->TryGetFieldValue( - script, - "InvalidSelectionMentionsScriptableBase", - invalidSelectionMentionsScriptableBase)); - EXPECT_TRUE(invalidSelectionMentionsScriptableBase); + "InitialAssetWasNull", + initialAssetWasNull)); + EXPECT_TRUE(initialAssetWasNull); EXPECT_TRUE(runtime->TryGetFieldValue( script, "SelectionRoundTripSucceeded", @@ -335,10 +331,15 @@ TEST_F(MonoScriptRuntimeTest, ManagedGraphicsSettingsRoundTripsRenderPipelineAss EXPECT_TRUE(selectionRoundTripSucceeded); EXPECT_TRUE(runtime->TryGetFieldValue( script, - "SelectedPipelineTypeName", - selectedPipelineTypeName)); + "SelectionReferencePreserved", + selectionReferencePreserved)); + EXPECT_TRUE(selectionReferencePreserved); + EXPECT_TRUE(runtime->TryGetFieldValue( + script, + "SelectedPipelineAssetTypeName", + selectedPipelineAssetTypeName)); EXPECT_EQ( - selectedPipelineTypeName, + selectedPipelineAssetTypeName, "Gameplay.RenderPipelineApiProbeAsset"); } @@ -524,6 +525,7 @@ TEST_F( int observedRecordMainSceneCallCount = 0; int observedRecordSceneCallCount = 0; int observedRecordPostProcessCallCount = 0; + XCEngine::Math::Vector4 observedPostProcessScale = {}; EXPECT_TRUE(runtime->TryGetFieldValue( selectionScript, "ObservedCreatePipelineCallCount", @@ -548,6 +550,10 @@ TEST_F( selectionScript, "ObservedRecordPostProcessCallCount", observedRecordPostProcessCallCount)); + EXPECT_TRUE(runtime->TryGetFieldValue( + selectionScript, + "ObservedPostProcessScale", + observedPostProcessScale)); EXPECT_EQ(observedCreatePipelineCallCount, 1); EXPECT_GT(observedSupportsMainSceneCallCount, 0); @@ -555,6 +561,10 @@ TEST_F( EXPECT_EQ(observedRecordMainSceneCallCount, 1); EXPECT_EQ(observedRecordSceneCallCount, 1); EXPECT_EQ(observedRecordPostProcessCallCount, 1); + EXPECT_FLOAT_EQ(observedPostProcessScale.x, 1.11f); + EXPECT_FLOAT_EQ(observedPostProcessScale.y, 0.97f); + EXPECT_FLOAT_EQ(observedPostProcessScale.z, 0.93f); + EXPECT_FLOAT_EQ(observedPostProcessScale.w, 1.0f); } TEST_F( @@ -859,6 +869,36 @@ TEST_F( EXPECT_FALSE(request.directionalShadow.IsValid()); } +TEST_F( + MonoScriptRuntimeTest, + ManagedRenderPipelineAssetReturnsManagedDefaultFinalColorSettings) { + const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = { + "GameScripts", + "Gameplay", + "ManagedFinalColorRenderPipelineProbeAsset" + }; + + XCEngine::Rendering::Pipelines::ManagedScriptableRenderPipelineAsset asset( + descriptor); + const XCEngine::Rendering::FinalColorSettings settings = + asset.GetDefaultFinalColorSettings(); + + EXPECT_EQ( + settings.outputTransferMode, + XCEngine::Rendering::FinalColorOutputTransferMode::LinearToSRGB); + EXPECT_EQ( + settings.exposureMode, + XCEngine::Rendering::FinalColorExposureMode::Fixed); + EXPECT_FLOAT_EQ(settings.exposureValue, 1.75f); + EXPECT_EQ( + settings.toneMappingMode, + XCEngine::Rendering::FinalColorToneMappingMode::ACES); + EXPECT_FLOAT_EQ(settings.finalColorScale.x, 0.90f); + EXPECT_FLOAT_EQ(settings.finalColorScale.y, 1.10f); + EXPECT_FLOAT_EQ(settings.finalColorScale.z, 1.20f); + EXPECT_FLOAT_EQ(settings.finalColorScale.w, 1.0f); +} + TEST_F(MonoScriptRuntimeTest, ClassFieldDefaultValueQueryReturnsNullComponentReferences) { std::vector fields;