RenderPipeline.cpp 41 KB

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