3
0

PassTests.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  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/RPI.Reflect/Pass/ComputePassData.h>
  9. #include <Atom/RPI.Reflect/Pass/PassRequest.h>
  10. #include <Atom/RPI.Reflect/Pass/PassTemplate.h>
  11. #include <Atom/RPI.Public/Pass/ComputePass.h>
  12. #include <Atom/RPI.Public/Pass/CopyPass.h>
  13. #include <Atom/RPI.Public/Pass/ParentPass.h>
  14. #include <Atom/RPI.Public/Pass/Pass.h>
  15. #include <Atom/RPI.Public/Pass/PassFactory.h>
  16. #include <Atom/RPI.Public/Pass/PassFilter.h>
  17. #include <Atom/RPI.Public/Pass/PassSystem.h>
  18. #include <Atom/RPI.Public/Pass/RasterPass.h>
  19. #include <Atom/RPI.Public/RenderPipeline.h>
  20. #include <AzCore/UnitTest/TestTypes.h>
  21. #include <Common/RPITestFixture.h>
  22. namespace UnitTest
  23. {
  24. using namespace AZ;
  25. using namespace RPI;
  26. // This class holds and sets up some data for the tests
  27. // This is it's own class so we can delete it before the teardown phase, otherwise
  28. // name dictionary fails because we have remaining names in the PassTemplates
  29. struct PassTestData
  30. {
  31. AZ_CLASS_ALLOCATOR(PassTestData, SystemAllocator);
  32. PassTemplate m_parentPass;
  33. // Child passes
  34. PassTemplate m_depthPrePass;
  35. PassTemplate m_lightCullPass;
  36. PassTemplate m_forwardPass;
  37. PassTemplate m_postProcessPass;
  38. static const size_t NumberOfChildPasses = 4;
  39. void CreatePassTemplates()
  40. {
  41. // Depth Pre Pass Dummy...
  42. {
  43. m_depthPrePass.m_name = "DepthPrePass";
  44. m_depthPrePass.m_passClass = "Pass";
  45. {
  46. PassSlot slot;
  47. slot.m_name = "DepthOutput";
  48. slot.m_slotType = RPI::PassSlotType::Output;
  49. slot.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::RenderTarget;
  50. m_depthPrePass.AddSlot(slot);
  51. }
  52. {
  53. PassImageAttachmentDesc depthBuffer;
  54. depthBuffer.m_name = "DepthBuffer";
  55. depthBuffer.m_imageDescriptor = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::DepthStencil | RHI::ImageBindFlags::ShaderReadWrite, 1600, 900, RHI::Format::D32_FLOAT_S8X24_UINT);
  56. depthBuffer.m_lifetime = RHI::AttachmentLifetimeType::Transient;
  57. m_depthPrePass.AddImageAttachment(depthBuffer);
  58. }
  59. {
  60. PassConnection connection;
  61. connection.m_localSlot = "DepthOutput";
  62. connection.m_attachmentRef.m_pass = "This";
  63. connection.m_attachmentRef.m_attachment = "DepthBuffer";
  64. m_depthPrePass.AddOutputConnection(connection);
  65. }
  66. }
  67. // Light Culling Pass Dummy...
  68. {
  69. m_lightCullPass.m_name = "LightCullPass";
  70. m_lightCullPass.m_passClass = "Pass";
  71. {
  72. PassSlot slot;
  73. slot.m_name = "LightListOutput";
  74. slot.m_slotType = RPI::PassSlotType::Output;
  75. slot.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::Shader;
  76. m_lightCullPass.AddSlot(slot);
  77. }
  78. {
  79. PassBufferAttachmentDesc lightListBuffer;
  80. lightListBuffer.m_name = "LightList";
  81. lightListBuffer.m_lifetime = RHI::AttachmentLifetimeType::Transient;
  82. m_lightCullPass.AddBufferAttachment(lightListBuffer);
  83. }
  84. {
  85. PassConnection connection;
  86. connection.m_localSlot = "LightListOutput";
  87. connection.m_attachmentRef.m_pass = "This";
  88. connection.m_attachmentRef.m_attachment = "LightList";
  89. m_lightCullPass.AddOutputConnection(connection);
  90. }
  91. }
  92. // Forward Pass Dummy...
  93. {
  94. m_forwardPass.m_name = "ForwardPass";
  95. m_forwardPass.m_passClass = "Pass";
  96. {
  97. PassSlot slot;
  98. slot.m_name = "DepthInputOutput";
  99. slot.m_slotType = RPI::PassSlotType::InputOutput;
  100. slot.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::DepthStencil;
  101. m_forwardPass.AddSlot(slot);
  102. }
  103. {
  104. PassSlot slot;
  105. slot.m_name = "LightListInput";
  106. slot.m_slotType = RPI::PassSlotType::Input;
  107. m_forwardPass.AddSlot(slot);
  108. }
  109. {
  110. PassSlot slot;
  111. slot.m_name = "LightingOutput";
  112. slot.m_slotType = RPI::PassSlotType::Output;
  113. slot.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::RenderTarget;
  114. m_forwardPass.AddSlot(slot);
  115. }
  116. {
  117. PassImageAttachmentDesc lightingOutput;
  118. lightingOutput.m_name = "LightingBuffer";
  119. lightingOutput.m_imageDescriptor.m_format = RHI::Format::R16G16B16A16_FLOAT;
  120. lightingOutput.m_lifetime = RHI::AttachmentLifetimeType::Transient;
  121. lightingOutput.m_sizeSource.m_source.m_pass = "This";
  122. lightingOutput.m_sizeSource.m_source.m_attachment = "DepthInputOutput";
  123. lightingOutput.m_sizeSource.m_multipliers.m_widthMultiplier = 1.0f;
  124. lightingOutput.m_sizeSource.m_multipliers.m_heightMultiplier = 1.0f;
  125. m_forwardPass.AddImageAttachment(lightingOutput);
  126. }
  127. {
  128. PassConnection connection;
  129. connection.m_localSlot = "LightingOutput";
  130. connection.m_attachmentRef.m_pass = "This";
  131. connection.m_attachmentRef.m_attachment = "LightingBuffer";
  132. m_forwardPass.AddOutputConnection(connection);
  133. }
  134. }
  135. // Post Process Pass Dummy...
  136. {
  137. m_postProcessPass.m_name = "PostProcessPass";
  138. m_postProcessPass.m_passClass = "Pass";
  139. {
  140. PassSlot slot;
  141. slot.m_name = "DepthInput";
  142. slot.m_slotType = RPI::PassSlotType::Input;
  143. slot.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::Shader;
  144. m_postProcessPass.AddSlot(slot);
  145. }
  146. {
  147. PassSlot slot;
  148. slot.m_name = "LightingInput";
  149. slot.m_slotType = RPI::PassSlotType::Input;
  150. slot.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::Shader;
  151. m_postProcessPass.AddSlot(slot);
  152. }
  153. {
  154. PassSlot slot;
  155. slot.m_name = "FinalOutput";
  156. slot.m_slotType = RPI::PassSlotType::Output;
  157. slot.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::Shader;
  158. m_postProcessPass.AddSlot(slot);
  159. }
  160. {
  161. PassImageAttachmentDesc finalImage;
  162. finalImage.m_name = "FinalImage";
  163. finalImage.m_lifetime = RHI::AttachmentLifetimeType::Transient;
  164. finalImage.m_formatSource.m_pass = "This";
  165. finalImage.m_formatSource.m_attachment = "LightingInput";
  166. finalImage.m_sizeSource.m_source.m_pass = "This";
  167. finalImage.m_sizeSource.m_source.m_attachment = "LightingInput";
  168. finalImage.m_sizeSource.m_multipliers.m_widthMultiplier = 0.5f;
  169. finalImage.m_sizeSource.m_multipliers.m_heightMultiplier = 0.5f;
  170. m_postProcessPass.AddImageAttachment(finalImage);
  171. }
  172. {
  173. PassConnection connection;
  174. connection.m_localSlot = "FinalOutput";
  175. connection.m_attachmentRef.m_pass = "This";
  176. connection.m_attachmentRef.m_attachment = "FinalImage";
  177. m_postProcessPass.AddOutputConnection(connection);
  178. }
  179. }
  180. // Parent Pass Dummy...
  181. {
  182. m_parentPass.m_name = "ParentPass";
  183. m_parentPass.m_passClass = "ParentPass";
  184. {
  185. PassSlot slot;
  186. slot.m_name = "Output";
  187. slot.m_slotType = RPI::PassSlotType::Output;
  188. m_parentPass.AddSlot(slot);
  189. }
  190. {
  191. PassRequest request;
  192. request.m_passName = "DepthPrePass";
  193. request.m_templateName = "DepthPrePass";
  194. m_parentPass.AddPassRequest(request);
  195. }
  196. {
  197. PassRequest request;
  198. request.m_passName = "LightCullPass";
  199. request.m_templateName = "LightCullPass";
  200. m_parentPass.AddPassRequest(request);
  201. }
  202. {
  203. PassRequest request;
  204. request.m_passName = "ForwardPass";
  205. request.m_templateName = "ForwardPass";
  206. PassConnection connection;
  207. connection.m_localSlot = "DepthInputOutput";
  208. connection.m_attachmentRef.m_pass = "DepthPrePass";
  209. connection.m_attachmentRef.m_attachment = "DepthOutput";
  210. request.AddInputConnection(connection);
  211. connection.m_localSlot = "LightListInput";
  212. connection.m_attachmentRef.m_pass = "LightCullPass";
  213. connection.m_attachmentRef.m_attachment = "LightListOutput";
  214. request.AddInputConnection(connection);
  215. m_parentPass.AddPassRequest(request);
  216. }
  217. {
  218. PassRequest request;
  219. request.m_passName = "PostProcessPass";
  220. request.m_templateName = "PostProcessPass";
  221. PassConnection connection;
  222. connection.m_localSlot = "DepthInput";
  223. connection.m_attachmentRef.m_pass = "ForwardPass";
  224. connection.m_attachmentRef.m_attachment = "DepthInputOutput";
  225. request.AddInputConnection(connection);
  226. connection.m_localSlot = "LightingInput";
  227. connection.m_attachmentRef.m_pass = "ForwardPass";
  228. connection.m_attachmentRef.m_attachment = "LightingOutput";
  229. request.AddInputConnection(connection);
  230. m_parentPass.AddPassRequest(request);
  231. }
  232. {
  233. PassConnection connection;
  234. connection.m_localSlot = "Output";
  235. connection.m_attachmentRef.m_pass = "PostProcessPass";
  236. connection.m_attachmentRef.m_attachment = "FinalOutput";
  237. m_parentPass.AddOutputConnection(connection);
  238. }
  239. }
  240. }
  241. void AddPassTemplatesToLibrary()
  242. {
  243. PassSystemInterface* passSystem = PassSystemInterface::Get();
  244. passSystem->AddPassTemplate(Name("DepthPrePass"), m_depthPrePass.Clone());
  245. passSystem->AddPassTemplate(Name("LightCullPass"), m_lightCullPass.Clone());
  246. passSystem->AddPassTemplate(Name("ForwardPass"), m_forwardPass.Clone());
  247. passSystem->AddPassTemplate(Name("PostProcessPass"), m_postProcessPass.Clone());
  248. passSystem->AddPassTemplate(Name("ParentPass"), m_parentPass.Clone());
  249. }
  250. };
  251. class PassTests
  252. : public RPITestFixture
  253. {
  254. protected:
  255. static Ptr<Pass> Create(const PassDescriptor& descriptor)
  256. {
  257. Ptr<Pass> pass = aznew Pass(descriptor);
  258. return pass;
  259. }
  260. // Setup functions...
  261. void SetUp() override
  262. {
  263. RPITestFixture::SetUp();
  264. m_passSystem = azrtti_cast<PassSystem*>(PassSystemInterface::Get());
  265. m_data = aznew PassTestData();
  266. // We don't ever instantiate the base Pass class in the runtime, however we use it here to facilitate testing
  267. m_passSystem->AddPassCreator(Name("Pass"), &PassTests::Create);
  268. m_data->CreatePassTemplates();
  269. }
  270. void TearDown() override
  271. {
  272. // Delete PassTemplates so Names are released
  273. delete m_data;
  274. RPITestFixture::TearDown();
  275. }
  276. Ptr<Pass> CreateBuildAndValidateParentPass(PassValidationResults& validationResults)
  277. {
  278. Ptr<Pass> parentPass = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("ParentPass"));
  279. parentPass->m_flags.m_partOfHierarchy = true;
  280. parentPass->OnHierarchyChange();
  281. parentPass->Reset();
  282. parentPass->Build();
  283. parentPass->Validate(validationResults);
  284. return parentPass;
  285. }
  286. void CreatePassTestTree(Ptr<Pass>& pass, Ptr<Pass>& parent1, Ptr<Pass>& parent2, Ptr<Pass>& parent3)
  287. {
  288. pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1"));
  289. parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1"));
  290. parent2 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent2"));
  291. parent3 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent3"));
  292. // Set Building to avoid state check errors when adding passes
  293. parent1->m_state = PassState::Building;
  294. parent2->m_state = PassState::Building;
  295. parent3->m_state = PassState::Building;
  296. parent3->AsParent()->AddChild(parent2);
  297. parent2->AsParent()->AddChild(parent1);
  298. parent1->AsParent()->AddChild(pass);
  299. pass->m_state = PassState::Idle;
  300. parent1->m_state = PassState::Idle;
  301. parent2->m_state = PassState::Idle;
  302. parent3->m_state = PassState::Idle;
  303. }
  304. // Members...
  305. PassSystem* m_passSystem;
  306. PassTestData* m_data;
  307. // Tests...
  308. // Tests that we can build the passes outlined in PassTestData and that the validation of the pass hierarchy returns no errors
  309. void TestPassConstructionAndValidation()
  310. {
  311. m_data->AddPassTemplatesToLibrary();
  312. PassValidationResults validationResults;
  313. Ptr<Pass> parentPass = CreateBuildAndValidateParentPass(validationResults);
  314. EXPECT_TRUE(validationResults.IsValid());
  315. EXPECT_TRUE(parentPass->m_name == Name("ParentPass"));
  316. EXPECT_TRUE(parentPass->AsParent()->GetChildren().size() == PassTestData::NumberOfChildPasses);
  317. }
  318. // Tests that validation correctly fails when connection's local slot name is set to a garbage value
  319. void TestInvalidLocalSlotName()
  320. {
  321. AZ_TEST_START_TRACE_SUPPRESSION;
  322. // Set the connection's local slot name to a garbage value
  323. m_data->m_parentPass.m_passRequests[3].m_connections[1].m_localSlot = "NonExistantName";
  324. m_data->AddPassTemplatesToLibrary();
  325. PassValidationResults validationResults;
  326. Ptr<Pass> parentPass = CreateBuildAndValidateParentPass(validationResults);
  327. EXPECT_FALSE(validationResults.IsValid());
  328. EXPECT_EQ(1, validationResults.m_passesWithErrors.size());
  329. AZ_TEST_STOP_TRACE_SUPPRESSION(2);
  330. }
  331. // Tests that validation correctly fails when connection's target slot name is set to a garbage value
  332. void TestInvalidConnectedSlotName()
  333. {
  334. AZ_TEST_START_TRACE_SUPPRESSION;
  335. // Set the connection's target slot name to a garbage value
  336. m_data->m_parentPass.m_passRequests[3].m_connections[1].m_attachmentRef.m_attachment = "NonExistantName";
  337. m_data->AddPassTemplatesToLibrary();
  338. PassValidationResults validationResults;
  339. Ptr<Pass> parentPass = CreateBuildAndValidateParentPass(validationResults);
  340. EXPECT_FALSE(validationResults.IsValid());
  341. EXPECT_EQ(1, validationResults.m_passesWithErrors.size());
  342. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  343. }
  344. // Tests that validation correctly fails when connection's target slot name is set to a garbage value
  345. void TestInvalidConnectedPassName()
  346. {
  347. AZ_TEST_START_TRACE_SUPPRESSION;
  348. // Set the connection's target pass name to a garbage value
  349. m_data->m_parentPass.m_passRequests[3].m_connections[1].m_attachmentRef.m_pass = "NonExistantName";
  350. m_data->AddPassTemplatesToLibrary();
  351. PassValidationResults validationResults;
  352. Ptr<Pass> parentPass = CreateBuildAndValidateParentPass(validationResults);
  353. EXPECT_FALSE(validationResults.IsValid());
  354. EXPECT_EQ(1, validationResults.m_passesWithErrors.size());
  355. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  356. }
  357. // Tests that validation correctly fails when connection's slots are mismatched
  358. void TestSlotTypeMismatch()
  359. {
  360. AZ_TEST_START_TRACE_SUPPRESSION;
  361. // Set one of the inputs to be connected to another input, which is invalid
  362. m_data->m_parentPass.m_passRequests[3].m_connections[1].m_attachmentRef.m_attachment = "LightListInput";
  363. m_data->AddPassTemplatesToLibrary();
  364. PassValidationResults validationResults;
  365. Ptr<Pass> parentPass = CreateBuildAndValidateParentPass(validationResults);
  366. EXPECT_FALSE(validationResults.IsValid());
  367. EXPECT_EQ(1, validationResults.m_passesWithErrors.size());
  368. AZ_TEST_STOP_TRACE_SUPPRESSION(2);
  369. }
  370. // Tests that validation correctly fails when parent-child connection's slots are mismatched (mismatches are different for parent to child connections)
  371. void TestParentChildSlotTypeMismatch()
  372. {
  373. AZ_TEST_START_TRACE_SUPPRESSION;
  374. // Set parent output to be connect to child input, which is invalid
  375. m_data->m_parentPass.m_connections[0].m_attachmentRef.m_attachment = "LightingInput";
  376. m_data->AddPassTemplatesToLibrary();
  377. PassValidationResults validationResults;
  378. Ptr<Pass> parentPass = CreateBuildAndValidateParentPass(validationResults);
  379. EXPECT_FALSE(validationResults.IsValid());
  380. EXPECT_EQ(1, validationResults.m_passesWithErrors.size());
  381. AZ_TEST_STOP_TRACE_SUPPRESSION(2);
  382. }
  383. // Checks that pass factory has all the default name
  384. void TestFactoryDefaultCreators()
  385. {
  386. EXPECT_TRUE(m_passSystem->HasCreatorForClass(Name("ParentPass")));
  387. EXPECT_TRUE(m_passSystem->HasCreatorForClass(Name("RasterPass")));
  388. EXPECT_TRUE(m_passSystem->HasCreatorForClass(Name("CopyPass")));
  389. EXPECT_TRUE(m_passSystem->HasCreatorForClass(Name("FullScreenTriangle")));
  390. EXPECT_TRUE(m_passSystem->HasCreatorForClass(Name("ComputePass")));
  391. EXPECT_TRUE(m_passSystem->HasCreatorForClass(Name("MSAAResolvePass")));
  392. EXPECT_TRUE(m_passSystem->HasCreatorForClass(Name("DownsampleMipChainPass")));
  393. }
  394. // Tests that all creation methods return null with invalid arguments
  395. void TestCreationMethodsFailure()
  396. {
  397. Name doesNotExist("doesNotExist");
  398. Ptr<Pass> pass;
  399. AZStd::shared_ptr<PassTemplate> nullTemplate = nullptr;
  400. AZ_TEST_START_TRACE_SUPPRESSION;
  401. pass = m_passSystem->CreatePassFromClass(doesNotExist, doesNotExist);
  402. EXPECT_TRUE(pass == nullptr);
  403. pass = m_passSystem->CreatePassFromTemplate(doesNotExist, doesNotExist);
  404. EXPECT_TRUE(pass == nullptr);
  405. pass = m_passSystem->CreatePassFromTemplate(nullTemplate, doesNotExist);
  406. EXPECT_TRUE(pass == nullptr);
  407. pass = m_passSystem->CreatePassFromRequest(nullptr);
  408. EXPECT_TRUE(pass == nullptr);
  409. AZ_TEST_STOP_TRACE_SUPPRESSION(4);
  410. }
  411. // Tests that all creation methods successfully create passes with valid arguments
  412. void TestCreationMethodsSuccess()
  413. {
  414. m_data->AddPassTemplatesToLibrary();
  415. Ptr<Pass> pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("Test01"));
  416. EXPECT_TRUE(pass != nullptr);
  417. pass = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("Test02"));
  418. EXPECT_TRUE(pass != nullptr);
  419. AZStd::shared_ptr<PassTemplate> parentPassTemplate = m_data->m_parentPass.Clone();
  420. pass = m_passSystem->CreatePassFromTemplate(parentPassTemplate, Name("Test03"));
  421. EXPECT_TRUE(pass != nullptr);
  422. PassRequest request;
  423. request.m_passName = "Test04";
  424. request.m_templateName = "ParentPass";
  425. pass = m_passSystem->CreatePassFromRequest(&request);
  426. EXPECT_TRUE(pass != nullptr);
  427. pass = m_passSystem->CreatePass<CopyPass>(Name("Test05"));
  428. EXPECT_TRUE(pass != nullptr);
  429. }
  430. void TestPassFilter_PassHierarchy()
  431. {
  432. m_data->AddPassTemplatesToLibrary();
  433. // create a pass tree
  434. Ptr<Pass> pass, parent1, parent2, parent3;
  435. CreatePassTestTree(pass, parent1, parent2, parent3);
  436. {
  437. // Filter with pass hierarchy which has only one element
  438. PassFilter filter = PassFilter::CreateWithPassHierarchy({ Name("pass1") });
  439. EXPECT_TRUE(filter.Matches(pass.get()));
  440. }
  441. {
  442. // Filter with empty pass hierarchy, triggers one assert
  443. AZ_TEST_START_TRACE_SUPPRESSION;
  444. PassFilter filter = PassFilter::CreateWithPassHierarchy(AZStd::vector<Name>{});
  445. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  446. }
  447. {
  448. // Filters with partial hierarchy by using string vector
  449. AZStd::vector<AZStd::string> passHierarchy1 = { "parent1", "pass1" };
  450. PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1);
  451. EXPECT_TRUE(filter1.Matches(pass.get()));
  452. AZStd::vector<AZStd::string> passHierarchy2 = { "parent2", "pass1" };
  453. PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2);
  454. EXPECT_TRUE(filter2.Matches(pass.get()));
  455. AZStd::vector<AZStd::string> passHierarchy3 = { "parent3", "parent2", "pass1" };
  456. PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3);
  457. EXPECT_TRUE(filter3.Matches(pass.get()));
  458. }
  459. {
  460. // Filters with partial hierarchy by using Name vector
  461. AZStd::vector<Name> passHierarchy1 = { Name("parent1"), Name("pass1") };
  462. PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1);
  463. EXPECT_TRUE(filter1.Matches(pass.get()));
  464. AZStd::vector<Name> passHierarchy2 = { Name("parent2"), Name("pass1") };
  465. PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2);
  466. EXPECT_TRUE(filter2.Matches(pass.get()));
  467. AZStd::vector<Name> passHierarchy3 = { Name("parent3"), Name("parent2"), Name("pass1") };
  468. PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3);
  469. EXPECT_TRUE(filter3.Matches(pass.get()));
  470. }
  471. {
  472. // Find non-leaf pass
  473. PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector<AZStd::string>{"parent3", "parent1"});
  474. EXPECT_TRUE(filter1.Matches(parent1.get()));
  475. PassFilter filter2 = PassFilter::CreateWithPassHierarchy({ Name("parent1") });
  476. EXPECT_TRUE(filter2.Matches(parent1.get()));
  477. EXPECT_FALSE(filter2.Matches(pass.get()));
  478. }
  479. {
  480. // Failed to find pass
  481. // Mis-matching hierarchy
  482. PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector<AZStd::string>{"Parent1", "Parent3", "pass1"});
  483. EXPECT_FALSE(filter1.Matches(pass.get()));
  484. // Mis-matching name
  485. PassFilter filter2 = PassFilter::CreateWithPassHierarchy(AZStd::vector<AZStd::string>{"Parent1", "pass1"});
  486. EXPECT_FALSE(filter2.Matches(parent1.get()));
  487. }
  488. }
  489. void TestPassFilter_Empty_Success()
  490. {
  491. m_data->AddPassTemplatesToLibrary();
  492. // create a pass tree
  493. Ptr<Pass> pass, parent1, parent2, parent3;
  494. CreatePassTestTree(pass, parent1, parent2, parent3);
  495. PassFilter filter;
  496. // Any pass can match an empty filter
  497. EXPECT_TRUE(filter.Matches(pass.get()));
  498. EXPECT_TRUE(filter.Matches(parent1.get()));
  499. EXPECT_TRUE(filter.Matches(parent2.get()));
  500. EXPECT_TRUE(filter.Matches(parent3.get()));
  501. }
  502. void TestPassFilter_PassClass_Success()
  503. {
  504. m_data->AddPassTemplatesToLibrary();
  505. // create a pass tree
  506. Ptr<Pass> pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1"));
  507. Ptr<Pass> depthPass = m_passSystem->CreatePassFromTemplate(Name("DepthPrePass"), Name("depthPass"));
  508. Ptr<Pass> parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1"));
  509. // Set Building to avoid state check errors when adding passes
  510. parent1->m_state = PassState::Building;
  511. parent1->AsParent()->AddChild(pass);
  512. parent1->AsParent()->AddChild(depthPass);
  513. parent1->m_state = PassState::Idle;
  514. PassFilter filter1 = PassFilter::CreateWithPassClass<Pass>();
  515. EXPECT_TRUE(filter1.Matches(pass.get()));
  516. EXPECT_TRUE(filter1.Matches(parent1.get())); // ParentPass inherits from Pass
  517. PassFilter filter2 = PassFilter::CreateWithPassClass<ParentPass>();
  518. EXPECT_FALSE(filter2.Matches(pass.get()));
  519. EXPECT_TRUE(filter2.Matches(parent1.get()));
  520. }
  521. void TestPassFilter_PassTemplate_Success()
  522. {
  523. m_data->AddPassTemplatesToLibrary();
  524. // create a pass tree
  525. Ptr<Pass> childPass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1"));
  526. Ptr<Pass> parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1"));
  527. PassFilter filter1 = PassFilter::CreateWithTemplateName(Name("Pass"), (Scene*) nullptr);
  528. // childPass doesn't have a template
  529. EXPECT_FALSE(filter1.Matches(childPass.get()));
  530. PassFilter filter2 = PassFilter::CreateWithTemplateName(Name("ParentPass"), (Scene*) nullptr);
  531. EXPECT_TRUE(filter2.Matches(parent1.get()));
  532. }
  533. void TestForEachPass_PassTemplateFilter_Success()
  534. {
  535. m_data->AddPassTemplatesToLibrary();
  536. // create a pass tree
  537. Ptr<Pass> pass, parent1, parent2, parent3;
  538. CreatePassTestTree(pass, parent1, parent2, parent3);
  539. // Create render pipeline
  540. const RPI::PipelineViewTag viewTag{ "viewTag1" };
  541. RPI::RenderPipelineDescriptor desc;
  542. desc.m_mainViewTagName = viewTag.GetStringView();
  543. desc.m_name = "TestPipeline";
  544. RPI::RenderPipelinePtr pipeline = RPI::RenderPipeline::CreateRenderPipeline(desc);
  545. Ptr<Pass> parent4 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent4"));
  546. // Set Building to avoid state check errors when adding passes
  547. pipeline->GetRootPass()->m_state = PassState::Building;
  548. pipeline->GetRootPass()->AddChild(parent4);
  549. pipeline->GetRootPass()->m_state = PassState::Idle;
  550. Name templateName = Name("ParentPass");
  551. PassFilter filter1 = PassFilter::CreateWithTemplateName(templateName, (RenderPipeline*)nullptr);
  552. int count = 0;
  553. m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow
  554. {
  555. EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName);
  556. count++;
  557. return PassFilterExecutionFlow::ContinueVisitingPasses;
  558. });
  559. // three from CreatePassFromTemplate() calls and one from Render Pipeline.
  560. EXPECT_TRUE(count == 4);
  561. count = 0;
  562. m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow
  563. {
  564. EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName);
  565. count++;
  566. return PassFilterExecutionFlow::StopVisitingPasses;
  567. });
  568. EXPECT_TRUE(count == 1);
  569. PassFilter filter2 = PassFilter::CreateWithTemplateName(templateName, pipeline.get());
  570. count = 0;
  571. m_passSystem->ForEachPass(filter2, [&count]([[maybe_unused]] RPI::Pass* pass) -> PassFilterExecutionFlow
  572. {
  573. count++;
  574. return PassFilterExecutionFlow::ContinueVisitingPasses;
  575. });
  576. // only the ParentPass in the render pipeline was found
  577. EXPECT_TRUE(count == 1);
  578. }
  579. };
  580. TEST_F(PassTests, ConstructionAndValidation)
  581. {
  582. TestPassConstructionAndValidation();
  583. }
  584. TEST_F(PassTests, InvalidLocalSlotName)
  585. {
  586. TestInvalidLocalSlotName();
  587. }
  588. TEST_F(PassTests, InvalidConnectedSlotName)
  589. {
  590. TestInvalidConnectedSlotName();
  591. }
  592. TEST_F(PassTests, InvalidConnectedPassName)
  593. {
  594. TestInvalidConnectedPassName();
  595. }
  596. TEST_F(PassTests, SlotTypeMismatch)
  597. {
  598. TestSlotTypeMismatch();
  599. }
  600. TEST_F(PassTests, ParentChildSlotTypeMismatch)
  601. {
  602. TestParentChildSlotTypeMismatch();
  603. }
  604. TEST_F(PassTests, FactoryDefaultCreators)
  605. {
  606. TestFactoryDefaultCreators();
  607. }
  608. TEST_F(PassTests, CreationMethodsFailure)
  609. {
  610. TestCreationMethodsFailure();
  611. }
  612. TEST_F(PassTests, CreationMethodsSuccess)
  613. {
  614. TestCreationMethodsSuccess();
  615. }
  616. TEST_F(PassTests, PassFilter_PassHierarchy)
  617. {
  618. TestPassFilter_PassHierarchy();
  619. }
  620. TEST_F(PassTests, PassFilter_Empty_Success)
  621. {
  622. TestPassFilter_Empty_Success();
  623. }
  624. TEST_F(PassTests, PassFilter_PassClass_Success)
  625. {
  626. TestPassFilter_PassClass_Success();
  627. }
  628. TEST_F(PassTests, PassFilter_PassTemplate_Success)
  629. {
  630. TestPassFilter_PassTemplate_Success();
  631. }
  632. TEST_F(PassTests, ForEachPass_PassTemplateFilter_Success)
  633. {
  634. TestForEachPass_PassTemplateFilter_Success();
  635. }
  636. }