BsVulkanQueue.cpp 8.6 KB

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