3
0

RenderPipeline.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  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 <Atom/RHI/DrawListTagRegistry.h>
  9. #include <Atom/RPI.Public/Base.h>
  10. #include <Atom/RPI.Public/Pass/PassFilter.h>
  11. #include <Atom/RPI.Public/Pass/PassSystem.h>
  12. #include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
  13. #include <Atom/RPI.Public/RenderPipeline.h>
  14. #include <Atom/RHI/RHISystemInterface.h>
  15. #include <Atom/RPI.Public/Scene.h>
  16. #include <Atom/RPI.Public/SceneBus.h>
  17. #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
  18. #include <Atom/RPI.Public/View.h>
  19. #include <Atom/RPI.Public/ViewProviderBus.h>
  20. #include <Atom/RPI.Reflect/System/AnyAsset.h>
  21. namespace AZ
  22. {
  23. namespace RPI
  24. {
  25. RenderPipelinePtr RenderPipeline::CreateRenderPipeline(const RenderPipelineDescriptor& desc)
  26. {
  27. PassSystemInterface* passSystem = PassSystemInterface::Get();
  28. RenderPipeline* pipeline = aznew RenderPipeline();
  29. Name passName{ desc.m_name };
  30. if (!desc.m_rootPassTemplate.empty())
  31. {
  32. // Create pass from asset if there is a valid one
  33. PassRequest rootRequest;
  34. rootRequest.m_passName = passName;
  35. rootRequest.m_templateName = desc.m_rootPassTemplate;
  36. Ptr<Pass> rootPass = passSystem->CreatePassFromRequest(&rootRequest);
  37. pipeline->m_passTree.m_rootPass = azrtti_cast<ParentPass*>(rootPass.get());
  38. }
  39. else
  40. {
  41. // Otherwise create an empty root pass with pipeline name
  42. pipeline->m_passTree.m_rootPass = passSystem->CreatePass<ParentPass>(passName);
  43. }
  44. AZ_Assert(pipeline->m_passTree.m_rootPass != nullptr, "Error creating root pass for pipeline!");
  45. InitializeRenderPipeline(pipeline, desc);
  46. return RenderPipelinePtr(pipeline);
  47. }
  48. RenderPipelinePtr RenderPipeline::CreateRenderPipelineFromAsset(Data::Asset<AnyAsset> pipelineAsset)
  49. {
  50. const RenderPipelineDescriptor* renderPipelineDescriptor = GetDataFromAnyAsset<RenderPipelineDescriptor>(pipelineAsset);
  51. if (renderPipelineDescriptor == nullptr)
  52. {
  53. return nullptr;
  54. }
  55. RenderPipelinePtr pipeline = RenderPipeline::CreateRenderPipeline(*renderPipelineDescriptor);
  56. if (pipeline == nullptr)
  57. {
  58. AZ_Error("RPISystem", false, "Failed to create render pipeline from asset %s", pipelineAsset.GetHint().c_str());
  59. return nullptr;
  60. }
  61. return pipeline;
  62. }
  63. RenderPipelinePtr RenderPipeline::CreateRenderPipelineForWindow(Data::Asset<AnyAsset> pipelineAsset, const WindowContext& windowContext)
  64. {
  65. const RenderPipelineDescriptor* renderPipelineDescriptor = GetDataFromAnyAsset<RenderPipelineDescriptor>(pipelineAsset);
  66. if (renderPipelineDescriptor == nullptr)
  67. {
  68. return nullptr;
  69. }
  70. return CreateRenderPipelineForWindow(*renderPipelineDescriptor, windowContext);
  71. }
  72. RenderPipelinePtr RenderPipeline::CreateRenderPipelineForWindow(const RenderPipelineDescriptor& desc, const WindowContext& windowContext,
  73. const ViewType viewType)
  74. {
  75. RenderPipelinePtr pipeline{aznew RenderPipeline()};
  76. PassSystemInterface* passSystem = PassSystemInterface::Get();
  77. PassDescriptor swapChainDescriptor(Name(desc.m_name));
  78. Name templateName = Name(desc.m_rootPassTemplate.c_str());
  79. swapChainDescriptor.m_passTemplate = passSystem->GetPassTemplate(templateName);
  80. if (!swapChainDescriptor.m_passTemplate)
  81. {
  82. AZ_Error("RPISystem", false, "Root-PassTemplate %s not found!", templateName.GetCStr());
  83. return nullptr;
  84. }
  85. pipeline->m_passTree.m_rootPass = aznew SwapChainPass(swapChainDescriptor, &windowContext, viewType);
  86. pipeline->m_windowHandle = windowContext.GetWindowHandle();
  87. pipeline->m_viewType = viewType;
  88. InitializeRenderPipeline(pipeline.get(), desc);
  89. return pipeline;
  90. }
  91. RenderPipelinePtr RenderPipeline::CreateRenderPipelineForImage(const RenderPipelineDescriptor& desc, Data::Asset<AttachmentImageAsset> imageAsset)
  92. {
  93. RenderPipelinePtr pipeline{aznew RenderPipeline()};
  94. PassSystemInterface* passSystem = PassSystemInterface::Get();
  95. PassRequest passRequest;
  96. PassImageAttachmentDesc imageAttachmentDesc;
  97. imageAttachmentDesc.m_assetRef.m_assetId = imageAsset.GetId();
  98. imageAttachmentDesc.m_lifetime = RHI::AttachmentLifetimeType::Imported;
  99. imageAttachmentDesc.m_name = Name("OutputImage");
  100. passRequest.m_imageAttachmentOverrides.push_back(imageAttachmentDesc);
  101. auto passTemplate = passSystem->GetPassTemplate(Name(desc.m_rootPassTemplate));
  102. if (!passTemplate)
  103. {
  104. AZ_Error("RPI", false, "Failed to create a RenderPipeline: the render pipeline root pass template doesn't exist");
  105. return nullptr;
  106. }
  107. PassConnection passConnection;
  108. // use first output slot for connection
  109. for (auto slot : passTemplate->m_slots)
  110. {
  111. if (slot.m_slotType == RPI::PassSlotType::Output || slot.m_slotType == RPI::PassSlotType::InputOutput)
  112. {
  113. passConnection.m_localSlot = slot.m_name;
  114. break;
  115. }
  116. }
  117. if (passConnection.m_localSlot.IsEmpty())
  118. {
  119. AZ_Error("RPI", false, "Failed to create a RenderPipeline: the render pipeline root pass template doesn't have output slot for render target");
  120. return nullptr;
  121. }
  122. passConnection.m_attachmentRef.m_pass = "This";
  123. passConnection.m_attachmentRef.m_attachment = imageAttachmentDesc.m_name;
  124. passRequest.m_passName = desc.m_name;
  125. passRequest.m_templateName = desc.m_rootPassTemplate;
  126. passRequest.m_connections.push_back(passConnection);
  127. auto rootPass = passSystem->CreatePassFromRequest(&passRequest);
  128. if (!rootPass)
  129. {
  130. AZ_Error("RPI", false, "Failed to create a RenderPipeline: failed to create root pass for the render pipeline");
  131. return nullptr;
  132. }
  133. pipeline->m_passTree.m_rootPass = azrtti_cast<ParentPass*>(rootPass.get());
  134. InitializeRenderPipeline(pipeline.get(), desc);
  135. return pipeline;
  136. }
  137. void RenderPipeline::InitializeRenderPipeline(RenderPipeline* pipeline, const RenderPipelineDescriptor& desc)
  138. {
  139. pipeline->m_descriptor = desc;
  140. pipeline->m_mainViewTag = Name(desc.m_mainViewTagName);
  141. pipeline->m_nameId = desc.m_name.data();
  142. pipeline->m_materialPipelineTagName = Name{desc.m_materialPipelineTag};
  143. pipeline->m_activeRenderSettings = desc.m_renderSettings;
  144. pipeline->m_passTree.m_rootPass->SetRenderPipeline(pipeline);
  145. pipeline->m_passTree.m_rootPass->m_flags.m_isPipelineRoot = true;
  146. pipeline->m_passTree.m_rootPass->ManualPipelineBuildAndInitialize();
  147. pipeline->UpdateViewportScissor();
  148. }
  149. void RenderPipeline::UpdateViewportScissor()
  150. {
  151. for (PassAttachmentBinding& binding : m_passTree.m_rootPass->m_attachmentBindings)
  152. {
  153. if (binding.m_slotType == PassSlotType::Output || binding.m_slotType == PassSlotType::InputOutput)
  154. {
  155. auto attachment = binding.GetAttachment();
  156. if (attachment && attachment->GetAttachmentType() == RHI::AttachmentType::Image)
  157. {
  158. RHI::ImageDescriptor imageDesc;
  159. if (attachment->m_importedResource)
  160. {
  161. AttachmentImage* image = static_cast<AttachmentImage*>(attachment->m_importedResource.get());
  162. imageDesc = image->GetDescriptor();
  163. }
  164. else
  165. {
  166. imageDesc = attachment->m_descriptor.m_image;
  167. }
  168. m_viewport = RHI::Viewport(0, (float)imageDesc.m_size.m_width, 0, (float)imageDesc.m_size.m_height);
  169. m_scissor = RHI::Scissor(0, 0, imageDesc.m_size.m_width, imageDesc.m_size.m_height);
  170. return;
  171. }
  172. }
  173. }
  174. }
  175. RenderPipeline::~RenderPipeline()
  176. {
  177. if (m_passTree.m_rootPass)
  178. {
  179. m_passTree.m_rootPass->SetRenderPipeline(nullptr);
  180. }
  181. }
  182. void RenderPipeline::BuildPipelineViews()
  183. {
  184. if (m_passTree.m_rootPass == nullptr)
  185. {
  186. return;
  187. }
  188. // Get view tags from all passes.
  189. PipelineViewTags viewTags;
  190. m_passTree.m_rootPass->GetPipelineViewTags(viewTags);
  191. // Use a new list for building pipeline views since we may need information from the previous list in m_views in the process
  192. PipelineViewMap newViewsByTag;
  193. for (const auto& tag : viewTags)
  194. {
  195. PipelineViews pipelineViews;
  196. if (m_pipelineViewsByTag.find(tag) != m_pipelineViewsByTag.end())
  197. {
  198. // Copy the content from existing if it already exists
  199. pipelineViews = m_pipelineViewsByTag[tag];
  200. pipelineViews.m_drawListMask.reset();
  201. if (pipelineViews.m_type == PipelineViewType::Transient)
  202. {
  203. pipelineViews.m_views.clear();
  204. }
  205. }
  206. else
  207. {
  208. pipelineViews.m_viewTag = tag;
  209. pipelineViews.m_type = PipelineViewType::Unknown;
  210. }
  211. newViewsByTag[tag] = pipelineViews;
  212. CollectDrawListMaskForViews(newViewsByTag[tag]);
  213. }
  214. m_pipelineViewsByTag = AZStd::move(newViewsByTag);
  215. }
  216. void RenderPipeline::CollectDrawListMaskForViews(PipelineViews& views)
  217. {
  218. views.m_drawListMask.reset();
  219. views.m_passesByDrawList.clear();
  220. m_passTree.m_rootPass->GetViewDrawListInfo(views.m_drawListMask, views.m_passesByDrawList, views.m_viewTag);
  221. }
  222. bool RenderPipeline::CanRegisterView(const PipelineViewTag& allowedViewTag, const View* view) const
  223. {
  224. auto registeredViewItr = m_persistentViewsByViewTag.find(view);
  225. if (registeredViewItr != m_persistentViewsByViewTag.end() && registeredViewItr->second != allowedViewTag)
  226. {
  227. AZ_Warning("RenderPipeline", false, "View [%s] is already registered for persistent ViewTag [%s].",
  228. view->GetName().GetCStr(), registeredViewItr->second.GetCStr());
  229. return false;
  230. }
  231. registeredViewItr = m_transientViewsByViewTag.find(view);
  232. if (registeredViewItr != m_transientViewsByViewTag.end() && registeredViewItr->second != allowedViewTag)
  233. {
  234. AZ_Warning("RenderPipeline", false, "View [%s] is already registered for transient ViewTag [%s].",
  235. view->GetName().GetCStr(), registeredViewItr->second.GetCStr());
  236. return false;
  237. }
  238. return true;
  239. }
  240. void RenderPipeline::UnregisterView(ViewPtr view)
  241. {
  242. auto registeredViewItr = m_persistentViewsByViewTag.find(view.get());
  243. if (registeredViewItr != m_persistentViewsByViewTag.end())
  244. {
  245. return ResetPersistentView(registeredViewItr->second, view);
  246. }
  247. registeredViewItr = m_transientViewsByViewTag.find(view.get());
  248. if (registeredViewItr != m_transientViewsByViewTag.end())
  249. {
  250. return RemoveTransientView(registeredViewItr->second, view);
  251. }
  252. }
  253. void RenderPipeline::RemoveTransientView(const PipelineViewTag viewTag, ViewPtr view)
  254. {
  255. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  256. if (viewItr != m_pipelineViewsByTag.end())
  257. {
  258. PipelineViews& pipelineViews = viewItr->second;
  259. if (pipelineViews.m_type == PipelineViewType::Persistent)
  260. {
  261. AZ_Assert(
  262. false, "View [%s] was set as persistent view. Use ResetPersistentView to remove this view", viewTag.GetCStr());
  263. return;
  264. }
  265. for (int viewIndex = 0; viewIndex < pipelineViews.m_views.size(); ++viewIndex)
  266. {
  267. if (pipelineViews.m_views[viewIndex] == view)
  268. {
  269. view->SetPassesByDrawList(nullptr);
  270. pipelineViews.m_views.erase(pipelineViews.m_views.begin() + viewIndex);
  271. m_transientViewsByViewTag.erase(view.get());
  272. break;
  273. }
  274. }
  275. if (pipelineViews.m_views.empty())
  276. {
  277. m_pipelineViewsByTag.erase(viewTag);
  278. }
  279. }
  280. }
  281. void RenderPipeline::ResetPersistentView(const PipelineViewTag viewTag, ViewPtr view)
  282. {
  283. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  284. if (viewItr != m_pipelineViewsByTag.end())
  285. {
  286. PipelineViews& pipelineViews = viewItr->second;
  287. if (pipelineViews.m_views.size() == 0)
  288. {
  289. return;
  290. }
  291. if (pipelineViews.m_type == PipelineViewType::Transient)
  292. {
  293. AZ_Assert(
  294. false,
  295. "View [%s] is a transient view. Use RemoveTransientView to remove it, or wait until the next frame.",
  296. viewTag.GetCStr());
  297. return;
  298. }
  299. AZ_Assert(
  300. pipelineViews.m_views[0] == view,
  301. "View [%s] is not registered for persistent view tag [%s]",
  302. pipelineViews.m_views[0]->GetName().GetCStr(),
  303. viewTag.GetCStr());
  304. pipelineViews.m_views[0]->SetPassesByDrawList(nullptr);
  305. m_persistentViewsByViewTag.erase(pipelineViews.m_views[0].get());
  306. m_pipelineViewsByTag.erase(viewTag);
  307. pipelineViews.m_views.clear();
  308. if (m_scene)
  309. {
  310. ViewPtr newView{ nullptr };
  311. SceneNotificationBus::Event(
  312. m_scene->GetId(), &SceneNotification::OnRenderPipelinePersistentViewChanged, this, viewTag, newView, view);
  313. }
  314. }
  315. }
  316. void RenderPipeline::SetPersistentView(const PipelineViewTag& viewTag, ViewPtr view)
  317. {
  318. // If a view is registered for multiple viewTags, it gets only the PassesByDrawList of whatever
  319. // DrawList it was registered last, which will cause a crash during SortDrawList later. So we check
  320. // here if the view is already registered with another viewTag.
  321. // TODO: remove this check and merge the PassesByDrawList if that behaviour is actually needed.
  322. if (!CanRegisterView(viewTag, view.get()))
  323. {
  324. AZ_Assert(false, "Can't register view [%s] with viewTag [%s]", view->GetName().GetCStr(), viewTag.GetCStr());
  325. return;
  326. }
  327. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  328. if (viewItr != m_pipelineViewsByTag.end())
  329. {
  330. PipelineViews& pipelineViews = viewItr->second;
  331. if (pipelineViews.m_type == PipelineViewType::Transient)
  332. {
  333. AZ_Assert(false, "View [%s] was set as transient view. Use AddTransientView function to add a view for this tag.", viewTag.GetCStr());
  334. return;
  335. }
  336. if (pipelineViews.m_type == PipelineViewType::Unknown)
  337. {
  338. pipelineViews.m_type = PipelineViewType::Persistent;
  339. pipelineViews.m_views.resize(1);
  340. }
  341. ViewPtr previousView = pipelineViews.m_views[0];
  342. if (view)
  343. {
  344. view->OnAddToRenderPipeline();
  345. }
  346. pipelineViews.m_views[0] = view;
  347. m_persistentViewsByViewTag[view.get()] = viewTag;
  348. if (previousView)
  349. {
  350. previousView->SetPassesByDrawList(nullptr);
  351. m_persistentViewsByViewTag.erase(previousView.get());
  352. }
  353. if (m_scene)
  354. {
  355. SceneNotificationBus::Event(m_scene->GetId(), &SceneNotification::OnRenderPipelinePersistentViewChanged, this, viewTag, view, previousView);
  356. }
  357. }
  358. else
  359. {
  360. AZ_Assert(false, "View [%s] doesn't exist in render pipeline [%s]", viewTag.GetCStr(), m_nameId.GetCStr());
  361. }
  362. }
  363. void RenderPipeline::SetDefaultView(ViewPtr view)
  364. {
  365. SetPersistentView(m_mainViewTag, view);
  366. }
  367. ViewPtr RenderPipeline::GetDefaultView()
  368. {
  369. return GetFirstView(m_mainViewTag);
  370. }
  371. ViewPtr RenderPipeline::GetFirstView(const PipelineViewTag& viewTag)
  372. {
  373. const AZStd::vector<ViewPtr>& views = GetViews(viewTag);
  374. if (!views.empty())
  375. {
  376. return views[0];
  377. }
  378. return {};
  379. }
  380. void RenderPipeline::SetDefaultViewFromEntity(EntityId entityId)
  381. {
  382. ViewPtr cameraView;
  383. ViewProviderBus::EventResult(cameraView, entityId, &ViewProvider::GetView);
  384. if (cameraView)
  385. {
  386. SetDefaultView(cameraView);
  387. }
  388. }
  389. void RenderPipeline::SetDefaultStereoscopicViewFromEntity(EntityId entityId, RPI::ViewType viewType)
  390. {
  391. ViewPtr cameraView;
  392. ViewProviderBus::EventResult(cameraView, entityId, &ViewProvider::GetStereoscopicView, viewType);
  393. if (cameraView)
  394. {
  395. SetDefaultView(cameraView);
  396. }
  397. }
  398. void RenderPipeline::AddTransientView(const PipelineViewTag& viewTag, ViewPtr view)
  399. {
  400. // If a view is registered for multiple viewTags, it gets only the PassesByDrawList of whatever
  401. // DrawList it was registered last, which will cause a crash during SortDrawList later. So we check
  402. // here if the view is already registered with another viewTag.
  403. // TODO: remove this check and merge the PassesByDrawList if that behaviour is actually needed.
  404. if (!CanRegisterView(viewTag, view.get()))
  405. {
  406. AZ_Assert(false, "Can't register transient view [%s] with viewTag [%s]", view->GetName().GetCStr(), viewTag.GetCStr());
  407. return;
  408. }
  409. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  410. if (viewItr != m_pipelineViewsByTag.end())
  411. {
  412. PipelineViews& pipelineViews = viewItr->second;
  413. if (pipelineViews.m_type == PipelineViewType::Persistent)
  414. {
  415. AZ_Assert(false, "View [%s] was set as persistent view. Use SetPersistentView function to set a view for this tag", viewTag.GetCStr());
  416. return;
  417. }
  418. if (pipelineViews.m_type == PipelineViewType::Unknown)
  419. {
  420. pipelineViews.m_type = PipelineViewType::Transient;
  421. }
  422. view->SetPassesByDrawList(&pipelineViews.m_passesByDrawList);
  423. view->OnAddToRenderPipeline();
  424. pipelineViews.m_views.push_back(view);
  425. m_transientViewsByViewTag[view.get()] = viewTag;
  426. }
  427. }
  428. bool RenderPipeline::HasViewTag(const PipelineViewTag& viewTag) const
  429. {
  430. return m_pipelineViewsByTag.find(viewTag) != m_pipelineViewsByTag.end();
  431. }
  432. const PipelineViewTag& RenderPipeline::GetMainViewTag() const
  433. {
  434. return m_mainViewTag;
  435. }
  436. const AZStd::vector<ViewPtr>& RenderPipeline::GetViews(const PipelineViewTag& viewTag) const
  437. {
  438. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  439. if (viewItr != m_pipelineViewsByTag.end())
  440. {
  441. return viewItr->second.m_views;
  442. }
  443. static AZStd::vector<ViewPtr> emptyList;
  444. return emptyList;
  445. }
  446. const RHI::DrawListMask& RenderPipeline::GetDrawListMask(const PipelineViewTag& viewTag) const
  447. {
  448. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  449. if (viewItr != m_pipelineViewsByTag.end())
  450. {
  451. return viewItr->second.m_drawListMask;
  452. }
  453. static RHI::DrawListMask emptyMask;
  454. return emptyMask;
  455. }
  456. const RenderPipeline::PipelineViewMap& RenderPipeline::GetPipelineViews() const
  457. {
  458. return m_pipelineViewsByTag;
  459. }
  460. void RenderPipeline::OnAddedToScene(Scene* scene)
  461. {
  462. AZ_Assert(m_scene == nullptr, "Pipeline was added to another scene");
  463. m_scene = scene;
  464. PassSystemInterface::Get()->AddRenderPipeline(this);
  465. }
  466. void RenderPipeline::OnRemovedFromScene([[maybe_unused]] Scene* scene)
  467. {
  468. m_passTree.ClearQueues();
  469. AZ_Assert(m_scene == scene, "Pipeline isn't added to the specified scene");
  470. m_scene = nullptr;
  471. PassSystemInterface::Get()->RemoveRenderPipeline(this);
  472. m_drawFilterTagForPipelineInstanceName.Reset();
  473. m_drawFilterTagForMaterialPipeline.Reset();
  474. m_drawFilterMask = 0;
  475. }
  476. void RenderPipeline::ProcessQueuedPassChanges()
  477. {
  478. m_passTree.ProcessQueuedChanges();
  479. }
  480. void RenderPipeline::UpdatePasses()
  481. {
  482. // Rebuild Pipeline if needed, for example if passes where hot reloaded
  483. if (PipelineNeedsRebuild(m_pipelinePassChanges))
  484. {
  485. // Process any queued changes before we attempt to reload the pipeline
  486. m_passTree.ProcessQueuedChanges();
  487. // Attempt to re-create hierarchy under root pass
  488. Ptr<ParentPass> newRoot = azrtti_cast<ParentPass*>(m_passTree.m_rootPass->Recreate().get());
  489. newRoot->SetRenderPipeline(this);
  490. newRoot->m_flags.m_isPipelineRoot = true;
  491. newRoot->ManualPipelineBuildAndInitialize();
  492. // Validate the new root
  493. PassValidationResults validation;
  494. newRoot->Validate(validation);
  495. if (validation.IsValid())
  496. {
  497. // Remove old pass
  498. m_passTree.m_rootPass->SetRenderPipeline(nullptr);
  499. m_passTree.m_rootPass->QueueForRemoval();
  500. // Set new root
  501. m_passTree.m_rootPass = newRoot;
  502. PassSystemInterface::Get()->GetRootPass()->AddChild(m_passTree.m_rootPass);
  503. // Re-Apply render pipeline change
  504. m_wasModifiedByScene = false;
  505. m_scene->TryApplyRenderPipelineChanges(this);
  506. }
  507. else
  508. {
  509. AZ_Printf("PassSystem", "\n>> Pass validation failed after hot reloading pas assets. Reverting to previously valid render pipeline.\n");
  510. validation.PrintValidationIfError();
  511. #if AZ_RPI_ENABLE_PASS_DEBUGGING
  512. AZ_Printf("PassSystem", "\nConstructed pass hierarchy with validation errors is as follows:\n");
  513. newRoot->DebugPrint();
  514. #endif
  515. }
  516. }
  517. // Build and initialize any queued passes
  518. m_passTree.ProcessQueuedChanges();
  519. if (m_pipelinePassChanges != PipelinePassChanges::NoPassChanges)
  520. {
  521. m_passTree.m_rootPass->SetRenderPipeline(this);
  522. // Pipeline views
  523. if (PipelineViewsNeedRebuild(m_pipelinePassChanges))
  524. {
  525. BuildPipelineViews();
  526. }
  527. if (m_scene)
  528. {
  529. SceneNotificationBus::Event(m_scene->GetId(), &SceneNotification::OnRenderPipelinePassesChanged, this);
  530. SceneNotificationBus::Event(m_scene->GetId(), &SceneNotification::OnRenderPipelineChanged, this,
  531. SceneNotification::RenderPipelineChangeType::PassChanged);
  532. // Pipeline state lookup
  533. if (PipelineStateLookupNeedsRebuild(m_pipelinePassChanges))
  534. {
  535. SceneRequestBus::Event(m_scene->GetId(), &SceneRequest::PipelineStateLookupNeedsRebuild);
  536. }
  537. }
  538. UpdateViewportScissor();
  539. // Reset change flags
  540. m_pipelinePassChanges = PipelinePassChanges::NoPassChanges;
  541. if (m_scene)
  542. {
  543. // Process any changes that may have happened due to SceneNotification Events. This may cause the
  544. // m_pipelinePassChanges flag to change and be handled later.
  545. m_passTree.ProcessQueuedChanges();
  546. }
  547. }
  548. }
  549. bool RenderPipeline::IsExecuteOnce()
  550. {
  551. return m_descriptor.m_executeOnce;
  552. }
  553. void RenderPipeline::RemoveFromScene()
  554. {
  555. if (m_scene == nullptr)
  556. {
  557. AZ_Assert(false, "RenderPipeline::RemoveFromScene: Pipeline [%s] isn't added to any scene", m_nameId.GetCStr());
  558. return;
  559. }
  560. m_scene->RemoveRenderPipeline(m_nameId);
  561. }
  562. void RenderPipeline::OnStartFrame([[maybe_unused]] float time)
  563. {
  564. AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame");
  565. UpdatePasses();
  566. for (auto& viewItr : m_pipelineViewsByTag)
  567. {
  568. PipelineViews& pipelineViews = viewItr.second;
  569. if (pipelineViews.m_type == PipelineViewType::Transient)
  570. {
  571. // Clear transient views
  572. pipelineViews.m_views.clear();
  573. }
  574. else if (pipelineViews.m_type == PipelineViewType::Persistent)
  575. {
  576. pipelineViews.m_views[0]->SetPassesByDrawList(&pipelineViews.m_passesByDrawList);
  577. }
  578. }
  579. m_transientViewsByViewTag.clear();
  580. }
  581. void RenderPipeline::OnFrameEnd()
  582. {
  583. if (m_renderMode == RenderMode::RenderOnce)
  584. {
  585. RemoveFromRenderTick();
  586. }
  587. }
  588. void RenderPipeline::PassSystemFrameBegin(Pass::FramePrepareParams params)
  589. {
  590. AZ_PROFILE_FUNCTION(RPI);
  591. if (GetRenderMode() != RenderPipeline::RenderMode::NoRender)
  592. {
  593. params.m_viewportState = m_viewport;
  594. params.m_scissorState = m_scissor;
  595. m_passTree.m_rootPass->FrameBegin(params);
  596. }
  597. }
  598. void RenderPipeline::PassSystemFrameEnd()
  599. {
  600. AZ_PROFILE_FUNCTION(RPI);
  601. if (GetRenderMode() != RenderPipeline::RenderMode::NoRender)
  602. {
  603. m_passTree.m_rootPass->FrameEnd();
  604. }
  605. }
  606. void RenderPipeline::CollectPersistentViews(AZStd::map<ViewPtr, RHI::DrawListMask>& outViewMasks) const
  607. {
  608. for (auto& viewItr : m_pipelineViewsByTag)
  609. {
  610. const PipelineViews& pipelineViews = viewItr.second;
  611. if (pipelineViews.m_type == PipelineViewType::Persistent)
  612. {
  613. ViewPtr view = pipelineViews.m_views[0];
  614. if (outViewMasks.find(view) == outViewMasks.end())
  615. {
  616. // Add the view to the map with its DrawListMask if the view isn't in the list
  617. outViewMasks[view] = pipelineViews.m_drawListMask;
  618. }
  619. else
  620. {
  621. // Combine the DrawListMask with the existing one if the view already exist.
  622. outViewMasks[view] |= pipelineViews.m_drawListMask;
  623. }
  624. }
  625. }
  626. }
  627. const PipelineGlobalBinding* RenderPipeline::GetPipelineGlobalConnection(const Name& globalName) const
  628. {
  629. for (const PipelineGlobalBinding& connection : m_pipelineGlobalConnections)
  630. {
  631. if (connection.m_globalName == globalName)
  632. {
  633. return &connection;
  634. }
  635. }
  636. return nullptr;
  637. }
  638. void RenderPipeline::AddPipelineGlobalConnection(const Name& globalName, PassAttachmentBinding* binding, Pass* pass)
  639. {
  640. m_pipelineGlobalConnections.push_back(PipelineGlobalBinding{ globalName, binding, pass });
  641. }
  642. void RenderPipeline::RemovePipelineGlobalConnectionsFromPass(Pass* passOnwer)
  643. {
  644. auto iter = m_pipelineGlobalConnections.begin();
  645. while (iter != m_pipelineGlobalConnections.end())
  646. {
  647. if (iter->m_pass == passOnwer)
  648. {
  649. m_pipelineGlobalConnections.erase(iter);
  650. }
  651. else
  652. {
  653. ++iter;
  654. }
  655. }
  656. }
  657. void RenderPipeline::ClearGlobalBindings()
  658. {
  659. m_pipelineGlobalConnections.clear();
  660. }
  661. RenderPipelineId RenderPipeline::GetId() const
  662. {
  663. return m_nameId;
  664. }
  665. const Ptr<ParentPass>& RenderPipeline::GetRootPass() const
  666. {
  667. return m_passTree.m_rootPass;
  668. }
  669. void RenderPipeline::MarkPipelinePassChanges(u32 passChangeFlags)
  670. {
  671. m_pipelinePassChanges |= passChangeFlags;
  672. }
  673. Scene* RenderPipeline::GetScene() const
  674. {
  675. return m_scene;
  676. }
  677. AzFramework::NativeWindowHandle RenderPipeline::GetWindowHandle() const
  678. {
  679. return m_windowHandle;
  680. }
  681. PipelineRenderSettings& RenderPipeline::GetRenderSettings()
  682. {
  683. return m_activeRenderSettings;
  684. }
  685. const PipelineRenderSettings& RenderPipeline::GetRenderSettings() const
  686. {
  687. return m_activeRenderSettings;
  688. }
  689. void RenderPipeline::RevertRenderSettings()
  690. {
  691. m_activeRenderSettings = m_descriptor.m_renderSettings;
  692. }
  693. void RenderPipeline::AddToRenderTickOnce()
  694. {
  695. m_renderMode = RenderMode::RenderOnce;
  696. }
  697. void RenderPipeline::AddToRenderTick()
  698. {
  699. m_renderMode = RenderMode::RenderEveryTick;
  700. }
  701. void RenderPipeline::RemoveFromRenderTick()
  702. {
  703. m_renderMode = RenderMode::NoRender;
  704. }
  705. RenderPipeline::RenderMode RenderPipeline::GetRenderMode() const
  706. {
  707. return m_renderMode;
  708. }
  709. bool RenderPipeline::NeedsRender() const
  710. {
  711. return m_renderMode != RenderMode::NoRender;
  712. }
  713. RHI::DrawFilterMask RenderPipeline::GetDrawFilterMask() const
  714. {
  715. return m_drawFilterMask;
  716. }
  717. void RenderPipeline::SetDrawFilterTags(RHI::DrawFilterTagRegistry* tagRegistry)
  718. {
  719. m_drawFilterTagForPipelineInstanceName = tagRegistry->AcquireTag(m_nameId);
  720. m_drawFilterTagForMaterialPipeline = tagRegistry->AcquireTag(m_materialPipelineTagName);
  721. m_drawFilterMask = 0;
  722. if (m_drawFilterTagForPipelineInstanceName.IsValid())
  723. {
  724. m_drawFilterMask |= 1 << m_drawFilterTagForPipelineInstanceName.GetIndex();
  725. }
  726. if (m_drawFilterTagForMaterialPipeline.IsValid())
  727. {
  728. m_drawFilterMask |= 1 << m_drawFilterTagForMaterialPipeline.GetIndex();
  729. }
  730. }
  731. void RenderPipeline::ReleaseDrawFilterTags(RHI::DrawFilterTagRegistry* tagRegistry)
  732. {
  733. tagRegistry->ReleaseTag(m_drawFilterTagForPipelineInstanceName);
  734. tagRegistry->ReleaseTag(m_drawFilterTagForMaterialPipeline);
  735. m_drawFilterTagForPipelineInstanceName.Reset();
  736. m_drawFilterTagForMaterialPipeline.Reset();
  737. }
  738. const RenderPipelineDescriptor& RenderPipeline::GetDescriptor() const
  739. {
  740. return m_descriptor;
  741. }
  742. bool RenderPipeline::AddPassBefore(Ptr<Pass> newPass, const AZ::Name& referencePassName)
  743. {
  744. auto foundPass = FindFirstPass(referencePassName);
  745. if (!foundPass)
  746. {
  747. AZ_Warning("RenderPipeline", false, "Add pass to render pipeline failed: can't find reference pass [%s] in render pipeline [%s]",
  748. referencePassName.GetCStr(), GetId().GetCStr());
  749. return false;
  750. }
  751. // insert the pass
  752. auto parentPass = foundPass->GetParent();
  753. auto passIndex = parentPass->FindChildPassIndex(referencePassName);
  754. // Note: no need to check if passIndex is valid since the pass was already found
  755. return parentPass->InsertChild(newPass, passIndex.GetIndex());
  756. }
  757. bool RenderPipeline::AddPassAfter(Ptr<Pass> newPass, const AZ::Name& referencePassName)
  758. {
  759. auto foundPass = FindFirstPass(referencePassName);
  760. if (!foundPass)
  761. {
  762. AZ_Warning("RenderPipeline", false, "Add pass to render pipeline failed: can't find reference pass [%s] in render pipeline [%s]",
  763. referencePassName.GetCStr(), GetId().GetCStr());
  764. return false;
  765. }
  766. // insert the pass
  767. auto parentPass = foundPass->GetParent();
  768. auto passIndex = parentPass->FindChildPassIndex(referencePassName);
  769. // Note: no need to check if passIndex is valid since the pass was already found
  770. return parentPass->InsertChild(newPass, passIndex.GetIndex()+1);
  771. }
  772. Ptr<Pass> RenderPipeline::FindFirstPass(const AZ::Name& passName)
  773. {
  774. auto passFilter = RPI::PassFilter::CreateWithPassHierarchy({passName});
  775. passFilter.SetOwnerRenderPipeline(this);
  776. RPI::Ptr<RPI::Pass> foundPass = nullptr;
  777. RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&foundPass](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
  778. {
  779. foundPass = pass;
  780. return RPI::PassFilterExecutionFlow::StopVisitingPasses;
  781. });
  782. return foundPass;
  783. }
  784. ViewType RenderPipeline::GetViewType() const
  785. {
  786. return m_viewType;
  787. }
  788. }
  789. }