123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <BootstrapSystemComponent.h>
- #include <AzCore/Asset/AssetCommon.h>
- #include <AzCore/Component/ComponentApplicationBus.h>
- #include <AzCore/Component/ComponentApplicationLifecycle.h>
- #include <AzCore/Component/Entity.h>
- #include <AzCore/NativeUI/NativeUIRequests.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzCore/std/smart_ptr/make_shared.h>
- #include <AzCore/Utils/Utils.h>
- #include <AzCore/StringFunc/StringFunc.h>
- #include <AzFramework/API/ApplicationAPI.h>
- #include <AzFramework/Components/TransformComponent.h>
- #include <AzFramework/Entity/GameEntityContextBus.h>
- #include <AzFramework/Asset/AssetSystemBus.h>
- #include <ISystem.h>
- #include <Atom/RHI/RHISystemInterface.h>
- #include <Atom/RPI.Reflect/Image/AttachmentImageAsset.h>
- #include <Atom/RPI.Reflect/Image/AttachmentImageAssetCreator.h>
- #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
- #include <Atom/RPI.Public/Pass/Pass.h>
- #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
- #include <Atom/RPI.Public/RenderPipeline.h>
- #include <Atom/RPI.Public/ViewportContextBus.h>
- #include <Atom/RPI.Public/RPISystemInterface.h>
- #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
- #include <Atom/RPI.Public/Shader/ShaderSystem.h>
- #include <Atom/Bootstrap/DefaultWindowBus.h>
- #include <Atom/Bootstrap/BootstrapNotificationBus.h>
- #include <Atom/RPI.Reflect/System/AnyAsset.h>
- #include <AzCore/Console/IConsole.h>
- #include <BootstrapSystemComponent_Traits_Platform.h>
- void cvar_r_renderPipelinePath_Changed(const AZ::CVarFixedString& newPipelinePath)
- {
- auto viewportContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
- if (!viewportContextManager)
- {
- return;
- }
- auto viewportContext = viewportContextManager->GetDefaultViewportContext();
- if (!viewportContext)
- {
- return;
- }
- AZ::Data::Asset<AZ::RPI::AnyAsset> pipelineAsset =
- AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::AnyAsset>(newPipelinePath.data(), AZ::RPI::AssetUtils::TraceLevel::Error);
- if (pipelineAsset)
- {
- AZ::RPI::RenderPipelineDescriptor renderPipelineDescriptor =
- *AZ::RPI::GetDataFromAnyAsset<AZ::RPI::RenderPipelineDescriptor>(pipelineAsset); // Copy descriptor from asset
- AZ::Render::Bootstrap::RequestBus::Broadcast(&AZ::Render::Bootstrap::RequestBus::Events::SwitchRenderPipeline, renderPipelineDescriptor, viewportContext);
- }
- else
- {
- AZ_Warning("SetDefaultPipeline", false, "Failed to switch default render pipeline to %s: can't load the asset", newPipelinePath.data());
- }
- }
- void cvar_r_antiAliasing_Changed(const AZ::CVarFixedString& newAntiAliasing)
- {
- auto viewportContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
- if (!viewportContextManager)
- {
- return;
- }
- auto viewportContext = viewportContextManager->GetDefaultViewportContext();
- if (!viewportContext)
- {
- return;
- }
- AZ::Render::Bootstrap::RequestBus::Broadcast(&AZ::Render::Bootstrap::RequestBus::Events::SwitchAntiAliasing, newAntiAliasing.c_str(), viewportContext);
- }
- void cvar_r_multiSample_Changed(const uint16_t& newSampleCount)
- {
- auto viewportContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
- if (!viewportContextManager)
- {
- return;
- }
- auto viewportContext = viewportContextManager->GetDefaultViewportContext();
- if (!viewportContext)
- {
- return;
- }
- if (newSampleCount > 0 && ((newSampleCount & (newSampleCount - 1))) == 0)
- {
- AZ::Render::Bootstrap::RequestBus::Broadcast(&AZ::Render::Bootstrap::RequestBus::Events::SwitchMultiSample, AZStd::clamp(newSampleCount, uint16_t(1), uint16_t(8)), viewportContext);
- }
- else
- {
- AZ_Warning("SetMultiSampleCount", false, "Failed to set multi-sample count %d: invalid multi-sample count", newSampleCount);
- }
- }
- AZ_CVAR(AZ::CVarFixedString, r_renderPipelinePath, AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME, cvar_r_renderPipelinePath_Changed, AZ::ConsoleFunctorFlags::DontReplicate, "The asset (.azasset) path for default render pipeline");
- AZ_CVAR(AZ::CVarFixedString, r_default_openxr_pipeline_name, "passes/MultiViewRenderPipeline.azasset", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default openXr render pipeline name");
- AZ_CVAR(AZ::CVarFixedString, r_default_openxr_left_pipeline_name, "passes/XRLeftRenderPipeline.azasset", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default openXr Left eye render pipeline name");
- AZ_CVAR(AZ::CVarFixedString, r_default_openxr_right_pipeline_name, "passes/XRRightRenderPipeline.azasset", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default openXr Right eye render pipeline name");
- AZ_CVAR(uint32_t, r_width, 1920, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Starting window width in pixels.");
- AZ_CVAR(uint32_t, r_height, 1080, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Starting window height in pixels.");
- AZ_CVAR(uint32_t, r_fullscreen, false, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Starting fullscreen state.");
- AZ_CVAR(uint32_t, r_resolutionMode, 0, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "0: render resolution same as window client area size, 1: render resolution use the values specified by r_width and r_height");
- void cvar_r_renderScale_Changed(const float& newRenderScale)
- {
- AZ_Error("AtomBootstrap", newRenderScale > 0, "RenderScale should be greater than 0");
- if (newRenderScale > 0)
- {
- AzFramework::WindowSize newSize =
- AzFramework::WindowSize(static_cast<uint32_t>(r_width * newRenderScale), static_cast<uint32_t>(r_height * newRenderScale));
- AzFramework::WindowRequestBus::Broadcast(&AzFramework::WindowRequestBus::Events::SetEnableCustomizedResolution, true);
- AzFramework::WindowRequestBus::Broadcast(&AzFramework::WindowRequestBus::Events::SetRenderResolution, newSize);
- }
- }
- AZ_CVAR(float, r_renderScale, 1.0f, cvar_r_renderScale_Changed, AZ::ConsoleFunctorFlags::DontReplicate, "Scale to apply to the window resolution.");
- AZ_CVAR(AZ::CVarFixedString, r_antiAliasing, "", cvar_r_antiAliasing_Changed, AZ::ConsoleFunctorFlags::DontReplicate, "The anti-aliasing to be used for the current render pipeline. Available options: MSAA, TAA, SMAA");
- AZ_CVAR(uint16_t, r_multiSampleCount, 0, cvar_r_multiSample_Changed, AZ::ConsoleFunctorFlags::DontReplicate, "The multi-sample count to be used for the current render pipeline."); // 0 stands for unchanged, load the default setting from the pipeline itself
- namespace AZ
- {
- namespace Render
- {
- namespace Bootstrap
- {
- void BootstrapSystemComponent::Reflect(ReflectContext* context)
- {
- if (SerializeContext* serialize = azrtti_cast<SerializeContext*>(context))
- {
- serialize->Class<BootstrapSystemComponent, Component>()
- ->Version(1)
- ;
- if (EditContext* ec = serialize->GetEditContext())
- {
- ec->Class<BootstrapSystemComponent>("Atom RPI", "Atom Renderer")
- ->ClassElement(Edit::ClassElements::EditorData, "")
- ->Attribute(Edit::Attributes::AutoExpand, true)
- ;
- }
- }
- }
- void BootstrapSystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
- {
- provided.push_back(AZ_CRC("BootstrapSystemComponent", 0xb8f32711));
- }
- void BootstrapSystemComponent::GetRequiredServices(ComponentDescriptor::DependencyArrayType& required)
- {
- required.push_back(AZ_CRC("RPISystem", 0xf2add773));
- required.push_back(AZ_CRC("SceneSystemComponentService", 0xd8975435));
- }
- void BootstrapSystemComponent::GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent)
- {
- dependent.push_back(AZ_CRC("ImGuiSystemComponent", 0x2f08b9a7));
- dependent.push_back(AZ_CRC("PrimitiveSystemComponent", 0xc860fa59));
- dependent.push_back(AZ_CRC("MeshSystemComponent", 0x21e5bbb6));
- dependent.push_back(AZ_CRC("CoreLightsService", 0x91932ef6));
- dependent.push_back(AZ_CRC("DynamicDrawService", 0x023c1673));
- dependent.push_back(AZ_CRC("CommonService", 0x6398eec4));
- dependent.push_back(AZ_CRC_CE("HairService"));
- }
- void BootstrapSystemComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible)
- {
- incompatible.push_back(AZ_CRC("BootstrapSystemComponent", 0xb8f32711));
- }
- BootstrapSystemComponent::BootstrapSystemComponent()
- {
- }
- BootstrapSystemComponent::~BootstrapSystemComponent()
- {
- m_viewportContext.reset();
- }
- //! Helper function that parses the command line arguments
- //! looking for r_width, r_height and r_fullscreen.
- //! It is important to call this before using r_width, r_height or r_fullscreen
- //! because at the moment this system component initializes before Legacy System.cpp gets to parse
- //! command line arguments into cvars.
- static void UpdateCVarsFromCommandLine()
- {
- AZ::CommandLine* pCmdLine = nullptr;
- ComponentApplicationBus::BroadcastResult(pCmdLine, &AZ::ComponentApplicationBus::Events::GetAzCommandLine);
- if (!pCmdLine)
- {
- return;
- }
- const AZStd::string fullscreenCvarName("r_fullscreen");
- if (pCmdLine->HasSwitch(fullscreenCvarName))
- {
- auto numValues = pCmdLine->GetNumSwitchValues(fullscreenCvarName);
- if (numValues > 0)
- {
- auto valueStr = pCmdLine->GetSwitchValue(fullscreenCvarName);
- if (AZ::StringFunc::LooksLikeBool(valueStr.c_str()))
- {
- r_fullscreen = AZ::StringFunc::ToBool(valueStr.c_str());
- }
- }
- }
- const AZStd::string widthCvarName("r_width");
- if (pCmdLine->HasSwitch(widthCvarName))
- {
- auto numValues = pCmdLine->GetNumSwitchValues(widthCvarName);
- if (numValues > 0)
- {
- auto valueStr = pCmdLine->GetSwitchValue(widthCvarName);
- if (AZ::StringFunc::LooksLikeInt(valueStr.c_str()))
- {
- auto width = AZ::StringFunc::ToInt(valueStr.c_str());
- if (width > 0)
- {
- r_width = width;
- }
- }
- }
- }
- const AZStd::string heightCvarName("r_height");
- if (pCmdLine->HasSwitch(heightCvarName))
- {
- auto numValues = pCmdLine->GetNumSwitchValues(heightCvarName);
- if (numValues > 0)
- {
- auto valueStr = pCmdLine->GetSwitchValue(heightCvarName);
- if (AZ::StringFunc::LooksLikeInt(valueStr.c_str()))
- {
- auto height = AZ::StringFunc::ToInt(valueStr.c_str());
- if (height > 0)
- {
- r_height = height;
- }
- }
- }
- }
- const AZStd::string resolutionModeCvarName("r_resolutionMode");
- if (pCmdLine->HasSwitch(resolutionModeCvarName))
- {
- auto numValues = pCmdLine->GetNumSwitchValues(resolutionModeCvarName);
- if (numValues > 0)
- {
- auto valueStr = pCmdLine->GetSwitchValue(resolutionModeCvarName);
- if (AZ::StringFunc::LooksLikeInt(valueStr.c_str()))
- {
- auto resolutionMode = AZ::StringFunc::ToInt(valueStr.c_str());
- if (resolutionMode >= 0)
- {
- r_resolutionMode = resolutionMode;
- }
- }
- }
- }
- const AZStd::string renderScaleCvarName("r_renderScale");
- if (pCmdLine->HasSwitch(renderScaleCvarName))
- {
- auto numValues = pCmdLine->GetNumSwitchValues(renderScaleCvarName);
- if (numValues > 0)
- {
- auto valueStr = pCmdLine->GetSwitchValue(renderScaleCvarName);
- if (AZ::StringFunc::LooksLikeFloat(valueStr.c_str()))
- {
- auto renderScale = AZ::StringFunc::ToFloat(valueStr.c_str());
- if (renderScale > 0)
- {
- r_renderScale = renderScale;
- }
- }
- }
- }
- const AZStd::string multiSampleCvarName("r_multiSampleCount");
- if (pCmdLine->HasSwitch(multiSampleCvarName))
- {
- auto numValues = pCmdLine->GetNumSwitchValues(multiSampleCvarName);
- if (numValues > 0)
- {
- auto valueStr = pCmdLine->GetSwitchValue(multiSampleCvarName);
- if (AZ::StringFunc::LooksLikeInt(valueStr.c_str()))
- {
- auto multiSample = AZ::StringFunc::ToInt(valueStr.c_str());
- if (multiSample > 0)
- {
- r_multiSampleCount = static_cast<uint16_t>(multiSample);
- }
- }
- }
- }
- }
- void BootstrapSystemComponent::Activate()
- {
- // Create a native window only if it's a launcher (or standalone)
- // LY editor create its own window which we can get its handle through AzFramework::WindowSystemNotificationBus::Handler's OnWindowCreated() function
- AZ::ApplicationTypeQuery appType;
- ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
- if (appType.IsHeadless())
- {
- m_nativeWindow = nullptr;
- }
- else if (!appType.IsValid() || appType.IsGame())
- {
- // GFX TODO - investigate window creation being part of the GameApplication.
- auto projectTitle = AZ::Utils::GetProjectDisplayName();
- // It is important to call this before using r_width, r_height or r_fullscreen
- // because at the moment this system component initializes before Legacy System.cpp gets to parse
- // command line arguments into cvars.
- UpdateCVarsFromCommandLine();
- auto windowSize = GetWindowResolution();
- m_nativeWindow = AZStd::make_unique<AzFramework::NativeWindow>(projectTitle.c_str(), AzFramework::WindowGeometry(0, 0, windowSize.m_width, windowSize.m_height));
- AZ_Assert(m_nativeWindow, "Failed to create the game window\n");
- m_nativeWindow->Activate();
- m_windowHandle = m_nativeWindow->GetWindowHandle();
- }
- else
- {
- // Disable default scene creation for non-games projects
- // This can be manually overridden via the DefaultWindowBus.
- m_createDefaultScene = false;
- }
- TickBus::Handler::BusConnect();
- // Listen for window system requests (e.g. requests for default window handle)
- AzFramework::WindowSystemRequestBus::Handler::BusConnect();
- // Listen for window system notifications (e.g. window being created by Editor)
- AzFramework::WindowSystemNotificationBus::Handler::BusConnect();
- Render::Bootstrap::DefaultWindowBus::Handler::BusConnect();
- Render::Bootstrap::RequestBus::Handler::BusConnect();
- // Listen for application's window creation/destruction (e.g. window is created/destroyed on Android when suspending the app)
- AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
- // delay one frame for Initialize which asset system is ready by then
- AZ::TickBus::QueueFunction(
- [this]()
- {
- Initialize();
- SetWindowResolution();
- });
- }
- void BootstrapSystemComponent::Deactivate()
- {
- AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect();
- Render::Bootstrap::RequestBus::Handler::BusDisconnect();
- Render::Bootstrap::DefaultWindowBus::Handler::BusDisconnect();
- AzFramework::WindowSystemRequestBus::Handler::BusDisconnect();
- AzFramework::WindowSystemNotificationBus::Handler::BusDisconnect();
- TickBus::Handler::BusDisconnect();
- m_brdfTexture = nullptr;
- RemoveRenderPipeline();
- DestroyDefaultScene();
- m_viewportContext.reset();
- m_nativeWindow = nullptr;
- m_windowHandle = nullptr;
- }
- void BootstrapSystemComponent::Initialize()
- {
- if (m_isInitialized)
- {
- return;
- }
- m_isInitialized = true;
- if (!RPI::RPISystemInterface::Get()->IsInitialized())
- {
- AZ::OSString msgBoxMessage;
- msgBoxMessage.append("RPI System could not initialize correctly. Check log for detail.");
- AZ::NativeUI::NativeUIRequestBus::Broadcast(
- &AZ::NativeUI::NativeUIRequestBus::Events::DisplayOkDialog, "O3DE Fatal Error", msgBoxMessage.c_str(), false);
- AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::ExitMainLoop);
- return;
- }
- // In the case of the game we want to call create and register the scene as a soon as we can
- // because a level could be loaded in autoexec.cfg and that will assert if there is no scene registered
- // to get the feature processors for the components. So we can't wait until the tick (whereas the Editor wants to wait)
- if (m_createDefaultScene)
- {
- CreateDefaultScene();
- }
- if (m_windowHandle)
- {
- CreateViewportContext();
- if (m_createDefaultScene)
- {
- CreateDefaultRenderPipeline();
- }
- }
- }
- void BootstrapSystemComponent::OnWindowCreated(AzFramework::NativeWindowHandle windowHandle)
- {
- // only handle the first window (default) created
- if (m_windowHandle == nullptr)
- {
- m_windowHandle = windowHandle;
- if (m_isInitialized)
- {
- CreateViewportContext();
- if (m_createDefaultScene)
- {
- CreateDefaultRenderPipeline();
- }
- }
- SetWindowResolution();
- }
- }
- void BootstrapSystemComponent::OnApplicationWindowCreated()
- {
- if (!m_nativeWindow)
- {
- auto projectTitle = AZ::Utils::GetProjectDisplayName();
- auto windowSize = GetWindowResolution();
- m_nativeWindow = AZStd::make_unique<AzFramework::NativeWindow>(projectTitle.c_str(), AzFramework::WindowGeometry(0, 0, windowSize.m_width, windowSize.m_height));
- AZ_Assert(m_nativeWindow, "Failed to create the game window\n");
- m_nativeWindow->Activate();
- OnWindowCreated(m_nativeWindow->GetWindowHandle());
- }
- }
- void BootstrapSystemComponent::OnApplicationWindowDestroy()
- {
- m_nativeWindow = nullptr;
- }
- void BootstrapSystemComponent::CreateViewportContext()
- {
- RHI::Device* device = RHI::RHISystemInterface::Get()->GetDevice();
- RPI::ViewportContextRequestsInterface::CreationParameters params;
- params.device = device;
- params.windowHandle = m_windowHandle;
- params.renderScene = m_defaultScene;
- // Setting the default ViewportContextID to an arbitrary and otherwise invalid (negative) value to ensure its uniqueness
- params.id = -10;
- auto viewContextManager = AZ::Interface<RPI::ViewportContextRequestsInterface>::Get();
- m_viewportContext = viewContextManager->CreateViewportContext(
- viewContextManager->GetDefaultViewportContextName(), params);
- DefaultWindowNotificationBus::Broadcast(&DefaultWindowNotificationBus::Events::DefaultWindowCreated);
- // Listen to window notification so we can request exit application when window closes
- AzFramework::WindowNotificationBus::Handler::BusConnect(GetDefaultWindowHandle());
- }
- void BootstrapSystemComponent::SetWindowResolution()
- {
- if (m_nativeWindow)
- {
- // wait until swapchain has been created before setting fullscreen state
- if (r_resolutionMode > 0u)
- {
- m_nativeWindow->SetEnableCustomizedResolution(true);
- m_nativeWindow->SetRenderResolution(GetWindowResolution());
- }
- else
- {
- m_nativeWindow->SetEnableCustomizedResolution(false);
- }
- m_nativeWindow->SetFullScreenState(r_fullscreen);
- }
- }
- AZ::RPI::ScenePtr BootstrapSystemComponent::GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene)
- {
- // Get or create a weak pointer to our scene
- // If it's valid, we're done, if not we need to create an Atom scene and update our scene map
- auto& atomSceneHandle = m_azSceneToAtomSceneMap[scene];
- if (!atomSceneHandle.expired())
- {
- return atomSceneHandle.lock();
- }
- // Create and register a scene with all available feature processors
- RPI::SceneDescriptor sceneDesc;
- sceneDesc.m_nameId = AZ::Name("Main");
- AZ::RPI::ScenePtr atomScene = RPI::Scene::CreateScene(sceneDesc);
- atomScene->EnableAllFeatureProcessors();
- atomScene->Activate();
- // Register scene to RPI system so it will be processed/rendered per tick
- RPI::RPISystemInterface::Get()->RegisterScene(atomScene);
- scene->SetSubsystem(atomScene);
- atomSceneHandle = atomScene;
- return atomScene;
- }
- void BootstrapSystemComponent::CreateDefaultScene()
- {
- // Bind atomScene to the GameEntityContext's AzFramework::Scene
- m_defaultFrameworkScene = AzFramework::SceneSystemInterface::Get()->GetScene(AzFramework::Scene::MainSceneName);
- // This should never happen unless scene creation has changed.
- AZ_Assert(m_defaultFrameworkScene, "Error: Scenes missing during system component initialization");
- m_sceneRemovalHandler = AzFramework::Scene::RemovalEvent::Handler(
- [this](AzFramework::Scene&, AzFramework::Scene::RemovalEventType eventType)
- {
- if (eventType == AzFramework::Scene::RemovalEventType::Zombified)
- {
- m_defaultFrameworkScene.reset();
- }
- });
- m_defaultFrameworkScene->ConnectToEvents(m_sceneRemovalHandler);
- m_defaultScene = GetOrCreateAtomSceneFromAzScene(m_defaultFrameworkScene.get());
- }
- bool BootstrapSystemComponent::EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext)
- {
- AZ::RPI::XRRenderingInterface* xrSystem = AZ::RPI::RPISystemInterface::Get()->GetXRSystem();
- const bool loadDefaultRenderPipeline = !xrSystem || xrSystem->GetRHIXRRenderingInterface()->IsDefaultRenderPipelineNeeded();
- AZ::RHI::MultisampleState multisampleState;
- // Load the main default pipeline if applicable
- if (loadDefaultRenderPipeline)
- {
- AZ::CVarFixedString pipelineName = static_cast<AZ::CVarFixedString>(r_renderPipelinePath);
- if (xrSystem)
- {
- // When running launcher on PC having an XR system present then the default render pipeline is suppose to reflect
- // what's being rendered into XR device. XR render pipeline uses multiview render pipeline.
- AZ::ApplicationTypeQuery appType;
- ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
- if (appType.IsGame())
- {
- pipelineName = r_default_openxr_pipeline_name;
- }
- }
- RPI::RenderPipelinePtr renderPipeline = LoadPipeline(scene, viewportContext, pipelineName, AZ::RPI::ViewType::Default, multisampleState);
- if (!renderPipeline)
- {
- return false;
- }
- AZ::CVarFixedString antiAliasing = static_cast<AZ::CVarFixedString>(r_antiAliasing);
- if (antiAliasing != "")
- {
- renderPipeline->SetActiveAAMethod(antiAliasing.c_str());
- }
- // As part of our initialization we need to create the BRDF texture generation pipeline
- AZ::RPI::RenderPipelineDescriptor pipelineDesc;
- pipelineDesc.m_mainViewTagName = "MainCamera";
- pipelineDesc.m_name = AZStd::string::format("BRDFTexturePipeline_%i", viewportContext->GetId());
- pipelineDesc.m_rootPassTemplate = "BRDFTexturePipeline";
- pipelineDesc.m_executeOnce = true;
- // Save a reference to the generated BRDF texture so it doesn't get deleted if all the passes refering to it get deleted
- // and it's ref count goes to zero
- if (!m_brdfTexture)
- {
- const AZStd::shared_ptr<const RPI::PassTemplate> brdfTextureTemplate =
- RPI::PassSystemInterface::Get()->GetPassTemplate(Name("BRDFTextureTemplate"));
- Data::Asset<RPI::AttachmentImageAsset> brdfImageAsset = RPI::AssetUtils::LoadAssetById<RPI::AttachmentImageAsset>(
- brdfTextureTemplate->m_imageAttachments[0].m_assetRef.m_assetId, RPI::AssetUtils::TraceLevel::Error);
- if (brdfImageAsset.IsReady())
- {
- m_brdfTexture = RPI::AttachmentImage::FindOrCreate(brdfImageAsset);
- }
- }
- if (!scene->GetRenderPipeline(AZ::Name(pipelineDesc.m_name)))
- {
- RPI::RenderPipelinePtr brdfTexturePipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc);
- scene->AddRenderPipeline(brdfTexturePipeline);
- }
- }
- // Load XR pipelines if applicable
- if (xrSystem)
- {
- for (AZ::u32 i = 0; i < xrSystem->GetNumViews(); i++)
- {
- const AZ::RPI::ViewType viewType = (i == 0)
- ? AZ::RPI::ViewType::XrLeft
- : AZ::RPI::ViewType::XrRight;
- const AZStd::string_view xrPipelineAssetName = (viewType == AZ::RPI::ViewType::XrLeft)
- ? static_cast<AZ::CVarFixedString>(r_default_openxr_left_pipeline_name)
- : static_cast<AZ::CVarFixedString>(r_default_openxr_right_pipeline_name);
- if (!LoadPipeline(scene, viewportContext, xrPipelineAssetName, viewType, multisampleState))
- {
- return false;
- }
- }
- }
- // Apply MSAA state to all the render pipelines.
- // It's important to do this after all the pipelines have
- // been created so the same values are applied to all.
- // As it cannot be applied MSAA values per pipeline,
- // it's setting the MSAA state from the last pipeline loaded.
- const auto cvarMultiSample = static_cast<uint16_t>(r_multiSampleCount);
- if (cvarMultiSample > 0 && ((cvarMultiSample & (cvarMultiSample - 1))) == 0)
- {
- multisampleState.m_samples = static_cast<uint16_t>(cvarMultiSample);
- }
- AZ::RPI::RPISystemInterface::Get()->SetApplicationMultisampleState(multisampleState);
- // Send notification when the scene and its pipeline are ready.
- // Use the first created pipeline's scene as our default scene for now to allow
- // consumers waiting on scene availability to initialize.
- if (!m_defaultSceneReady)
- {
- m_defaultScene = scene;
- Render::Bootstrap::NotificationBus::Broadcast(
- &Render::Bootstrap::NotificationBus::Handler::OnBootstrapSceneReady, m_defaultScene.get());
- m_defaultSceneReady = true;
- }
- return true;
- }
- void BootstrapSystemComponent::SwitchRenderPipeline(const AZ::RPI::RenderPipelineDescriptor& newRenderPipelineDesc, AZ::RPI::ViewportContextPtr viewportContext)
- {
- AZ::RPI::RenderPipelineDescriptor pipelineDescriptor = newRenderPipelineDesc;
- pipelineDescriptor.m_name =
- AZStd::string::format("%s_%i", pipelineDescriptor.m_name.c_str(), viewportContext->GetId());
- if (pipelineDescriptor.m_renderSettings.m_multisampleState.m_customPositionsCount &&
- !RHI::RHISystemInterface::Get()->GetDevice()->GetFeatures().m_customSamplePositions)
- {
- // Disable custom sample positions because they are not supported
- AZ_Warning(
- "BootstrapSystemComponent",
- false,
- "Disabling custom sample positions for pipeline %s because they are not supported on this device",
- pipelineDescriptor.m_name.c_str());
- pipelineDescriptor.m_renderSettings.m_multisampleState.m_customPositions = {};
- pipelineDescriptor.m_renderSettings.m_multisampleState.m_customPositionsCount = 0;
- }
- // Create new render pipeline
- auto oldRenderPipeline = viewportContext->GetRenderScene()->GetDefaultRenderPipeline();
- RPI::RenderPipelinePtr newRenderPipeline = RPI::RenderPipeline::CreateRenderPipelineForWindow(
- pipelineDescriptor, *viewportContext->GetWindowContext().get(), AZ::RPI::ViewType::Default);
- // Switch render pipeline
- viewportContext->GetRenderScene()->RemoveRenderPipeline(oldRenderPipeline->GetId());
- auto view = oldRenderPipeline->GetDefaultView();
- oldRenderPipeline = nullptr;
- viewportContext->GetRenderScene()->AddRenderPipeline(newRenderPipeline);
- newRenderPipeline->SetDefaultView(view);
- AZ::RPI::RPISystemInterface::Get()->SetApplicationMultisampleState(newRenderPipeline->GetRenderSettings().m_multisampleState);
- }
- void BootstrapSystemComponent::SwitchAntiAliasing(const AZStd::string& newAntiAliasing, AZ::RPI::ViewportContextPtr viewportContext)
- {
- auto defaultRenderPipeline = viewportContext->GetRenderScene()->GetDefaultRenderPipeline();
- defaultRenderPipeline->SetActiveAAMethod(newAntiAliasing);
- }
- void BootstrapSystemComponent::SwitchMultiSample(const uint16_t newSampleCount, AZ::RPI::ViewportContextPtr viewportContext)
- {
- auto multiSampleStete = viewportContext->GetRenderScene()->GetDefaultRenderPipeline()->GetRenderSettings().m_multisampleState;
- multiSampleStete.m_samples = newSampleCount;
- AZ::RPI::RPISystemInterface::Get()->SetApplicationMultisampleState(multiSampleStete);
- }
- RPI::RenderPipelinePtr BootstrapSystemComponent::LoadPipeline( AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext,
- AZStd::string_view pipelineName, AZ::RPI::ViewType viewType, AZ::RHI::MultisampleState& multisampleState)
- {
- // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene.
- // When running with an Asset Processor, this will attempt to compile the asset before loading it.
- Data::Asset<RPI::AnyAsset> pipelineAsset =
- RPI::AssetUtils::LoadCriticalAsset<RPI::AnyAsset>(pipelineName.data(), RPI::AssetUtils::TraceLevel::Error);
- if (pipelineAsset)
- {
- RPI::RenderPipelineDescriptor renderPipelineDescriptor =
- *RPI::GetDataFromAnyAsset<RPI::RenderPipelineDescriptor>(pipelineAsset); // Copy descriptor from asset
- pipelineAsset.Release();
- renderPipelineDescriptor.m_name =
- AZStd::string::format("%s_%i", renderPipelineDescriptor.m_name.c_str(), viewportContext->GetId());
- if (renderPipelineDescriptor.m_renderSettings.m_multisampleState.m_customPositionsCount &&
- !RHI::RHISystemInterface::Get()->GetDevice()->GetFeatures().m_customSamplePositions)
- {
- // Disable custom sample positions because they are not supported
- AZ_Warning(
- "BootstrapSystemComponent",
- false,
- "Disabling custom sample positions for pipeline %s because they are not supported on this device",
- pipelineName.data());
- renderPipelineDescriptor.m_renderSettings.m_multisampleState.m_customPositions = {};
- renderPipelineDescriptor.m_renderSettings.m_multisampleState.m_customPositionsCount = 0;
- }
- multisampleState = renderPipelineDescriptor.m_renderSettings.m_multisampleState;
- // Create and add render pipeline to the scene (when not added already)
- RPI::RenderPipelinePtr renderPipeline = scene->GetRenderPipeline(AZ::Name(renderPipelineDescriptor.m_name));
- if (!renderPipeline)
- {
- renderPipeline = RPI::RenderPipeline::CreateRenderPipelineForWindow(
- renderPipelineDescriptor, *viewportContext->GetWindowContext().get(), viewType);
- scene->AddRenderPipeline(renderPipeline);
- }
- return renderPipeline;
- }
- else
- {
- AZ_Error("AtomBootstrap", false, "Pipeline file failed to load from path: %s.", pipelineName.data());
- return nullptr;
- }
- }
- AzFramework::WindowSize BootstrapSystemComponent::GetWindowResolution() const
- {
- float scale = AZStd::max(static_cast<float>(r_renderScale), 0.f);
- return AzFramework::WindowSize(static_cast<uint32_t>(r_width * scale), static_cast<uint32_t>(r_height * scale));
- }
- void BootstrapSystemComponent::CreateDefaultRenderPipeline()
- {
- EnsureDefaultRenderPipelineInstalledForScene(m_defaultScene, m_viewportContext);
- const auto pipeline = m_defaultScene->FindRenderPipelineForWindow(m_viewportContext->GetWindowHandle());
- if (pipeline)
- {
- m_renderPipelineId = pipeline->GetId();
- }
- }
- void BootstrapSystemComponent::DestroyDefaultScene()
- {
- if (m_defaultScene)
- {
- RPI::RPISystemInterface::Get()->UnregisterScene(m_defaultScene);
- // Unbind m_defaultScene to the GameEntityContext's AzFramework::Scene
- if (m_defaultFrameworkScene)
- {
- m_defaultFrameworkScene->UnsetSubsystem(m_defaultScene);
- }
- m_defaultScene = nullptr;
- m_defaultFrameworkScene = nullptr;
- }
- }
- void BootstrapSystemComponent::RemoveRenderPipeline()
- {
- if (m_defaultScene && m_defaultScene->GetRenderPipeline(m_renderPipelineId))
- {
- m_defaultScene->RemoveRenderPipeline(m_renderPipelineId);
- }
- m_renderPipelineId = "";
- }
- void BootstrapSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time)
- {
- // Temp: When running in the launcher without the legacy renderer
- // we need to call RenderTick on the viewport context each frame.
- if (m_viewportContext)
- {
- AZ::ApplicationTypeQuery appType;
- ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
- if (appType.IsGame())
- {
- m_viewportContext->RenderTick();
- }
- }
- }
- int BootstrapSystemComponent::GetTickOrder()
- {
- return TICK_LAST;
- }
- void BootstrapSystemComponent::OnWindowClosed()
- {
- m_windowHandle = nullptr;
- m_viewportContext.reset();
- // On some platforms (e.g. Android) the main window is destroyed when the app is suspended
- // but this doesn't mean that we need to exit the app. The window will be recreated when the app
- // is resumed.
- #if AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_EXIT_ON_WINDOW_CLOSE
- AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::ExitMainLoop);
- #endif
- AzFramework::WindowNotificationBus::Handler::BusDisconnect();
- }
- AzFramework::NativeWindowHandle BootstrapSystemComponent::GetDefaultWindowHandle()
- {
- return m_windowHandle;
- }
- AZStd::shared_ptr<RPI::WindowContext> BootstrapSystemComponent::GetDefaultWindowContext()
- {
- return m_viewportContext ? m_viewportContext->GetWindowContext() : nullptr;
- }
- void BootstrapSystemComponent::SetCreateDefaultScene(bool create)
- {
- m_createDefaultScene = create;
- }
- } // namespace Bootstrap
- } // namespace Render
- } // namespace AZ
|