BsVulkanQueryManager.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Managers/BsVulkanQueryManager.h"
  4. #include "BsVulkanEventQuery.h"
  5. #include "BsVulkanTimerQuery.h"
  6. #include "BsVulkanOcclusionQuery.h"
  7. #include "BsVulkanRenderAPI.h"
  8. #include "BsVulkanDevice.h"
  9. #include "BsVulkanCommandBuffer.h"
  10. namespace bs { namespace ct
  11. {
  12. VulkanQueryPool::VulkanQueryPool(VulkanDevice& device)
  13. :mDevice(device)
  14. {
  15. Lock lock(mMutex);
  16. allocatePool(VK_QUERY_TYPE_TIMESTAMP);
  17. allocatePool(VK_QUERY_TYPE_OCCLUSION);
  18. }
  19. VulkanQueryPool::~VulkanQueryPool()
  20. {
  21. Lock lock(mMutex);
  22. for (auto& entry : mTimerQueries)
  23. {
  24. if(entry != nullptr)
  25. entry->destroy();
  26. }
  27. for (auto& entry : mOcclusionQueries)
  28. {
  29. if(entry != nullptr)
  30. entry->destroy();
  31. }
  32. for (auto& entry : mTimerPools)
  33. vkDestroyQueryPool(mDevice.getLogical(), entry.pool, gVulkanAllocator);
  34. for (auto& entry : mOcclusionPools)
  35. vkDestroyQueryPool(mDevice.getLogical(), entry.pool, gVulkanAllocator);
  36. }
  37. VulkanQueryPool::PoolInfo& VulkanQueryPool::allocatePool(VkQueryType type)
  38. {
  39. VkQueryPoolCreateInfo queryPoolCI;
  40. queryPoolCI.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
  41. queryPoolCI.pNext = nullptr;
  42. queryPoolCI.flags = 0;
  43. queryPoolCI.pipelineStatistics = 0;
  44. queryPoolCI.queryCount = NUM_QUERIES_PER_POOL;
  45. queryPoolCI.queryType = type;
  46. PoolInfo poolInfo;
  47. VkResult result = vkCreateQueryPool(mDevice.getLogical(), &queryPoolCI, gVulkanAllocator, &poolInfo.pool);
  48. assert(result == VK_SUCCESS);
  49. Vector<PoolInfo>& poolInfos = type == VK_QUERY_TYPE_TIMESTAMP ? mTimerPools : mOcclusionPools;
  50. poolInfo.startIdx = (UINT32)poolInfos.size() * NUM_QUERIES_PER_POOL;
  51. poolInfos.push_back(poolInfo);
  52. Vector<VulkanQuery*>& queries = type == VK_QUERY_TYPE_TIMESTAMP ? mTimerQueries : mOcclusionQueries;
  53. for (UINT32 i = 0; i < NUM_QUERIES_PER_POOL; i++)
  54. queries.push_back(nullptr);
  55. return poolInfos.back();
  56. }
  57. VulkanQuery* VulkanQueryPool::getQuery(VkQueryType type)
  58. {
  59. Vector<VulkanQuery*>& queries = type == VK_QUERY_TYPE_TIMESTAMP ? mTimerQueries : mOcclusionQueries;
  60. Vector<PoolInfo>& poolInfos = type == VK_QUERY_TYPE_TIMESTAMP ? mTimerPools : mOcclusionPools;
  61. for (UINT32 i = 0; i < (UINT32)queries.size(); i++)
  62. {
  63. VulkanQuery* curQuery = queries[i];
  64. if (curQuery == nullptr)
  65. {
  66. div_t divResult = std::div(i, (INT32)NUM_QUERIES_PER_POOL);
  67. UINT32 poolIdx = (UINT32)divResult.quot;
  68. UINT32 queryIdx = (UINT32)divResult.rem;
  69. curQuery = mDevice.getResourceManager().create<VulkanQuery>(poolInfos[poolIdx].pool, queryIdx);
  70. queries[i] = curQuery;
  71. return curQuery;
  72. }
  73. else if (!curQuery->isBound() && curQuery->mFree)
  74. return curQuery;
  75. }
  76. PoolInfo& poolInfo = allocatePool(type);
  77. UINT32 queryIdx = poolInfo.startIdx % NUM_QUERIES_PER_POOL;
  78. VulkanQuery* query = mDevice.getResourceManager().create<VulkanQuery>(poolInfo.pool, queryIdx);
  79. queries[poolInfo.startIdx] = query;
  80. return query;
  81. }
  82. VulkanQuery* VulkanQueryPool::beginTimerQuery(VulkanCmdBuffer* cb)
  83. {
  84. Lock lock(mMutex);
  85. VulkanQuery* query = getQuery(VK_QUERY_TYPE_TIMESTAMP);
  86. query->mFree = false;
  87. VkCommandBuffer vkCmdBuf = cb->getHandle();
  88. cb->resetQuery(query);
  89. vkCmdWriteTimestamp(vkCmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, query->mPool, query->mQueryIdx);
  90. // Note: Must happen only here because we need to check VulkanResource::isBound under the same mutex
  91. cb->registerResource(query, VulkanUseFlag::Write);
  92. return query;
  93. }
  94. VulkanQuery* VulkanQueryPool::beginOcclusionQuery(VulkanCmdBuffer* cb, bool precise)
  95. {
  96. Lock lock(mMutex);
  97. VulkanQuery* query = getQuery(VK_QUERY_TYPE_TIMESTAMP);
  98. query->mFree = false;
  99. VkCommandBuffer vkCmdBuf = cb->getHandle();
  100. cb->resetQuery(query);
  101. vkCmdBeginQuery(vkCmdBuf, query->mPool, query->mQueryIdx, precise ? VK_QUERY_CONTROL_PRECISE_BIT : 0);
  102. // Note: Must happen only here because we need to check VulkanResource::isBound under the same mutex
  103. cb->registerResource(query, VulkanUseFlag::Write);
  104. return query;
  105. }
  106. void VulkanQueryPool::endOcclusionQuery(VulkanQuery* query, VulkanCmdBuffer* cb)
  107. {
  108. Lock lock(mMutex);
  109. VkCommandBuffer vkCmdBuf = cb->getHandle();
  110. vkCmdEndQuery(vkCmdBuf, query->mPool, query->mQueryIdx);
  111. }
  112. void VulkanQueryPool::releaseQuery(VulkanQuery* query)
  113. {
  114. Lock lock(mMutex);
  115. query->mFree = true;
  116. query->mNeedsReset = true;
  117. }
  118. VulkanQueryManager::VulkanQueryManager(VulkanRenderAPI& rapi)
  119. :mRenderAPI(rapi)
  120. { }
  121. VulkanQueryManager::~VulkanQueryManager()
  122. {
  123. }
  124. SPtr<EventQuery> VulkanQueryManager::createEventQuery(UINT32 deviceIdx) const
  125. {
  126. SPtr<VulkanDevice> device = mRenderAPI._getDevice(deviceIdx);
  127. SPtr<EventQuery> query = SPtr<VulkanEventQuery>(bs_new<VulkanEventQuery>(*device),
  128. &QueryManager::deleteEventQuery, StdAlloc<VulkanEventQuery>());
  129. mEventQueries.push_back(query.get());
  130. return query;
  131. }
  132. SPtr<TimerQuery> VulkanQueryManager::createTimerQuery(UINT32 deviceIdx) const
  133. {
  134. SPtr<VulkanDevice> device = mRenderAPI._getDevice(deviceIdx);
  135. SPtr<TimerQuery> query = SPtr<VulkanTimerQuery>(bs_new<VulkanTimerQuery>(*device),
  136. &QueryManager::deleteTimerQuery, StdAlloc<VulkanTimerQuery>());
  137. mTimerQueries.push_back(query.get());
  138. return query;
  139. }
  140. SPtr<OcclusionQuery> VulkanQueryManager::createOcclusionQuery(bool binary, UINT32 deviceIdx) const
  141. {
  142. SPtr<VulkanDevice> device = mRenderAPI._getDevice(deviceIdx);
  143. SPtr<OcclusionQuery> query = SPtr<VulkanOcclusionQuery>(bs_new<VulkanOcclusionQuery>(*device, binary),
  144. &QueryManager::deleteOcclusionQuery, StdAlloc<VulkanOcclusionQuery>());
  145. mOcclusionQueries.push_back(query.get());
  146. return query;
  147. }
  148. VulkanQuery::VulkanQuery(VulkanResourceManager* owner, VkQueryPool pool, UINT32 queryIdx)
  149. :VulkanResource(owner, false), mPool(pool), mQueryIdx(queryIdx), mFree(true)
  150. {
  151. }
  152. bool VulkanQuery::getResult(UINT64& result) const
  153. {
  154. // Note: A potentially better approach to get results is to make the query pool a VulkanResource, which we attach
  155. // to a command buffer upon use. Then when CB finishes executing we perform vkGetQueryPoolResults on all queries
  156. // in the pool at once.
  157. VkDevice vkDevice = mOwner->getDevice().getLogical();
  158. VkResult vkResult = vkGetQueryPoolResults(vkDevice, mPool, 0, 1, sizeof(result), &result, sizeof(result),
  159. VK_QUERY_RESULT_64_BIT);
  160. assert(vkResult == VK_SUCCESS || vkResult == VK_NOT_READY);
  161. return vkResult == VK_SUCCESS;
  162. }
  163. void VulkanQuery::reset(VkCommandBuffer cmdBuf)
  164. {
  165. vkCmdResetQueryPool(cmdBuf, mPool, mQueryIdx, 1);
  166. }
  167. }}