RPISystemComponent.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. /**
  9. * @file RPISystemComponent.cpp
  10. * @brief Contains the definition of the RPISystemComponent methods that aren't defined as inline
  11. */
  12. #include <RPI.Private/RPISystemComponent.h>
  13. #include <Atom/RHI/Factory.h>
  14. #include <AzCore/Asset/AssetManager.h>
  15. #include <AzCore/IO/IOUtils.h>
  16. #include <AzCore/NativeUI/NativeUIRequests.h>
  17. #include <AzCore/Serialization/SerializeContext.h>
  18. #include <AzCore/Settings/SettingsRegistry.h>
  19. #include <AzCore/PlatformId/PlatformId.h>
  20. #include <AzFramework/API/ApplicationAPI.h>
  21. #include <AzFramework/CommandLine/CommandLine.h>
  22. #include <AzFramework/Components/ConsoleBus.h>
  23. #ifdef RPI_EDITOR
  24. #include <Atom/RPI.Edit/Material/MaterialFunctorSourceDataRegistration.h>
  25. #endif
  26. namespace AZ
  27. {
  28. namespace RPI
  29. {
  30. void RPISystemComponent::Reflect(ReflectContext* context)
  31. {
  32. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  33. {
  34. serializeContext
  35. ->Class<RPISystemComponent, Component>()
  36. ->Version(0)
  37. ->Field("RpiDescriptor", &RPISystemComponent::m_rpiDescriptor)
  38. ;
  39. if (AZ::EditContext* ec = serializeContext->GetEditContext())
  40. {
  41. ec->Class<RPISystemComponent>("Atom RPI", "Atom Renderer")
  42. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  43. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  44. ->DataElement(AZ::Edit::UIHandlers::Default, &RPISystemComponent::m_rpiDescriptor, "RPI System Settings", "Settings for create RPI system")
  45. ;
  46. }
  47. }
  48. RPISystem::Reflect(context);
  49. }
  50. void RPISystemComponent::GetRequiredServices(ComponentDescriptor::DependencyArrayType& required)
  51. {
  52. required.push_back(RHI::Factory::GetComponentService());
  53. }
  54. void RPISystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
  55. {
  56. provided.push_back(AZ_CRC("RPISystem", 0xf2add773));
  57. }
  58. void RPISystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
  59. {
  60. dependent.push_back(AZ_CRC_CE("XRSystemService"));
  61. }
  62. RPISystemComponent::RPISystemComponent()
  63. {
  64. #ifdef RPI_EDITOR
  65. AZ_Assert(m_materialFunctorRegistration == nullptr, "Material functor registration should be initialized with nullptr. "
  66. "And allocated depending on the component is in editors or not.");
  67. m_materialFunctorRegistration = aznew MaterialFunctorSourceDataRegistration;
  68. m_materialFunctorRegistration->Init();
  69. #endif
  70. }
  71. RPISystemComponent::~RPISystemComponent()
  72. {
  73. #ifdef RPI_EDITOR
  74. if (m_materialFunctorRegistration)
  75. {
  76. m_materialFunctorRegistration->Shutdown();
  77. delete m_materialFunctorRegistration;
  78. }
  79. #endif
  80. }
  81. void RPISystemComponent::Activate()
  82. {
  83. InitializePerformanceCollector();
  84. auto settingsRegistry = AZ::SettingsRegistry::Get();
  85. const char* settingPath = "/O3DE/Atom/RPI/Initialization";
  86. // if the command line contains -NullRenderer, merge it to setting registry
  87. const char* nullRendererOption = "NullRenderer"; // command line option name
  88. const char* setregName = "NullRenderer"; // same as serialization context name for RPISystemDescriptor::m_isNullRenderer
  89. const AzFramework::CommandLine* commandLine = nullptr;
  90. AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetApplicationCommandLine);
  91. AZStd::string commandLineValue;
  92. if (commandLine)
  93. {
  94. if (commandLine->GetNumSwitchValues(nullRendererOption) > 0)
  95. {
  96. // add it to setting registry
  97. auto overrideArg = AZStd::string::format("%s/%s=true", settingPath, setregName);
  98. settingsRegistry->MergeCommandLineArgument(overrideArg, "");
  99. }
  100. }
  101. // load rpi desriptor from setting registry
  102. settingsRegistry->GetObject(m_rpiDescriptor, settingPath);
  103. m_rpiSystem.Initialize(m_rpiDescriptor);
  104. // Part of RPI system initialization requires asset system to be ready
  105. // which happens after the game system started
  106. // Use the tick bus to delay this initialization
  107. AZ::TickBus::QueueFunction(
  108. [this]()
  109. {
  110. m_rpiSystem.InitializeSystemAssets();
  111. });
  112. AZ::SystemTickBus::Handler::BusConnect();
  113. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  114. }
  115. void RPISystemComponent::Deactivate()
  116. {
  117. AZ::SystemTickBus::Handler::BusDisconnect();
  118. m_rpiSystem.Shutdown();
  119. AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
  120. }
  121. void RPISystemComponent::OnSystemTick()
  122. {
  123. if (m_performanceCollector)
  124. {
  125. if (m_gpuPassProfiler && !m_performanceCollector->IsWaitingBeforeCapture() && m_gpuPassProfiler->IsGpuTimeMeasurementEnabled())
  126. {
  127. uint64_t durationNanoseconds = m_gpuPassProfiler->MeasureGpuTimeInNanoseconds(AZ::RPI::PassSystemInterface::Get()->GetRootPass());
  128. // The first three frames, it is expected to be zero. So only record non-zero samples.
  129. if (durationNanoseconds > 0)
  130. {
  131. m_performanceCollector->RecordSample(PerformanceSpecGpuTime, AZStd::chrono::microseconds(aznumeric_cast<int64_t>(durationNanoseconds / 1000)));
  132. }
  133. }
  134. m_performanceCollector->RecordPeriodicEvent(PerformanceSpecEngineCpuTime);
  135. m_performanceCollector->FrameTick();
  136. }
  137. {
  138. AZ::Debug::ScopeDuration performanceScopeDuration(m_performanceCollector.get(), PerformanceSpecGraphicsSimulationTime);
  139. m_rpiSystem.SimulationTick();
  140. }
  141. {
  142. AZ::Debug::ScopeDuration performanceScopeDuration(m_performanceCollector.get(), PerformanceSpecGraphicsRenderTime);
  143. m_rpiSystem.RenderTick();
  144. }
  145. }
  146. void RPISystemComponent::OnDeviceRemoved([[maybe_unused]] RHI::Device* device)
  147. {
  148. #if defined(AZ_FORCE_CPU_GPU_INSYNC)
  149. 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());
  150. #else
  151. const AZStd::string errorMessage = "GPU device was removed. Check the log file for more detail.";
  152. #endif
  153. if (auto nativeUI = AZ::Interface<AZ::NativeUI::NativeUIRequests>::Get(); nativeUI != nullptr)
  154. {
  155. nativeUI->DisplayOkDialog("O3DE Fatal Error", errorMessage.c_str(), false);
  156. }
  157. else
  158. {
  159. AZ_Error("Atom", false, "O3DE Fatal Error: %s\n", errorMessage.c_str());
  160. }
  161. // Stop execution since we can't recover from device removal error
  162. Debug::Trace::Instance().Crash();
  163. }
  164. void RPISystemComponent::RegisterXRInterface(XRRenderingInterface* xrSystemInterface)
  165. {
  166. m_rpiSystem.RegisterXRSystem(xrSystemInterface);
  167. }
  168. void RPISystemComponent::UnRegisterXRInterface()
  169. {
  170. m_rpiSystem.UnregisterXRSystem();
  171. }
  172. AZ_CVAR_EXTERNED(AZ::u32, r_metricsNumberOfCaptureBatches);
  173. AZ_CVAR_EXTERNED(AZ::CVarFixedString, r_metricsDataLogType);
  174. AZ_CVAR_EXTERNED(AZ::u32, r_metricsWaitTimePerCaptureBatch);
  175. AZ_CVAR_EXTERNED(AZ::u32, r_metricsFrameCountPerCaptureBatch);
  176. AZ_CVAR_EXTERNED(bool, r_metricsMeasureGpuTime);
  177. AZ_CVAR_EXTERNED(bool, r_metricsQuitUponCompletion);
  178. AZStd::string RPISystemComponent::GetLogCategory()
  179. {
  180. AZStd::string platformName = AZ::GetPlatformName(AZ::g_currentPlatform);
  181. AZ::Name apiName = AZ::RHI::Factory::Get().GetName();
  182. auto logCategory = AZStd::string::format("%.*s-%s-%s", AZ_STRING_ARG(PerformanceLogCategory), platformName.c_str(), apiName.GetCStr());
  183. return logCategory;
  184. }
  185. void RPISystemComponent::InitializePerformanceCollector()
  186. {
  187. auto onBatchCompleteCallback = [&](AZ::u32 pendingBatches) {
  188. AZ_TracePrintf("RPISystem", "Completed a performance batch, still %u batches are pending.\n", pendingBatches);
  189. r_metricsNumberOfCaptureBatches = pendingBatches;
  190. if (pendingBatches == 0)
  191. {
  192. m_gpuPassProfiler->SetGpuTimeMeasurementEnabled(false);
  193. // Force disabling timestamp collection in the root pass.
  194. AZ::RPI::PassSystemInterface::Get()->GetRootPass()->SetTimestampQueryEnabled(false);
  195. }
  196. if (r_metricsQuitUponCompletion && (pendingBatches == 0))
  197. {
  198. AzFramework::ConsoleRequestBus::Broadcast(
  199. &AzFramework::ConsoleRequests::ExecuteConsoleCommand, "quit");
  200. }
  201. };
  202. auto performanceMetrics = AZStd::to_array<AZStd::string_view>({
  203. PerformanceSpecGraphicsSimulationTime,
  204. PerformanceSpecGraphicsRenderTime,
  205. PerformanceSpecEngineCpuTime,
  206. PerformanceSpecGpuTime,
  207. });
  208. AZStd::string logCategory = GetLogCategory();
  209. m_performanceCollector = AZStd::make_unique<AZ::Debug::PerformanceCollector>(
  210. logCategory, performanceMetrics, onBatchCompleteCallback);
  211. m_gpuPassProfiler = AZStd::make_unique<GpuPassProfiler>();
  212. //Feed the CVAR values.
  213. m_gpuPassProfiler->SetGpuTimeMeasurementEnabled(r_metricsMeasureGpuTime);
  214. m_performanceCollector->UpdateDataLogType(GetDataLogTypeFromCVar(r_metricsDataLogType));
  215. m_performanceCollector->UpdateFrameCountPerCaptureBatch(r_metricsFrameCountPerCaptureBatch);
  216. m_performanceCollector->UpdateWaitTimeBeforeEachBatch(AZStd::chrono::seconds(r_metricsWaitTimePerCaptureBatch));
  217. m_performanceCollector->UpdateNumberOfCaptureBatches(r_metricsNumberOfCaptureBatches);
  218. }
  219. } // namespace RPI
  220. } // namespace AZ