3
0

GpuQueryTests.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  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 <AzCore/UnitTest/TestTypes.h>
  9. #include <Atom/RPI.Public/GpuQuery/GpuQueryTypes.h>
  10. #include <Atom/RPI.Public/GpuQuery/GpuQuerySystem.h>
  11. #include <Atom/RPI.Public/GpuQuery/TimestampQueryPool.h>
  12. #include <Atom/RPI.Public/GpuQuery/GpuQuerySystemInterface.h>
  13. #include <Atom/RHI/BufferScopeAttachment.h>
  14. #include <Atom/RHI/FrameGraph.h>
  15. #include <AzTest/AzTest.h>
  16. #include <Common/RPITestFixture.h>
  17. namespace UnitTest
  18. {
  19. using namespace AZ;
  20. using namespace AZ::RPI;
  21. class GpuQueryTests
  22. : public RPITestFixture
  23. {
  24. void SetUp() final
  25. {
  26. RPITestFixture::SetUp();
  27. }
  28. void TearDown() final
  29. {
  30. RPITestFixture::TearDown();
  31. }
  32. };
  33. // Unit test the RPI::QueryPool
  34. TEST_F(GpuQueryTests, TestQueryPools)
  35. {
  36. const uint32_t QueryCount = 1024u;
  37. const uint32_t QueriesPerInstance = 1u;
  38. const RHI::QueryType Type = RHI::QueryType::Occlusion;
  39. const RHI::PipelineStatisticsFlags StatisticsFlags = RHI::PipelineStatisticsFlags::None;
  40. const uint32_t OcclusionQueryResultSize = sizeof(uint64_t);
  41. const RHI::FrameGraphExecuteContext::Descriptor desc = {};
  42. RHI::FrameGraphExecuteContext context(desc);
  43. // Setup the FrameGraph
  44. RHI::Scope scope;
  45. scope.Init(RHI::ScopeId("StubScope"));
  46. RHI::FrameGraph frameGraph;
  47. frameGraph.BeginScope(scope);
  48. AZStd::unique_ptr<RPI::QueryPool> queryPool = RPI::QueryPool::CreateQueryPool(QueryCount, QueriesPerInstance, Type, StatisticsFlags);
  49. const uint32_t resultSize = queryPool->GetQueryResultSize();
  50. EXPECT_EQ(resultSize, OcclusionQueryResultSize);
  51. // Test valid Queries
  52. {
  53. RHI::Ptr<RPI::Query> query = queryPool->CreateQuery(RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  54. EXPECT_TRUE(query.get());
  55. }
  56. // Test adding to the FrameGraph multiple times with one Query within a single frame
  57. {
  58. RHI::Ptr<RPI::Query> query = queryPool->CreateQuery(RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  59. QueryResultCode resultCode = query->AddToFrameGraph(frameGraph);
  60. EXPECT_EQ(resultCode, QueryResultCode::Success);
  61. resultCode = query->AddToFrameGraph(frameGraph);
  62. EXPECT_EQ(resultCode, QueryResultCode::Fail);
  63. // Next frame
  64. queryPool->Update();
  65. }
  66. // Test recording the same Query in different frames
  67. {
  68. RHI::Ptr<RPI::Query> query = queryPool->CreateQuery(RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  69. QueryResultCode resultCode = query->AddToFrameGraph(frameGraph);
  70. EXPECT_EQ(resultCode, QueryResultCode::Success);
  71. // Next frame
  72. queryPool->Update();
  73. resultCode = query->BeginQuery(context);
  74. EXPECT_EQ(resultCode, QueryResultCode::Fail);
  75. }
  76. // Test Query result
  77. {
  78. // Occlusion QueryPool result size is sizeof(uint64_t)
  79. EXPECT_EQ(queryPool->GetQueryResultSize(), sizeof(uint64_t));
  80. }
  81. // Test get result with invalid size
  82. {
  83. RHI::Ptr<RPI::Query> query = queryPool->CreateQuery(RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  84. EXPECT_TRUE(query.get());
  85. QueryResultCode resultCode = query->AddToFrameGraph(frameGraph);
  86. EXPECT_EQ(resultCode, QueryResultCode::Success);
  87. void* data = nullptr;
  88. // Query type of the pool is occlusion, which expects a result size of sizeof(uint64_t).
  89. resultCode = query->GetLatestResult(data, sizeof(uint32_t), RHI::MultiDevice::DefaultDeviceIndex);
  90. EXPECT_EQ(resultCode, QueryResultCode::Fail);
  91. }
  92. // Test going over QueryPool limit
  93. {
  94. // Temporary QueryPool with a limit of 1 Query
  95. AZStd::unique_ptr<RPI::QueryPool> tempRpiQueryPool = RPI::QueryPool::CreateQueryPool(1u, QueriesPerInstance, Type, StatisticsFlags);
  96. RHI::Ptr<RPI::Query> query = tempRpiQueryPool->CreateQuery(RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  97. EXPECT_TRUE(query.get());
  98. RHI::Ptr<RPI::Query> query1 = tempRpiQueryPool->CreateQuery(RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  99. EXPECT_TRUE(!query1.get());
  100. }
  101. // Test different Scopes for Begin() and End()
  102. {
  103. RHI::FrameGraphExecuteContext::Descriptor desc2;
  104. desc2.m_scopeId = RHI::ScopeId("Test");
  105. desc2.m_commandListIndex = 0;
  106. desc2.m_commandListCount = 1;
  107. desc2.m_commandList = nullptr;
  108. RHI::FrameGraphExecuteContext context2(desc2);
  109. RHI::Ptr<RPI::Query> query = queryPool->CreateQuery(RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  110. EXPECT_TRUE(query.get());
  111. QueryResultCode resultCode = query->AddToFrameGraph(frameGraph);
  112. EXPECT_EQ(resultCode, QueryResultCode::Success);
  113. resultCode = query->BeginQuery(context);
  114. EXPECT_EQ(resultCode, QueryResultCode::Success);
  115. resultCode = query->EndQuery(context2);
  116. EXPECT_EQ(resultCode, QueryResultCode::Fail);
  117. }
  118. }
  119. // Test occlusion QueryPool
  120. TEST_F(GpuQueryTests, TestOcclusionQueryPool)
  121. {
  122. const uint32_t QueryCount = 1024u;
  123. const uint32_t QueriesPerInstance = 1u;
  124. const RHI::QueryType Type = RHI::QueryType::Occlusion;
  125. const RHI::PipelineStatisticsFlags StatisticsFlags = RHI::PipelineStatisticsFlags::None;
  126. const uint32_t ResultSize = sizeof(uint64_t);
  127. uint64_t mockData;
  128. RHI::FrameGraphExecuteContext::Descriptor desc = {};
  129. uint64_t dummyCommandList;
  130. desc.m_commandList = reinterpret_cast<RHI::CommandList*>(&dummyCommandList);
  131. RHI::FrameGraphExecuteContext context(desc);
  132. RHI::Scope scope;
  133. scope.Init(RHI::ScopeId("StubScope"));
  134. RHI::FrameGraph frameGraph;
  135. frameGraph.BeginScope(scope);
  136. // Test get result of a Query successfully
  137. {
  138. const uint32_t LoopCount = 4u;
  139. QueryResultCode resultCode;
  140. AZStd::unique_ptr<RPI::QueryPool> tempRpiQueryPool = RPI::QueryPool::CreateQueryPool(QueryCount, QueriesPerInstance, Type, StatisticsFlags);
  141. RHI::Ptr<RPI::Query> query = tempRpiQueryPool->CreateQuery(RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  142. EXPECT_TRUE(query.get());
  143. for (uint32_t i = 0u; i < LoopCount; i++)
  144. {
  145. QueryResultCode resultCode2;
  146. resultCode2 = query->AddToFrameGraph(frameGraph);
  147. EXPECT_EQ(resultCode2, QueryResultCode::Success);
  148. resultCode2 = query->BeginQuery(context);
  149. EXPECT_EQ(resultCode2, QueryResultCode::Success);
  150. resultCode2 = query->EndQuery(context);
  151. EXPECT_EQ(resultCode2, QueryResultCode::Success);
  152. tempRpiQueryPool->Update();
  153. }
  154. void* data = reinterpret_cast<void*>(&mockData);
  155. resultCode = query->GetLatestResult(data, ResultSize, context.GetDeviceIndex());
  156. EXPECT_EQ(resultCode, QueryResultCode::Success);
  157. resultCode = query->GetLatestResultAndWait(data, ResultSize, context.GetDeviceIndex());
  158. EXPECT_EQ(resultCode, QueryResultCode::Success);
  159. }
  160. }
  161. // Test statistics QueryPool
  162. TEST_F(GpuQueryTests, TestStatisticsQueryPool)
  163. {
  164. const uint32_t QueryCount = 1024u;
  165. const uint32_t QueriesPerInstance = 1u;
  166. const RHI::QueryType Type = RHI::QueryType::PipelineStatistics;
  167. const RHI::PipelineStatisticsFlags StatisticsFlags =
  168. RHI::PipelineStatisticsFlags::CInvocations |
  169. RHI::PipelineStatisticsFlags::CPrimitives |
  170. RHI::PipelineStatisticsFlags::CSInvocations |
  171. RHI::PipelineStatisticsFlags::DSInvocations;
  172. const uint32_t ResultSize = sizeof(uint64_t) * 4u;
  173. uint64_t mockData;
  174. RHI::FrameGraphExecuteContext::Descriptor desc = {};
  175. uint64_t dummyCommandList;
  176. desc.m_commandList = reinterpret_cast<RHI::CommandList*>(&dummyCommandList);
  177. RHI::FrameGraphExecuteContext context(desc);
  178. RHI::Scope scope;
  179. scope.Init(RHI::ScopeId("StubScope"));
  180. RHI::FrameGraph frameGraph;
  181. frameGraph.BeginScope(scope);
  182. AZStd::unique_ptr<RPI::QueryPool> queryPool = RPI::QueryPool::CreateQueryPool(QueryCount, QueriesPerInstance, Type, StatisticsFlags);
  183. // Test expected result size
  184. {
  185. const uint32_t resultSize = queryPool->GetQueryResultSize();
  186. EXPECT_EQ(resultSize, ResultSize);
  187. }
  188. // Test get result with invalid size
  189. {
  190. RHI::Ptr<RPI::Query> query = queryPool->CreateQuery(RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  191. EXPECT_TRUE(query.get());
  192. QueryResultCode resultCode = query->AddToFrameGraph(frameGraph);
  193. EXPECT_EQ(resultCode, QueryResultCode::Success);
  194. void* data = nullptr;
  195. // Query type of the pool is statistics, which expects a result size of sizeof(uint64_t) * number of active flags.
  196. resultCode = query->GetLatestResult(data, sizeof(uint64_t) * 3u, RHI::MultiDevice::DefaultDeviceIndex);
  197. EXPECT_EQ(resultCode, QueryResultCode::Fail);
  198. }
  199. // Test get result of a Query successfully
  200. {
  201. const uint32_t LoopCount = 4u;
  202. QueryResultCode resultCode;
  203. AZStd::unique_ptr<RPI::QueryPool> tempRpiQueryPool = RPI::QueryPool::CreateQueryPool(QueryCount, QueriesPerInstance, Type, StatisticsFlags);
  204. RHI::Ptr<RPI::Query> query = tempRpiQueryPool->CreateQuery(RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  205. EXPECT_TRUE(query.get());
  206. for (uint32_t i = 0u; i < LoopCount; i++)
  207. {
  208. QueryResultCode resultCode2;
  209. resultCode2 = query->AddToFrameGraph(frameGraph);
  210. EXPECT_EQ(resultCode2, QueryResultCode::Success);
  211. resultCode2 = query->BeginQuery(context);
  212. EXPECT_EQ(resultCode2, QueryResultCode::Success);
  213. resultCode2 = query->EndQuery(context);
  214. EXPECT_EQ(resultCode2, QueryResultCode::Success);
  215. tempRpiQueryPool->Update();
  216. }
  217. void* data = reinterpret_cast<void*>(&mockData);
  218. resultCode = query->GetLatestResult(data, ResultSize, RHI::MultiDevice::DefaultDeviceIndex);
  219. EXPECT_EQ(resultCode, QueryResultCode::Success);
  220. resultCode = query->GetLatestResultAndWait(data, ResultSize, RHI::MultiDevice::DefaultDeviceIndex);
  221. EXPECT_EQ(resultCode, QueryResultCode::Success);
  222. }
  223. }
  224. // Test timestamp QueryPool
  225. TEST_F(GpuQueryTests, TestTimestampQueryPool)
  226. {
  227. const uint32_t QueryCount = 1024u;
  228. const uint32_t ResultSize = sizeof(uint64_t) * 2u;
  229. uint64_t mockData;
  230. RHI::FrameGraphExecuteContext::Descriptor desc = {};
  231. uint64_t dummyCommandList;
  232. desc.m_commandList = reinterpret_cast<RHI::CommandList*>(&dummyCommandList);
  233. RHI::FrameGraphExecuteContext context(desc);
  234. RHI::Scope scope;
  235. scope.Init(RHI::ScopeId("StubScope"));
  236. RHI::FrameGraph frameGraph;
  237. frameGraph.BeginScope(scope);
  238. // Test get result of a Query successfully
  239. {
  240. const uint32_t LoopCount = 4u;
  241. QueryResultCode resultCode;
  242. AZStd::unique_ptr<RPI::QueryPool> tempRpiQueryPool = RPI::TimestampQueryPool::CreateTimestampQueryPool(QueryCount);
  243. RHI::Ptr<RPI::Query> query = tempRpiQueryPool->CreateQuery(RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  244. EXPECT_TRUE(query.get());
  245. for (uint32_t i = 0u; i < LoopCount; i++)
  246. {
  247. QueryResultCode resultCode2;
  248. resultCode2 = query->AddToFrameGraph(frameGraph);
  249. EXPECT_EQ(resultCode2, QueryResultCode::Success);
  250. resultCode2 = query->BeginQuery(context);
  251. EXPECT_EQ(resultCode2, QueryResultCode::Success);
  252. resultCode2 = query->EndQuery(context);
  253. EXPECT_EQ(resultCode2, QueryResultCode::Success);
  254. tempRpiQueryPool->Update();
  255. }
  256. void* data = reinterpret_cast<void*>(&mockData);
  257. resultCode = query->GetLatestResult(data, ResultSize, RHI::MultiDevice::DefaultDeviceIndex);
  258. EXPECT_EQ(resultCode, QueryResultCode::Success);
  259. resultCode = query->GetLatestResultAndWait(data, ResultSize, RHI::MultiDevice::DefaultDeviceIndex);
  260. EXPECT_EQ(resultCode, QueryResultCode::Success);
  261. }
  262. }
  263. }; // namespace UnitTest