| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /*
- * 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
- *
- */
- /**
- * @file RPISystemComponent.cpp
- * @brief Contains the definition of the RPISystemComponent methods that aren't defined as inline
- */
- #include <RPI.Private/RPISystemComponent.h>
- #include <Atom/RHI/Factory.h>
- #include <AzCore/Asset/AssetManager.h>
- #include <AzCore/IO/IOUtils.h>
- #include <AzCore/NativeUI/NativeUIRequests.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzCore/Settings/SettingsRegistry.h>
- #include <AzCore/PlatformId/PlatformId.h>
- #include <AzFramework/API/ApplicationAPI.h>
- #include <AzFramework/CommandLine/CommandLine.h>
- #include <AzFramework/Components/ConsoleBus.h>
- #ifdef RPI_EDITOR
- #include <Atom/RPI.Edit/Material/MaterialFunctorSourceDataRegistration.h>
- #endif
- namespace AZ
- {
- namespace RPI
- {
- void RPISystemComponent::Reflect(ReflectContext* context)
- {
- if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
- {
- serializeContext
- ->Class<RPISystemComponent, Component>()
- ->Version(0)
- ->Field("RpiDescriptor", &RPISystemComponent::m_rpiDescriptor)
- ;
- if (AZ::EditContext* ec = serializeContext->GetEditContext())
- {
- ec->Class<RPISystemComponent>("Atom RPI", "Atom Renderer")
- ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
- ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
- ->DataElement(AZ::Edit::UIHandlers::Default, &RPISystemComponent::m_rpiDescriptor, "RPI System Settings", "Settings for create RPI system")
- ;
- }
- }
- RPISystem::Reflect(context);
- }
- void RPISystemComponent::GetRequiredServices(ComponentDescriptor::DependencyArrayType& required)
- {
- required.push_back(RHI::Factory::GetComponentService());
- }
- void RPISystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
- {
- provided.push_back(AZ_CRC("RPISystem", 0xf2add773));
- }
- void RPISystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
- {
- dependent.push_back(AZ_CRC_CE("XRSystemService"));
- }
- RPISystemComponent::RPISystemComponent()
- {
- #ifdef RPI_EDITOR
- AZ_Assert(m_materialFunctorRegistration == nullptr, "Material functor registration should be initialized with nullptr. "
- "And allocated depending on the component is in editors or not.");
- m_materialFunctorRegistration = aznew MaterialFunctorSourceDataRegistration;
- m_materialFunctorRegistration->Init();
- #endif
- }
- RPISystemComponent::~RPISystemComponent()
- {
- #ifdef RPI_EDITOR
- if (m_materialFunctorRegistration)
- {
- m_materialFunctorRegistration->Shutdown();
- delete m_materialFunctorRegistration;
- }
- #endif
- }
- void RPISystemComponent::Activate()
- {
- InitializePerformanceCollector();
- auto settingsRegistry = AZ::SettingsRegistry::Get();
- const char* settingPath = "/O3DE/Atom/RPI/Initialization";
- const char* setregName = "NullRenderer"; // same as serialization context name for RPISystemDescriptor::m_isNullRenderer
- AZ::ApplicationTypeQuery appType;
- ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
-
- bool isNullRenderer = false;
- if (appType.IsHeadless())
- {
- // if the application is `headless`, merge `NullRenderer` attribute to the setting registry
- isNullRenderer = true;
- }
- else
- {
- // Otherwise if the command line contains -NullRenderer merge it to setting registry
- const char* nullRendererOption = "NullRenderer"; // command line option name
- const AzFramework::CommandLine* commandLine = nullptr;
- AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetApplicationCommandLine);
- if (commandLine->GetNumSwitchValues(nullRendererOption) > 0)
- {
- isNullRenderer = true;
- }
- }
- if (isNullRenderer)
- {
- // add it to setting registry
- auto overrideArg = AZStd::string::format("%s/%s=true", settingPath, setregName);
- settingsRegistry->MergeCommandLineArgument(overrideArg, "");
- }
- // load rpi desriptor from setting registry
- settingsRegistry->GetObject(m_rpiDescriptor, settingPath);
- m_rpiSystem.Initialize(m_rpiDescriptor);
- // Part of RPI system initialization requires asset system to be ready
- // which happens after the game system started
- // Use the tick bus to delay this initialization
- AZ::TickBus::QueueFunction(
- [this]()
- {
- m_rpiSystem.InitializeSystemAssets();
- });
- AZ::SystemTickBus::Handler::BusConnect();
- AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
- }
- void RPISystemComponent::Deactivate()
- {
- AZ::SystemTickBus::Handler::BusDisconnect();
- m_rpiSystem.Shutdown();
- AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
- }
- void RPISystemComponent::OnSystemTick()
- {
- if (m_performanceCollector)
- {
- if (m_gpuPassProfiler && !m_performanceCollector->IsWaitingBeforeCapture() && m_gpuPassProfiler->IsGpuTimeMeasurementEnabled())
- {
- uint64_t durationNanoseconds = m_gpuPassProfiler->MeasureGpuTimeInNanoseconds(AZ::RPI::PassSystemInterface::Get()->GetRootPass());
- // The first three frames, it is expected to be zero. So only record non-zero samples.
- if (durationNanoseconds > 0)
- {
- m_performanceCollector->RecordSample(PerformanceSpecGpuTime, AZStd::chrono::microseconds(aznumeric_cast<int64_t>(durationNanoseconds / 1000)));
- }
- }
- m_performanceCollector->RecordPeriodicEvent(PerformanceSpecEngineCpuTime);
- m_performanceCollector->FrameTick();
- }
- {
- AZ::Debug::ScopeDuration performanceScopeDuration(m_performanceCollector.get(), PerformanceSpecGraphicsSimulationTime);
- m_rpiSystem.SimulationTick();
- }
- {
- AZ::Debug::ScopeDuration performanceScopeDuration(m_performanceCollector.get(), PerformanceSpecGraphicsRenderTime);
- m_rpiSystem.RenderTick();
- }
- }
-
- void RPISystemComponent::OnDeviceRemoved([[maybe_unused]] RHI::Device* device)
- {
- #if defined(AZ_FORCE_CPU_GPU_INSYNC)
- const AZStd::string errorMessage = AZStd::string::format("GPU device was removed while working on pass %s. Check the log file for more detail.", device->GetLastExecutingScope().data());
- #else
- const AZStd::string errorMessage = "GPU device was removed. Check the log file for more detail.";
- #endif
- if (auto nativeUI = AZ::Interface<AZ::NativeUI::NativeUIRequests>::Get(); nativeUI != nullptr)
- {
- nativeUI->DisplayOkDialog("O3DE Fatal Error", errorMessage.c_str(), false);
- }
- else
- {
- AZ_Error("Atom", false, "O3DE Fatal Error: %s\n", errorMessage.c_str());
- }
- // Stop execution since we can't recover from device removal error
- Debug::Trace::Instance().Crash();
- }
- void RPISystemComponent::RegisterXRInterface(XRRenderingInterface* xrSystemInterface)
- {
- m_rpiSystem.RegisterXRSystem(xrSystemInterface);
- }
- void RPISystemComponent::UnRegisterXRInterface()
- {
- m_rpiSystem.UnregisterXRSystem();
- }
- AZ_CVAR_EXTERNED(AZ::u32, r_metricsNumberOfCaptureBatches);
- AZ_CVAR_EXTERNED(AZ::CVarFixedString, r_metricsDataLogType);
- AZ_CVAR_EXTERNED(AZ::u32, r_metricsWaitTimePerCaptureBatch);
- AZ_CVAR_EXTERNED(AZ::u32, r_metricsFrameCountPerCaptureBatch);
- AZ_CVAR_EXTERNED(bool, r_metricsMeasureGpuTime);
- AZ_CVAR_EXTERNED(bool, r_metricsQuitUponCompletion);
- AZStd::string RPISystemComponent::GetLogCategory()
- {
- AZStd::string platformName = AZ::GetPlatformName(AZ::g_currentPlatform);
- AZ::Name apiName = AZ::RHI::Factory::Get().GetName();
- auto logCategory = AZStd::string::format("%.*s-%s-%s", AZ_STRING_ARG(PerformanceLogCategory), platformName.c_str(), apiName.GetCStr());
- return logCategory;
- }
- void RPISystemComponent::InitializePerformanceCollector()
- {
- auto onBatchCompleteCallback = [&](AZ::u32 pendingBatches) {
- AZ_TracePrintf("RPISystem", "Completed a performance batch, still %u batches are pending.\n", pendingBatches);
- r_metricsNumberOfCaptureBatches = pendingBatches;
- if (pendingBatches == 0)
- {
- m_gpuPassProfiler->SetGpuTimeMeasurementEnabled(false);
- // Force disabling timestamp collection in the root pass.
- AZ::RPI::PassSystemInterface::Get()->GetRootPass()->SetTimestampQueryEnabled(false);
- }
- if (r_metricsQuitUponCompletion && (pendingBatches == 0))
- {
- AzFramework::ConsoleRequestBus::Broadcast(
- &AzFramework::ConsoleRequests::ExecuteConsoleCommand, "quit");
- }
- };
- auto performanceMetrics = AZStd::to_array<AZStd::string_view>({
- PerformanceSpecGraphicsSimulationTime,
- PerformanceSpecGraphicsRenderTime,
- PerformanceSpecEngineCpuTime,
- PerformanceSpecGpuTime,
- });
- AZStd::string logCategory = GetLogCategory();
- m_performanceCollector = AZStd::make_unique<AZ::Debug::PerformanceCollector>(
- logCategory, performanceMetrics, onBatchCompleteCallback);
- m_gpuPassProfiler = AZStd::make_unique<GpuPassProfiler>();
- //Feed the CVAR values.
- m_gpuPassProfiler->SetGpuTimeMeasurementEnabled(r_metricsMeasureGpuTime);
- m_performanceCollector->UpdateDataLogType(GetDataLogTypeFromCVar(r_metricsDataLogType));
- m_performanceCollector->UpdateFrameCountPerCaptureBatch(r_metricsFrameCountPerCaptureBatch);
- m_performanceCollector->UpdateWaitTimeBeforeEachBatch(AZStd::chrono::seconds(r_metricsWaitTimePerCaptureBatch));
- m_performanceCollector->UpdateNumberOfCaptureBatches(r_metricsNumberOfCaptureBatches);
- }
- } // namespace RPI
- } // namespace AZ
|