PassSystem.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  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 <AzCore/Asset/AssetManager.h>
  9. #include <AzCore/Asset/AssetManagerBus.h>
  10. #include <AzCore/Component/Entity.h>
  11. #include <AzCore/IO/FileIO.h>
  12. #include <AzCore/IO/SystemFile.h>
  13. #include <AzCore/Serialization/Utils.h>
  14. #include <AzCore/Serialization/SerializeContext.h>
  15. #include <AzCore/Interface/Interface.h>
  16. #include <AzCore/Serialization/Json/JsonUtils.h>
  17. #include <Atom/RHI/FrameGraphBuilder.h>
  18. #include <Atom/RPI.Public/Pass/FullscreenTrianglePass.h>
  19. #include <Atom/RPI.Public/Pass/PassDefines.h>
  20. #include <Atom/RPI.Public/Pass/PassFactory.h>
  21. #include <Atom/RPI.Public/Pass/PassLibrary.h>
  22. #include <Atom/RPI.Public/Pass/PassSystem.h>
  23. #include <Atom/RPI.Public/Pass/PassUtils.h>
  24. #include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
  25. #include <Atom/RPI.Public/RenderPipeline.h>
  26. #include <Atom/RPI.Reflect/Pass/ComputePassData.h>
  27. #include <Atom/RPI.Reflect/Pass/CopyPassData.h>
  28. #include <Atom/RPI.Reflect/Pass/DownsampleMipChainPassData.h>
  29. #include <Atom/RPI.Reflect/Pass/FullscreenTrianglePassData.h>
  30. #include <Atom/RPI.Reflect/Pass/EnvironmentCubeMapPassData.h>
  31. #include <Atom/RPI.Reflect/Pass/RenderToTexturePassData.h>
  32. #include <Atom/RPI.Reflect/Pass/PassAsset.h>
  33. #include <Atom/RPI.Reflect/Pass/PassData.h>
  34. #include <Atom/RPI.Reflect/Pass/PassTemplate.h>
  35. #include <Atom/RPI.Reflect/Pass/RasterPassData.h>
  36. #include <Atom/RPI.Reflect/Pass/RenderPassData.h>
  37. #include <Atom/RPI.Reflect/Pass/SlowClearPassData.h>
  38. namespace AZ
  39. {
  40. namespace RPI
  41. {
  42. PassSystemInterface* PassSystemInterface::Get()
  43. {
  44. return Interface<PassSystemInterface>::Get();
  45. }
  46. PassSystem::PassSystem()
  47. {
  48. }
  49. void PassSystem::Reflect(AZ::ReflectContext* context)
  50. {
  51. PassAttachmentRef::Reflect(context);
  52. PassConnection::Reflect(context);
  53. PassFallbackConnection::Reflect(context);
  54. PassAttachmentSizeMultipliers::Reflect(context);
  55. PassAttachmentSizeSource::Reflect(context);
  56. PassAttachmentDesc::Reflect(context);
  57. PassImageAttachmentDesc::Reflect(context);
  58. PassBufferAttachmentDesc::Reflect(context);
  59. PassSlot::Reflect(context);
  60. PassData::Reflect(context);
  61. SlowClearPassData::Reflect(context);
  62. CopyPassData::Reflect(context);
  63. RenderPassData::Reflect(context);
  64. ComputePassData::Reflect(context);
  65. DownsampleMipChainPassData::Reflect(context);
  66. RasterPassData::Reflect(context);
  67. FullscreenTrianglePassData::Reflect(context);
  68. EnvironmentCubeMapPassData::Reflect(context);
  69. RenderToTexturePassData::Reflect(context);
  70. PassAsset::Reflect(context);
  71. PassTemplate::Reflect(context);
  72. PassRequest::Reflect(context);
  73. }
  74. void PassSystem::GetAssetHandlers(AssetHandlerPtrList& assetHandlers)
  75. {
  76. assetHandlers.emplace_back(MakeAssetHandler<PassAssetHandler>());
  77. }
  78. void PassSystem::Init()
  79. {
  80. m_state = PassSystemState::InitializingPassSystem;
  81. Interface<PassSystemInterface>::Register(this);
  82. m_passLibrary.Init();
  83. m_passFactory.Init(&m_passLibrary);
  84. // Build root pass
  85. m_rootPass = CreatePass<ParentPass>(Name{"Root"});
  86. m_rootPass->m_flags.m_partOfHierarchy = true;
  87. m_rootPass->m_flags.m_createChildren = false;
  88. // Manually clear pass list and build root pass since it is subject to enqueing expections
  89. m_passesWithoutPipeline.m_buildPassList.clear();
  90. m_rootPass->Build();
  91. m_rootPass->Initialize();
  92. m_rootPass->OnInitializationFinished();
  93. // Build root pass for PassesWithoutPipeline collection
  94. m_passesWithoutPipeline.m_rootPass = CreatePass<ParentPass>(Name{ "PassesWithoutPipeline" });
  95. m_passesWithoutPipeline.m_rootPass->m_flags.m_createChildren = false;
  96. m_rootPass->AddChild(m_passesWithoutPipeline.m_rootPass);
  97. ProcessQueuedChanges();
  98. // Here you can specify the name of a pass you would like to break into during execution
  99. // If you enable AZ_RPI_ENABLE_PASS_DEBUGGING, then any pass matching the specified name will debug
  100. // break on any instance of the AZ_RPI_BREAK_ON_TARGET_PASS macro. See Pass::Build for an example
  101. // m_targetedPassDebugName = "MyPassName";
  102. m_state = PassSystemState::Idle;
  103. }
  104. void PassSystem::InitPassTemplates()
  105. {
  106. AZ_Assert(m_rootPass, "PassSystem::Init() need to be called");
  107. m_loadTemplatesEvent.Signal();
  108. }
  109. bool PassSystem::LoadPassTemplateMappings(const AZStd::string& templateMappingPath)
  110. {
  111. return m_passLibrary.LoadPassTemplateMappings(templateMappingPath);
  112. }
  113. void PassSystem::WriteTemplateToFile(const PassTemplate& passTemplate, AZStd::string_view assetFilePath)
  114. {
  115. PassAsset passAsset;
  116. passAsset.m_passTemplate = passTemplate.CloneUnique();
  117. JsonSerializationUtils::SaveObjectToFile(&passAsset, assetFilePath);
  118. }
  119. // --- Queue Functions ---
  120. void PassSystem::QueueForBuild(Pass* pass)
  121. {
  122. AZ_Assert(pass != nullptr, "Queuing nullptr pass in PassSystem::QueueForBuild");
  123. if (pass == m_rootPass.get())
  124. {
  125. return;
  126. }
  127. else if (pass->GetRenderPipeline())
  128. {
  129. pass->GetRenderPipeline()->m_passTree.m_buildPassList.push_back(pass);
  130. }
  131. else
  132. {
  133. m_passesWithoutPipeline.m_buildPassList.push_back(pass);
  134. }
  135. }
  136. void PassSystem::QueueForRemoval(Pass* pass)
  137. {
  138. AZ_Assert(pass != nullptr, "Queuing nullptr pass in PassSystem::QueueForRemoval");
  139. if (pass == m_rootPass.get())
  140. {
  141. return;
  142. }
  143. else if (pass->GetRenderPipeline())
  144. {
  145. pass->GetRenderPipeline()->m_passTree.m_removePassList.push_back(pass);
  146. }
  147. else
  148. {
  149. m_passesWithoutPipeline.m_removePassList.push_back(pass);
  150. }
  151. }
  152. void PassSystem::QueueForInitialization(Pass* pass)
  153. {
  154. AZ_Assert(pass != nullptr, "Queuing nullptr pass in PassSystem::QueueForInitialization");
  155. if (pass == m_rootPass.get())
  156. {
  157. return;
  158. }
  159. else if (pass->GetRenderPipeline())
  160. {
  161. pass->GetRenderPipeline()->m_passTree.m_initializePassList.push_back(pass);
  162. }
  163. else
  164. {
  165. m_passesWithoutPipeline.m_initializePassList.push_back(pass);
  166. }
  167. }
  168. // --- Frame Update Functions ---
  169. void PassSystem::ProcessQueuedChanges()
  170. {
  171. AZ_PROFILE_SCOPE(RPI, "PassSystem: ProcessQueuedChanges");
  172. // Erase any passes with pipelines from the passes without pipeline container
  173. m_passesWithoutPipeline.EraseFromLists([](const RHI::Ptr<Pass>& currentPass)
  174. {
  175. return (currentPass->m_pipeline != nullptr);
  176. });
  177. // Process passes that don't have a pipeline
  178. m_passesWithoutPipeline.ProcessQueuedChanges();
  179. }
  180. void PassSystem::FrameUpdate(RHI::FrameGraphBuilder& frameGraphBuilder)
  181. {
  182. AZ_PROFILE_FUNCTION(RPI);
  183. ResetFrameStatistics();
  184. ProcessQueuedChanges();
  185. m_state = PassSystemState::Rendering;
  186. Pass::FramePrepareParams params{ &frameGraphBuilder };
  187. for (RenderPipeline*& pipeline : m_renderPipelines)
  188. {
  189. pipeline->PassSystemFrameBegin(params);
  190. }
  191. m_passesWithoutPipeline.m_rootPass->UpdateConnectedBindings();
  192. m_passesWithoutPipeline.m_rootPass->FrameBegin(params);
  193. }
  194. void PassSystem::FrameEnd()
  195. {
  196. AZ_PROFILE_FUNCTION(RPI);
  197. m_state = PassSystemState::FrameEnd;
  198. for (RenderPipeline*& pipeline : m_renderPipelines)
  199. {
  200. pipeline->PassSystemFrameEnd();
  201. }
  202. m_passesWithoutPipeline.m_rootPass->FrameEnd();
  203. // Copy list of render pipelines because some pipelines might be removed in next loop execution
  204. AZStd::vector< RenderPipeline* > renderPipelinesCopy = m_renderPipelines;
  205. // Remove any pipelines that are marked as ExecuteOnce
  206. for (RenderPipeline*& pipeline : renderPipelinesCopy)
  207. {
  208. if (pipeline && pipeline->IsExecuteOnce())
  209. {
  210. pipeline->RemoveFromScene();
  211. }
  212. }
  213. m_state = PassSystemState::Idle;
  214. }
  215. // --- Misc ---
  216. void PassSystem::Shutdown()
  217. {
  218. m_passesWithoutPipeline.ClearQueues();
  219. m_passesWithoutPipeline.m_rootPass = nullptr;
  220. m_rootPass = nullptr;
  221. AZ_Assert(m_passCounter == 0, "Pass leaking has occurred! There are %d passes that have not been deleted.\n", m_passCounter);
  222. m_passFactory.Shutdown();
  223. m_passLibrary.Shutdown();
  224. Interface<PassSystemInterface>::Unregister(this);
  225. }
  226. const Ptr<ParentPass>& PassSystem::GetRootPass()
  227. {
  228. return m_rootPass;
  229. }
  230. void PassSystem::AddRenderPipeline(RenderPipeline* renderPipeline)
  231. {
  232. m_renderPipelines.push_back(renderPipeline);
  233. m_rootPass->AddChild(renderPipeline->m_passTree.m_rootPass);
  234. }
  235. void PassSystem::RemoveRenderPipeline(RenderPipeline* renderPipeline)
  236. {
  237. renderPipeline->m_passTree.ProcessQueuedChanges();
  238. renderPipeline->m_passTree.m_rootPass->SetEnabled(false);
  239. renderPipeline->m_passTree.m_rootPass->QueueForRemoval();
  240. renderPipeline->m_passTree.ProcessQueuedChanges();
  241. erase(m_renderPipelines, renderPipeline);
  242. }
  243. void PassSystem::AddPassWithoutPipeline(const Ptr<Pass>& pass)
  244. {
  245. m_passesWithoutPipeline.m_rootPass->AddChild(pass);
  246. }
  247. PassSystemState PassSystem::GetState() const
  248. {
  249. return m_state;
  250. }
  251. void PassSystem::DebugPrintPassHierarchy()
  252. {
  253. AZ_Printf("PassSystem", "\n------- PASS HIERARCHY -------\n");
  254. m_rootPass->DebugPrint();
  255. AZ_Printf("PassSystem", "\n------------------------------\n");
  256. }
  257. void PassSystem::SetTargetedPassDebuggingName(const AZ::Name& targetPassName)
  258. {
  259. m_targetedPassDebugName = targetPassName;
  260. }
  261. const AZ::Name& PassSystem::GetTargetedPassDebuggingName() const
  262. {
  263. return m_targetedPassDebugName;
  264. }
  265. void PassSystem::ConnectEvent(OnReadyLoadTemplatesEvent::Handler& handler)
  266. {
  267. handler.Connect(m_loadTemplatesEvent);
  268. }
  269. void PassSystem::ResetFrameStatistics()
  270. {
  271. m_frameStatistics.m_numRenderPassesExecuted = 0;
  272. m_frameStatistics.m_totalDrawItemsRendered = 0;
  273. m_frameStatistics.m_maxDrawItemsRenderedInAPass = 0;
  274. }
  275. PassSystemFrameStatistics PassSystem::GetFrameStatistics()
  276. {
  277. return m_frameStatistics;
  278. }
  279. void PassSystem::IncrementFrameDrawItemCount(u32 numDrawItems)
  280. {
  281. m_frameStatistics.m_totalDrawItemsRendered += numDrawItems;
  282. m_frameStatistics.m_maxDrawItemsRenderedInAPass = AZStd::max(m_frameStatistics.m_maxDrawItemsRenderedInAPass, numDrawItems);
  283. }
  284. void PassSystem::IncrementFrameRenderPassCount()
  285. {
  286. ++m_frameStatistics.m_numRenderPassesExecuted;
  287. }
  288. void PassSystem::DebugBreakOnPass(const Pass* pass) const
  289. {
  290. // Users can leverage this function and customize it's logic to facilitate their own debugging
  291. // However, any customization should be reverted and never submitted. The default logic just checks
  292. // the pass's name against the TargetedPassDebuggingName
  293. if (!pass->GetName().IsEmpty() && pass->GetName() == GetTargetedPassDebuggingName())
  294. {
  295. AZ::Debug::Trace::Instance().Break();
  296. }
  297. }
  298. // --- Pass Factory Functions ---
  299. void PassSystem::AddPassCreator(Name className, PassCreator createFunction)
  300. {
  301. m_passFactory.AddPassCreator(className, createFunction);
  302. }
  303. Ptr<Pass> PassSystem::CreatePassFromClass(Name passClassName, Name passName)
  304. {
  305. return m_passFactory.CreatePassFromClass(passClassName, passName);
  306. }
  307. Ptr<Pass> PassSystem::CreatePassFromTemplate(const AZStd::shared_ptr<const PassTemplate>& passTemplate, Name passName)
  308. {
  309. return m_passFactory.CreatePassFromTemplate(passTemplate, passName);
  310. }
  311. Ptr<Pass> PassSystem::CreatePassFromTemplate(Name templateName, Name passName)
  312. {
  313. return m_passFactory.CreatePassFromTemplate(templateName, passName);
  314. }
  315. Ptr<Pass> PassSystem::CreatePassFromRequest(const PassRequest* passRequest)
  316. {
  317. return m_passFactory.CreatePassFromRequest(passRequest);
  318. }
  319. bool PassSystem::HasCreatorForClass(Name passClassName)
  320. {
  321. return m_passFactory.HasCreatorForClass(passClassName);
  322. }
  323. // --- Pass Library Functions ---
  324. bool PassSystem::HasTemplate(const Name& templateName) const
  325. {
  326. return m_passLibrary.HasTemplate(templateName);
  327. }
  328. bool PassSystem::HasPassesForTemplateName(const Name& templateName) const
  329. {
  330. return m_passLibrary.HasPassesForTemplate(templateName);
  331. }
  332. bool PassSystem::AddPassTemplate(const Name& name, const AZStd::shared_ptr<PassTemplate>& passTemplate)
  333. {
  334. return m_passLibrary.AddPassTemplate(name, passTemplate);
  335. }
  336. const AZStd::shared_ptr<const PassTemplate> PassSystem::GetPassTemplate(const Name& name) const
  337. {
  338. return m_passLibrary.GetPassTemplate(name);
  339. }
  340. void PassSystem::RemovePassTemplate(const Name& name)
  341. {
  342. m_passLibrary.RemovePassTemplate(name);
  343. }
  344. void PassSystem::RemovePassFromLibrary(Pass* pass)
  345. {
  346. m_passLibrary.RemovePassFromLibrary(pass);
  347. }
  348. void PassSystem::RegisterPass(Pass* pass)
  349. {
  350. ++m_passCounter;
  351. m_passLibrary.AddPass(pass);
  352. }
  353. void PassSystem::UnregisterPass(Pass* pass)
  354. {
  355. RemovePassFromLibrary(pass);
  356. --m_passCounter;
  357. }
  358. void PassSystem::ForEachPass(const PassFilter& filter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction)
  359. {
  360. return m_passLibrary.ForEachPass(filter, passFunction);
  361. }
  362. Pass* PassSystem::FindFirstPass(const PassFilter& filter)
  363. {
  364. Pass* foundPass = nullptr;
  365. m_passLibrary.ForEachPass(filter, [&foundPass](RPI::Pass* pass) ->PassFilterExecutionFlow
  366. {
  367. foundPass = pass;
  368. return PassFilterExecutionFlow::StopVisitingPasses;
  369. });
  370. return foundPass;
  371. }
  372. SwapChainPass* PassSystem::FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const
  373. {
  374. for (const Ptr<Pass>& pass : m_rootPass->m_children)
  375. {
  376. SwapChainPass* swapChainPass = azrtti_cast<SwapChainPass*>(pass.get());
  377. if (swapChainPass && swapChainPass->GetWindowHandle() == windowHandle)
  378. {
  379. return swapChainPass;
  380. }
  381. }
  382. return nullptr;
  383. }
  384. } // namespace RPI
  385. } // namespace AZ