diff --git a/engine/include/XCEngine/Scripting/Mono/MonoScriptRuntime.h b/engine/include/XCEngine/Scripting/Mono/MonoScriptRuntime.h index c435dd1c..1a566cef 100644 --- a/engine/include/XCEngine/Scripting/Mono/MonoScriptRuntime.h +++ b/engine/include/XCEngine/Scripting/Mono/MonoScriptRuntime.h @@ -215,6 +215,7 @@ private: void DiscoverRenderPipelineAssetClassesInImage( const std::string& assemblyName, MonoImage* image); + bool TryConfigureDefaultProjectRenderPipelineAsset(); bool IsMonoBehaviourSubclass(MonoClass* monoClass) const; bool IsSupportedComponentFieldClass(MonoClass* monoClass) const; bool IsScriptComponentFieldClass(MonoClass* monoClass) const; diff --git a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp index fd487582..6d1dc4b5 100644 --- a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp +++ b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp @@ -62,6 +62,10 @@ namespace Scripting { namespace { constexpr const char* kManagedRenderingNamespace = "XCEngine.Rendering"; +constexpr const char* kProjectDefaultRenderPipelineAssetNamespace = + "ProjectScripts"; +constexpr const char* kProjectDefaultRenderPipelineAssetClassName = + "ProjectDefaultRenderPipelineAsset"; struct MonoRootState { MonoDomain* rootDomain = nullptr; @@ -6819,6 +6823,41 @@ bool MonoScriptRuntime::TryGetAvailableRenderPipelineAssetClasses( return true; } +bool MonoScriptRuntime::TryConfigureDefaultProjectRenderPipelineAsset() { + if (!m_initialized) { + return false; + } + + Rendering::GraphicsSettingsState& graphicsSettings = + Rendering::GetGraphicsSettingsState(); + if (graphicsSettings + .GetConfiguredRenderPipelineAssetDescriptor() + .IsValid()) { + return false; + } + + const ScriptClassDescriptor defaultAssetClass = { + m_settings.appAssemblyName, + kProjectDefaultRenderPipelineAssetNamespace, + kProjectDefaultRenderPipelineAssetClassName + }; + const auto defaultAssetIt = std::find( + m_renderPipelineAssetClasses.begin(), + m_renderPipelineAssetClasses.end(), + defaultAssetClass); + if (defaultAssetIt == m_renderPipelineAssetClasses.end()) { + return false; + } + + graphicsSettings.SetConfiguredRenderPipelineAssetDescriptor( + Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor{ + defaultAssetIt->assemblyName, + defaultAssetIt->namespaceName, + defaultAssetIt->className, + 0u}); + return true; +} + std::vector MonoScriptRuntime::GetScriptClassNames(const std::string& assemblyName) const { std::vector classes; if (!TryGetAvailableScriptClasses(classes)) { @@ -6942,6 +6981,7 @@ void MonoScriptRuntime::OnRuntimeStart(Components::Scene* scene) { m_activeScene = nullptr; GetInternalCallDeltaTime() = 0.0f; if (Initialize()) { + TryConfigureDefaultProjectRenderPipelineAsset(); m_activeScene = scene; GetInternalCallScene() = scene; } diff --git a/project/Assets/Scripts/ProjectDefaultRenderPipelineAsset.cs b/project/Assets/Scripts/ProjectDefaultRenderPipelineAsset.cs new file mode 100644 index 00000000..93ee935f --- /dev/null +++ b/project/Assets/Scripts/ProjectDefaultRenderPipelineAsset.cs @@ -0,0 +1,9 @@ +using XCEngine.Rendering.Universal; + +namespace ProjectScripts +{ + public sealed class ProjectDefaultRenderPipelineAsset + : UniversalRenderPipelineAsset + { + } +} diff --git a/project/Assets/Scripts/ProjectDefaultRenderPipelineAsset.cs.meta b/project/Assets/Scripts/ProjectDefaultRenderPipelineAsset.cs.meta new file mode 100644 index 00000000..cc0337f8 --- /dev/null +++ b/project/Assets/Scripts/ProjectDefaultRenderPipelineAsset.cs.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 1 +guid: 920e57abb9730cf689c849aa85f94604 +folderAsset: false +importer: DefaultImporter +importerVersion: 7 diff --git a/tests/scripting/test_mono_script_runtime.cpp b/tests/scripting/test_mono_script_runtime.cpp index 7cb2ed21..7cc448a9 100644 --- a/tests/scripting/test_mono_script_runtime.cpp +++ b/tests/scripting/test_mono_script_runtime.cpp @@ -4055,7 +4055,7 @@ TEST_F( const XCEngine::Rendering::RenderContext renderContext = {}; ASSERT_TRUE(recorder->Initialize(renderContext)); - EXPECT_FALSE( + EXPECT_TRUE( recorder->SupportsStageRenderGraph( XCEngine::Rendering::CameraFrameStage::MainScene)); ASSERT_TRUE( @@ -4070,11 +4070,15 @@ TEST_F( colorDesc.format = static_cast( XCEngine::RHI::Format::R8G8B8A8_UNorm); + XCTest::TestRenderResourceView sourceColorView( + XCEngine::RHI::ResourceViewType::ShaderResource, + XCEngine::RHI::ResourceViewDimension::Texture2D, + XCEngine::RHI::Format::R8G8B8A8_UNorm); const XCEngine::Rendering::RenderGraphTextureHandle sourceColor = graphBuilder.ImportTexture( "ManagedPostProcessSource", colorDesc, - reinterpret_cast(801), + &sourceColorView, {}); const XCEngine::Rendering::RenderGraphTextureHandle outputColor = graphBuilder.CreateTransientTexture("ManagedPostProcessOutput", colorDesc); @@ -4116,10 +4120,10 @@ TEST_F( ASSERT_EQ(compiledGraph.GetPassCount(), 2u); EXPECT_STREQ( compiledGraph.GetPassName(0).CStr(), - "ManagedPostProcess.Pass0"); + "ColorScale"); EXPECT_STREQ( compiledGraph.GetPassName(1).CStr(), - "ManagedPostProcess.Pass1"); + "ColorScale"); recorder->Shutdown(); } @@ -4228,10 +4232,18 @@ TEST_F( XCEngine::Rendering::CameraRenderRequest request = {}; request.context = {}; request.surface = XCEngine::Rendering::RenderSurface(64u, 64u); + XCTest::TestRenderResourceView colorAttachmentView( + XCEngine::RHI::ResourceViewType::RenderTarget, + XCEngine::RHI::ResourceViewDimension::Texture2D, + XCEngine::RHI::Format::R8G8B8A8_UNorm); + XCTest::TestRenderResourceView depthAttachmentView( + XCEngine::RHI::ResourceViewType::DepthStencil, + XCEngine::RHI::ResourceViewDimension::Texture2D, + XCEngine::RHI::Format::D32_Float); request.surface.SetColorAttachment( - reinterpret_cast(1)); + &colorAttachmentView); request.surface.SetDepthAttachment( - reinterpret_cast(2)); + &depthAttachmentView); XCEngine::Rendering::RenderPipelineHost host(asset); const std::vector plans = diff --git a/tests/scripting/test_project_script_assembly.cpp b/tests/scripting/test_project_script_assembly.cpp index 04e7d527..3375dd46 100644 --- a/tests/scripting/test_project_script_assembly.cpp +++ b/tests/scripting/test_project_script_assembly.cpp @@ -21,9 +21,14 @@ #include #ifdef _WIN32 +#ifndef NOMINMAX +#define NOMINMAX +#endif #include #endif +#include "../Fixtures/RenderTestRhiStubs.h" + using namespace XCEngine::Components; using namespace XCEngine::Scripting; @@ -205,6 +210,15 @@ TEST_F(ProjectScriptAssemblyTest, DiscoversProjectAssetRenderPipelineAssetClasse std::vector classes; ASSERT_TRUE(runtime->TryGetAvailableRenderPipelineAssetClasses(classes)); + EXPECT_NE( + std::find( + classes.begin(), + classes.end(), + ScriptClassDescriptor{ + "GameScripts", + "ProjectScripts", + "ProjectDefaultRenderPipelineAsset"}), + classes.end()); EXPECT_NE( std::find( classes.begin(), @@ -225,6 +239,76 @@ TEST_F(ProjectScriptAssemblyTest, DiscoversProjectAssetRenderPipelineAssetClasse classes.end()); } +TEST_F( + ProjectScriptAssemblyTest, + AutoConfiguresProjectDefaultRenderPipelineAssetOnRuntimeStart) { + Scene* runtimeScene = + CreateScene("ProjectDefaultRenderPipelineScene"); + + engine->OnRuntimeStart(runtimeScene); + + const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor + descriptor = + XCEngine::Rendering::Pipelines:: + GetConfiguredManagedRenderPipelineAssetDescriptor(); + ASSERT_TRUE(descriptor.IsValid()); + EXPECT_EQ(descriptor.assemblyName, "GameScripts"); + EXPECT_EQ(descriptor.namespaceName, "ProjectScripts"); + EXPECT_EQ( + descriptor.className, + "ProjectDefaultRenderPipelineAsset"); + + const auto bridge = + XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge(); + ASSERT_NE(bridge, nullptr); + + std::shared_ptr + assetRuntime = bridge->CreateAssetRuntime(descriptor); + ASSERT_NE(assetRuntime, nullptr); + + std::unique_ptr + recorder = assetRuntime->CreateStageRecorder(); + ASSERT_NE(recorder, nullptr); + + const XCEngine::Rendering::RenderContext context = {}; + ASSERT_TRUE(recorder->Initialize(context)); + EXPECT_TRUE( + recorder->SupportsStageRenderGraph( + XCEngine::Rendering::CameraFrameStage::MainScene)); + + recorder->Shutdown(); +} + +TEST_F( + ProjectScriptAssemblyTest, + DoesNotOverrideExplicitProjectRenderPipelineDescriptorOnRuntimeStart) { + const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor + explicitDescriptor = { + "GameScripts", + "ProjectScripts", + "ProjectUniversalFeaturePipelineAsset" + }; + XCEngine::Rendering::Pipelines:: + SetConfiguredManagedRenderPipelineAssetDescriptor( + explicitDescriptor); + + Scene* runtimeScene = + CreateScene("ProjectExplicitRenderPipelineScene"); + engine->OnRuntimeStart(runtimeScene); + + const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor + descriptor = + XCEngine::Rendering::Pipelines:: + GetConfiguredManagedRenderPipelineAssetDescriptor(); + ASSERT_TRUE(descriptor.IsValid()); + EXPECT_EQ(descriptor.assemblyName, explicitDescriptor.assemblyName); + EXPECT_EQ(descriptor.namespaceName, explicitDescriptor.namespaceName); + EXPECT_EQ(descriptor.className, explicitDescriptor.className); + EXPECT_EQ( + descriptor.managedAssetHandle, + explicitDescriptor.managedAssetHandle); +} + TEST_F( ProjectScriptAssemblyTest, CreatesProjectAssetUniversalFeatureRuntimeThroughManagedBridge) { @@ -268,11 +352,15 @@ TEST_F( colorDesc.format = static_cast( XCEngine::RHI::Format::R8G8B8A8_UNorm); + XCTest::TestRenderResourceView sourceColorView( + XCEngine::RHI::ResourceViewType::ShaderResource, + XCEngine::RHI::ResourceViewDimension::Texture2D, + XCEngine::RHI::Format::R8G8B8A8_UNorm); const XCEngine::Rendering::RenderGraphTextureHandle sourceColor = graphBuilder.ImportTexture( "ProjectManagedPostProcessSource", colorDesc, - reinterpret_cast(901), + &sourceColorView, {}); const XCEngine::Rendering::RenderGraphTextureHandle outputColor = graphBuilder.CreateTransientTexture( @@ -316,7 +404,7 @@ TEST_F( ASSERT_EQ(compiledGraph.GetPassCount(), 1u); EXPECT_STREQ( compiledGraph.GetPassName(0).CStr(), - "ProjectManagedPostProcess"); + "Universal.ColorScaleFullscreen"); recorder->Shutdown(); }