QueryTests.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  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 "RHITestFixture.h"
  9. #include <AzCore/std/containers/bitset.h>
  10. #include <Tests/Factory.h>
  11. #include <Tests/Device.h>
  12. #include <Atom/RHI/FrameEventBus.h>
  13. namespace UnitTest
  14. {
  15. using namespace AZ;
  16. class QueryTests
  17. : public RHITestFixture
  18. {
  19. public:
  20. QueryTests()
  21. : RHITestFixture()
  22. {
  23. }
  24. ~QueryTests()
  25. {
  26. }
  27. private:
  28. void SetUp() override
  29. {
  30. RHITestFixture::SetUp();
  31. m_factory.reset(aznew Factory());
  32. m_device = MakeTestDevice();
  33. }
  34. void TearDown() override
  35. {
  36. m_factory.reset();
  37. m_device.reset();
  38. RHITestFixture::TearDown();
  39. }
  40. protected:
  41. AZStd::unique_ptr<Factory> m_factory;
  42. RHI::Ptr<RHI::Device> m_device;
  43. };
  44. TEST_F(QueryTests, TestNoop)
  45. {
  46. RHI::Ptr<RHI::DeviceQuery> noopQuery;
  47. noopQuery = RHI::Factory::Get().CreateQuery();
  48. AZ_TEST_ASSERT(noopQuery);
  49. RHI::Ptr<RHI::DeviceQueryPool> noopQueryPool;
  50. noopQueryPool = RHI::Factory::Get().CreateQueryPool();
  51. AZ_TEST_ASSERT(noopQueryPool);
  52. }
  53. TEST_F(QueryTests, Test)
  54. {
  55. RHI::Ptr<RHI::DeviceQuery> queryA;
  56. queryA = RHI::Factory::Get().CreateQuery();
  57. queryA->SetName(Name("QueryA"));
  58. AZ_TEST_ASSERT(queryA->GetName().GetStringView() == "QueryA");
  59. AZ_TEST_ASSERT(queryA->use_count() == 1);
  60. {
  61. RHI::Ptr<RHI::DeviceQueryPool> queryPool;
  62. queryPool = RHI::Factory::Get().CreateQueryPool();
  63. EXPECT_EQ(1, queryPool->use_count());
  64. RHI::Ptr<RHI::DeviceQuery> queryB;
  65. queryB = RHI::Factory::Get().CreateQuery();
  66. EXPECT_EQ(1, queryB->use_count());
  67. RHI::QueryPoolDescriptor queryPoolDesc;
  68. queryPoolDesc.m_queriesCount = 2;
  69. queryPoolDesc.m_type = RHI::QueryType::Occlusion;
  70. queryPoolDesc.m_pipelineStatisticsMask = RHI::PipelineStatisticsFlags::None;
  71. queryPool->Init(*m_device, queryPoolDesc);
  72. EXPECT_FALSE(queryA->IsInitialized());
  73. EXPECT_FALSE(queryB->IsInitialized());
  74. queryPool->InitQuery(queryA.get());
  75. EXPECT_EQ(1, queryA->use_count());
  76. EXPECT_TRUE(queryA->IsInitialized());
  77. queryPool->InitQuery(queryB.get());
  78. EXPECT_TRUE(queryB->IsInitialized());
  79. EXPECT_EQ(queryA->GetPool(), queryPool.get());
  80. EXPECT_EQ(queryB->GetPool(), queryPool.get());
  81. EXPECT_EQ(queryPool->GetResourceCount(), 2);
  82. {
  83. uint32_t queryIndex = 0;
  84. const RHI::DeviceQuery* queries[] =
  85. {
  86. queryA.get(),
  87. queryB.get()
  88. };
  89. queryPool->ForEach<RHI::DeviceQuery>([&queryIndex, &queries]([[maybe_unused]] RHI::DeviceQuery& query)
  90. {
  91. AZ_UNUSED(queries); // Prevent unused warning in release builds
  92. AZ_Assert(queries[queryIndex] == &query, "Queries don't match");
  93. queryIndex++;
  94. });
  95. }
  96. queryB->Shutdown();
  97. EXPECT_EQ(queryB->GetPool(), nullptr);
  98. RHI::Ptr<RHI::DeviceQueryPool> queryPoolB;
  99. queryPoolB = RHI::Factory::Get().CreateQueryPool();
  100. queryPoolB->Init(*m_device, queryPoolDesc);
  101. queryPoolB->InitQuery(queryB.get());
  102. EXPECT_EQ(queryB->GetPool(), queryPoolB.get());
  103. //Since we are switching queryPool for queryB it adds a refcount and invalidates the views.
  104. //We need this to ensure the views are fully invalidated in order to release the refcount and avoid a leak.
  105. RHI::ResourceInvalidateBus::ExecuteQueuedEvents();
  106. queryPoolB->Shutdown();
  107. EXPECT_EQ(queryPoolB->GetResourceCount(), 0);
  108. }
  109. EXPECT_EQ(queryA->GetPool(), nullptr);
  110. EXPECT_EQ(queryA->use_count(), 1);
  111. }
  112. TEST_F(QueryTests, TestAllocations)
  113. {
  114. static const uint32_t numQueries = 10;
  115. AZStd::array<RHI::Ptr<RHI::DeviceQuery>, numQueries> queries;
  116. for (auto& query : queries)
  117. {
  118. query = RHI::Factory::Get().CreateQuery();
  119. }
  120. RHI::Ptr<RHI::DeviceQueryPool> queryPool;
  121. queryPool = RHI::Factory::Get().CreateQueryPool();
  122. RHI::QueryPoolDescriptor queryPoolDesc;
  123. queryPoolDesc.m_queriesCount = numQueries;
  124. queryPoolDesc.m_type = RHI::QueryType::Occlusion;
  125. queryPoolDesc.m_pipelineStatisticsMask = RHI::PipelineStatisticsFlags::None;
  126. queryPool->Init(*m_device, queryPoolDesc);
  127. AZStd::vector<RHI::DeviceQuery*> queriesToInitialize(numQueries);
  128. for (size_t i = 0; i < queries.size(); ++i)
  129. {
  130. queriesToInitialize[i] = queries[i].get();
  131. }
  132. RHI::ResultCode result = queryPool->InitQuery(queriesToInitialize.data(), static_cast<uint32_t>(queriesToInitialize.size()));
  133. EXPECT_EQ(result, RHI::ResultCode::Success);
  134. auto checkSlotsFunc = [](const AZStd::vector<RHI::DeviceQuery*>& queries)
  135. {
  136. if (queries.size() < 2)
  137. {
  138. return true;
  139. }
  140. AZStd::vector<uint32_t> indices;
  141. for (auto& query : queries)
  142. {
  143. indices.push_back(query->GetHandle().GetIndex());
  144. }
  145. AZStd::sort(indices.begin(), indices.end());
  146. for (size_t i = 0; i < indices.size() - 1; ++i)
  147. {
  148. if (indices[i] != (indices[i + 1] + 1))
  149. {
  150. return false;
  151. }
  152. }
  153. return true;
  154. };
  155. checkSlotsFunc(queriesToInitialize);
  156. auto extraQuery = RHI::Factory::Get().CreateQuery();
  157. EXPECT_EQ(queryPool->InitQuery(extraQuery.get()), RHI::ResultCode::OutOfMemory);
  158. AZ_TEST_ASSERT(!extraQuery->IsInitialized());
  159. AZStd::vector<uint32_t> queriesIndicesToShutdown = { 5, 6 };
  160. AZStd::vector<RHI::DeviceQuery*> queriesToShutdown;
  161. for (auto& index : queriesIndicesToShutdown)
  162. {
  163. queries[index]->Shutdown();
  164. queriesToShutdown.push_back(queries[index].get());
  165. }
  166. EXPECT_EQ(queryPool->GetResourceCount(), numQueries - static_cast<uint32_t>(queriesIndicesToShutdown.size()));
  167. result = queryPool->InitQuery(queriesToShutdown.data(), static_cast<uint32_t>(queriesIndicesToShutdown.size()));
  168. EXPECT_EQ(result, RHI::ResultCode::Success);
  169. checkSlotsFunc(queriesToShutdown);
  170. queriesIndicesToShutdown = {2, 5, 9};
  171. queriesToShutdown.clear();
  172. for (auto& index : queriesIndicesToShutdown)
  173. {
  174. queries[index]->Shutdown();
  175. queriesToShutdown.push_back(queries[index].get());
  176. }
  177. EXPECT_EQ(queryPool->GetResourceCount(), (numQueries - static_cast<uint32_t>(queriesIndicesToShutdown.size())));
  178. result = queryPool->InitQuery(queriesToShutdown.data(), static_cast<uint32_t>(queriesToShutdown.size()));
  179. //Since we are switching queryPools for some queries it adds a refcount and invalidates the views.
  180. //We need to ensure the views are fully invalidated in order to release the refcount and avoid leaks.
  181. RHI::ResourceInvalidateBus::ExecuteQueuedEvents();
  182. checkSlotsFunc(queriesToInitialize);
  183. }
  184. TEST_F(QueryTests, TestIntervals)
  185. {
  186. static const uint32_t numQueries = 10;
  187. AZStd::array<RHI::Ptr<RHI::DeviceQuery>, numQueries> queries;
  188. for (auto& query : queries)
  189. {
  190. query = RHI::Factory::Get().CreateQuery();
  191. }
  192. RHI::Ptr<RHI::DeviceQueryPool> queryPool;
  193. queryPool = RHI::Factory::Get().CreateQueryPool();
  194. RHI::QueryPoolDescriptor queryPoolDesc;
  195. queryPoolDesc.m_queriesCount = numQueries;
  196. queryPoolDesc.m_type = RHI::QueryType::Occlusion;
  197. queryPoolDesc.m_pipelineStatisticsMask = RHI::PipelineStatisticsFlags::None;
  198. queryPool->Init(*m_device, queryPoolDesc);
  199. AZStd::vector<RHI::DeviceQuery*> queriesToInitialize(numQueries);
  200. for (size_t i = 0; i < queries.size(); ++i)
  201. {
  202. queriesToInitialize[i] = queries[i].get();
  203. }
  204. RHI::ResultCode result = queryPool->InitQuery(queriesToInitialize.data(), static_cast<uint32_t>(queriesToInitialize.size()));
  205. EXPECT_EQ(result, RHI::ResultCode::Success);
  206. auto* testQueryPool = static_cast<UnitTest::QueryPool*>(queryPool.get());
  207. auto& testQueryPoolIntervals = testQueryPool->m_calledIntervals;
  208. uint64_t results[numQueries] = {};
  209. EXPECT_EQ(queryPool->GetResults(results, numQueries, RHI::QueryResultFlagBits::None), RHI::ResultCode::Success);
  210. EXPECT_EQ(testQueryPoolIntervals.size(), 1);
  211. EXPECT_EQ(testQueryPoolIntervals.front(), RHI::Interval(0, numQueries - 1));
  212. testQueryPoolIntervals.clear();
  213. auto* queryToTest = queries[5].get();
  214. EXPECT_EQ(queryPool->GetResults(queryToTest, results, 1, RHI::QueryResultFlagBits::None), RHI::ResultCode::Success);
  215. EXPECT_EQ(testQueryPoolIntervals.size(), 1);
  216. EXPECT_EQ(testQueryPoolIntervals.front(), RHI::Interval(queryToTest->GetHandle().GetIndex(), queryToTest->GetHandle().GetIndex()));
  217. AZStd::vector<RHI::Interval> intervalsToTest = { RHI::Interval(5, 5), RHI::Interval(0, 3), RHI::Interval(8, 9) };
  218. AZStd::vector<RHI::DeviceQuery*> queriesToTest;
  219. for (auto& interval : intervalsToTest)
  220. {
  221. for (uint32_t i = interval.m_min; i <= interval.m_max; ++i)
  222. {
  223. queriesToTest.push_back(queries[i].get());
  224. }
  225. }
  226. testQueryPoolIntervals.clear();
  227. EXPECT_EQ(queryPool->GetResults(queriesToTest.data(), static_cast<uint32_t>(queriesToTest.size()), results, numQueries, RHI::QueryResultFlagBits::None), RHI::ResultCode::Success);
  228. EXPECT_EQ(testQueryPoolIntervals.size(), intervalsToTest.size());
  229. for (auto& interval : intervalsToTest)
  230. {
  231. auto foundIt = AZStd::find(testQueryPoolIntervals.begin(), testQueryPoolIntervals.end(), interval);
  232. EXPECT_NE(foundIt, testQueryPoolIntervals.end());
  233. }
  234. }
  235. TEST_F(QueryTests, TestQuery)
  236. {
  237. AZStd::array<RHI::Ptr<RHI::DeviceQueryPool>, RHI::QueryTypeCount> queryPools;
  238. for (size_t i = 0; i < queryPools.size(); ++i)
  239. {
  240. auto& queryPool = queryPools[i];
  241. queryPool = RHI::Factory::Get().CreateQueryPool();
  242. RHI::QueryPoolDescriptor queryPoolDesc;
  243. queryPoolDesc.m_queriesCount = 1;
  244. queryPoolDesc.m_type = static_cast<RHI::QueryType>(i);
  245. queryPoolDesc.m_pipelineStatisticsMask = queryPoolDesc.m_type == RHI::QueryType::PipelineStatistics ? RHI::PipelineStatisticsFlags::CInvocations : RHI::PipelineStatisticsFlags::None;
  246. queryPool->Init(*m_device, queryPoolDesc);
  247. }
  248. auto& occlusionQueryPool = queryPools[static_cast<uint32_t>(RHI::QueryType::Occlusion)];
  249. auto& timestampQueryPool = queryPools[static_cast<uint32_t>(RHI::QueryType::Timestamp)];
  250. auto& statisticsQueryPool = queryPools[static_cast<uint32_t>(RHI::QueryType::PipelineStatistics)];
  251. uint64_t data;
  252. RHI::CommandList& dummyCommandList = reinterpret_cast<RHI::CommandList&>(data);
  253. // Correct begin and end for occlusion
  254. {
  255. auto query = RHI::Factory::Get().CreateQuery();
  256. EXPECT_EQ(occlusionQueryPool->InitQuery(query.get()), RHI::ResultCode::Success);
  257. EXPECT_EQ(query->Begin(dummyCommandList), RHI::ResultCode::Success);
  258. EXPECT_EQ(query->End(dummyCommandList), RHI::ResultCode::Success);
  259. }
  260. // Double Begin
  261. {
  262. auto query = RHI::Factory::Get().CreateQuery();
  263. occlusionQueryPool->InitQuery(query.get());
  264. query->Begin(dummyCommandList);
  265. AZ_TEST_START_ASSERTTEST;
  266. EXPECT_EQ(RHI::ResultCode::Fail, query->Begin(dummyCommandList));
  267. AZ_TEST_STOP_ASSERTTEST(1);
  268. }
  269. // End without Begin
  270. {
  271. auto query = RHI::Factory::Get().CreateQuery();
  272. occlusionQueryPool->InitQuery(query.get());
  273. AZ_TEST_START_ASSERTTEST;
  274. EXPECT_EQ(RHI::ResultCode::Fail, query->End(dummyCommandList));
  275. AZ_TEST_STOP_ASSERTTEST(1);
  276. }
  277. // End with another command list
  278. {
  279. auto query = RHI::Factory::Get().CreateQuery();
  280. occlusionQueryPool->InitQuery(query.get());
  281. uint64_t anotherData;
  282. RHI::CommandList& anotherDummyCmdList = reinterpret_cast<RHI::CommandList&>(anotherData);
  283. EXPECT_EQ(RHI::ResultCode::Success, query->Begin(dummyCommandList));
  284. AZ_TEST_START_ASSERTTEST;
  285. EXPECT_EQ(RHI::ResultCode::InvalidArgument, query->End(anotherDummyCmdList));
  286. AZ_TEST_STOP_ASSERTTEST(1);
  287. }
  288. // Invalid flag
  289. {
  290. auto query = RHI::Factory::Get().CreateQuery();
  291. statisticsQueryPool->InitQuery(query.get());
  292. AZ_TEST_START_ASSERTTEST;
  293. EXPECT_EQ(RHI::ResultCode::InvalidArgument, query->Begin(dummyCommandList, RHI::QueryControlFlags::PreciseOcclusion));
  294. AZ_TEST_STOP_ASSERTTEST(1);
  295. }
  296. // Invalid Begin for Timestamp
  297. {
  298. auto query = RHI::Factory::Get().CreateQuery();
  299. timestampQueryPool->InitQuery(query.get());
  300. AZ_TEST_START_ASSERTTEST;
  301. EXPECT_EQ(RHI::ResultCode::Fail, query->Begin(dummyCommandList));
  302. AZ_TEST_STOP_ASSERTTEST(1);
  303. }
  304. // Invalid End for Timestamp
  305. {
  306. auto query = RHI::Factory::Get().CreateQuery();
  307. timestampQueryPool->InitQuery(query.get());
  308. AZ_TEST_START_ASSERTTEST;
  309. EXPECT_EQ(RHI::ResultCode::Fail, query->End(dummyCommandList));
  310. AZ_TEST_STOP_ASSERTTEST(1);
  311. }
  312. // Invalid WriteTimestamp
  313. {
  314. auto query = RHI::Factory::Get().CreateQuery();
  315. occlusionQueryPool->InitQuery(query.get());
  316. AZ_TEST_START_ASSERTTEST;
  317. EXPECT_EQ(RHI::ResultCode::Fail, query->WriteTimestamp(dummyCommandList));
  318. AZ_TEST_STOP_ASSERTTEST(1);
  319. }
  320. // Correct WriteTimestamp
  321. {
  322. auto query = RHI::Factory::Get().CreateQuery();
  323. timestampQueryPool->InitQuery(query.get());
  324. EXPECT_EQ(RHI::ResultCode::Success, query->WriteTimestamp(dummyCommandList));
  325. }
  326. }
  327. TEST_F(QueryTests, TestQueryPoolInitialization)
  328. {
  329. RHI::Ptr<RHI::DeviceQueryPool> queryPool;
  330. queryPool = RHI::Factory::Get().CreateQueryPool();
  331. RHI::QueryPoolDescriptor queryPoolDesc;
  332. queryPoolDesc.m_queriesCount = 0;
  333. queryPoolDesc.m_type = RHI::QueryType::Occlusion;
  334. queryPoolDesc.m_pipelineStatisticsMask = RHI::PipelineStatisticsFlags::None;
  335. // Count of 0
  336. AZ_TEST_START_ASSERTTEST;
  337. EXPECT_EQ(queryPool->Init(*m_device, queryPoolDesc), RHI::ResultCode::InvalidArgument);
  338. AZ_TEST_STOP_ASSERTTEST(1);
  339. // valid m_pipelineStatisticsMask for Occlusion QueryType
  340. queryPoolDesc.m_queriesCount = 1;
  341. queryPoolDesc.m_pipelineStatisticsMask = RHI::PipelineStatisticsFlags::CInvocations;
  342. EXPECT_EQ(queryPool->Init(*m_device, queryPoolDesc), RHI::ResultCode::Success);
  343. // invalid m_pipelineStatisticsMask for PipelineStatistics QueryType
  344. queryPoolDesc.m_type = RHI::QueryType::PipelineStatistics;
  345. queryPoolDesc.m_pipelineStatisticsMask = RHI::PipelineStatisticsFlags::None;
  346. AZ_TEST_START_ASSERTTEST;
  347. EXPECT_EQ(queryPool->Init(*m_device, queryPoolDesc), RHI::ResultCode::InvalidArgument);
  348. AZ_TEST_STOP_ASSERTTEST(1);
  349. }
  350. TEST_F(QueryTests, TestResults)
  351. {
  352. AZStd::array<RHI::Ptr<RHI::DeviceQueryPool>, 2> queryPools;
  353. RHI::PipelineStatisticsFlags mask = RHI::PipelineStatisticsFlags::CInvocations | RHI::PipelineStatisticsFlags::CPrimitives | RHI::PipelineStatisticsFlags::IAPrimitives;
  354. for (auto& queryPool : queryPools)
  355. {
  356. queryPool = RHI::Factory::Get().CreateQueryPool();
  357. RHI::QueryPoolDescriptor queryPoolDesc;
  358. queryPoolDesc.m_queriesCount = 2;
  359. queryPoolDesc.m_type = RHI::QueryType::PipelineStatistics;
  360. queryPoolDesc.m_pipelineStatisticsMask = mask;
  361. EXPECT_EQ(queryPool->Init(*m_device, queryPoolDesc), RHI::ResultCode::Success);
  362. }
  363. auto query = RHI::Factory::Get().CreateQuery();
  364. uint32_t numPipelineStatistics = RHI::CountBitsSet(static_cast<uint64_t>(mask));
  365. AZStd::vector<uint64_t> results(numPipelineStatistics * 2);
  366. // Using uninitialized query
  367. AZ_TEST_START_ASSERTTEST;
  368. EXPECT_EQ(queryPools[0]->GetResults(results.data(), numPipelineStatistics, RHI::QueryResultFlagBits::None), RHI::ResultCode::InvalidArgument);
  369. AZ_TEST_STOP_ASSERTTEST(3);
  370. // Wrong size for results count.
  371. queryPools[0]->InitQuery(query.get());
  372. AZ_TEST_START_ASSERTTEST;
  373. EXPECT_EQ(queryPools[0]->GetResults(results.data(), 1, RHI::QueryResultFlagBits::None), RHI::ResultCode::InvalidArgument);
  374. AZ_TEST_STOP_ASSERTTEST(1);
  375. // Using a query from another pool
  376. auto anotherQuery = RHI::Factory::Get().CreateQuery();
  377. queryPools[1]->InitQuery(anotherQuery.get());
  378. AZ_TEST_START_ASSERTTEST;
  379. EXPECT_EQ(queryPools[0]->GetResults(anotherQuery.get(), results.data(), numPipelineStatistics, RHI::QueryResultFlagBits::None), RHI::ResultCode::InvalidArgument);
  380. AZ_TEST_STOP_ASSERTTEST(1);
  381. // Results count is too small
  382. anotherQuery->Shutdown();
  383. queryPools[0]->InitQuery(anotherQuery.get());
  384. RHI::DeviceQuery* queries[] = { query.get(), anotherQuery.get() };
  385. AZ_TEST_START_ASSERTTEST;
  386. EXPECT_EQ(queryPools[0]->GetResults(queries, 2, results.data(), numPipelineStatistics, RHI::QueryResultFlagBits::None), RHI::ResultCode::InvalidArgument);
  387. AZ_TEST_STOP_ASSERTTEST(1);
  388. // Correct usage
  389. EXPECT_EQ(queryPools[0]->GetResults(queries, 2, results.data(), numPipelineStatistics * 5, RHI::QueryResultFlagBits::None), RHI::ResultCode::Success);
  390. // Unsorted queries
  391. {
  392. const size_t numQueries = 5;
  393. AZStd::array<RHI::Ptr<AZ::RHI::DeviceQuery>, numQueries> queries2;
  394. AZStd::vector<uint64_t> results2(numQueries);
  395. RHI::Ptr<RHI::DeviceQueryPool> queryPool = RHI::Factory::Get().CreateQueryPool();
  396. RHI::QueryPoolDescriptor queryPoolDesc;
  397. queryPoolDesc.m_queriesCount = 5;
  398. queryPoolDesc.m_type = RHI::QueryType::Occlusion;
  399. EXPECT_EQ(queryPool->Init(*m_device, queryPoolDesc), RHI::ResultCode::Success);
  400. for (size_t i = 0; i < queries2.size(); ++i)
  401. {
  402. queries2[i] = RHI::Factory::Get().CreateQuery();
  403. queryPool->InitQuery(queries2[i].get());
  404. }
  405. AZStd::array<RHI::DeviceQuery*, numQueries> queriesPtr = { queries2[2].get(), queries2[0].get(), queries2[1].get(), queries2[3].get(), queries2[4].get() };
  406. EXPECT_EQ(queryPool->GetResults(queriesPtr.data(), numQueries, results2.data(), numQueries, RHI::QueryResultFlagBits::None), RHI::ResultCode::Success);
  407. for (uint32_t i = 0; i < numQueries; ++i)
  408. {
  409. EXPECT_EQ(results2[i], queriesPtr[i]->GetHandle().GetIndex());
  410. }
  411. }
  412. //Since we are switching queryPools for some queries it adds a refcount and invalidates the views.
  413. //We need to ensure the views are fully invalidated in order to release the refcount and avoid leaks.
  414. RHI::ResourceInvalidateBus::ExecuteQueuedEvents();
  415. }
  416. }