SampleComponentManager.cpp 75 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885
  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 <SampleComponentManager.h>
  9. #include <SampleComponentConfig.h>
  10. #include <Atom/Component/DebugCamera/CameraComponent.h>
  11. #include <Atom/Component/DebugCamera/NoClipControllerComponent.h>
  12. #include <Atom/Component/DebugCamera/ArcBallControllerComponent.h>
  13. #include <Atom/Feature/ImGui/ImGuiUtils.h>
  14. #include <Atom/Feature/ImGui/SystemBus.h>
  15. #include <Atom/Feature/Mesh/MeshFeatureProcessorInterface.h>
  16. #include <Atom/Feature/PostProcessing/PostProcessingConstants.h>
  17. #include <Atom/Feature/SkinnedMesh/SkinnedMeshInputBuffers.h>
  18. #include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
  19. #include <Atom/RPI.Public/Pass/Pass.h>
  20. #include <Atom/RPI.Public/Pass/ParentPass.h>
  21. #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
  22. #include <Atom/RPI.Public/Pass/RenderPass.h>
  23. #include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
  24. #include <Atom/RPI.Public/RenderPipeline.h>
  25. #include <Atom/RPI.Public/RPISystemInterface.h>
  26. #include <Atom/RPI.Public/Scene.h>
  27. #include <Atom/RPI.Public/Shader/ShaderSystemInterface.h>
  28. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  29. #include <Atom/RPI.Reflect/Image/AttachmentImageAsset.h>
  30. #include <Atom/RPI.Reflect/Image/AttachmentImageAssetCreator.h>
  31. #include <Atom/RPI.Reflect/Shader/IShaderVariantFinder.h>
  32. #include <Atom/RHI/Factory.h>
  33. #include <Atom/RHI/RHISystemInterface.h>
  34. #include <Atom/RHI/RHIMemoryStatisticsInterface.h>
  35. #include <Atom/RHI/RHIUtils.h>
  36. #include <Atom/RHI.Reflect/AliasedHeapEnums.h>
  37. #include <Automation/ScriptManager.h>
  38. #include <RHI/AlphaToCoverageExampleComponent.h>
  39. #include <RHI/AsyncComputeExampleComponent.h>
  40. #include <RHI/BasicRHIComponent.h>
  41. #include <RHI/ComputeExampleComponent.h>
  42. #include <RHI/CopyQueueComponent.h>
  43. #include <RHI/DualSourceBlendingComponent.h>
  44. #include <RHI/IndirectRenderingExampleComponent.h>
  45. #include <RHI/InputAssemblyExampleComponent.h>
  46. #include <RHI/SubpassExampleComponent.h>
  47. #include <RHI/MRTExampleComponent.h>
  48. #include <RHI/MSAAExampleComponent.h>
  49. #include <RHI/MultiThreadComponent.h>
  50. #include <RHI/MultiGPUExampleComponent.h>
  51. #include <RHI/MultiViewportSwapchainComponent.h>
  52. #include <RHI/MultipleViewsComponent.h>
  53. #include <RHI/QueryExampleComponent.h>
  54. #include <RHI/StencilExampleComponent.h>
  55. #include <RHI/SwapchainExampleComponent.h>
  56. #include <RHI/SphericalHarmonicsExampleComponent.h>
  57. #include <RHI/Texture3dExampleComponent.h>
  58. #include <RHI/TextureArrayExampleComponent.h>
  59. #include <RHI/TextureExampleComponent.h>
  60. #include <RHI/TextureMapExampleComponent.h>
  61. #include <RHI/TriangleExampleComponent.h>
  62. #include <RHI/XRExampleComponent.h>
  63. #include <RHI/TrianglesConstantBufferExampleComponent.h>
  64. #include <RHI/BindlessPrototypeExampleComponent.h>
  65. #include <RHI/RayTracingExampleComponent.h>
  66. #include <RHI/MatrixAlignmentTestExampleComponent.h>
  67. #include <RHI/VariableRateShadingExampleComponent.h>
  68. #include <Performance/100KDrawable_SingleView_ExampleComponent.h>
  69. #include <Performance/100KDraw_10KDrawable_MultiView_ExampleComponent.h>
  70. #include <AreaLightExampleComponent.h>
  71. #include <AssetLoadTestComponent.h>
  72. #include <AuxGeomExampleComponent.h>
  73. #include <BakedShaderVariantExampleComponent.h>
  74. #include <SponzaBenchmarkComponent.h>
  75. #include <BloomExampleComponent.h>
  76. #include <CheckerboardExampleComponent.h>
  77. #include <CullingAndLodExampleComponent.h>
  78. #include <DecalExampleComponent.h>
  79. #include <DepthOfFieldExampleComponent.h>
  80. #include <DynamicDrawExampleComponent.h>
  81. #include <DynamicMaterialTestComponent.h>
  82. #include <ExposureExampleComponent.h>
  83. #include <EyeMaterialExampleComponent.h>
  84. #include <SceneReloadSoakTestComponent.h>
  85. #include <LightCullingExampleComponent.h>
  86. #include <MeshExampleComponent.h>
  87. #include <MSAA_RPI_ExampleComponent.h>
  88. #include <MultiGPURPIExampleComponent.h>
  89. #include <MultiRenderPipelineExampleComponent.h>
  90. #include <MultiSceneExampleComponent.h>
  91. #include <ParallaxMappingExampleComponent.h>
  92. #include <RayTracingIntersectionShaderExampleComponent.h>
  93. #include <RayTracingVertexFormatExampleComponent.h>
  94. #include <RenderTargetTextureExampleComponent.h>
  95. #include <SceneReloadSoakTestComponent.h>
  96. #include <ShadowExampleComponent.h>
  97. #include <ShadowedSponzaExampleComponent.h>
  98. #include <SkinnedMeshExampleComponent.h>
  99. #include <SsaoExampleComponent.h>
  100. #include <StreamingImageExampleComponent.h>
  101. #include <RootConstantsExampleComponent.h>
  102. #include <MultiViewSingleSceneAuxGeomExampleComponent.h>
  103. #include <TonemappingExampleComponent.h>
  104. #include <TransparencyExampleComponent.h>
  105. #include <DiffuseGIExampleComponent.h>
  106. #include <SSRExampleComponent.h>
  107. #include <XRRPIExampleComponent.h>
  108. #include <ShaderReloadTestComponent.h>
  109. #include <ReadbackExampleComponent.h>
  110. #include <Subpass_RPI_ExampleComponent.h>
  111. #include <Atom/Bootstrap/DefaultWindowBus.h>
  112. #include <AzCore/Component/Entity.h>
  113. #include <AzCore/Debug/Profiler.h>
  114. #include <AzCore/Debug/ProfilerBus.h>
  115. #include <AzCore/IO/IStreamerProfiler.h>
  116. #include <AzCore/Serialization/SerializeContext.h>
  117. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  118. #include <AzCore/std/smart_ptr/make_shared.h>
  119. #include <AzCore/std/algorithm.h>
  120. #include <AzFramework/API/ApplicationAPI.h>
  121. #include <AzFramework/Components/ConsoleBus.h>
  122. #include <AzFramework/Components/TransformComponent.h>
  123. #include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
  124. #include <AzFramework/Entity/GameEntityContextBus.h>
  125. #include <AzFramework/Scene/Scene.h>
  126. #include <AzFramework/Scene/SceneSystemInterface.h>
  127. #include <Passes/RayTracingAmbientOcclusionPass.h>
  128. #include <Utils/Utils.h>
  129. #include <Profiler/ProfilerImGuiBus.h>
  130. #include "ExampleComponentBus.h"
  131. #include <EntityUtilityFunctions.h>
  132. namespace Platform
  133. {
  134. const char* GetPipelineName();
  135. }
  136. namespace AtomSampleViewer
  137. {
  138. namespace
  139. {
  140. constexpr const char* PassTreeToolName = "PassTree";
  141. constexpr const char* CpuProfilerToolName = "CPU Profiler";
  142. constexpr const char* GpuProfilerToolName = "GPU Profiler";
  143. constexpr const char* FileIoProfilerToolName = "File IO Profiler";
  144. constexpr const char* TransientAttachmentProfilerToolName = "Transient Attachment Profiler";
  145. constexpr const char* SampleSetting = "/O3DE/AtomSampleViewer/Sample";
  146. }
  147. bool IsValidNumMSAASamples(int16_t numSamples)
  148. {
  149. return (numSamples == 1) || (numSamples == 2) || (numSamples == 4) || (numSamples == 8);
  150. }
  151. template <typename T>
  152. static SampleEntry NewRHISample(const AZStd::string& name)
  153. {
  154. return NewSample<T>(SamplePipelineType::RHI, "RHI", name);
  155. }
  156. template <typename T>
  157. static SampleEntry NewRHISample(const AZStd::string& name, AZStd::function<bool()> isSupportedFunction)
  158. {
  159. SampleEntry entry = NewSample<T>(SamplePipelineType::RHI, "RHI", name, isSupportedFunction);
  160. entry.m_isSupportedFunc = isSupportedFunction;
  161. return entry;
  162. }
  163. template <typename T>
  164. static SampleEntry NewRPISample(const AZStd::string& name)
  165. {
  166. return NewSample<T>(SamplePipelineType::RPI, "RPI", name);
  167. }
  168. template <typename T>
  169. static SampleEntry NewRPISample(const AZStd::string& name, AZStd::function<bool()> isSupportedFunction)
  170. {
  171. return NewSample<T>(SamplePipelineType::RPI, "RPI", name, isSupportedFunction);
  172. }
  173. template <typename T>
  174. static SampleEntry NewFeaturesSample(const AZStd::string& name)
  175. {
  176. return NewSample<T>(SamplePipelineType::RPI, "Features", name);
  177. }
  178. template <typename T>
  179. static SampleEntry NewFeaturesSample(const AZStd::string& name, AZStd::function<bool()> isSupportedFunction)
  180. {
  181. return NewSample<T>(SamplePipelineType::RPI, "Features", name, isSupportedFunction);
  182. }
  183. template <typename T>
  184. static SampleEntry NewPerfSample(const AZStd::string& name)
  185. {
  186. return NewSample<T>(SamplePipelineType::RPI, "Performance", name);
  187. }
  188. template <typename T>
  189. static SampleEntry NewPerfSample(const AZStd::string& name, AZStd::function<bool()> isSupportedFunction)
  190. {
  191. return NewSample<T>(SamplePipelineType::RPI, "Performance", name, isSupportedFunction);
  192. }
  193. static AZStd::string GetTargetSampleName()
  194. {
  195. //Check command line option
  196. const AzFramework::CommandLine* commandLine = nullptr;
  197. AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine);
  198. if (commandLine->HasSwitch("sample"))
  199. {
  200. AZStd::string targetSampleName = commandLine->GetSwitchValue("sample", 0);
  201. return targetSampleName;
  202. }
  203. //Check settings registry
  204. if (AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get())
  205. {
  206. if (AZStd::string targetSampleName;
  207. settingsRegistry->Get(targetSampleName, SampleSetting))
  208. {
  209. return targetSampleName;
  210. }
  211. }
  212. return {};
  213. }
  214. void SampleComponentManager::Reflect(AZ::ReflectContext* context)
  215. {
  216. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  217. {
  218. serializeContext->Class<SampleComponentManager, AZ::Component>()
  219. ->Version(0)
  220. ;
  221. // This registration matches ShaderOptionValuesSourceData, which is needed by ImGuiShaderUtils, to support
  222. // generating JSON for shader variants.
  223. serializeContext->RegisterGenericType<AZStd::unordered_map<Name, Name>>();
  224. }
  225. }
  226. void SampleComponentManager::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  227. {
  228. required.push_back(AZ_CRC_CE("PrototypeLmbrCentralService"));
  229. }
  230. void SampleComponentManager::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  231. {
  232. provided.push_back(AZ_CRC_CE("SampleComponentManagerService"));
  233. }
  234. void SampleComponentManager::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
  235. {
  236. dependent.push_back(AZ_CRC_CE("AzFrameworkConfigurationSystemComponentService")); // Ensures a scene is created for the GameEntityContext
  237. }
  238. AZStd::vector<SampleEntry> SampleComponentManager::GetSamples()
  239. {
  240. return {
  241. NewRHISample<AlphaToCoverageExampleComponent>("AlphaToCoverage"),
  242. NewRHISample<AsyncComputeExampleComponent>("AsyncCompute"),
  243. NewRHISample<BindlessPrototypeExampleComponent>("BindlessPrototype"),
  244. NewRHISample<ComputeExampleComponent>("Compute"),
  245. NewRHISample<CopyQueueComponent>("CopyQueue"),
  246. NewRHISample<DualSourceBlendingComponent>("DualSourceBlending", []() {return Utils::GetRHIDevice()->GetFeatures().m_dualSourceBlending; }),
  247. NewRHISample<IndirectRenderingExampleComponent>("IndirectRendering", []() {return Utils::GetRHIDevice()->GetFeatures().m_indirectCommandTier > RHI::IndirectCommandTiers::Tier0; }),
  248. NewRHISample<InputAssemblyExampleComponent>("InputAssembly"),
  249. NewRHISample<MSAAExampleComponent>("MSAA"),
  250. NewRHISample<MultipleViewsComponent>("MultipleViews"),
  251. NewRHISample<MRTExampleComponent>("MultiRenderTarget"),
  252. NewRHISample<MultiThreadComponent>("MultiThread"),
  253. NewRHISample<MultiGPUExampleComponent>("MultiGPU", []() { return AZ::RHI::RHISystemInterface::Get()->GetDeviceCount() >= 2; }),
  254. NewRHISample<MultiViewportSwapchainComponent>("MultiViewportSwapchainComponent", [] { return IsMultiViewportSwapchainSampleSupported(); }),
  255. NewRHISample<QueryExampleComponent>("Queries"),
  256. NewRHISample<RayTracingExampleComponent>("RayTracing", []() {return Utils::GetRHIDevice()->GetFeatures().m_rayTracing; }),
  257. NewRHISample<SphericalHarmonicsExampleComponent>("SphericalHarmonics"),
  258. NewRHISample<StencilExampleComponent>("Stencil"),
  259. NewRHISample<SubpassExampleComponent>("Subpass", []() { return RHI::RHISystemInterface::Get()->CanMergeSubpasses(); }),
  260. NewRHISample<SwapchainExampleComponent>("Swapchain"),
  261. NewRHISample<TextureExampleComponent>("Texture"),
  262. NewRHISample<Texture3dExampleComponent>("Texture3d"),
  263. NewRHISample<TextureArrayExampleComponent>("TextureArray"),
  264. NewRHISample<TextureMapExampleComponent>("TextureMap"),
  265. NewRHISample<TriangleExampleComponent>("Triangle"),
  266. NewRHISample<TrianglesConstantBufferExampleComponent>("TrianglesConstantBuffer"),
  267. NewRHISample<XRExampleComponent>("OpenXr", []() { return AZ::RHI::RHISystemInterface::Get()->GetXRSystem() != nullptr; }),
  268. NewRHISample<MatrixAlignmentTestExampleComponent>("MatrixAlignmentTest"),
  269. NewRHISample<VariableRateShadingExampleComponent>("VariableRateShading", []() { return Utils::GetRHIDevice()->GetFeatures().m_shadingRateTypeMask != RHI::ShadingRateTypeFlags::None; }),
  270. NewRPISample<AssetLoadTestComponent>("AssetLoadTest"),
  271. NewRPISample<AuxGeomExampleComponent>("AuxGeom"),
  272. NewRPISample<BakedShaderVariantExampleComponent>("BakedShaderVariant"),
  273. NewRPISample<SponzaBenchmarkComponent>("SponzaBenchmark"),
  274. NewRPISample<CullingAndLodExampleComponent>("CullingAndLod"),
  275. NewRPISample<DecalExampleComponent>("Decals"),
  276. NewRPISample<DynamicDrawExampleComponent>("DynamicDraw"),
  277. NewRPISample<DynamicMaterialTestComponent>("DynamicMaterialTest"),
  278. NewRPISample<MeshExampleComponent>("Mesh"),
  279. NewRPISample<MSAA_RPI_ExampleComponent>("MSAA"),
  280. NewRPISample<MultiGPURPIExampleComponent>("MultiGPU", []() { return AZ::RHI::RHISystemInterface::Get()->GetDeviceCount() >= 2; }),
  281. NewRPISample<MultiRenderPipelineExampleComponent>("MultiRenderPipeline"),
  282. NewRPISample<MultiSceneExampleComponent>("MultiScene"),
  283. NewRPISample<MultiViewSingleSceneAuxGeomExampleComponent>("MultiViewSingleSceneAuxGeom"),
  284. NewRPISample<RayTracingVertexFormatExampleComponent>("RayTracingVertexFormat", []() { return Utils::GetRHIDevice()->GetFeatures().m_rayTracing; }),
  285. NewRPISample<ReadbackExampleComponent>("Readback"),
  286. NewRPISample<RenderTargetTextureExampleComponent>("RenderTargetTexture"),
  287. NewRPISample<RootConstantsExampleComponent>("RootConstants"),
  288. NewRPISample<SceneReloadSoakTestComponent>("SceneReloadSoakTest"),
  289. NewRPISample<StreamingImageExampleComponent>("StreamingImage"),
  290. NewRPISample<ShaderReloadTestComponent>("ShaderReloadTest"),
  291. NewRPISample<Subpass_RPI_ExampleComponent>("Subpass", []() { return RHI::RHISystemInterface::Get()->CanMergeSubpasses(); }),
  292. NewFeaturesSample<AreaLightExampleComponent>("AreaLight"),
  293. NewFeaturesSample<BloomExampleComponent>("Bloom"),
  294. NewFeaturesSample<CheckerboardExampleComponent>("Checkerboard", []() {return (Utils::GetRHIDevice()->GetPhysicalDevice().GetDescriptor().m_vendorId != RHI::VendorId::ARM && Utils::GetRHIDevice()->GetPhysicalDevice().GetDescriptor().m_vendorId != RHI::VendorId::Qualcomm); }),
  295. NewFeaturesSample<DepthOfFieldExampleComponent>("DepthOfField"),
  296. NewFeaturesSample<DiffuseGIExampleComponent>("DiffuseGI", []() {return Utils::GetRHIDevice()->GetFeatures().m_rayTracing; }),
  297. NewFeaturesSample<ExposureExampleComponent>("Exposure"),
  298. NewFeaturesSample<EyeMaterialExampleComponent>("EyeMaterial"),
  299. NewFeaturesSample<LightCullingExampleComponent>("LightCulling"),
  300. NewFeaturesSample<ParallaxMappingExampleComponent>("Parallax"),
  301. NewFeaturesSample<RayTracingIntersectionShaderExampleComponent>("RayTracingIntersectionShader", []() { return Utils::GetRHIDevice()->GetFeatures().m_rayTracing; }),
  302. NewFeaturesSample<ShadowExampleComponent>("Shadow"),
  303. NewFeaturesSample<ShadowedSponzaExampleComponent>("ShadowedSponza"),
  304. NewFeaturesSample<SkinnedMeshExampleComponent>("SkinnedMesh"),
  305. NewFeaturesSample<SsaoExampleComponent>("SSAO"),
  306. NewFeaturesSample<SSRExampleComponent>("SSR"),
  307. NewFeaturesSample<XRRPIExampleComponent>("OpenXR", []() { return AZ::RPI::RPISystemInterface::Get()->GetXRSystem() != nullptr; }),
  308. NewFeaturesSample<TonemappingExampleComponent>("Tonemapping"),
  309. NewFeaturesSample<TransparencyExampleComponent>("Transparency"),
  310. NewPerfSample<_100KDrawableExampleComponent>("100KDrawable_SingleView"),
  311. NewPerfSample<_100KDraw10KDrawableExampleComponent>("100KDraw_10KDrawable_MultiView"),
  312. };
  313. }
  314. void SampleComponentManager::RegisterSampleComponent(const SampleEntry& sample)
  315. {
  316. if (AZStd::find(m_availableSamples.begin(), m_availableSamples.end(), sample) == m_availableSamples.end())
  317. {
  318. m_availableSamples.push_back(sample);
  319. m_groupedSamples[sample.m_parentMenuName].push_back(static_cast<int32_t>(m_availableSamples.size() - 1));
  320. }
  321. }
  322. ScriptManager* SampleComponentManager::GetScriptManagerInstance()
  323. {
  324. AZ_Assert(m_scriptManager, "Script Manager is nullptr");
  325. return m_scriptManager.get();
  326. }
  327. ScriptableImGui* SampleComponentManager::GetScriptableImGuiInstance()
  328. {
  329. AZ_Assert(m_scriptableImGui, "Scriptable ImGui is nullptr");
  330. return m_scriptableImGui.get();
  331. }
  332. SampleComponentManager::SampleComponentManager()
  333. : m_imguiFrameCaptureSaver("@user@/frame_capture.xml")
  334. {
  335. m_imGuiFrameTimer = AZStd::make_unique<ImGuiHistogramQueue>(FrameTimeDefaultLogSize, FrameTimeDefaultLogSize, 250.0f);
  336. m_exampleEntity = aznew AZ::Entity();
  337. m_entityContextId = AzFramework::EntityContextId::CreateNull();
  338. }
  339. SampleComponentManager::~SampleComponentManager()
  340. {
  341. m_exampleEntity = nullptr;
  342. m_cameraEntity = nullptr;
  343. m_windowContext = nullptr;
  344. m_availableSamples.clear();
  345. }
  346. void SampleComponentManager::Init()
  347. {
  348. AZStd::vector<SampleEntry> samples = GetSamples();
  349. for (const SampleEntry& sample : samples)
  350. {
  351. RegisterSampleComponent(sample);
  352. }
  353. m_scriptManager = AZStd::make_unique<ScriptManager>();
  354. m_scriptableImGui = AZStd::make_unique<ScriptableImGui>();
  355. }
  356. void SampleComponentManager::Activate()
  357. {
  358. // We can only initialize this component after the asset catalog has been loaded.
  359. AzFramework::AssetCatalogEventBus::Handler::BusConnect();
  360. AZ::Render::ImGuiSystemNotificationBus::Handler::BusConnect();
  361. SampleComponentSingletonRequestBus::Handler::BusConnect();
  362. auto* passSystem = AZ::RPI::PassSystemInterface::Get();
  363. AZ_Assert(passSystem, "Cannot get the pass system.");
  364. passSystem->AddPassCreator(Name("RayTracingAmbientOcclusionPass"), &AZ::Render::RayTracingAmbientOcclusionPass::Create);
  365. }
  366. void SampleComponentManager::ActivateInternal()
  367. {
  368. using namespace AZ;
  369. AZ::ApplicationTypeQuery appType;
  370. ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
  371. if (!appType.IsValid() || !appType.IsGame())
  372. {
  373. return;
  374. }
  375. // ActivateInternal() may get called twice because the OnCatalogLoaded was called twice When run AtomSampleViewer launcher. One of those two events is from ly launcher framework and the other one is from
  376. // LoadCatalog call in AtomSampleViewer system component. Although load the same asset catalog twice doesn't seem to cause other issue.
  377. if (m_wasActivated)
  378. {
  379. return;
  380. }
  381. Render::Bootstrap::DefaultWindowBus::BroadcastResult(m_windowContext, &Render::Bootstrap::DefaultWindowBus::Events::GetDefaultWindowContext);
  382. AzFramework::GameEntityContextRequestBus::BroadcastResult(m_entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId);
  383. CreateDefaultCamera();
  384. // Add customized pass classes
  385. auto* passSystem = RPI::PassSystemInterface::Get();
  386. passSystem->AddPassCreator(Name("RHISamplePass"), &AtomSampleViewer::RHISamplePass::Create);
  387. // Use scene and render pipeline for RHI samples as default scene and render pipeline
  388. CreateSceneForRHISample();
  389. m_exampleEntity->Init();
  390. m_exampleEntity->Activate();
  391. m_isSampleSupported.resize(m_availableSamples.size());
  392. for (size_t i = 0; i < m_availableSamples.size(); ++i)
  393. {
  394. // Assume that the sample is supported if no m_isSupportedFunc is provided.
  395. m_isSampleSupported[i] = m_availableSamples[i].m_isSupportedFunc ? m_availableSamples[i].m_isSupportedFunc() : true;
  396. }
  397. AZ_Printf("SampleComponentManager", "Available Samples -------------------------\n");
  398. for (size_t i = 0; i < m_availableSamples.size(); ++i)
  399. {
  400. AZStd::string printStr = "\t[" + m_availableSamples[i].m_fullName + "]";
  401. if (!m_isSampleSupported[i])
  402. {
  403. printStr += " Not Supported ";
  404. }
  405. if (i < 9)
  406. {
  407. printStr += AZStd::string::format("\tctrl+%zu", i + 1);
  408. }
  409. printStr += "\n";
  410. AZ_Printf("SampleComponentManager", printStr.data());
  411. }
  412. AZ_Printf("SampleComponentManager", "-------------------------------------------\n");
  413. AzFramework::InputChannelEventListener::BusConnect();
  414. TickBus::Handler::BusConnect();
  415. [[maybe_unused]] bool targetSampleFound = false;
  416. if (AZStd::string targetSampleName = GetTargetSampleName();
  417. !targetSampleName.empty())
  418. {
  419. AZStd::to_lower(targetSampleName.begin(), targetSampleName.end());
  420. for (int32_t i = 0; i < m_availableSamples.size(); ++i)
  421. {
  422. AZStd::string sampleName = m_availableSamples[i].m_fullName;
  423. AZStd::to_lower(sampleName.begin(), sampleName.end());
  424. if (sampleName == targetSampleName)
  425. {
  426. if (m_isSampleSupported[i])
  427. {
  428. if (m_availableSamples[i].m_contentWarning.empty())
  429. {
  430. m_selectedSampleIndex = i;
  431. m_sampleChangeRequest = true;
  432. }
  433. else
  434. {
  435. m_contentWarningDialog.OpenPopupConfirmation(
  436. m_availableSamples[i].m_contentWarningTitle,
  437. m_availableSamples[i].m_contentWarning,
  438. [this, i]() {
  439. m_selectedSampleIndex = i;
  440. m_sampleChangeRequest = true;
  441. });
  442. }
  443. targetSampleFound = true;
  444. }
  445. break;
  446. }
  447. }
  448. AZ_Warning("SampleComponentManager", targetSampleFound, "Failed find target sample %s", targetSampleName.c_str());
  449. }
  450. const AzFramework::CommandLine* commandLine = nullptr;
  451. AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine);
  452. if (commandLine->HasSwitch("timingSamples"))
  453. {
  454. AZStd::string timingSamplesStr = commandLine->GetSwitchValue("timingSamples", 0);
  455. int timingSamplesCount = 0;
  456. if (AZ::StringFunc::LooksLikeInt(timingSamplesStr.c_str(), &timingSamplesCount))
  457. {
  458. timingSamplesCount = AZStd::clamp<int>(timingSamplesCount, FrameTimeMinLogSize, FrameTimeMaxLogSize);
  459. m_imGuiFrameTimer = AZStd::make_unique<ImGuiHistogramQueue>(timingSamplesCount, timingSamplesCount, 250.0f);
  460. }
  461. }
  462. // Set default screenshot folder to relative path 'Screenshots'
  463. AZ::IO::Path screenshotFolder = "Screenshots";
  464. // Get folder from command line if it exists
  465. static const char* screenshotFolderFlagName = "screenshotFolder";
  466. if (commandLine->HasSwitch(screenshotFolderFlagName))
  467. {
  468. screenshotFolder = commandLine->GetSwitchValue(screenshotFolderFlagName, 0);
  469. }
  470. // Make the screenshot directory relative to the Writeable Storage Path
  471. // The Path::operator/ smartly knows how to concatenate two absolute paths
  472. // i.e <absolute path1> / <absolute path2> = <absolute path2>
  473. auto settingsRegistry = AZ::SettingsRegistry::Get();
  474. AZ::IO::Path writableStoragePath;
  475. settingsRegistry->Get(writableStoragePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_DevWriteStorage);
  476. screenshotFolder = writableStoragePath / screenshotFolder;
  477. m_imguiFrameCaptureSaver.SetDefaultFolder(screenshotFolder.Native());
  478. m_imguiFrameCaptureSaver.SetDefaultFileName("screenshot");
  479. m_imguiFrameCaptureSaver.SetAvailableExtensions({ "png", "ppm", "dds" });
  480. m_imguiFrameCaptureSaver.Activate();
  481. SampleComponentManagerRequestBus::Handler::BusConnect();
  482. m_scriptManager->Activate();
  483. m_wasActivated = true;
  484. SampleComponentManagerNotificationBus::Broadcast(&SampleComponentManagerNotificationBus::Events::OnSampleManagerActivated);
  485. }
  486. void SampleComponentManager::Deactivate()
  487. {
  488. DestroyEntity(m_cameraEntity);
  489. AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
  490. AZ::Render::ImGuiSystemNotificationBus::Handler::BusDisconnect();
  491. m_scriptManager->Deactivate();
  492. m_imguiFrameCaptureSaver.Deactivate();
  493. SampleComponentSingletonRequestBus::Handler::BusDisconnect();
  494. SampleComponentManagerRequestBus::Handler::BusDisconnect();
  495. AZ::TickBus::Handler::BusDisconnect();
  496. AzFramework::InputChannelEventListener::Disconnect();
  497. Render::ImGuiSystemRequestBus::Broadcast(&Render::ImGuiSystemRequests::PopActiveContext);
  498. m_imguiPassTree.Reset();
  499. m_imguiFrameGraphVisualizer.Reset();
  500. m_windowContext = nullptr;
  501. m_brdfTexture.reset();
  502. ReleaseRHIScene();
  503. ReleaseRPIScene();
  504. }
  505. void SampleComponentManager::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  506. {
  507. if (auto* xrSystem = AZ::RPI::RPISystemInterface::Get()->GetXRSystem())
  508. {
  509. EnableRenderPipeline(xrSystem->GetRHIXRRenderingInterface()->IsDefaultRenderPipelineEnabledOnHost());
  510. //Only enable XR pipelines if the XR drivers indicate we have accurate pose information from the device
  511. EnableXrPipelines(xrSystem->ShouldRender());
  512. }
  513. if (m_imGuiFrameTimer)
  514. {
  515. m_imGuiFrameTimer->PushValue(deltaTime * 1000.0f);
  516. }
  517. bool screenshotRequest = false;
  518. if (m_ctrlModifierLDown || m_ctrlModifierRDown)
  519. {
  520. if (m_alphanumericQDown)
  521. {
  522. RequestExit();
  523. return;
  524. }
  525. if (m_alphanumericTDown && m_canCaptureRADTM)
  526. {
  527. #ifdef AZ_PROFILE_TELEMETRY
  528. Utils::ToggleRadTMCapture();
  529. m_canCaptureRADTM = false;
  530. #endif
  531. }
  532. else if (!m_alphanumericTDown)
  533. {
  534. m_canCaptureRADTM = true;
  535. }
  536. if (m_alphanumericPDown)
  537. {
  538. screenshotRequest = true;
  539. }
  540. }
  541. // Request a frame capture only once per key press, even if the keys are held down for multiple ticks.
  542. if (screenshotRequest)
  543. {
  544. ++m_screenshotKeyDownCount;
  545. if (m_screenshotKeyDownCount == 1)
  546. {
  547. RequestFrameCapture(m_imguiFrameCaptureSaver.GetNextAutoSaveFilePath(), true);
  548. }
  549. }
  550. else
  551. {
  552. m_screenshotKeyDownCount = 0;
  553. }
  554. RenderImGui(deltaTime);
  555. // SampleChange needs to happen after RenderImGui as some of the samples create sidebars on a separate ImGui context
  556. // which can interfere with m_imguiContext in the first frame
  557. if (m_sampleChangeRequest && m_canSwitchSample)
  558. {
  559. SampleChange();
  560. m_canSwitchSample = false;
  561. }
  562. else if (m_escapeDown && m_canSwitchSample)
  563. {
  564. Reset();
  565. m_canSwitchSample = false;
  566. Utils::ReportScriptableAction("OpenSample('')");
  567. }
  568. // Once a SampleChange/Reset request has been handled, it will not be handled again until there has been at least one frame where the sample hasn't changed
  569. if (!m_sampleChangeRequest && !m_escapeDown)
  570. {
  571. m_canSwitchSample = true;
  572. }
  573. // Since the event has been handled, clear the request
  574. m_sampleChangeRequest = false;
  575. m_escapeDown = false;
  576. m_scriptManager->TickScript(deltaTime);
  577. if (m_isFrameCapturePending)
  578. {
  579. if (m_countdownForFrameCapture > 0)
  580. {
  581. m_countdownForFrameCapture--;
  582. }
  583. else if (m_countdownForFrameCapture == 0)
  584. {
  585. AZ::Render::FrameCaptureOutcome capOutcome;
  586. AZ::Render::FrameCaptureRequestBus::BroadcastResult(capOutcome, &AZ::Render::FrameCaptureRequestBus::Events::CaptureScreenshot, m_frameCaptureFilePath);
  587. if (capOutcome.IsSuccess()) // if unsuccessfull leave state to attempt again next tick
  588. {
  589. m_frameCaptureId = capOutcome.GetValue();
  590. AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect(m_frameCaptureId);
  591. m_countdownForFrameCapture = -1; // Don't call CaptureScreenshot again
  592. }
  593. else
  594. {
  595. m_frameCaptureId = AZ::Render::InvalidFrameCaptureId;
  596. }
  597. }
  598. }
  599. }
  600. bool SampleComponentManager::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel)
  601. {
  602. const size_t samplesAvailableCount = m_availableSamples.size();
  603. AZStd::vector<AzFramework::InputChannelId> sampleInputMapping;
  604. sampleInputMapping.reserve(samplesAvailableCount);
  605. for (size_t i = 0; i < samplesAvailableCount; ++i)
  606. {
  607. switch (i)
  608. {
  609. case 0:
  610. sampleInputMapping.push_back(AzFramework::InputDeviceKeyboard::Key::Alphanumeric1);
  611. break;
  612. case 1:
  613. sampleInputMapping.push_back(AzFramework::InputDeviceKeyboard::Key::Alphanumeric2);
  614. break;
  615. case 2:
  616. sampleInputMapping.push_back(AzFramework::InputDeviceKeyboard::Key::Alphanumeric3);
  617. break;
  618. case 3:
  619. sampleInputMapping.push_back(AzFramework::InputDeviceKeyboard::Key::Alphanumeric4);
  620. break;
  621. case 4:
  622. sampleInputMapping.push_back(AzFramework::InputDeviceKeyboard::Key::Alphanumeric5);
  623. break;
  624. case 5:
  625. sampleInputMapping.push_back(AzFramework::InputDeviceKeyboard::Key::Alphanumeric6);
  626. break;
  627. case 6:
  628. sampleInputMapping.push_back(AzFramework::InputDeviceKeyboard::Key::Alphanumeric7);
  629. break;
  630. case 7:
  631. sampleInputMapping.push_back(AzFramework::InputDeviceKeyboard::Key::Alphanumeric8);
  632. break;
  633. case 8:
  634. sampleInputMapping.push_back(AzFramework::InputDeviceKeyboard::Key::Alphanumeric9);
  635. break;
  636. case 9:
  637. sampleInputMapping.push_back(AzFramework::InputDeviceKeyboard::Key::Alphanumeric0);
  638. break;
  639. default:
  640. break;
  641. }
  642. }
  643. const AzFramework::InputChannelId& inputChannelId = inputChannel.GetInputChannelId();
  644. switch (inputChannel.GetState())
  645. {
  646. case AzFramework::InputChannel::State::Began:
  647. case AzFramework::InputChannel::State::Updated:
  648. {
  649. if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::ModifierCtrlL)
  650. {
  651. m_ctrlModifierLDown = true;
  652. }
  653. else if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::ModifierCtrlR)
  654. {
  655. m_ctrlModifierRDown = true;
  656. }
  657. else if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::AlphanumericQ)
  658. {
  659. m_alphanumericQDown = true;
  660. }
  661. else if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::AlphanumericT)
  662. {
  663. m_alphanumericTDown = true;
  664. }
  665. else if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::AlphanumericP)
  666. {
  667. m_alphanumericPDown = true;
  668. }
  669. else if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::Escape)
  670. {
  671. m_escapeDown = true;
  672. }
  673. break;
  674. }
  675. case AzFramework::InputChannel::State::Ended:
  676. {
  677. if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::ModifierCtrlL)
  678. {
  679. m_ctrlModifierLDown = false;
  680. }
  681. else if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::ModifierCtrlR)
  682. {
  683. m_ctrlModifierRDown = false;
  684. }
  685. else if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::AlphanumericQ)
  686. {
  687. m_alphanumericQDown = false;
  688. }
  689. else if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::AlphanumericT)
  690. {
  691. m_alphanumericTDown = false;
  692. }
  693. else if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::AlphanumericP)
  694. {
  695. m_alphanumericPDown = false;
  696. }
  697. else if (inputChannelId == AzFramework::InputDeviceKeyboard::Key::Escape)
  698. {
  699. m_escapeDown = false;
  700. }
  701. break;
  702. }
  703. default:
  704. {
  705. break;
  706. }
  707. }
  708. return false;
  709. }
  710. void SampleComponentManager::RenderImGui(float deltaTime)
  711. {
  712. if (!m_isImGuiAvailable)
  713. {
  714. return;
  715. }
  716. ShowMenuBar();
  717. if (m_exitRequested)
  718. {
  719. return;
  720. }
  721. if (m_showResizeViewportDialog)
  722. {
  723. ShowResizeViewportDialog();
  724. }
  725. if (m_showFramerateHistogram)
  726. {
  727. ShowFramerateHistogram(deltaTime);
  728. }
  729. if (m_showFrameCaptureDialog)
  730. {
  731. ShowFrameCaptureDialog();
  732. }
  733. if (m_showImGuiMetrics)
  734. {
  735. ImGui::ShowMetricsWindow(&m_showImGuiMetrics);
  736. }
  737. if (m_showSampleHelper)
  738. {
  739. ShowSampleHelper();
  740. }
  741. if (m_showAbout)
  742. {
  743. ShowAboutWindow();
  744. }
  745. if (m_showPassTree)
  746. {
  747. ShowPassTreeWindow();
  748. }
  749. if (m_showFrameGraphVisualizer)
  750. {
  751. ShowFrameGraphVisualizerWindow();
  752. }
  753. if (m_showCullingDebugWindow)
  754. {
  755. AZ::RPI::Scene* rpiScene = AZ::RPI::RPISystemInterface::Get()->GetSceneByName(AZ::Name("RPI"));
  756. if (rpiScene)
  757. {
  758. AZ::Render::ImGuiDrawCullingDebug(m_showCullingDebugWindow, rpiScene);
  759. }
  760. }
  761. if (m_showCpuProfiler)
  762. {
  763. ShowCpuProfilerWindow();
  764. }
  765. if (m_showGpuProfiler)
  766. {
  767. ShowGpuProfilerWindow();
  768. }
  769. if (m_showFileIoProfiler)
  770. {
  771. ShowFileIoProfilerWindow();
  772. }
  773. if (m_showTransientAttachmentProfiler)
  774. {
  775. ShowTransientAttachmentProfilerWindow();
  776. }
  777. m_scriptManager->TickImGui();
  778. m_contentWarningDialog.TickPopup();
  779. }
  780. void SampleComponentManager::ShowMenuBar()
  781. {
  782. if (ImGui::BeginMainMenuBar())
  783. {
  784. // If imgui doesn't have enough room to render a menu, it will fall back to the safe area which
  785. // is typically 3 pixels. This causes the menu to overlap the menu bar, and makes it easy to
  786. // accidentally select the first item on that menu bar. By altering the safe area temporarily
  787. // while drawing the menu, this problem can be avoided.
  788. ImVec2 cachedSafeArea = ImGui::GetStyle().DisplaySafeAreaPadding;
  789. ImGui::GetStyle().DisplaySafeAreaPadding = ImVec2(cachedSafeArea.x, cachedSafeArea.y + 16.0f);
  790. if (ImGui::BeginMenu("File"))
  791. {
  792. if (ImGui::MenuItem("Exit", "Ctrl-Q"))
  793. {
  794. RequestExit();
  795. }
  796. if (ImGui::MenuItem("Capture Frame...", "Ctrl-P"))
  797. {
  798. m_showFrameCaptureDialog = true;
  799. }
  800. ImGui::EndMenu();
  801. }
  802. if (ImGui::BeginMenu("View"))
  803. {
  804. if (Utils::SupportsResizeClientArea() && ImGui::MenuItem("Resize Viewport..."))
  805. {
  806. m_showResizeViewportDialog = true;
  807. }
  808. if (Utils::SupportsToggleFullScreenOfDefaultWindow() && ImGui::MenuItem("Toggle Full Screen"))
  809. {
  810. Utils::ToggleFullScreenOfDefaultWindow();
  811. }
  812. if (ImGui::MenuItem("Frame Time Histogram"))
  813. {
  814. m_showFramerateHistogram = !m_showFramerateHistogram;
  815. }
  816. if (ImGui::MenuItem("ImGui Metrics"))
  817. {
  818. m_showImGuiMetrics = !m_showImGuiMetrics;
  819. }
  820. if (ImGui::MenuItem("Sample Helper"))
  821. {
  822. m_showSampleHelper = !m_showSampleHelper;
  823. }
  824. if (ImGui::MenuItem("Frame Graph Visualizer"))
  825. {
  826. m_showFrameGraphVisualizer = !m_showFrameGraphVisualizer;
  827. }
  828. ImGui::EndMenu();
  829. }
  830. if (ImGui::BeginMenu("Samples"))
  831. {
  832. for (auto&& [parentMenuName, samples] : m_groupedSamples)
  833. {
  834. if (ImGui::BeginMenu(parentMenuName.c_str()))
  835. {
  836. for (int32_t index : samples)
  837. {
  838. SampleEntry& sample = m_availableSamples[index];
  839. const char* sampleName = sample.m_sampleName.c_str();
  840. bool enabled = m_isSampleSupported[index];
  841. if (ImGui::MenuItem(sampleName, nullptr, false, enabled))
  842. {
  843. Utils::ReportScriptableAction("OpenSample('%s')", sample.m_sampleName.c_str());
  844. if (sample.m_contentWarning.empty())
  845. {
  846. m_sampleChangeRequest = true;
  847. m_selectedSampleIndex = index;
  848. }
  849. else
  850. {
  851. m_contentWarningDialog.OpenPopupConfirmation(
  852. sample.m_contentWarningTitle,
  853. sample.m_contentWarning,
  854. [this, index]() {
  855. m_sampleChangeRequest = true;
  856. m_selectedSampleIndex = index;
  857. });
  858. }
  859. }
  860. }
  861. ImGui::EndMenu();
  862. }
  863. }
  864. ImGui::EndMenu();
  865. }
  866. #ifdef AZ_PROFILE_TELEMETRY
  867. if (ImGui::BeginMenu("RADTelemetry"))
  868. {
  869. if (ImGui::MenuItem("Toggle Capture", "Ctrl-T"))
  870. {
  871. Utils::ToggleRadTMCapture();
  872. }
  873. ImGui::EndMenu();
  874. }
  875. #endif // AZ_PROFILE_TELEMETRY
  876. if (ImGui::BeginMenu("Automation"))
  877. {
  878. const char* AutomationContentWarningTitle = AtomSampleComponent::CommonPhotosensitiveWarningTitle;
  879. const char* AutomationContentWarning = "Running automated scripts will trigger flashing images that could cause seizures or other adverse effects in photosensitive individuals.";
  880. if (ImGui::MenuItem("Run Script..."))
  881. {
  882. m_contentWarningDialog.OpenPopupConfirmation(
  883. AutomationContentWarningTitle,
  884. AutomationContentWarning,
  885. [this]() {
  886. m_scriptManager->OpenScriptRunnerDialog();
  887. });
  888. }
  889. if (ImGui::MenuItem("Run Precommit Wizard..."))
  890. {
  891. m_contentWarningDialog.OpenPopupConfirmation(
  892. AutomationContentWarningTitle,
  893. AutomationContentWarning,
  894. [this]() {
  895. m_scriptManager->OpenPrecommitWizard();
  896. });
  897. }
  898. ImGui::EndMenu();
  899. }
  900. if (ImGui::BeginMenu("Pass"))
  901. {
  902. if (ImGui::MenuItem(PassTreeToolName))
  903. {
  904. m_showPassTree = !m_showPassTree;
  905. Utils::ReportScriptableAction("ShowTool('%s', %s)", PassTreeToolName, m_showPassTree?"true":"false");
  906. }
  907. ImGui::EndMenu();
  908. }
  909. if (ImGui::BeginMenu("Culling"))
  910. {
  911. if (ImGui::MenuItem("Culling Debug Window"))
  912. {
  913. m_showCullingDebugWindow = !m_showCullingDebugWindow;
  914. }
  915. ImGui::EndMenu();
  916. }
  917. if (ImGui::BeginMenu("Profile"))
  918. {
  919. if (ImGui::MenuItem(CpuProfilerToolName))
  920. {
  921. m_showCpuProfiler = !m_showCpuProfiler;
  922. if (auto profilerSystem = AZ::Debug::ProfilerSystemInterface::Get(); profilerSystem)
  923. {
  924. profilerSystem->SetActive(m_showCpuProfiler);
  925. }
  926. Utils::ReportScriptableAction("ShowTool('%s', %s)", CpuProfilerToolName, m_showCpuProfiler ? "true" : "false");
  927. }
  928. if (AZ::IO::StreamerProfiler::Get() != nullptr)
  929. {
  930. if (ImGui::MenuItem(FileIoProfilerToolName))
  931. {
  932. m_showFileIoProfiler = !m_showFileIoProfiler;
  933. Utils::ReportScriptableAction(
  934. "ShowTool('%s', %s)", FileIoProfilerToolName, m_showFileIoProfiler ? "true" : "false");
  935. }
  936. }
  937. if (ImGui::MenuItem(GpuProfilerToolName))
  938. {
  939. m_showGpuProfiler = !m_showGpuProfiler;
  940. Utils::ReportScriptableAction("ShowTool('%s', %s)", GpuProfilerToolName, m_showGpuProfiler ? "true" : "false");
  941. }
  942. if (ImGui::MenuItem(TransientAttachmentProfilerToolName))
  943. {
  944. m_showTransientAttachmentProfiler = !m_showTransientAttachmentProfiler;
  945. AZ::RHI::RHISystemInterface::Get()->ModifyFrameSchedulerStatisticsFlags(
  946. AZ::RHI::FrameSchedulerStatisticsFlags::GatherTransientAttachmentStatistics,
  947. m_showTransientAttachmentProfiler);
  948. Utils::ReportScriptableAction("ShowTool('%s', %s)", TransientAttachmentProfilerToolName, m_showTransientAttachmentProfiler ? "true" : "false");
  949. }
  950. ImGui::EndMenu();
  951. }
  952. if (ImGui::BeginMenu("Help"))
  953. {
  954. if (ImGui::MenuItem("About"))
  955. {
  956. m_showAbout = !m_showAbout;
  957. }
  958. ImGui::EndMenu();
  959. }
  960. // Restore original safe area.
  961. ImGui::GetStyle().DisplaySafeAreaPadding = cachedSafeArea;
  962. ImGui::EndMainMenuBar();
  963. }
  964. }
  965. void SampleComponentManager::ShowSampleHelper()
  966. {
  967. if (ImGui::Begin("Sample Helper", &m_showSampleHelper, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings))
  968. {
  969. if (ImGui::Button("Reset"))
  970. {
  971. //Removes the existing sample component and
  972. //resets the selection index
  973. Reset();
  974. CameraReset();
  975. m_selectedSampleIndex = -1;
  976. }
  977. ImGui::SameLine();
  978. if (ImGui::Button("Reset Sample"))
  979. {
  980. //Force a sample change event when the selection index
  981. //hasn't changed. This resets the sample component.
  982. SampleChange();
  983. }
  984. ImGui::SameLine();
  985. if (ImGui::Button("Reset Camera"))
  986. {
  987. CameraReset();
  988. }
  989. }
  990. ImGui::End();
  991. }
  992. void SampleComponentManager::ShowAboutWindow()
  993. {
  994. if (ImGui::Begin("About", &m_showAbout, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings))
  995. {
  996. ImGui::Text("RHI API: %s", AZ::RHI::Factory::Get().GetName().GetCStr());
  997. }
  998. ImGui::End();
  999. }
  1000. void SampleComponentManager::ShowPassTreeWindow()
  1001. {
  1002. m_imguiPassTree.Draw(m_showPassTree, AZ::RPI::PassSystemInterface::Get()->GetRootPass().get());
  1003. }
  1004. void SampleComponentManager::ShowFrameGraphVisualizerWindow()
  1005. {
  1006. AZ::RHI::Device* rhiDevice = Utils::GetRHIDevice().get();
  1007. m_imguiFrameGraphVisualizer.Init(rhiDevice);
  1008. m_imguiFrameGraphVisualizer.Draw(m_showFrameGraphVisualizer);
  1009. }
  1010. void SampleComponentManager::ShowCpuProfilerWindow()
  1011. {
  1012. if (auto profilerImGui = Profiler::ProfilerImGuiInterface::Get(); profilerImGui)
  1013. {
  1014. profilerImGui->ShowCpuProfilerWindow(m_showCpuProfiler);
  1015. }
  1016. }
  1017. void SampleComponentManager::ShowFileIoProfilerWindow()
  1018. {
  1019. if (auto profilerImGui = AZ::IO::StreamerProfiler::Get(); profilerImGui)
  1020. {
  1021. profilerImGui->DrawStatistics(m_showFileIoProfiler);
  1022. }
  1023. }
  1024. void SampleComponentManager::ShowGpuProfilerWindow()
  1025. {
  1026. m_imguiGpuProfiler.Draw(m_showGpuProfiler, AZ::RPI::PassSystemInterface::Get()->GetRootPass());
  1027. }
  1028. void SampleComponentManager::ShowTransientAttachmentProfilerWindow()
  1029. {
  1030. const auto& transientStats = AZ::RHI::RHIMemoryStatisticsInterface::Get()->GetTransientAttachmentStatistics();
  1031. if (!transientStats.empty())
  1032. {
  1033. m_showTransientAttachmentProfiler = m_imguiTransientAttachmentProfiler.Draw(transientStats);
  1034. }
  1035. }
  1036. void SampleComponentManager::ShowResizeViewportDialog()
  1037. {
  1038. static int size[2] = { 0, 0 };
  1039. if (size[0] <= 0)
  1040. {
  1041. size[0] = aznumeric_cast<int>(m_windowContext->GetViewport().m_maxX - m_windowContext->GetViewport().m_minX);
  1042. }
  1043. if (size[1] <= 0)
  1044. {
  1045. size[1] = aznumeric_cast<int>(m_windowContext->GetViewport().m_maxY - m_windowContext->GetViewport().m_minY);
  1046. }
  1047. bool dialogWasOpen = m_showResizeViewportDialog;
  1048. if (ImGui::Begin("Resize Viewport", &m_showResizeViewportDialog, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings))
  1049. {
  1050. ImGui::InputInt2("Size", size);
  1051. if (ImGui::Button("Resize"))
  1052. {
  1053. Utils::ResizeClientArea(size[0], size[1], AzFramework::WindowPosOptions());
  1054. Utils::ReportScriptableAction("ResizeViewport(%d, %d)", size[0], size[1]);
  1055. // Re-initialize the size fields on the next frame so we can see whether the
  1056. // correct size was achieved (should be the same values the user entered)...
  1057. size[0] = 0;
  1058. size[1] = 0;
  1059. }
  1060. }
  1061. ImGui::End();
  1062. if (dialogWasOpen && !m_showResizeViewportDialog)
  1063. {
  1064. // Re-initialize the size fields next time the dialog is shown...
  1065. size[0] = 0;
  1066. size[1] = 0;
  1067. }
  1068. }
  1069. void SampleComponentManager::ShowFramerateHistogram(float deltaTime)
  1070. {
  1071. if (m_imGuiFrameTimer && ImGui::Begin("Frame Time Histogram", &m_showFramerateHistogram, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings))
  1072. {
  1073. ImGuiHistogramQueue::WidgetSettings settings;
  1074. settings.m_reportInverse = false;
  1075. settings.m_units = "ms";
  1076. m_imGuiFrameTimer->Tick(deltaTime * 1000.0f, settings);
  1077. }
  1078. ImGui::End();
  1079. }
  1080. void SampleComponentManager::RequestFrameCapture(const AZStd::string& filePath, bool hideImGui)
  1081. {
  1082. AZ_Assert(false == m_isFrameCapturePending, "Frame capture already in progress");
  1083. AZ_Assert(AZ::Render::InvalidFrameCaptureId == m_frameCaptureId, "Unfinished frame capture detected");
  1084. m_isFrameCapturePending = true;
  1085. m_hideImGuiDuringFrameCapture = hideImGui;
  1086. m_frameCaptureFilePath = filePath;
  1087. // Don't continue the script while a frame capture is pending in case subsequent changes
  1088. // interfere with the pending capture.
  1089. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::PauseScript);
  1090. if (m_hideImGuiDuringFrameCapture)
  1091. {
  1092. AZ::Render::ImGuiSystemRequestBus::Broadcast(&AZ::Render::ImGuiSystemRequestBus::Events::HideAllImGuiPasses);
  1093. // We also hide Open 3D Engine's debug text
  1094. AzFramework::ConsoleRequestBus::Broadcast(&AzFramework::ConsoleRequests::ExecuteConsoleCommand, "r_DisplayInfo 0");
  1095. // The ExecuteConsoleCommand request is handled in a deferred manner, so we have to delay the screenshot a bit.
  1096. m_countdownForFrameCapture = 1;
  1097. }
  1098. else
  1099. {
  1100. m_countdownForFrameCapture = 0;
  1101. }
  1102. }
  1103. void SampleComponentManager::OnFrameCaptureFinished(AZ::Render::FrameCaptureResult /*result*/, const AZStd::string& /*info*/)
  1104. {
  1105. AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect();
  1106. if (m_hideImGuiDuringFrameCapture)
  1107. {
  1108. AZ::Render::ImGuiSystemRequestBus::Broadcast(&AZ::Render::ImGuiSystemRequestBus::Events::ShowAllImGuiPasses);
  1109. // We also show Open 3D Engine's debug text
  1110. AzFramework::ConsoleRequestBus::Broadcast(&AzFramework::ConsoleRequests::ExecuteConsoleCommand, "r_DisplayInfo 1");
  1111. }
  1112. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::ResumeScript);
  1113. m_isFrameCapturePending = false;
  1114. }
  1115. bool SampleComponentManager::IsFrameCapturePending()
  1116. {
  1117. return m_isFrameCapturePending;
  1118. }
  1119. void SampleComponentManager::RunMainTestSuite(const AZStd::string& suiteFilePath, bool exitOnTestEnd, int randomSeed)
  1120. {
  1121. if (m_scriptManager)
  1122. {
  1123. m_scriptManager->RunMainTestSuite(suiteFilePath, exitOnTestEnd, randomSeed);
  1124. }
  1125. }
  1126. void SampleComponentManager::SetNumMSAASamples(int16_t numMSAASamples)
  1127. {
  1128. AZ_Assert(IsValidNumMSAASamples(numMSAASamples), "Invalid MSAA sample setting");
  1129. m_numMsaaSamples = numMSAASamples;
  1130. }
  1131. int16_t SampleComponentManager::GetNumMSAASamples()
  1132. {
  1133. return m_numMsaaSamples;
  1134. }
  1135. void SampleComponentManager::SetDefaultNumMSAASamples(int16_t defaultNumMsaaSamples)
  1136. {
  1137. m_defaultNumMsaaSamples = defaultNumMsaaSamples;
  1138. }
  1139. int16_t SampleComponentManager::GetDefaultNumMSAASamples()
  1140. {
  1141. return m_defaultNumMsaaSamples;
  1142. }
  1143. void SampleComponentManager::ResetNumMSAASamples()
  1144. {
  1145. m_numMsaaSamples = m_defaultNumMsaaSamples;
  1146. }
  1147. void SampleComponentManager::ResetRPIScene()
  1148. {
  1149. ReleaseRPIScene();
  1150. SwitchSceneForRPISample();
  1151. }
  1152. void SampleComponentManager::ClearRPIScene()
  1153. {
  1154. ReleaseRPIScene();
  1155. }
  1156. void SampleComponentManager::EnableRenderPipeline(bool value)
  1157. {
  1158. if (m_renderPipeline)
  1159. {
  1160. if (value)
  1161. {
  1162. m_renderPipeline->AddToRenderTick();
  1163. }
  1164. else
  1165. {
  1166. m_renderPipeline->RemoveFromRenderTick();
  1167. }
  1168. }
  1169. }
  1170. void SampleComponentManager::EnableXrPipelines(bool value)
  1171. {
  1172. for (RPI::RenderPipelinePtr xrPipeline : m_xrPipelines)
  1173. {
  1174. if (xrPipeline)
  1175. {
  1176. if (value)
  1177. {
  1178. xrPipeline->AddToRenderTick();
  1179. }
  1180. else
  1181. {
  1182. xrPipeline->RemoveFromRenderTick();
  1183. }
  1184. }
  1185. }
  1186. }
  1187. void SampleComponentManager::ShowFrameCaptureDialog()
  1188. {
  1189. static bool requestCaptureOnNextFrame = false;
  1190. static bool hideImGuiFromFrameCapture = true;
  1191. if (requestCaptureOnNextFrame)
  1192. {
  1193. requestCaptureOnNextFrame = false;
  1194. RequestFrameCapture(m_imguiFrameCaptureSaver.GetSaveFilePath(), hideImGuiFromFrameCapture);
  1195. }
  1196. else if (!m_isFrameCapturePending) // Hide this dialog while taking a capture
  1197. {
  1198. if (ImGui::Begin("Frame Capture", &m_showFrameCaptureDialog))
  1199. {
  1200. ImGui::Checkbox("Hide ImGui", &hideImGuiFromFrameCapture);
  1201. ImGuiSaveFilePath::WidgetSettings settings;
  1202. settings.m_labels.m_filePath = "File Path (.png, .ppm, or .dds):";
  1203. m_imguiFrameCaptureSaver.Tick(settings);
  1204. if (ImGui::Button("Capture"))
  1205. {
  1206. // Don't actually do the capture until the next frame, so we can hide this dialog first
  1207. requestCaptureOnNextFrame = true;
  1208. if (hideImGuiFromFrameCapture)
  1209. {
  1210. Utils::ReportScriptableAction("CaptureScreenshot('%s')", m_imguiFrameCaptureSaver.GetSaveFilePath().c_str());
  1211. }
  1212. else
  1213. {
  1214. Utils::ReportScriptableAction("CaptureScreenshotWithImGui('%s')", m_imguiFrameCaptureSaver.GetSaveFilePath().c_str());
  1215. }
  1216. }
  1217. }
  1218. ImGui::End();
  1219. }
  1220. }
  1221. void SampleComponentManager::RequestExit()
  1222. {
  1223. AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::ExitMainLoop);
  1224. AZ::TickBus::Handler::BusDisconnect();
  1225. AzFramework::InputChannelEventListener::Disconnect();
  1226. m_exitRequested = true;
  1227. }
  1228. void SampleComponentManager::ShutdownActiveSample()
  1229. {
  1230. m_exampleEntity->Deactivate();
  1231. // Pointer to all the passes within m_rhiSamplePasses must be nullified before all the samples within m_activeSamples are destroyed.
  1232. SetRHISamplePass(nullptr);
  1233. for (AZ::Component* activeComponent : m_activeSamples)
  1234. {
  1235. if (activeComponent != nullptr)
  1236. {
  1237. // Disable the camera controller just in case the active sample enabled it and didn't disable in Deactivate().
  1238. AZ::Debug::CameraControllerRequestBus::Event(m_cameraEntity->GetId(), &AZ::Debug::CameraControllerRequestBus::Events::Disable);
  1239. m_exampleEntity->RemoveComponent(activeComponent);
  1240. delete activeComponent;
  1241. }
  1242. }
  1243. m_activeSamples.clear();
  1244. // Force a reset of the shader variant finder to get more consistent testing of samples every time they are run, rather
  1245. // than the first time for each sample being "special".
  1246. auto variantFinder = AZ::Interface<AZ::RPI::IShaderVariantFinder>::Get();
  1247. variantFinder->Reset();
  1248. }
  1249. void SampleComponentManager::Reset()
  1250. {
  1251. ShutdownActiveSample();
  1252. m_exampleEntity->Activate();
  1253. // Reset to RHI sample pipeline
  1254. SwitchSceneForRHISample();
  1255. SetRHISamplePass(nullptr);
  1256. }
  1257. void SampleComponentManager::CreateDefaultCamera()
  1258. {
  1259. if (m_cameraEntity)
  1260. {
  1261. return;
  1262. }
  1263. // A camera entity will be created by the entity context request bus so that the component for this entity can use a feature processor.
  1264. AzFramework::EntityContextRequestBus::EventResult(m_cameraEntity, m_entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "CameraEntity");
  1265. //Add debug camera and controller components
  1266. AZ::Debug::CameraComponentConfig cameraConfig(m_windowContext);
  1267. cameraConfig.m_fovY = AZ::Constants::QuarterPi;
  1268. cameraConfig.m_depthFar = 1000.0f;
  1269. m_cameraEntity->CreateComponent(azrtti_typeid<AZ::Debug::CameraComponent>())
  1270. ->SetConfiguration(cameraConfig);
  1271. m_cameraEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
  1272. m_cameraEntity->CreateComponent(azrtti_typeid<AZ::Debug::ArcBallControllerComponent>());
  1273. m_cameraEntity->CreateComponent(azrtti_typeid<AZ::Debug::NoClipControllerComponent>());
  1274. m_cameraEntity->Activate();
  1275. m_scriptManager->SetCameraEntity(m_cameraEntity);
  1276. }
  1277. void SampleComponentManager::SetupImGuiContext()
  1278. {
  1279. AdjustImGuiFontScale();
  1280. // Add imgui context
  1281. Render::ImGuiSystemRequestBus::BroadcastResult(m_isImGuiAvailable, &Render::ImGuiSystemRequests::PushActiveContextFromDefaultPass);
  1282. AZ_Assert(m_isImGuiAvailable, "Unable set default imgui context to active. Does your pipeline have an ImGui pass marked as default? Your pass assets may need to be rebuilt.");
  1283. }
  1284. void SampleComponentManager::ActiveImGuiContextChanged(ImGuiContext* context)
  1285. {
  1286. ImGui::SetCurrentContext(context);
  1287. }
  1288. bool SampleComponentManager::OpenSample(const AZStd::string& sampleName)
  1289. {
  1290. for (int32_t i = 0; i < m_availableSamples.size(); i++)
  1291. {
  1292. if (m_availableSamples[i].m_parentMenuName + '/' + m_availableSamples[i].m_sampleName == sampleName)
  1293. {
  1294. if (!m_availableSamples[i].m_isSupportedFunc || m_availableSamples[i].m_isSupportedFunc())
  1295. {
  1296. m_selectedSampleIndex = i;
  1297. m_sampleChangeRequest = true;
  1298. return true;
  1299. }
  1300. else
  1301. {
  1302. AZ_Error("SampleComponentManager", false, "Sample '%s' is not supported on this platform.", sampleName.c_str());
  1303. }
  1304. }
  1305. }
  1306. return false;
  1307. }
  1308. bool SampleComponentManager::ShowTool(const AZStd::string& toolName, bool enable)
  1309. {
  1310. if (toolName == PassTreeToolName)
  1311. {
  1312. m_showPassTree = enable;
  1313. return true;
  1314. }
  1315. else if (toolName == CpuProfilerToolName)
  1316. {
  1317. m_showCpuProfiler = enable;
  1318. return true;
  1319. }
  1320. else if (toolName == FileIoProfilerToolName)
  1321. {
  1322. m_showFileIoProfiler = enable;
  1323. return true;
  1324. }
  1325. else if (toolName == GpuProfilerToolName)
  1326. {
  1327. m_showGpuProfiler = enable;
  1328. return true;
  1329. }
  1330. else if (toolName == TransientAttachmentProfilerToolName)
  1331. {
  1332. m_showTransientAttachmentProfiler = enable;
  1333. return true;
  1334. }
  1335. return false;
  1336. }
  1337. void SampleComponentManager::SampleChange()
  1338. {
  1339. if (m_selectedSampleIndex == -1)
  1340. {
  1341. return;
  1342. }
  1343. ShutdownActiveSample();
  1344. // Reset the camera *before* activating the sample, because the sample's Activate() function might
  1345. // want to reposition the camera.
  1346. CameraReset();
  1347. const SampleEntry& sampleEntry = m_availableSamples[m_selectedSampleIndex];
  1348. // Create scene and render pipeline before create sample component
  1349. if (sampleEntry.m_pipelineType == SamplePipelineType::RHI)
  1350. {
  1351. SwitchSceneForRHISample();
  1352. }
  1353. else if (sampleEntry.m_pipelineType == SamplePipelineType::RPI)
  1354. {
  1355. SwitchSceneForRPISample();
  1356. }
  1357. SampleComponentConfig config(m_windowContext, m_cameraEntity->GetId(), m_entityContextId);
  1358. // special setup for RHI samples
  1359. if (sampleEntry.m_pipelineType == SamplePipelineType::RHI)
  1360. {
  1361. for (AZ::RPI::Ptr<RHISamplePass> samplePass : m_rhiSamplePasses)
  1362. {
  1363. BasicRHIComponent* rhiSampleComponent = static_cast<BasicRHIComponent*>(m_exampleEntity->CreateComponent(sampleEntry.m_sampleUuid));
  1364. rhiSampleComponent->SetConfiguration(config);
  1365. rhiSampleComponent->SetViewIndex(samplePass->GetViewIndex());
  1366. if (rhiSampleComponent->IsSupportedRHISamplePipeline())
  1367. {
  1368. samplePass->SetRHISample(rhiSampleComponent);
  1369. }
  1370. else
  1371. {
  1372. samplePass->SetRHISample(nullptr);
  1373. }
  1374. m_activeSamples.push_back(rhiSampleComponent);
  1375. }
  1376. }
  1377. else
  1378. {
  1379. AZ::Component* newComponent = m_exampleEntity->CreateComponent(sampleEntry.m_sampleUuid);
  1380. newComponent->SetConfiguration(config);
  1381. m_activeSamples.push_back(newComponent);
  1382. }
  1383. m_exampleEntity->Activate();
  1384. // Even though this is done in CameraReset(), the example component wasn't activated at the time so we have to send this event again.
  1385. ExampleComponentRequestBus::Event(m_exampleEntity->GetId(), &ExampleComponentRequestBus::Events::ResetCamera);
  1386. }
  1387. void SampleComponentManager::CameraReset()
  1388. {
  1389. // Reset the camera transform. Some examples do not use a controller or use a controller that doesn't override the whole transform.
  1390. // Set to a transform that is 5 units away from the origin and looking at the origin along the Y axis.
  1391. const AZ::EntityId cameraEntityId = m_cameraEntity->GetId();
  1392. AZ::TransformBus::Event(cameraEntityId, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3(0.0f, -5.0f, 0.0f)));
  1393. AZ::Debug::CameraControllerRequestBus::Event(cameraEntityId, &AZ::Debug::CameraControllerRequestBus::Events::Reset);
  1394. // Tell the current example to reset the camera, any example that controls the camera and preserves controller state should implement this event
  1395. ExampleComponentRequestBus::Event(m_exampleEntity->GetId(), &ExampleComponentRequestBus::Events::ResetCamera);
  1396. }
  1397. void SampleComponentManager::CreateSceneForRHISample()
  1398. {
  1399. // Create and register the rhi scene with only feature processors required for AtomShimRenderer (only for AtomSampleViewerLauncher)
  1400. RPI::SceneDescriptor sceneDesc;
  1401. sceneDesc.m_nameId = AZ::Name("RHI");
  1402. sceneDesc.m_featureProcessorNames.push_back("AZ::Render::AuxGeomFeatureProcessor");
  1403. m_rhiScene = RPI::Scene::CreateScene(sceneDesc);
  1404. m_rhiScene->Activate();
  1405. auto* xrSystem = AZ::RHI::RHISystemInterface::Get()->GetXRSystem();
  1406. const bool createDefaultRenderPipeline = !xrSystem || xrSystem->IsDefaultRenderPipelineNeeded();
  1407. if (createDefaultRenderPipeline)
  1408. {
  1409. RPI::RenderPipelineDescriptor pipelineDesc;
  1410. pipelineDesc.m_name = "RHISamplePipeline";
  1411. pipelineDesc.m_rootPassTemplate = "RHISamplePipelineTemplate";
  1412. // Add view to pipeline since there are few RHI samples are using ViewSrg
  1413. pipelineDesc.m_mainViewTagName = "MainCamera";
  1414. m_renderPipeline = RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineDesc, *m_windowContext.get());
  1415. m_rhiScene->AddRenderPipeline(m_renderPipeline);
  1416. m_renderPipeline->SetDefaultViewFromEntity(m_cameraEntity->GetId());
  1417. // Get RHISamplePass
  1418. AZ::RPI::PassFilter passFilter = AZ::RPI::PassFilter::CreateWithPassName(AZ::Name("RHISamplePass"), m_renderPipeline.get());
  1419. m_rhiSamplePasses.push_back(azrtti_cast<RHISamplePass*>(AZ::RPI::PassSystemInterface::Get()->FindFirstPass(passFilter)));
  1420. // Enable or disable default pipeline on host while there is an xr system.
  1421. if (xrSystem)
  1422. {
  1423. EnableRenderPipeline(xrSystem->IsDefaultRenderPipelineEnabledOnHost());
  1424. }
  1425. }
  1426. if (xrSystem)
  1427. {
  1428. RPI::RenderPipelineDescriptor xrPipelineDesc;
  1429. xrPipelineDesc.m_mainViewTagName = "MainCamera";
  1430. // Build the pipeline for left eye
  1431. xrPipelineDesc.m_name = "RHISamplePipelineXRLeft";
  1432. xrPipelineDesc.m_rootPassTemplate = "RHISamplePipelineXRLeftTemplate";
  1433. RPI::RenderPipelinePtr renderPipelineLeft = RPI::RenderPipeline::CreateRenderPipelineForWindow(xrPipelineDesc, *m_windowContext.get(), AZ::RPI::ViewType::XrLeft);
  1434. // Build the pipeline for right eye
  1435. xrPipelineDesc.m_name = "RHISamplePipelineXRRight";
  1436. xrPipelineDesc.m_rootPassTemplate = "RHISamplePipelineXRRightTemplate";
  1437. RPI::RenderPipelinePtr renderPipelineRight = RPI::RenderPipeline::CreateRenderPipelineForWindow(xrPipelineDesc, *m_windowContext.get(), AZ::RPI::ViewType::XrRight);
  1438. //Add both the pipelines to the scene
  1439. m_rhiScene->AddRenderPipeline(renderPipelineLeft);
  1440. m_rhiScene->AddRenderPipeline(renderPipelineRight);
  1441. renderPipelineLeft->SetDefaultViewFromEntity(m_cameraEntity->GetId());
  1442. renderPipelineRight->SetDefaultViewFromEntity(m_cameraEntity->GetId());
  1443. // Set the correct view index for the RHI sample passes
  1444. AZ::RPI::PassFilter rhiSamplePassFilterLeft = AZ::RPI::PassFilter::CreateWithPassName(AZ::Name("RHISamplePass"), renderPipelineLeft.get());
  1445. AZ::RPI::Ptr<RHISamplePass> rhiSamplePassLeft = azrtti_cast<RHISamplePass*>(AZ::RPI::PassSystemInterface::Get()->FindFirstPass(rhiSamplePassFilterLeft));
  1446. rhiSamplePassLeft->SetViewIndex(0);
  1447. m_rhiSamplePasses.push_back(rhiSamplePassLeft);
  1448. AZ::RPI::PassFilter rhiSamplePassFilterRight = AZ::RPI::PassFilter::CreateWithPassName(AZ::Name("RHISamplePass"), renderPipelineRight.get());
  1449. AZ::RPI::Ptr<RHISamplePass> rhiSamplePassRight = azrtti_cast<RHISamplePass*>(AZ::RPI::PassSystemInterface::Get()->FindFirstPass(rhiSamplePassFilterRight));
  1450. rhiSamplePassRight->SetViewIndex(1);
  1451. m_rhiSamplePasses.push_back(rhiSamplePassRight);
  1452. //Cache the pipelines in case we want to enable/disable them
  1453. m_xrPipelines.push_back(renderPipelineLeft);
  1454. m_xrPipelines.push_back(renderPipelineRight);
  1455. //Disable XR pipelines by default
  1456. EnableXrPipelines(false);
  1457. }
  1458. // Register the RHi scene
  1459. RPI::RPISystemInterface::Get()->RegisterScene(m_rhiScene);
  1460. // Setup imGui since a new render pipeline with imgui pass was created
  1461. SetupImGuiContext();
  1462. }
  1463. void SampleComponentManager::ReleaseRHIScene()
  1464. {
  1465. if (m_rhiScene)
  1466. {
  1467. m_rhiSamplePasses.clear();
  1468. m_xrPipelines.clear();
  1469. m_renderPipeline = nullptr;
  1470. RPI::RPISystemInterface::Get()->UnregisterScene(m_rhiScene);
  1471. m_rhiScene = nullptr;
  1472. }
  1473. }
  1474. void SampleComponentManager::SwitchSceneForRHISample()
  1475. {
  1476. ReleaseRPIScene();
  1477. ReleaseRHIScene();
  1478. CreateSceneForRHISample();
  1479. }
  1480. void SampleComponentManager::CreateSceneForRPISample()
  1481. {
  1482. // set pipeline MSAA samples
  1483. AZ_Assert(IsValidNumMSAASamples(m_numMsaaSamples), "Invalid MSAA sample setting");
  1484. const bool isNonMsaaPipeline = (m_numMsaaSamples == 1);
  1485. const char* supervariantName = isNonMsaaPipeline ? AZ::RPI::NoMsaaSupervariantName : "";
  1486. AZ::RPI::ShaderSystemInterface::Get()->SetSupervariantName(AZ::Name(supervariantName));
  1487. // Create and register a scene with all available feature processors
  1488. RPI::SceneDescriptor sceneDesc;
  1489. sceneDesc.m_nameId = AZ::Name("RPI");
  1490. m_rpiScene = RPI::Scene::CreateScene(sceneDesc);
  1491. m_rpiScene->EnableAllFeatureProcessors();
  1492. // Bind m_rpiScene to the GameEntityContext's AzFramework::Scene so the RPI Scene can be found by the entity context
  1493. auto sceneSystem = AzFramework::SceneSystemInterface::Get();
  1494. AZ_Assert(sceneSystem, "SampleComponentManager requires an implementation of the scene system.");
  1495. AZStd::shared_ptr<AzFramework::Scene> mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName);
  1496. AZ_Assert(mainScene, "Main scene missing during system component initialization"); // This should never happen unless scene creation has changed.
  1497. // Add RPI::Scene as a sub system for the default AzFramework Scene
  1498. [[maybe_unused]] bool result = mainScene->SetSubsystem(m_rpiScene);
  1499. AZ_Assert(result, "SampleComponentManager failed to register the RPI scene with the general scene.");
  1500. m_rpiScene->Activate();
  1501. // Register scene to RPI system so it will be processed/rendered per tick
  1502. RPI::RPISystemInterface::Get()->RegisterScene(m_rpiScene);
  1503. auto* xrSystem = AZ::RHI::RHISystemInterface::Get()->GetXRSystem();
  1504. const bool createDefaultRenderPipeline = !xrSystem || xrSystem->IsDefaultRenderPipelineNeeded();
  1505. if (createDefaultRenderPipeline)
  1506. {
  1507. // Create MainPipeline as its render pipeline
  1508. RPI::RenderPipelineDescriptor pipelineDesc;
  1509. pipelineDesc.m_name = "RPISamplePipeline";
  1510. pipelineDesc.m_rootPassTemplate = GetRootPassTemplateName();
  1511. pipelineDesc.m_materialPipelineTag = GetMaterialPipelineName();
  1512. pipelineDesc.m_mainViewTagName = "MainCamera";
  1513. pipelineDesc.m_allowModification = true;
  1514. pipelineDesc.m_renderSettings.m_multisampleState.m_samples = static_cast<uint16_t>(m_numMsaaSamples);
  1515. m_renderPipeline = RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineDesc, *m_windowContext.get());
  1516. m_rpiScene->AddRenderPipeline(m_renderPipeline);
  1517. m_renderPipeline->SetDefaultViewFromEntity(m_cameraEntity->GetId());
  1518. // Enable or disable default pipeline on host while there is an xr system.
  1519. if (xrSystem)
  1520. {
  1521. EnableRenderPipeline(xrSystem->IsDefaultRenderPipelineEnabledOnHost());
  1522. }
  1523. }
  1524. if (xrSystem)
  1525. {
  1526. RPI::RenderPipelineDescriptor xrPipelineDesc;
  1527. xrPipelineDesc.m_mainViewTagName = "MainCamera";
  1528. xrPipelineDesc.m_renderSettings.m_multisampleState.m_samples = static_cast<uint16_t>(m_numMsaaSamples);
  1529. // Build the pipeline for left eye
  1530. xrPipelineDesc.m_name = "RPISamplePipelineXRLeft";
  1531. xrPipelineDesc.m_materialPipelineTag = "MultiViewPipeline";
  1532. xrPipelineDesc.m_rootPassTemplate = "MultiViewPipelineTemplate";
  1533. RPI::RenderPipelinePtr renderPipelineLeft = RPI::RenderPipeline::CreateRenderPipelineForWindow(xrPipelineDesc, *m_windowContext.get(), AZ::RPI::ViewType::XrLeft);
  1534. // Build the pipeline for right eye
  1535. xrPipelineDesc.m_name = "RHISamplePipelineXRRight";
  1536. xrPipelineDesc.m_materialPipelineTag = "MultiViewPipeline";
  1537. xrPipelineDesc.m_rootPassTemplate = "MultiViewPipelineTemplate";
  1538. RPI::RenderPipelinePtr renderPipelineRight = RPI::RenderPipeline::CreateRenderPipelineForWindow(xrPipelineDesc, *m_windowContext.get(), AZ::RPI::ViewType::XrRight);
  1539. //Add both the pipelines to the scene
  1540. m_rpiScene->AddRenderPipeline(renderPipelineLeft);
  1541. m_rpiScene->AddRenderPipeline(renderPipelineRight);
  1542. renderPipelineLeft->SetDefaultStereoscopicViewFromEntity(m_cameraEntity->GetId(), RPI::ViewType::XrLeft); //Left eye
  1543. renderPipelineRight->SetDefaultStereoscopicViewFromEntity(m_cameraEntity->GetId(), RPI::ViewType::XrRight); //Right eye
  1544. //Cache the pipelines in case we want to enable/disable them
  1545. m_xrPipelines.push_back(renderPipelineLeft);
  1546. m_xrPipelines.push_back(renderPipelineRight);
  1547. // Disable XR pipelines by default
  1548. EnableXrPipelines(false);
  1549. }
  1550. // As part of our initialization we need to create the BRDF texture generation pipeline
  1551. AZ::RPI::RenderPipelineDescriptor brdfPipelineDesc;
  1552. brdfPipelineDesc.m_mainViewTagName = "MainCamera";
  1553. brdfPipelineDesc.m_name = "BRDFTexturePipeline";
  1554. brdfPipelineDesc.m_rootPassTemplate = "BRDFTexturePipeline";
  1555. brdfPipelineDesc.m_executeOnce = true;
  1556. RPI::RenderPipelinePtr brdfTexturePipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(brdfPipelineDesc);
  1557. m_rpiScene->AddRenderPipeline(brdfTexturePipeline);
  1558. // Save a reference to the generated BRDF texture so it doesn't get deleted if all the passes referring to it get deleted and it's ref count goes to zero
  1559. if (!m_brdfTexture)
  1560. {
  1561. const AZStd::shared_ptr<const RPI::PassTemplate> brdfTextureTemplate = RPI::PassSystemInterface::Get()->GetPassTemplate(Name("BRDFTextureTemplate"));
  1562. Data::Asset<RPI::AttachmentImageAsset> brdfImageAsset = RPI::AssetUtils::LoadAssetById<RPI::AttachmentImageAsset>(
  1563. brdfTextureTemplate->m_imageAttachments[0].m_assetRef.m_assetId, RPI::AssetUtils::TraceLevel::Error);
  1564. if (brdfImageAsset.IsReady())
  1565. {
  1566. m_brdfTexture = RPI::AttachmentImage::FindOrCreate(brdfImageAsset);
  1567. }
  1568. }
  1569. // Setup imGui since a new render pipeline with imgui pass was created
  1570. SetupImGuiContext();
  1571. }
  1572. void SampleComponentManager::ReleaseRPIScene()
  1573. {
  1574. if (m_rpiScene)
  1575. {
  1576. m_xrPipelines.clear();
  1577. m_renderPipeline = nullptr;
  1578. RPI::RPISystemInterface::Get()->UnregisterScene(m_rpiScene);
  1579. auto sceneSystem = AzFramework::SceneSystemInterface::Get();
  1580. AZ_Assert(sceneSystem, "Scene system was destroyed before SampleComponentManager was able to unregister the RPI scene.");
  1581. AZStd::shared_ptr<AzFramework::Scene> scene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName);
  1582. AZ_Assert(scene, "The main scene wasn't found in the scene system.");
  1583. [[maybe_unused]] bool result = scene->UnsetSubsystem(m_rpiScene);
  1584. AZ_Assert(result, "SampleComponentManager failed to unregister its RPI scene from the general scene.");
  1585. m_rpiScene = nullptr;
  1586. }
  1587. }
  1588. void SampleComponentManager::SwitchSceneForRPISample()
  1589. {
  1590. ReleaseRHIScene();
  1591. ReleaseRPIScene();
  1592. CreateSceneForRPISample();
  1593. }
  1594. // AzFramework::AssetCatalogEventBus::Handler overrides ...
  1595. void SampleComponentManager::OnCatalogLoaded([[maybe_unused]] const char* catalogFile)
  1596. {
  1597. AZ::TickBus::QueueFunction([&]()
  1598. {
  1599. ActivateInternal();
  1600. });
  1601. }
  1602. void SampleComponentManager::SetRHISamplePass(BasicRHIComponent* sampleComponent)
  1603. {
  1604. for (AZ::RPI::Ptr<RHISamplePass> samplePass : m_rhiSamplePasses)
  1605. {
  1606. samplePass->SetRHISample(sampleComponent);
  1607. }
  1608. }
  1609. } // namespace AtomSampleViewer