BsVulkanQueue.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsVulkanQueue.h"
  4. #include "BsVulkanCommandBuffer.h"
  5. #include "BsVulkanSwapChain.h"
  6. namespace bs { namespace ct
  7. {
  8. VulkanQueue::VulkanQueue(VulkanDevice& device, VkQueue queue, GpuQueueType type, UINT32 index)
  9. : mDevice(device), mQueue(queue), mType(type), mIndex(index), mLastCommandBuffer(nullptr)
  10. , mLastCBSemaphoreUsed(false), mNextSubmitIdx(1)
  11. {
  12. for (UINT32 i = 0; i < BS_MAX_UNIQUE_QUEUES; i++)
  13. mSubmitDstWaitMask[i] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  14. }
  15. bool VulkanQueue::isExecuting() const
  16. {
  17. if (mLastCommandBuffer == nullptr)
  18. return false;
  19. return mLastCommandBuffer->isSubmitted();
  20. }
  21. void VulkanQueue::submit(VulkanCmdBuffer* cmdBuffer, VulkanSemaphore** waitSemaphores, UINT32 semaphoresCount)
  22. {
  23. VkSemaphore signalSemaphores[BS_MAX_VULKAN_CB_DEPENDENCIES + 1];
  24. cmdBuffer->allocateSemaphores(signalSemaphores);
  25. VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
  26. mSemaphoresTemp.resize(semaphoresCount + 1); // +1 for self semaphore
  27. prepareSemaphores(waitSemaphores, mSemaphoresTemp.data(), semaphoresCount);
  28. VkSubmitInfo submitInfo;
  29. getSubmitInfo(&vkCmdBuffer, signalSemaphores, BS_MAX_VULKAN_CB_DEPENDENCIES + 1,
  30. mSemaphoresTemp.data(), semaphoresCount, submitInfo);
  31. VkResult result = vkQueueSubmit(mQueue, 1, &submitInfo, cmdBuffer->getFence());
  32. assert(result == VK_SUCCESS);
  33. cmdBuffer->setIsSubmitted();
  34. mLastCommandBuffer = cmdBuffer;
  35. mLastCBSemaphoreUsed = false;
  36. mActiveSubmissions.push_back(SubmitInfo(cmdBuffer, mNextSubmitIdx++, semaphoresCount, 1));
  37. mActiveBuffers.push(cmdBuffer);
  38. }
  39. void VulkanQueue::queueSubmit(VulkanCmdBuffer* cmdBuffer, VulkanSemaphore** waitSemaphores, UINT32 semaphoresCount)
  40. {
  41. mQueuedBuffers.push_back(SubmitInfo(cmdBuffer, 0, semaphoresCount, 1));
  42. for (UINT32 i = 0; i < semaphoresCount; i++)
  43. mQueuedSemaphores.push_back(waitSemaphores[i]);
  44. }
  45. void VulkanQueue::submitQueued()
  46. {
  47. UINT32 numCBs = (UINT32)mQueuedBuffers.size();
  48. if (numCBs == 0)
  49. return;
  50. UINT32 totalNumWaitSemaphores = (UINT32)mQueuedSemaphores.size() + numCBs;
  51. UINT32 signalSemaphoresPerCB = (BS_MAX_VULKAN_CB_DEPENDENCIES + 1);
  52. UINT8* data = (UINT8*)bs_stack_alloc((sizeof(VkSubmitInfo) + sizeof(VkCommandBuffer)) *
  53. numCBs + sizeof(VkSemaphore) * signalSemaphoresPerCB * numCBs + sizeof(VkSemaphore) * totalNumWaitSemaphores);
  54. UINT8* dataPtr = data;
  55. VkSubmitInfo* submitInfos = (VkSubmitInfo*)dataPtr;
  56. dataPtr += sizeof(VkSubmitInfo) * numCBs;
  57. VkCommandBuffer* commandBuffers = (VkCommandBuffer*)dataPtr;
  58. dataPtr += sizeof(VkCommandBuffer) * numCBs;
  59. VkSemaphore* signalSemaphores = (VkSemaphore*)dataPtr;
  60. dataPtr += sizeof(VkSemaphore) * signalSemaphoresPerCB * numCBs;
  61. VkSemaphore* waitSemaphores = (VkSemaphore*)dataPtr;
  62. dataPtr += sizeof(VkSemaphore) * totalNumWaitSemaphores;
  63. UINT32 readSemaphoreIdx = 0;
  64. UINT32 writeSemaphoreIdx = 0;
  65. UINT32 signalSemaphoreIdx = 0;
  66. for(UINT32 i = 0; i < numCBs; i++)
  67. {
  68. const SubmitInfo& entry = mQueuedBuffers[i];
  69. commandBuffers[i] = entry.cmdBuffer->getHandle();
  70. entry.cmdBuffer->allocateSemaphores(&signalSemaphores[signalSemaphoreIdx]);
  71. UINT32 semaphoresCount = entry.numSemaphores;
  72. prepareSemaphores(mQueuedSemaphores.data() + readSemaphoreIdx, &waitSemaphores[writeSemaphoreIdx], semaphoresCount);
  73. getSubmitInfo(&commandBuffers[i], &signalSemaphores[signalSemaphoreIdx], signalSemaphoresPerCB,
  74. &waitSemaphores[writeSemaphoreIdx], semaphoresCount, submitInfos[i]);
  75. entry.cmdBuffer->setIsSubmitted();
  76. mLastCommandBuffer = entry.cmdBuffer; // Needs to be set because getSubmitInfo depends on it
  77. mLastCBSemaphoreUsed = false;
  78. mActiveBuffers.push(entry.cmdBuffer);
  79. readSemaphoreIdx += entry.numSemaphores;
  80. writeSemaphoreIdx += semaphoresCount;
  81. signalSemaphoreIdx += signalSemaphoresPerCB;
  82. }
  83. VulkanCmdBuffer* lastCB = mQueuedBuffers[numCBs - 1].cmdBuffer;
  84. UINT32 totalNumSemaphores = writeSemaphoreIdx;
  85. mActiveSubmissions.push_back(SubmitInfo(lastCB, mNextSubmitIdx++, totalNumSemaphores, numCBs));
  86. VkResult result = vkQueueSubmit(mQueue, numCBs, submitInfos, mLastCommandBuffer->getFence());
  87. assert(result == VK_SUCCESS);
  88. mQueuedBuffers.clear();
  89. mQueuedSemaphores.clear();
  90. bs_stack_free(data);
  91. }
  92. void VulkanQueue::getSubmitInfo(VkCommandBuffer* cmdBuffer, VkSemaphore* signalSemaphores, UINT32 numSignalSemaphores,
  93. VkSemaphore* waitSemaphores, UINT32 numWaitSemaphores, VkSubmitInfo& submitInfo)
  94. {
  95. submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  96. submitInfo.pNext = nullptr;
  97. submitInfo.commandBufferCount = 1;
  98. submitInfo.pCommandBuffers = cmdBuffer;
  99. submitInfo.signalSemaphoreCount = numSignalSemaphores;
  100. submitInfo.pSignalSemaphores = signalSemaphores;
  101. submitInfo.waitSemaphoreCount = numWaitSemaphores;
  102. if (numWaitSemaphores > 0)
  103. {
  104. submitInfo.pWaitSemaphores = waitSemaphores;
  105. submitInfo.pWaitDstStageMask = mSubmitDstWaitMask;
  106. }
  107. else
  108. {
  109. submitInfo.pWaitSemaphores = nullptr;
  110. submitInfo.pWaitDstStageMask = nullptr;
  111. }
  112. }
  113. void VulkanQueue::present(VulkanSwapChain* swapChain, VulkanSemaphore** waitSemaphores, UINT32 semaphoresCount)
  114. {
  115. UINT32 backBufferIdx;
  116. if (!swapChain->prepareForPresent(backBufferIdx))
  117. return; // Nothing to present (back buffer wasn't even acquired)
  118. mSemaphoresTemp.resize(semaphoresCount + 1); // +1 for self semaphore
  119. prepareSemaphores(waitSemaphores, mSemaphoresTemp.data(), semaphoresCount);
  120. VkSwapchainKHR vkSwapChain = swapChain->getHandle();
  121. VkPresentInfoKHR presentInfo;
  122. presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
  123. presentInfo.pNext = nullptr;
  124. presentInfo.swapchainCount = 1;
  125. presentInfo.pSwapchains = &vkSwapChain;
  126. presentInfo.pImageIndices = &backBufferIdx;
  127. presentInfo.pResults = nullptr;
  128. // Wait before presenting, if required
  129. if (semaphoresCount > 0)
  130. {
  131. presentInfo.pWaitSemaphores = mSemaphoresTemp.data();
  132. presentInfo.waitSemaphoreCount = semaphoresCount;
  133. }
  134. else
  135. {
  136. presentInfo.pWaitSemaphores = nullptr;
  137. presentInfo.waitSemaphoreCount = 0;
  138. }
  139. VkResult result = vkQueuePresentKHR(mQueue, &presentInfo);
  140. assert(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR);
  141. mActiveSubmissions.push_back(SubmitInfo(nullptr, mNextSubmitIdx++, semaphoresCount, 0));
  142. }
  143. void VulkanQueue::waitIdle() const
  144. {
  145. VkResult result = vkQueueWaitIdle(mQueue);
  146. assert(result == VK_SUCCESS);
  147. }
  148. void VulkanQueue::refreshStates(bool forceWait, bool queueEmpty)
  149. {
  150. UINT32 lastFinishedSubmission = 0;
  151. auto iter = mActiveSubmissions.begin();
  152. while (iter != mActiveSubmissions.end())
  153. {
  154. VulkanCmdBuffer* cmdBuffer = iter->cmdBuffer;
  155. if (cmdBuffer == nullptr)
  156. {
  157. ++iter;
  158. continue;
  159. }
  160. if (!cmdBuffer->checkFenceStatus(forceWait))
  161. {
  162. assert(!forceWait);
  163. break; // No chance of any later CBs of being done either
  164. }
  165. lastFinishedSubmission = iter->submitIdx;
  166. ++iter;
  167. }
  168. // If last submission was a present() call, it won't be freed until a command buffer after it is done. However on
  169. // shutdown there might not be a CB following it. So we instead check this special flag and free everything when its
  170. // true.
  171. if (queueEmpty)
  172. lastFinishedSubmission = mNextSubmitIdx - 1;
  173. iter = mActiveSubmissions.begin();
  174. while (iter != mActiveSubmissions.end())
  175. {
  176. if (iter->submitIdx > lastFinishedSubmission)
  177. break;
  178. for (UINT32 i = 0; i < iter->numSemaphores; i++)
  179. {
  180. VulkanSemaphore* semaphore = mActiveSemaphores.front();
  181. mActiveSemaphores.pop();
  182. semaphore->notifyDone(0, VulkanUseFlag::Read | VulkanUseFlag::Write);
  183. }
  184. for(UINT32 i = 0; i < iter->numCommandBuffers; i++)
  185. {
  186. VulkanCmdBuffer* cb = mActiveBuffers.front();
  187. mActiveBuffers.pop();
  188. cb->reset();
  189. }
  190. iter = mActiveSubmissions.erase(iter);
  191. }
  192. }
  193. void VulkanQueue::prepareSemaphores(VulkanSemaphore** inSemaphores, VkSemaphore* outSemaphores, UINT32& semaphoresCount)
  194. {
  195. UINT32 semaphoreIdx = 0;
  196. for (UINT32 i = 0; i < semaphoresCount; i++)
  197. {
  198. VulkanSemaphore* semaphore = inSemaphores[i];
  199. semaphore->notifyBound();
  200. semaphore->notifyUsed(0, 0, VulkanUseFlag::Read | VulkanUseFlag::Write);
  201. outSemaphores[semaphoreIdx++] = semaphore->getHandle();
  202. mActiveSemaphores.push(semaphore);
  203. }
  204. // Wait on previous CB, as we want execution to proceed in order
  205. if (mLastCommandBuffer != nullptr && mLastCommandBuffer->isSubmitted() && !mLastCBSemaphoreUsed)
  206. {
  207. VulkanSemaphore* prevSemaphore = mLastCommandBuffer->getIntraQueueSemaphore();
  208. prevSemaphore->notifyBound();
  209. prevSemaphore->notifyUsed(0, 0, VulkanUseFlag::Read | VulkanUseFlag::Write);
  210. outSemaphores[semaphoreIdx++] = prevSemaphore->getHandle();
  211. mActiveSemaphores.push(prevSemaphore);
  212. // This will prevent command buffers submitted after present() to use the same semaphore. This also means that
  213. // there will be no intra-queue dependencies between commands for on the other ends of a present call
  214. // (Meaning those queue submissions could execute concurrently).
  215. mLastCBSemaphoreUsed = true;
  216. }
  217. semaphoresCount = semaphoreIdx;
  218. }
  219. }}