|
|
@@ -7,7 +7,8 @@
|
|
|
namespace bs
|
|
|
{
|
|
|
VulkanQueue::VulkanQueue(VulkanDevice& device, VkQueue queue, GpuQueueType type, UINT32 index)
|
|
|
- :mDevice(device), mQueue(queue), mType(type), mIndex(index), mLastCommandBuffer(nullptr), mNextSubmitIdx(1)
|
|
|
+ : mDevice(device), mQueue(queue), mType(type), mIndex(index), mLastCommandBuffer(nullptr)
|
|
|
+ , mLastCBSemaphoreUsed(false), mNextSubmitIdx(1)
|
|
|
{
|
|
|
for (UINT32 i = 0; i < BS_MAX_UNIQUE_QUEUES; i++)
|
|
|
mSubmitDstWaitMask[i] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
|
@@ -23,26 +24,104 @@ namespace bs
|
|
|
|
|
|
void VulkanQueue::submit(VulkanCmdBuffer* cmdBuffer, VulkanSemaphore** waitSemaphores, UINT32 semaphoresCount)
|
|
|
{
|
|
|
- VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
|
|
|
- VulkanSemaphore* semaphore = cmdBuffer->allocateSemaphore();
|
|
|
+ VulkanSemaphore* signalSemaphore = cmdBuffer->allocateSemaphore();
|
|
|
|
|
|
- VkSemaphore vkSemaphore = semaphore->getHandle();
|
|
|
+ VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
|
|
|
+ VkSemaphore vkSemaphore = signalSemaphore->getHandle();
|
|
|
|
|
|
+ prepareSemaphores(waitSemaphores, mSemaphoresTemp, semaphoresCount);
|
|
|
+
|
|
|
VkSubmitInfo submitInfo;
|
|
|
+ getSubmitInfo(&vkCmdBuffer, &vkSemaphore, mSemaphoresTemp, semaphoresCount, submitInfo);
|
|
|
+
|
|
|
+ VkResult result = vkQueueSubmit(mQueue, 1, &submitInfo, cmdBuffer->getFence());
|
|
|
+ assert(result == VK_SUCCESS);
|
|
|
+
|
|
|
+ cmdBuffer->setIsSubmitted();
|
|
|
+ mLastCommandBuffer = cmdBuffer;
|
|
|
+ mLastCBSemaphoreUsed = false;
|
|
|
+
|
|
|
+ mActiveBuffers.push_back(SubmitInfo(cmdBuffer, mNextSubmitIdx++, semaphoresCount));
|
|
|
+ }
|
|
|
+
|
|
|
+ void VulkanQueue::queueSubmit(VulkanCmdBuffer* cmdBuffer, VulkanSemaphore** waitSemaphores, UINT32 semaphoresCount)
|
|
|
+ {
|
|
|
+ mQueuedBuffers.push_back(SubmitInfo(cmdBuffer, 0, semaphoresCount));
|
|
|
+
|
|
|
+ for (UINT32 i = 0; i < semaphoresCount; i++)
|
|
|
+ mQueuedSemaphores.push_back(waitSemaphores[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ void VulkanQueue::submitQueued()
|
|
|
+ {
|
|
|
+ UINT32 numSubmits = (UINT32)mQueuedBuffers.size();
|
|
|
+ if (numSubmits == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ UINT32 totalNumWaitSemaphores = (UINT32)mQueuedSemaphores.size() + numSubmits;
|
|
|
+
|
|
|
+ UINT8* data = (UINT8*)bs_stack_alloc((sizeof(VkSubmitInfo) + sizeof(VkCommandBuffer) + sizeof(VkSemaphore)) *
|
|
|
+ numSubmits + sizeof(VkSemaphore) * totalNumWaitSemaphores);
|
|
|
+ UINT8* dataPtr = data;
|
|
|
+
|
|
|
+ VkSubmitInfo* submitInfos = (VkSubmitInfo*)dataPtr;
|
|
|
+ dataPtr += sizeof(VkSubmitInfo) * numSubmits;
|
|
|
+
|
|
|
+ VkCommandBuffer* commandBuffers = (VkCommandBuffer*)dataPtr;
|
|
|
+ dataPtr += sizeof(VkCommandBuffer) * numSubmits;
|
|
|
+
|
|
|
+ VkSemaphore* signalSemaphores = (VkSemaphore*)dataPtr;
|
|
|
+ dataPtr += sizeof(VkSemaphore) * numSubmits;
|
|
|
+
|
|
|
+ VkSemaphore* waitSemaphores = (VkSemaphore*)dataPtr;
|
|
|
+ dataPtr += sizeof(VkSemaphore) * totalNumWaitSemaphores;
|
|
|
+
|
|
|
+ UINT32 semaphoreIdx = 0;
|
|
|
+ for(UINT32 i = 0; i < numSubmits; i++)
|
|
|
+ {
|
|
|
+ const SubmitInfo& entry = mQueuedBuffers[i];
|
|
|
+
|
|
|
+ VulkanSemaphore* signalSemaphore = entry.cmdBuffer->getSemaphore();
|
|
|
+ commandBuffers[i] = entry.cmdBuffer->getHandle();
|
|
|
+ signalSemaphores[i] = signalSemaphore->getHandle();
|
|
|
+
|
|
|
+ UINT32 semaphoresCount = entry.numSemaphores;
|
|
|
+ prepareSemaphores(&mQueuedSemaphores[semaphoreIdx], &waitSemaphores[semaphoreIdx], semaphoresCount);
|
|
|
+
|
|
|
+ getSubmitInfo(&commandBuffers[i], &signalSemaphores[i], &waitSemaphores[semaphoreIdx], semaphoresCount,
|
|
|
+ submitInfos[i]);
|
|
|
+
|
|
|
+ entry.cmdBuffer->setIsSubmitted();
|
|
|
+ mLastCommandBuffer = entry.cmdBuffer; // Needs to be set because getSubmitInfo depends on it
|
|
|
+ mLastCBSemaphoreUsed = false;
|
|
|
+
|
|
|
+ mActiveBuffers.push_back(SubmitInfo(entry.cmdBuffer, mNextSubmitIdx++, semaphoresCount));
|
|
|
+ semaphoreIdx += semaphoresCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ VkResult result = vkQueueSubmit(mQueue, 1, submitInfos, mLastCommandBuffer->getFence());
|
|
|
+ assert(result == VK_SUCCESS);
|
|
|
+
|
|
|
+ mQueuedBuffers.clear();
|
|
|
+ mQueuedSemaphores.clear();
|
|
|
+
|
|
|
+ bs_stack_free(data);
|
|
|
+ }
|
|
|
+
|
|
|
+ void VulkanQueue::getSubmitInfo(VkCommandBuffer* cmdBuffer, VkSemaphore* signalSemaphore, VkSemaphore* waitSemaphores,
|
|
|
+ UINT32 semaphoresCount, VkSubmitInfo& submitInfo)
|
|
|
+ {
|
|
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
|
submitInfo.pNext = nullptr;
|
|
|
submitInfo.commandBufferCount = 1;
|
|
|
- submitInfo.pCommandBuffers = &vkCmdBuffer;
|
|
|
+ submitInfo.pCommandBuffers = cmdBuffer;
|
|
|
submitInfo.signalSemaphoreCount = 1;
|
|
|
- submitInfo.pSignalSemaphores = &vkSemaphore;
|
|
|
+ submitInfo.pSignalSemaphores = signalSemaphore;
|
|
|
submitInfo.waitSemaphoreCount = semaphoresCount;
|
|
|
|
|
|
if (semaphoresCount > 0)
|
|
|
{
|
|
|
- for (UINT32 i = 0; i < semaphoresCount; i++)
|
|
|
- mSemaphoresTemp[i] = waitSemaphores[i]->getHandle();
|
|
|
-
|
|
|
- submitInfo.pWaitSemaphores = mSemaphoresTemp;
|
|
|
+ submitInfo.pWaitSemaphores = waitSemaphores;
|
|
|
submitInfo.pWaitDstStageMask = mSubmitDstWaitMask;
|
|
|
}
|
|
|
else
|
|
|
@@ -50,22 +129,6 @@ namespace bs
|
|
|
submitInfo.pWaitSemaphores = nullptr;
|
|
|
submitInfo.pWaitDstStageMask = nullptr;
|
|
|
}
|
|
|
-
|
|
|
- VkResult result = vkQueueSubmit(mQueue, 1, &submitInfo, cmdBuffer->getFence());
|
|
|
- assert(result == VK_SUCCESS);
|
|
|
-
|
|
|
- cmdBuffer->setIsSubmitted();
|
|
|
- mLastCommandBuffer = cmdBuffer;
|
|
|
-
|
|
|
- for (UINT32 i = 0; i < semaphoresCount; i++)
|
|
|
- {
|
|
|
- waitSemaphores[i]->notifyBound();
|
|
|
- waitSemaphores[i]->notifyUsed(0, 0, VulkanUseFlag::Read | VulkanUseFlag::Write);
|
|
|
-
|
|
|
- mActiveSemaphores.push(waitSemaphores[i]);
|
|
|
- }
|
|
|
-
|
|
|
- mActiveBuffers.push_back(SubmitInfo(cmdBuffer, mNextSubmitIdx++, semaphoresCount));
|
|
|
}
|
|
|
|
|
|
void VulkanQueue::present(VulkanSwapChain* swapChain, VulkanSemaphore** waitSemaphores, UINT32 semaphoresCount)
|
|
|
@@ -74,8 +137,9 @@ namespace bs
|
|
|
if (!swapChain->prepareForPresent(backBufferIdx))
|
|
|
return; // Nothing to present (back buffer wasn't even acquired)
|
|
|
|
|
|
- VkSwapchainKHR vkSwapChain = swapChain->getHandle();
|
|
|
+ prepareSemaphores(waitSemaphores, mSemaphoresTemp, semaphoresCount);
|
|
|
|
|
|
+ VkSwapchainKHR vkSwapChain = swapChain->getHandle();
|
|
|
VkPresentInfoKHR presentInfo;
|
|
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
|
|
presentInfo.pNext = nullptr;
|
|
|
@@ -87,9 +151,6 @@ namespace bs
|
|
|
// Wait before presenting, if required
|
|
|
if (semaphoresCount > 0)
|
|
|
{
|
|
|
- for (UINT32 i = 0; i < semaphoresCount; i++)
|
|
|
- mSemaphoresTemp[i] = waitSemaphores[i]->getHandle();
|
|
|
-
|
|
|
presentInfo.pWaitSemaphores = mSemaphoresTemp;
|
|
|
presentInfo.waitSemaphoreCount = semaphoresCount;
|
|
|
}
|
|
|
@@ -102,14 +163,6 @@ namespace bs
|
|
|
VkResult result = vkQueuePresentKHR(mQueue, &presentInfo);
|
|
|
assert(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR);
|
|
|
|
|
|
- for (UINT32 i = 0; i < semaphoresCount; i++)
|
|
|
- {
|
|
|
- waitSemaphores[i]->notifyBound();
|
|
|
- waitSemaphores[i]->notifyUsed(0, 0, VulkanUseFlag::Read | VulkanUseFlag::Write);
|
|
|
-
|
|
|
- mActiveSemaphores.push(waitSemaphores[i]);
|
|
|
- }
|
|
|
-
|
|
|
mActiveBuffers.push_back(SubmitInfo(nullptr, mNextSubmitIdx++, semaphoresCount));
|
|
|
}
|
|
|
|
|
|
@@ -164,4 +217,38 @@ namespace bs
|
|
|
iter = mActiveBuffers.erase(iter);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ void VulkanQueue::prepareSemaphores(VulkanSemaphore** inSemaphores, VkSemaphore* outSemaphores, UINT32& semaphoresCount)
|
|
|
+ {
|
|
|
+ UINT32 semaphoreIdx = 0;
|
|
|
+ for (UINT32 i = 0; i < semaphoresCount; i++)
|
|
|
+ {
|
|
|
+ VulkanSemaphore* semaphore = inSemaphores[i];
|
|
|
+
|
|
|
+ semaphore->notifyBound();
|
|
|
+ semaphore->notifyUsed(0, 0, VulkanUseFlag::Read | VulkanUseFlag::Write);
|
|
|
+
|
|
|
+ outSemaphores[semaphoreIdx++] = semaphore->getHandle();
|
|
|
+ mActiveSemaphores.push(semaphore);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Wait on previous CB, as we want execution to proceed in order
|
|
|
+ if (mLastCommandBuffer != nullptr && mLastCommandBuffer->isSubmitted() && !mLastCBSemaphoreUsed)
|
|
|
+ {
|
|
|
+ VulkanSemaphore* prevSemaphore = mLastCommandBuffer->getSemaphore();
|
|
|
+
|
|
|
+ prevSemaphore->notifyBound();
|
|
|
+ prevSemaphore->notifyUsed(0, 0, VulkanUseFlag::Read | VulkanUseFlag::Write);
|
|
|
+
|
|
|
+ outSemaphores[semaphoreIdx++] = prevSemaphore->getHandle();
|
|
|
+ mActiveSemaphores.push(prevSemaphore);
|
|
|
+
|
|
|
+ // This will prevent command buffers submitted after present() to use the same semaphore. This also means that
|
|
|
+ // there will be no intra-queue dependencies between commands for on the other ends of a present call
|
|
|
+ // (Meaning those queue submissions could execute concurrently).
|
|
|
+ mLastCBSemaphoreUsed = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ semaphoresCount = semaphoreIdx;
|
|
|
+ }
|
|
|
}
|