3
0

GpuQueryTests.cpp 13 KB

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