AtomSampleViewerSystemComponent.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. #include <AtomSampleViewerSystemComponent.h>
  9. #include <Automation/ImageComparisonConfig.h>
  10. #include <EntityLatticeTestComponent.h>
  11. #include <AzCore/Asset/AssetManagerBus.h>
  12. #include <AzCore/Asset/AssetManager.h>
  13. #include <AzCore/Serialization/SerializeContext.h>
  14. #include <AzCore/Component/Entity.h>
  15. #include <AzCore/IO/Path/Path.h>
  16. #include <AzCore/IO/SystemFile.h>
  17. #include <AzFramework/Input/Buses/Requests/InputSystemCursorRequestBus.h>
  18. #include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
  19. #include <AzFramework/IO/LocalFileIO.h>
  20. #include <Atom/Bootstrap/DefaultWindowBus.h>
  21. #include <Atom/RHI/Factory.h>
  22. #include <Atom/RPI.Public/RPISystemInterface.h>
  23. #include <ISystem.h>
  24. #include <IConsole.h>
  25. #include <Utils/ImGuiAssetBrowser.h>
  26. #include <Utils/ImGuiSidebar.h>
  27. #include <Utils/ImGuiSaveFilePath.h>
  28. #include <Utils/Utils.h>
  29. AZ_DEFINE_BUDGET(AtomSampleViewer);
  30. namespace AtomSampleViewer
  31. {
  32. void AtomSampleViewerSystemComponent::Reflect(AZ::ReflectContext* context)
  33. {
  34. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  35. {
  36. serializeContext->Class<AtomSampleViewerSystemComponent, AZ::Component>()
  37. ->Version(0)
  38. ;
  39. }
  40. PerfMetrics::Reflect(context);
  41. ImGuiAssetBrowser::Reflect(context);
  42. ImGuiSidebar::Reflect(context);
  43. ImGuiSaveFilePath::Reflect(context);
  44. ImageComparisonConfig::Reflect(context);
  45. // Abstract base components is used by multiple components and needs to be reflected in a single location.
  46. CommonSampleComponentBase::Reflect(context);
  47. EntityLatticeTestComponent::Reflect(context);
  48. }
  49. void AtomSampleViewerSystemComponent::PerfMetrics::Reflect(AZ::ReflectContext* context)
  50. {
  51. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  52. {
  53. serializeContext->Class<PerfMetrics>()
  54. ->Version(1)
  55. ->Field("TestDurationSeconds", &PerfMetrics::m_timingTargetSeconds)
  56. ->Field("AverageFramesPerSecond", &PerfMetrics::m_averageDeltaSeconds)
  57. ->Field("SecondsToRender", &PerfMetrics::m_timeToFirstRenderSeconds)
  58. ;
  59. }
  60. }
  61. void AtomSampleViewerSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  62. {
  63. provided.push_back(AZ_CRC_CE("PrototypeLmbrCentralService"));
  64. }
  65. void AtomSampleViewerSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  66. {
  67. required.push_back(AZ::RHI::Factory::GetComponentService());
  68. required.push_back(AZ_CRC_CE("AssetDatabaseService"));
  69. required.push_back(AZ_CRC_CE("RPISystem"));
  70. required.push_back(AZ_CRC_CE("BootstrapSystemComponent"));
  71. }
  72. AtomSampleViewerSystemComponent::AtomSampleViewerSystemComponent()
  73. : m_timestamp(HighResTimer::now())
  74. {
  75. m_atomSampleViewerEntity = aznew AZ::Entity();
  76. m_atomSampleViewerEntity->Init();
  77. }
  78. AtomSampleViewerSystemComponent::~AtomSampleViewerSystemComponent()
  79. {
  80. }
  81. void AtomSampleViewerSystemComponent::Activate()
  82. {
  83. AZ::EntitySystemBus::Handler::BusConnect();
  84. AZ::ApplicationTypeQuery appType;
  85. AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
  86. if (appType.IsValid() && !appType.IsEditor())
  87. {
  88. // AtomSampleViewer SampleComponentManager creates and manages its own scene and render pipelines.
  89. // We disable the creation of default scene in BootStrapSystemComponent
  90. AZ::Render::Bootstrap::DefaultWindowBus::Broadcast(&AZ::Render::Bootstrap::DefaultWindowBus::Events::SetCreateDefaultScene, false);
  91. }
  92. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@products@/assetcatalog.xml");
  93. m_atomSampleViewerEntity->Activate();
  94. AZ::TickBus::Handler::BusConnect();
  95. CrySystemEventBus::Handler::BusConnect();
  96. // Add customized pass classes
  97. auto* passSystem = AZ::RPI::PassSystemInterface::Get();
  98. // Load ASV's own pass templates mapping
  99. // It can be loaded here and it doesn't need be added via OnReadyLoadTemplatesEvent::Handler
  100. // since the first render pipeline is created after this point.
  101. const char* asvPassTemplatesFile = "Passes/ASV/PassTemplates.azasset";
  102. bool loaded = passSystem->LoadPassTemplateMappings(asvPassTemplatesFile);
  103. if (!loaded)
  104. {
  105. AZ_Fatal("SampleComponentManager", "Failed to load AtomSampleViewer's pass templates at %s", asvPassTemplatesFile);
  106. }
  107. }
  108. void AtomSampleViewerSystemComponent::Deactivate()
  109. {
  110. CrySystemEventBus::Handler::BusDisconnect();
  111. AZ::TickBus::Handler::BusDisconnect();
  112. if (m_atomSampleViewerEntity != nullptr)
  113. {
  114. m_atomSampleViewerEntity->Deactivate();
  115. }
  116. AZ::EntitySystemBus::Handler::BusDisconnect();
  117. }
  118. void AtomSampleViewerSystemComponent::OnEntityDestroyed(const AZ::EntityId& entityId)
  119. {
  120. if (m_atomSampleViewerEntity && m_atomSampleViewerEntity->GetId() == entityId)
  121. {
  122. m_atomSampleViewerEntity = nullptr;
  123. }
  124. }
  125. void AtomSampleViewerSystemComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time)
  126. {
  127. AZ_UNUSED(time);
  128. TickTimeoutShutdown(deltaTime);
  129. #if defined(AZ_DEBUG_BUILD)
  130. TrackPerfMetrics(deltaTime);
  131. #endif
  132. }
  133. void AtomSampleViewerSystemComponent::OnCrySystemInitialized(ISystem& system, const SSystemInitParams&)
  134. {
  135. system.GetIConsole()->GetCVar("sys_asserts")->Set(2);
  136. // Currently CSystem::Init hides and constrains the mouse cursor.
  137. // For AtomSampleViewer we want it visible so that we can use the ImGui menus
  138. AzFramework::InputSystemCursorRequestBus::Event(AzFramework::InputDeviceMouse::Id,
  139. &AzFramework::InputSystemCursorRequests::SetSystemCursorState,
  140. AzFramework::SystemCursorState::UnconstrainedAndVisible);
  141. ReadTimeoutShutdown();
  142. }
  143. void AtomSampleViewerSystemComponent::ReadTimeoutShutdown()
  144. {
  145. const AzFramework::CommandLine* commandLine = nullptr;
  146. AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::Bus::Events::GetApplicationCommandLine);
  147. if (commandLine)
  148. {
  149. if (commandLine->HasSwitch("timeout"))
  150. {
  151. const AZStd::string& timeoutValue = commandLine->GetSwitchValue("timeout", 0);
  152. const float timeoutInSeconds = static_cast<float>(atoi(timeoutValue.c_str()));
  153. AZ_Printf("AtomSampleViewer", "starting up with timeout shutdown of %f seconds", timeoutInSeconds);
  154. m_secondsBeforeShutdown = timeoutInSeconds;
  155. }
  156. }
  157. }
  158. void AtomSampleViewerSystemComponent::TickTimeoutShutdown(float deltaTimeInSeconds)
  159. {
  160. if (m_secondsBeforeShutdown > 0.f)
  161. {
  162. m_secondsBeforeShutdown -= deltaTimeInSeconds;
  163. if (m_secondsBeforeShutdown <= 0.f)
  164. {
  165. AZ_Printf("AtomSampleViewer", "Timeout reached, shutting down");
  166. AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::ExitMainLoop); // or ::TerminateOnError for a more forceful option
  167. }
  168. }
  169. }
  170. void AtomSampleViewerSystemComponent::TrackPerfMetrics(const float deltaTime)
  171. {
  172. m_frameCount++;
  173. if (m_frameCount != 1) // don't accumulate delta on the first frame
  174. {
  175. m_accumulatedDeltaSeconds += deltaTime;
  176. }
  177. if (!m_testsLogged)
  178. {
  179. auto elapsedTime = AZStd::chrono::duration_cast<AZStd::chrono::duration<float>>(HighResTimer::now() - m_timestamp);
  180. if (m_frameCount == 1)
  181. {
  182. m_perfMetrics.m_timeToFirstRenderSeconds = elapsedTime.count();
  183. }
  184. if (elapsedTime.count() >= m_perfMetrics.m_timingTargetSeconds)
  185. {
  186. if (m_frameCount > 1)
  187. {
  188. m_perfMetrics.m_averageDeltaSeconds = m_accumulatedDeltaSeconds / static_cast<float>(m_frameCount - 1);
  189. }
  190. LogPerfMetrics();
  191. m_testsLogged = true;
  192. }
  193. }
  194. }
  195. void AtomSampleViewerSystemComponent::LogPerfMetrics() const
  196. {
  197. AZ::IO::FixedMaxPath resolvedPath;
  198. AZ::IO::LocalFileIO::GetInstance()->ResolvePath(resolvedPath, "@user@/PerformanceMetrics.xml");
  199. AZ::Utils::SaveObjectToFile(resolvedPath.String(), AZ::DataStream::ST_XML, &m_perfMetrics);
  200. }
  201. } // namespace AtomSampleViewer