3
0

RenderPipeline.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  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_activeAAMethod = GetAAMethodByName(desc.m_defaultAAMethod);
  145. pipeline->m_passTree.m_rootPass->SetRenderPipeline(pipeline);
  146. pipeline->m_passTree.m_rootPass->m_flags.m_isPipelineRoot = true;
  147. pipeline->m_passTree.m_rootPass->ManualPipelineBuildAndInitialize();
  148. pipeline->SetActiveAAMethod(desc.m_defaultAAMethod);
  149. pipeline->UpdateViewportScissor();
  150. }
  151. void RenderPipeline::UpdateViewportScissor()
  152. {
  153. for (PassAttachmentBinding& binding : m_passTree.m_rootPass->m_attachmentBindings)
  154. {
  155. if (binding.m_slotType == PassSlotType::Output || binding.m_slotType == PassSlotType::InputOutput)
  156. {
  157. auto attachment = binding.GetAttachment();
  158. if (attachment && attachment->GetAttachmentType() == RHI::AttachmentType::Image)
  159. {
  160. RHI::ImageDescriptor imageDesc;
  161. if (attachment->m_importedResource)
  162. {
  163. AttachmentImage* image = static_cast<AttachmentImage*>(attachment->m_importedResource.get());
  164. imageDesc = image->GetDescriptor();
  165. }
  166. else
  167. {
  168. imageDesc = attachment->m_descriptor.m_image;
  169. }
  170. m_viewport = RHI::Viewport(0, (float)imageDesc.m_size.m_width, 0, (float)imageDesc.m_size.m_height);
  171. m_scissor = RHI::Scissor(0, 0, imageDesc.m_size.m_width, imageDesc.m_size.m_height);
  172. return;
  173. }
  174. }
  175. }
  176. }
  177. RenderPipeline::~RenderPipeline()
  178. {
  179. if (m_passTree.m_rootPass)
  180. {
  181. m_passTree.m_rootPass->SetRenderPipeline(nullptr);
  182. }
  183. }
  184. void RenderPipeline::BuildPipelineViews()
  185. {
  186. if (m_passTree.m_rootPass == nullptr)
  187. {
  188. return;
  189. }
  190. // Get view tags from all passes.
  191. PipelineViewTags viewTags;
  192. m_passTree.m_rootPass->GetPipelineViewTags(viewTags);
  193. // Use a new list for building pipeline views since we may need information from the previous list in m_views in the process
  194. PipelineViewMap newViewsByTag;
  195. // re-register only views where the view-tag still exists after rebuilding.
  196. m_persistentViewsByViewTag.clear();
  197. for (const auto& tag : viewTags)
  198. {
  199. PipelineViews pipelineViews;
  200. if (m_pipelineViewsByTag.find(tag) != m_pipelineViewsByTag.end())
  201. {
  202. // Copy the content from existing if it already exists
  203. pipelineViews = m_pipelineViewsByTag[tag];
  204. pipelineViews.m_drawListMask.reset();
  205. if (pipelineViews.m_type == PipelineViewType::Transient)
  206. {
  207. pipelineViews.m_views.clear();
  208. }
  209. else if (pipelineViews.m_type == PipelineViewType::Persistent)
  210. {
  211. for (auto& view : pipelineViews.m_views)
  212. {
  213. if (view)
  214. {
  215. m_persistentViewsByViewTag[view.get()] = pipelineViews.m_viewTag;
  216. }
  217. }
  218. }
  219. }
  220. else
  221. {
  222. pipelineViews.m_viewTag = tag;
  223. pipelineViews.m_type = PipelineViewType::Unknown;
  224. }
  225. newViewsByTag[tag] = pipelineViews;
  226. CollectDrawListMaskForViews(newViewsByTag[tag]);
  227. }
  228. m_pipelineViewsByTag = AZStd::move(newViewsByTag);
  229. // transient views are re-registered every frame anyway
  230. m_transientViewsByViewTag.clear();
  231. }
  232. void RenderPipeline::CollectDrawListMaskForViews(PipelineViews& views)
  233. {
  234. views.m_drawListMask.reset();
  235. views.m_passesByDrawList.clear();
  236. m_passTree.m_rootPass->GetViewDrawListInfo(views.m_drawListMask, views.m_passesByDrawList, views.m_viewTag);
  237. }
  238. bool RenderPipeline::CanRegisterView(const PipelineViewTag& allowedViewTag, const View* view) const
  239. {
  240. auto registeredViewItr = m_persistentViewsByViewTag.find(view);
  241. if (registeredViewItr != m_persistentViewsByViewTag.end() && registeredViewItr->second != allowedViewTag)
  242. {
  243. AZ_Warning("RenderPipeline", false, "View [%s] is already registered for persistent ViewTag [%s].",
  244. view->GetName().GetCStr(), registeredViewItr->second.GetCStr());
  245. return false;
  246. }
  247. registeredViewItr = m_transientViewsByViewTag.find(view);
  248. if (registeredViewItr != m_transientViewsByViewTag.end() && registeredViewItr->second != allowedViewTag)
  249. {
  250. AZ_Warning("RenderPipeline", false, "View [%s] is already registered for transient ViewTag [%s].",
  251. view->GetName().GetCStr(), registeredViewItr->second.GetCStr());
  252. return false;
  253. }
  254. return true;
  255. }
  256. void RenderPipeline::UnregisterView(ViewPtr view)
  257. {
  258. auto registeredViewItr = m_persistentViewsByViewTag.find(view.get());
  259. if (registeredViewItr != m_persistentViewsByViewTag.end())
  260. {
  261. return ResetPersistentView(registeredViewItr->second, view);
  262. }
  263. registeredViewItr = m_transientViewsByViewTag.find(view.get());
  264. if (registeredViewItr != m_transientViewsByViewTag.end())
  265. {
  266. return RemoveTransientView(registeredViewItr->second, view);
  267. }
  268. }
  269. void RenderPipeline::RemoveTransientView(const PipelineViewTag viewTag, ViewPtr view)
  270. {
  271. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  272. if (viewItr != m_pipelineViewsByTag.end())
  273. {
  274. PipelineViews& pipelineViews = viewItr->second;
  275. if (pipelineViews.m_type == PipelineViewType::Persistent)
  276. {
  277. AZ_Assert(
  278. false, "View [%s] was set as persistent view. Use ResetPersistentView to remove this view", viewTag.GetCStr());
  279. return;
  280. }
  281. for (int viewIndex = 0; viewIndex < pipelineViews.m_views.size(); ++viewIndex)
  282. {
  283. if (pipelineViews.m_views[viewIndex] == view)
  284. {
  285. view->SetPassesByDrawList(nullptr);
  286. pipelineViews.m_views.erase(pipelineViews.m_views.begin() + viewIndex);
  287. m_transientViewsByViewTag.erase(view.get());
  288. break;
  289. }
  290. }
  291. if (pipelineViews.m_views.empty())
  292. {
  293. pipelineViews.m_type = PipelineViewType::Unknown;
  294. }
  295. }
  296. }
  297. void RenderPipeline::ResetPersistentView(const PipelineViewTag viewTag, ViewPtr view)
  298. {
  299. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  300. if (viewItr != m_pipelineViewsByTag.end())
  301. {
  302. PipelineViews& pipelineViews = viewItr->second;
  303. if (pipelineViews.m_views.size() == 0)
  304. {
  305. return;
  306. }
  307. if (pipelineViews.m_type == PipelineViewType::Transient)
  308. {
  309. AZ_Assert(
  310. false,
  311. "View [%s] is a transient view. Use RemoveTransientView to remove it, or wait until the next frame.",
  312. viewTag.GetCStr());
  313. return;
  314. }
  315. AZ_Assert(
  316. pipelineViews.m_views[0] == view,
  317. "View [%s] is not registered for persistent view tag [%s]",
  318. pipelineViews.m_views[0]->GetName().GetCStr(),
  319. viewTag.GetCStr());
  320. // persistent views always have exactly one view
  321. pipelineViews.m_views[0]->SetPassesByDrawList(nullptr);
  322. m_persistentViewsByViewTag.erase(pipelineViews.m_views[0].get());
  323. // we are removing the only view, so we have to set the type to Unknown or the engine assumes m_views[0] is valid
  324. pipelineViews.m_views.clear();
  325. pipelineViews.m_type = PipelineViewType::Unknown;
  326. if (m_scene)
  327. {
  328. ViewPtr newView{ nullptr };
  329. SceneNotificationBus::Event(
  330. m_scene->GetId(), &SceneNotification::OnRenderPipelinePersistentViewChanged, this, viewTag, newView, view);
  331. }
  332. }
  333. }
  334. void RenderPipeline::SetPersistentView(const PipelineViewTag& viewTag, ViewPtr view)
  335. {
  336. // If a view is registered for multiple viewTags, it gets only the PassesByDrawList of whatever
  337. // DrawList it was registered last, which will cause a crash during SortDrawList later. So we check
  338. // here if the view is already registered with another viewTag.
  339. // TODO: remove this check and merge the PassesByDrawList if that behaviour is actually needed.
  340. if (!CanRegisterView(viewTag, view.get()))
  341. {
  342. AZ_Assert(false, "Can't register view [%s] with viewTag [%s]", view->GetName().GetCStr(), viewTag.GetCStr());
  343. return;
  344. }
  345. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  346. if (viewItr != m_pipelineViewsByTag.end())
  347. {
  348. PipelineViews& pipelineViews = viewItr->second;
  349. ViewPtr previousView{ nullptr };
  350. if (pipelineViews.m_type == PipelineViewType::Transient)
  351. {
  352. AZ_Assert(false, "View [%s] was set as transient view. Use AddTransientView function to add a view for this tag.", viewTag.GetCStr());
  353. return;
  354. }
  355. else if (pipelineViews.m_type == PipelineViewType::Unknown) // first time registering a view for this viewTag
  356. {
  357. pipelineViews.m_type = PipelineViewType::Persistent;
  358. pipelineViews.m_views.resize(1, nullptr);
  359. }
  360. else if (pipelineViews.m_type == PipelineViewType::Persistent) // re-registering a view
  361. {
  362. AZ_Assert(
  363. pipelineViews.m_views.size() == 1, "SetPersistentView(): PipelineViewType::Persistent needs exactly one view.");
  364. AZ_Assert(pipelineViews.m_views[0] != nullptr, "SetPersistentView(): previous view is invalid.");
  365. previousView = pipelineViews.m_views[0];
  366. }
  367. if (view)
  368. {
  369. view->OnAddToRenderPipeline();
  370. pipelineViews.m_views[0] = view;
  371. m_persistentViewsByViewTag[view.get()] = viewTag;
  372. }
  373. else { // view == nullptr
  374. // we are removing the view, so we have to set the type to Unknown or the engine assumes m_views[0] is valid
  375. pipelineViews.m_views.clear();
  376. pipelineViews.m_type = PipelineViewType::Unknown;
  377. }
  378. if (previousView)
  379. {
  380. previousView->SetPassesByDrawList(nullptr);
  381. m_persistentViewsByViewTag.erase(previousView.get());
  382. }
  383. if (m_scene)
  384. {
  385. SceneNotificationBus::Event(m_scene->GetId(), &SceneNotification::OnRenderPipelinePersistentViewChanged, this, viewTag, view, previousView);
  386. }
  387. }
  388. else
  389. {
  390. AZ_Assert(false, "View [%s] doesn't exist in render pipeline [%s]", viewTag.GetCStr(), m_nameId.GetCStr());
  391. }
  392. }
  393. void RenderPipeline::SetDefaultView(ViewPtr view)
  394. {
  395. SetPersistentView(m_mainViewTag, view);
  396. }
  397. ViewPtr RenderPipeline::GetDefaultView()
  398. {
  399. return GetFirstView(m_mainViewTag);
  400. }
  401. ViewPtr RenderPipeline::GetFirstView(const PipelineViewTag& viewTag)
  402. {
  403. const AZStd::vector<ViewPtr>& views = GetViews(viewTag);
  404. if (!views.empty())
  405. {
  406. return views[0];
  407. }
  408. return {};
  409. }
  410. void RenderPipeline::SetDefaultViewFromEntity(EntityId entityId)
  411. {
  412. ViewPtr cameraView;
  413. ViewProviderBus::EventResult(cameraView, entityId, &ViewProvider::GetView);
  414. if (cameraView)
  415. {
  416. SetDefaultView(cameraView);
  417. }
  418. }
  419. void RenderPipeline::SetDefaultStereoscopicViewFromEntity(EntityId entityId, RPI::ViewType viewType)
  420. {
  421. ViewPtr cameraView;
  422. ViewProviderBus::EventResult(cameraView, entityId, &ViewProvider::GetStereoscopicView, viewType);
  423. if (cameraView)
  424. {
  425. SetDefaultView(cameraView);
  426. }
  427. }
  428. void RenderPipeline::AddTransientView(const PipelineViewTag& viewTag, ViewPtr view)
  429. {
  430. AZ_Assert(view, "Transient View for ViewTag [%s] is invalid.", viewTag.GetCStr());
  431. // If a view is registered for multiple viewTags, it gets only the PassesByDrawList of whatever
  432. // DrawList it was registered last, which will cause a crash during SortDrawList later. So we check
  433. // here if the view is already registered with another viewTag.
  434. // TODO: remove this check and merge the PassesByDrawList if that behaviour is actually needed.
  435. if (!CanRegisterView(viewTag, view.get()))
  436. {
  437. AZ_Assert(false, "Can't register transient view [%s] with viewTag [%s]", view->GetName().GetCStr(), viewTag.GetCStr());
  438. return;
  439. }
  440. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  441. if (viewItr != m_pipelineViewsByTag.end())
  442. {
  443. PipelineViews& pipelineViews = viewItr->second;
  444. if (pipelineViews.m_type == PipelineViewType::Persistent)
  445. {
  446. AZ_Assert(false, "View [%s] was set as persistent view. Use SetPersistentView function to set a view for this tag", viewTag.GetCStr());
  447. return;
  448. }
  449. if (pipelineViews.m_type == PipelineViewType::Unknown)
  450. {
  451. pipelineViews.m_type = PipelineViewType::Transient;
  452. }
  453. view->SetPassesByDrawList(&pipelineViews.m_passesByDrawList);
  454. view->OnAddToRenderPipeline();
  455. pipelineViews.m_views.push_back(view);
  456. m_transientViewsByViewTag[view.get()] = viewTag;
  457. }
  458. }
  459. bool RenderPipeline::HasViewTag(const PipelineViewTag& viewTag) const
  460. {
  461. return m_pipelineViewsByTag.find(viewTag) != m_pipelineViewsByTag.end();
  462. }
  463. const PipelineViewTag& RenderPipeline::GetMainViewTag() const
  464. {
  465. return m_mainViewTag;
  466. }
  467. const AZStd::vector<ViewPtr>& RenderPipeline::GetViews(const PipelineViewTag& viewTag) const
  468. {
  469. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  470. if (viewItr != m_pipelineViewsByTag.end())
  471. {
  472. return viewItr->second.m_views;
  473. }
  474. static AZStd::vector<ViewPtr> emptyList;
  475. return emptyList;
  476. }
  477. const RHI::DrawListMask& RenderPipeline::GetDrawListMask(const PipelineViewTag& viewTag) const
  478. {
  479. auto viewItr = m_pipelineViewsByTag.find(viewTag);
  480. if (viewItr != m_pipelineViewsByTag.end())
  481. {
  482. return viewItr->second.m_drawListMask;
  483. }
  484. static RHI::DrawListMask emptyMask;
  485. return emptyMask;
  486. }
  487. const RenderPipeline::PipelineViewMap& RenderPipeline::GetPipelineViews() const
  488. {
  489. return m_pipelineViewsByTag;
  490. }
  491. void RenderPipeline::OnAddedToScene(Scene* scene)
  492. {
  493. AZ_Assert(m_scene == nullptr, "Pipeline was added to another scene");
  494. m_scene = scene;
  495. PassSystemInterface::Get()->AddRenderPipeline(this);
  496. }
  497. void RenderPipeline::OnRemovedFromScene([[maybe_unused]] Scene* scene)
  498. {
  499. m_passTree.ClearQueues();
  500. AZ_Assert(m_scene == scene, "Pipeline isn't added to the specified scene");
  501. m_scene = nullptr;
  502. PassSystemInterface::Get()->RemoveRenderPipeline(this);
  503. m_drawFilterTagForPipelineInstanceName.Reset();
  504. m_drawFilterTagForMaterialPipeline.Reset();
  505. m_drawFilterMask = 0;
  506. }
  507. void RenderPipeline::ProcessQueuedPassChanges()
  508. {
  509. m_passTree.ProcessQueuedChanges();
  510. }
  511. void RenderPipeline::UpdatePasses()
  512. {
  513. // Rebuild Pipeline if needed, for example if passes where hot reloaded
  514. if (PipelineNeedsRebuild(m_pipelinePassChanges))
  515. {
  516. // Process any queued changes before we attempt to reload the pipeline
  517. m_passTree.ProcessQueuedChanges();
  518. // Attempt to re-create hierarchy under root pass
  519. Ptr<ParentPass> newRoot = azrtti_cast<ParentPass*>(m_passTree.m_rootPass->Recreate().get());
  520. newRoot->SetRenderPipeline(this);
  521. newRoot->m_flags.m_isPipelineRoot = true;
  522. newRoot->ManualPipelineBuildAndInitialize();
  523. // Validate the new root
  524. PassValidationResults validation;
  525. newRoot->Validate(validation);
  526. if (validation.IsValid())
  527. {
  528. // Remove old pass
  529. m_passTree.m_rootPass->SetRenderPipeline(nullptr);
  530. m_passTree.m_rootPass->QueueForRemoval();
  531. // Set new root
  532. m_passTree.m_rootPass = newRoot;
  533. PassSystemInterface::Get()->GetRootPass()->AddChild(m_passTree.m_rootPass);
  534. // Re-Apply render pipeline change
  535. m_wasModifiedByScene = false;
  536. m_scene->TryApplyRenderPipelineChanges(this);
  537. }
  538. else
  539. {
  540. AZ_Printf("PassSystem", "\n>> Pass validation failed after hot reloading pas assets. Reverting to previously valid render pipeline.\n");
  541. validation.PrintValidationIfError();
  542. #if AZ_RPI_ENABLE_PASS_DEBUGGING
  543. AZ_Printf("PassSystem", "\nConstructed pass hierarchy with validation errors is as follows:\n");
  544. newRoot->DebugPrint();
  545. #endif
  546. }
  547. SetAAMethod(this, m_activeAAMethod);
  548. }
  549. // Build and initialize any queued passes
  550. m_passTree.ProcessQueuedChanges();
  551. if (m_pipelinePassChanges != PipelinePassChanges::NoPassChanges)
  552. {
  553. m_passTree.m_rootPass->SetRenderPipeline(this);
  554. // Pipeline views
  555. if (PipelineViewsNeedRebuild(m_pipelinePassChanges))
  556. {
  557. BuildPipelineViews();
  558. }
  559. if (m_scene)
  560. {
  561. SceneNotificationBus::Event(m_scene->GetId(), &SceneNotification::OnRenderPipelinePassesChanged, this);
  562. SceneNotificationBus::Event(m_scene->GetId(), &SceneNotification::OnRenderPipelineChanged, this,
  563. SceneNotification::RenderPipelineChangeType::PassChanged);
  564. // Pipeline state lookup
  565. if (PipelineStateLookupNeedsRebuild(m_pipelinePassChanges))
  566. {
  567. SceneRequestBus::Event(m_scene->GetId(), &SceneRequest::PipelineStateLookupNeedsRebuild);
  568. }
  569. }
  570. UpdateViewportScissor();
  571. // Reset change flags
  572. m_pipelinePassChanges = PipelinePassChanges::NoPassChanges;
  573. if (m_scene)
  574. {
  575. // Process any changes that may have happened due to SceneNotification Events. This may cause the
  576. // m_pipelinePassChanges flag to change and be handled later.
  577. m_passTree.ProcessQueuedChanges();
  578. }
  579. }
  580. }
  581. bool RenderPipeline::IsExecuteOnce()
  582. {
  583. return m_descriptor.m_executeOnce;
  584. }
  585. void RenderPipeline::RemoveFromScene()
  586. {
  587. if (m_scene == nullptr)
  588. {
  589. AZ_Assert(false, "RenderPipeline::RemoveFromScene: Pipeline [%s] isn't added to any scene", m_nameId.GetCStr());
  590. return;
  591. }
  592. m_scene->RemoveRenderPipeline(m_nameId);
  593. }
  594. void RenderPipeline::OnStartFrame([[maybe_unused]] float time)
  595. {
  596. AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame");
  597. UpdatePasses();
  598. for (auto& viewItr : m_pipelineViewsByTag)
  599. {
  600. PipelineViews& pipelineViews = viewItr.second;
  601. if (pipelineViews.m_type == PipelineViewType::Transient)
  602. {
  603. // Clear transient views
  604. pipelineViews.m_views.clear();
  605. }
  606. else if (pipelineViews.m_type == PipelineViewType::Persistent)
  607. {
  608. pipelineViews.m_views[0]->SetPassesByDrawList(&pipelineViews.m_passesByDrawList);
  609. }
  610. }
  611. m_transientViewsByViewTag.clear();
  612. }
  613. void RenderPipeline::OnFrameEnd()
  614. {
  615. if (m_renderMode == RenderMode::RenderOnce)
  616. {
  617. RemoveFromRenderTick();
  618. }
  619. }
  620. void RenderPipeline::PassSystemFrameBegin(Pass::FramePrepareParams params)
  621. {
  622. AZ_PROFILE_FUNCTION(RPI);
  623. if (GetRenderMode() != RenderPipeline::RenderMode::NoRender)
  624. {
  625. params.m_viewportState = m_viewport;
  626. params.m_scissorState = m_scissor;
  627. m_passTree.m_rootPass->UpdateConnectedBindings();
  628. m_passTree.m_rootPass->FrameBegin(params);
  629. }
  630. }
  631. void RenderPipeline::PassSystemFrameEnd()
  632. {
  633. AZ_PROFILE_FUNCTION(RPI);
  634. if (GetRenderMode() != RenderPipeline::RenderMode::NoRender)
  635. {
  636. m_passTree.m_rootPass->FrameEnd();
  637. }
  638. }
  639. void RenderPipeline::CollectPersistentViews(AZStd::map<ViewPtr, RHI::DrawListMask>& outViewMasks) const
  640. {
  641. for (auto& viewItr : m_pipelineViewsByTag)
  642. {
  643. const PipelineViews& pipelineViews = viewItr.second;
  644. if (pipelineViews.m_type == PipelineViewType::Persistent)
  645. {
  646. ViewPtr view = pipelineViews.m_views[0];
  647. if (outViewMasks.find(view) == outViewMasks.end())
  648. {
  649. // Add the view to the map with its DrawListMask if the view isn't in the list
  650. outViewMasks[view] = pipelineViews.m_drawListMask;
  651. }
  652. else
  653. {
  654. // Combine the DrawListMask with the existing one if the view already exist.
  655. outViewMasks[view] |= pipelineViews.m_drawListMask;
  656. }
  657. }
  658. }
  659. }
  660. const PipelineGlobalBinding* RenderPipeline::GetPipelineGlobalConnection(const Name& globalName) const
  661. {
  662. for (const PipelineGlobalBinding& connection : m_pipelineGlobalConnections)
  663. {
  664. if (connection.m_globalName == globalName)
  665. {
  666. return &connection;
  667. }
  668. }
  669. return nullptr;
  670. }
  671. void RenderPipeline::AddPipelineGlobalConnection(const Name& globalName, PassAttachmentBinding* binding, Pass* pass)
  672. {
  673. m_pipelineGlobalConnections.push_back(PipelineGlobalBinding{ globalName, binding, pass });
  674. }
  675. void RenderPipeline::RemovePipelineGlobalConnectionsFromPass(Pass* passOnwer)
  676. {
  677. auto iter = m_pipelineGlobalConnections.begin();
  678. while (iter != m_pipelineGlobalConnections.end())
  679. {
  680. if (iter->m_pass == passOnwer)
  681. {
  682. m_pipelineGlobalConnections.erase(iter);
  683. }
  684. else
  685. {
  686. ++iter;
  687. }
  688. }
  689. }
  690. void RenderPipeline::ClearGlobalBindings()
  691. {
  692. m_pipelineGlobalConnections.clear();
  693. }
  694. RenderPipelineId RenderPipeline::GetId() const
  695. {
  696. return m_nameId;
  697. }
  698. const Ptr<ParentPass>& RenderPipeline::GetRootPass() const
  699. {
  700. return m_passTree.m_rootPass;
  701. }
  702. void RenderPipeline::MarkPipelinePassChanges(u32 passChangeFlags)
  703. {
  704. m_pipelinePassChanges |= passChangeFlags;
  705. }
  706. Scene* RenderPipeline::GetScene() const
  707. {
  708. return m_scene;
  709. }
  710. AzFramework::NativeWindowHandle RenderPipeline::GetWindowHandle() const
  711. {
  712. return m_windowHandle;
  713. }
  714. PipelineRenderSettings& RenderPipeline::GetRenderSettings()
  715. {
  716. return m_activeRenderSettings;
  717. }
  718. const PipelineRenderSettings& RenderPipeline::GetRenderSettings() const
  719. {
  720. return m_activeRenderSettings;
  721. }
  722. void RenderPipeline::RevertRenderSettings()
  723. {
  724. m_activeRenderSettings = m_descriptor.m_renderSettings;
  725. }
  726. void RenderPipeline::AddToRenderTickOnce()
  727. {
  728. m_renderMode = RenderMode::RenderOnce;
  729. }
  730. void RenderPipeline::AddToRenderTick()
  731. {
  732. m_renderMode = RenderMode::RenderEveryTick;
  733. }
  734. void RenderPipeline::RemoveFromRenderTick()
  735. {
  736. m_renderMode = RenderMode::NoRender;
  737. }
  738. RenderPipeline::RenderMode RenderPipeline::GetRenderMode() const
  739. {
  740. return m_renderMode;
  741. }
  742. bool RenderPipeline::NeedsRender() const
  743. {
  744. return m_renderMode != RenderMode::NoRender;
  745. }
  746. RHI::DrawFilterMask RenderPipeline::GetDrawFilterMask() const
  747. {
  748. return m_drawFilterMask;
  749. }
  750. void RenderPipeline::SetDrawFilterTags(RHI::DrawFilterTagRegistry* tagRegistry)
  751. {
  752. m_drawFilterTagForPipelineInstanceName = tagRegistry->AcquireTag(m_nameId);
  753. m_drawFilterTagForMaterialPipeline = tagRegistry->AcquireTag(m_materialPipelineTagName);
  754. m_drawFilterMask = 0;
  755. if (m_drawFilterTagForPipelineInstanceName.IsValid())
  756. {
  757. m_drawFilterMask |= 1 << m_drawFilterTagForPipelineInstanceName.GetIndex();
  758. }
  759. if (m_drawFilterTagForMaterialPipeline.IsValid())
  760. {
  761. m_drawFilterMask |= 1 << m_drawFilterTagForMaterialPipeline.GetIndex();
  762. }
  763. }
  764. void RenderPipeline::ReleaseDrawFilterTags(RHI::DrawFilterTagRegistry* tagRegistry)
  765. {
  766. tagRegistry->ReleaseTag(m_drawFilterTagForPipelineInstanceName);
  767. tagRegistry->ReleaseTag(m_drawFilterTagForMaterialPipeline);
  768. m_drawFilterTagForPipelineInstanceName.Reset();
  769. m_drawFilterTagForMaterialPipeline.Reset();
  770. }
  771. const RenderPipelineDescriptor& RenderPipeline::GetDescriptor() const
  772. {
  773. return m_descriptor;
  774. }
  775. bool RenderPipeline::AddPassBefore(Ptr<Pass> newPass, const AZ::Name& referencePassName)
  776. {
  777. auto foundPass = FindFirstPass(referencePassName);
  778. if (!foundPass)
  779. {
  780. AZ_Warning("RenderPipeline", false, "Add pass to render pipeline failed: can't find reference pass [%s] in render pipeline [%s]",
  781. referencePassName.GetCStr(), GetId().GetCStr());
  782. return false;
  783. }
  784. // insert the pass
  785. auto parentPass = foundPass->GetParent();
  786. auto passIndex = parentPass->FindChildPassIndex(referencePassName);
  787. // Note: no need to check if passIndex is valid since the pass was already found
  788. return parentPass->InsertChild(newPass, passIndex.GetIndex());
  789. }
  790. bool RenderPipeline::AddPassAfter(Ptr<Pass> newPass, const AZ::Name& referencePassName)
  791. {
  792. auto foundPass = FindFirstPass(referencePassName);
  793. if (!foundPass)
  794. {
  795. AZ_Warning("RenderPipeline", false, "Add pass to render pipeline failed: can't find reference pass [%s] in render pipeline [%s]",
  796. referencePassName.GetCStr(), GetId().GetCStr());
  797. return false;
  798. }
  799. // insert the pass
  800. auto parentPass = foundPass->GetParent();
  801. auto passIndex = parentPass->FindChildPassIndex(referencePassName);
  802. // Note: no need to check if passIndex is valid since the pass was already found
  803. return parentPass->InsertChild(newPass, passIndex.GetIndex()+1);
  804. }
  805. Ptr<Pass> RenderPipeline::FindFirstPass(const AZ::Name& passName)
  806. {
  807. auto passFilter = RPI::PassFilter::CreateWithPassHierarchy({passName});
  808. passFilter.SetOwnerRenderPipeline(this);
  809. RPI::Ptr<RPI::Pass> foundPass = nullptr;
  810. RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&foundPass](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
  811. {
  812. foundPass = pass;
  813. return RPI::PassFilterExecutionFlow::StopVisitingPasses;
  814. });
  815. return foundPass;
  816. }
  817. ViewType RenderPipeline::GetViewType() const
  818. {
  819. return m_viewType;
  820. }
  821. // ---------------------------- Anti-aliasing
  822. bool RenderPipeline::SetActiveAAMethod(AZStd::string aaMethodName)
  823. {
  824. AntiAliasingMode antiAliasingMode = GetAAMethodByName(aaMethodName);
  825. if (antiAliasingMode == AntiAliasingMode::Default)
  826. {
  827. return false;
  828. }
  829. m_activeAAMethod = antiAliasingMode;
  830. return SetAAMethod(this, m_activeAAMethod);
  831. }
  832. AntiAliasingMode RenderPipeline::GetActiveAAMethod()
  833. {
  834. return m_activeAAMethod;
  835. }
  836. AntiAliasingMode RenderPipeline::GetAAMethodByName(AZStd::string aaMethodName)
  837. {
  838. const AZStd::unordered_map<AZStd::string, AntiAliasingMode> AAMethodsLookup = {
  839. {"MSAA", AntiAliasingMode::MSAA}, {"SMAA", AntiAliasingMode::SMAA},
  840. {"TAA", AntiAliasingMode::TAA}
  841. };
  842. auto findIt = AAMethodsLookup.find(aaMethodName);
  843. if (findIt != AAMethodsLookup.end())
  844. {
  845. return findIt->second;
  846. }
  847. return AntiAliasingMode::Default;
  848. }
  849. AZStd::string RenderPipeline::GetAAMethodNameByIndex(AntiAliasingMode aaMethodIndex)
  850. {
  851. const AZStd::unordered_map<AntiAliasingMode, AZStd::string> AAMethodNameLookup = {
  852. {AntiAliasingMode::MSAA, "MSAA"}, {AntiAliasingMode::SMAA, "SMAA"},
  853. {AntiAliasingMode::TAA, "TAA"}
  854. };
  855. auto findIt = AAMethodNameLookup.find(aaMethodIndex);
  856. if (findIt != AAMethodNameLookup.end())
  857. {
  858. return findIt->second;
  859. }
  860. return "MSAA";
  861. }
  862. bool RenderPipeline::EnablePass(RenderPipeline* pipeline, Name& passName, bool enable)
  863. {
  864. PassFilter passFilter = PassFilter::CreateWithPassName(passName, pipeline);
  865. Ptr<Pass> aaPass = PassSystemInterface::Get()->FindFirstPass(passFilter);
  866. if (!aaPass)
  867. {
  868. return false;
  869. }
  870. if (aaPass->IsEnabled() != enable)
  871. {
  872. aaPass->SetEnabled(enable);
  873. }
  874. return true;
  875. }
  876. bool RenderPipeline::SetAAMethod(RenderPipeline* pipeline, AZStd::string aaMethodName)
  877. {
  878. AntiAliasingMode antiAliasingMode = GetAAMethodByName(aaMethodName);
  879. return SetAAMethod(pipeline, antiAliasingMode);
  880. }
  881. bool RenderPipeline::SetAAMethod(RenderPipeline* pipeline, AntiAliasingMode antiAliasingMode)
  882. {
  883. if (antiAliasingMode == AntiAliasingMode::Default)
  884. {
  885. return false;
  886. }
  887. const AZStd::unordered_map<AntiAliasingMode, AZStd::vector<Name>> AAPassNamesLookup = {
  888. {AntiAliasingMode::SMAA, {Name("SMAA1xApplyLinearHDRColorPass")}},
  889. {AntiAliasingMode::TAA, {Name("TaaPass"), Name("ContrastAdaptiveSharpeningPass")}}
  890. };
  891. for (auto& aaPassMap : AAPassNamesLookup)
  892. {
  893. AZStd::for_each(aaPassMap.second.begin(), aaPassMap.second.end(), [&pipeline, &aaPassMap, &antiAliasingMode](Name passName){
  894. EnablePass(pipeline, passName, aaPassMap.first == antiAliasingMode);
  895. });
  896. }
  897. return true;
  898. }
  899. }
  900. }