| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "BsVulkanQueue.h"
- #include "BsVulkanCommandBuffer.h"
- #include "BsVulkanSwapChain.h"
- namespace bs { namespace ct
- {
- VulkanQueue::VulkanQueue(VulkanDevice& device, VkQueue queue, GpuQueueType type, UINT32 index)
- : 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;
- }
- bool VulkanQueue::isExecuting() const
- {
- if (mLastCommandBuffer == nullptr)
- return false;
- return mLastCommandBuffer->isSubmitted();
- }
- void VulkanQueue::submit(VulkanCmdBuffer* cmdBuffer, VulkanSemaphore** waitSemaphores, UINT32 semaphoresCount)
- {
- VkSemaphore signalSemaphores[BS_MAX_VULKAN_CB_DEPENDENCIES + 1];
- cmdBuffer->allocateSemaphores(signalSemaphores);
- VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
- mSemaphoresTemp.resize(semaphoresCount + 1); // +1 for self semaphore
- prepareSemaphores(waitSemaphores, mSemaphoresTemp.data(), semaphoresCount);
-
- VkSubmitInfo submitInfo;
- getSubmitInfo(&vkCmdBuffer, signalSemaphores, BS_MAX_VULKAN_CB_DEPENDENCIES + 1,
- mSemaphoresTemp.data(), semaphoresCount, submitInfo);
- VkResult result = vkQueueSubmit(mQueue, 1, &submitInfo, cmdBuffer->getFence());
- assert(result == VK_SUCCESS);
- cmdBuffer->setIsSubmitted();
- mLastCommandBuffer = cmdBuffer;
- mLastCBSemaphoreUsed = false;
- mActiveSubmissions.push_back(SubmitInfo(cmdBuffer, mNextSubmitIdx++, semaphoresCount, 1));
- mActiveBuffers.push(cmdBuffer);
- }
- void VulkanQueue::queueSubmit(VulkanCmdBuffer* cmdBuffer, VulkanSemaphore** waitSemaphores, UINT32 semaphoresCount)
- {
- mQueuedBuffers.push_back(SubmitInfo(cmdBuffer, 0, semaphoresCount, 1));
- for (UINT32 i = 0; i < semaphoresCount; i++)
- mQueuedSemaphores.push_back(waitSemaphores[i]);
- }
- void VulkanQueue::submitQueued()
- {
- UINT32 numCBs = (UINT32)mQueuedBuffers.size();
- if (numCBs == 0)
- return;
- UINT32 totalNumWaitSemaphores = (UINT32)mQueuedSemaphores.size() + numCBs;
- UINT32 signalSemaphoresPerCB = (BS_MAX_VULKAN_CB_DEPENDENCIES + 1);
- UINT8* data = (UINT8*)bs_stack_alloc((sizeof(VkSubmitInfo) + sizeof(VkCommandBuffer)) *
- numCBs + sizeof(VkSemaphore) * signalSemaphoresPerCB * numCBs + sizeof(VkSemaphore) * totalNumWaitSemaphores);
- UINT8* dataPtr = data;
- VkSubmitInfo* submitInfos = (VkSubmitInfo*)dataPtr;
- dataPtr += sizeof(VkSubmitInfo) * numCBs;
- VkCommandBuffer* commandBuffers = (VkCommandBuffer*)dataPtr;
- dataPtr += sizeof(VkCommandBuffer) * numCBs;
- VkSemaphore* signalSemaphores = (VkSemaphore*)dataPtr;
- dataPtr += sizeof(VkSemaphore) * signalSemaphoresPerCB * numCBs;
- VkSemaphore* waitSemaphores = (VkSemaphore*)dataPtr;
- dataPtr += sizeof(VkSemaphore) * totalNumWaitSemaphores;
- UINT32 readSemaphoreIdx = 0;
- UINT32 writeSemaphoreIdx = 0;
- UINT32 signalSemaphoreIdx = 0;
- for(UINT32 i = 0; i < numCBs; i++)
- {
- const SubmitInfo& entry = mQueuedBuffers[i];
- commandBuffers[i] = entry.cmdBuffer->getHandle();
- entry.cmdBuffer->allocateSemaphores(&signalSemaphores[signalSemaphoreIdx]);
- UINT32 semaphoresCount = entry.numSemaphores;
- prepareSemaphores(mQueuedSemaphores.data() + readSemaphoreIdx, &waitSemaphores[writeSemaphoreIdx], semaphoresCount);
- getSubmitInfo(&commandBuffers[i], &signalSemaphores[signalSemaphoreIdx], signalSemaphoresPerCB,
- &waitSemaphores[writeSemaphoreIdx], semaphoresCount, submitInfos[i]);
- entry.cmdBuffer->setIsSubmitted();
- mLastCommandBuffer = entry.cmdBuffer; // Needs to be set because getSubmitInfo depends on it
- mLastCBSemaphoreUsed = false;
- mActiveBuffers.push(entry.cmdBuffer);
- readSemaphoreIdx += entry.numSemaphores;
- writeSemaphoreIdx += semaphoresCount;
- signalSemaphoreIdx += signalSemaphoresPerCB;
- }
- VulkanCmdBuffer* lastCB = mQueuedBuffers[numCBs - 1].cmdBuffer;
- UINT32 totalNumSemaphores = writeSemaphoreIdx;
- mActiveSubmissions.push_back(SubmitInfo(lastCB, mNextSubmitIdx++, totalNumSemaphores, numCBs));
- VkResult result = vkQueueSubmit(mQueue, numCBs, submitInfos, mLastCommandBuffer->getFence());
- assert(result == VK_SUCCESS);
- mQueuedBuffers.clear();
- mQueuedSemaphores.clear();
- bs_stack_free(data);
- }
- void VulkanQueue::getSubmitInfo(VkCommandBuffer* cmdBuffer, VkSemaphore* signalSemaphores, UINT32 numSignalSemaphores,
- VkSemaphore* waitSemaphores, UINT32 numWaitSemaphores, VkSubmitInfo& submitInfo)
- {
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.pNext = nullptr;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = cmdBuffer;
- submitInfo.signalSemaphoreCount = numSignalSemaphores;
- submitInfo.pSignalSemaphores = signalSemaphores;
- submitInfo.waitSemaphoreCount = numWaitSemaphores;
- if (numWaitSemaphores > 0)
- {
- submitInfo.pWaitSemaphores = waitSemaphores;
- submitInfo.pWaitDstStageMask = mSubmitDstWaitMask;
- }
- else
- {
- submitInfo.pWaitSemaphores = nullptr;
- submitInfo.pWaitDstStageMask = nullptr;
- }
- }
- void VulkanQueue::present(VulkanSwapChain* swapChain, VulkanSemaphore** waitSemaphores, UINT32 semaphoresCount)
- {
- UINT32 backBufferIdx;
- if (!swapChain->prepareForPresent(backBufferIdx))
- return; // Nothing to present (back buffer wasn't even acquired)
- mSemaphoresTemp.resize(semaphoresCount + 1); // +1 for self semaphore
- prepareSemaphores(waitSemaphores, mSemaphoresTemp.data(), semaphoresCount);
- VkSwapchainKHR vkSwapChain = swapChain->getHandle();
- VkPresentInfoKHR presentInfo;
- presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
- presentInfo.pNext = nullptr;
- presentInfo.swapchainCount = 1;
- presentInfo.pSwapchains = &vkSwapChain;
- presentInfo.pImageIndices = &backBufferIdx;
- presentInfo.pResults = nullptr;
- // Wait before presenting, if required
- if (semaphoresCount > 0)
- {
- presentInfo.pWaitSemaphores = mSemaphoresTemp.data();
- presentInfo.waitSemaphoreCount = semaphoresCount;
- }
- else
- {
- presentInfo.pWaitSemaphores = nullptr;
- presentInfo.waitSemaphoreCount = 0;
- }
- VkResult result = vkQueuePresentKHR(mQueue, &presentInfo);
- assert(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR);
- mActiveSubmissions.push_back(SubmitInfo(nullptr, mNextSubmitIdx++, semaphoresCount, 0));
- }
- void VulkanQueue::waitIdle() const
- {
- VkResult result = vkQueueWaitIdle(mQueue);
- assert(result == VK_SUCCESS);
- }
- void VulkanQueue::refreshStates(bool forceWait, bool queueEmpty)
- {
- UINT32 lastFinishedSubmission = 0;
- auto iter = mActiveSubmissions.begin();
- while (iter != mActiveSubmissions.end())
- {
- VulkanCmdBuffer* cmdBuffer = iter->cmdBuffer;
- if (cmdBuffer == nullptr)
- {
- ++iter;
- continue;
- }
- if (!cmdBuffer->checkFenceStatus(forceWait))
- {
- assert(!forceWait);
- break; // No chance of any later CBs of being done either
- }
- lastFinishedSubmission = iter->submitIdx;
- ++iter;
- }
- // If last submission was a present() call, it won't be freed until a command buffer after it is done. However on
- // shutdown there might not be a CB following it. So we instead check this special flag and free everything when its
- // true.
- if (queueEmpty)
- lastFinishedSubmission = mNextSubmitIdx - 1;
- iter = mActiveSubmissions.begin();
- while (iter != mActiveSubmissions.end())
- {
- if (iter->submitIdx > lastFinishedSubmission)
- break;
- for (UINT32 i = 0; i < iter->numSemaphores; i++)
- {
- VulkanSemaphore* semaphore = mActiveSemaphores.front();
- mActiveSemaphores.pop();
- semaphore->notifyDone(0, VulkanUseFlag::Read | VulkanUseFlag::Write);
- }
- for(UINT32 i = 0; i < iter->numCommandBuffers; i++)
- {
- VulkanCmdBuffer* cb = mActiveBuffers.front();
- mActiveBuffers.pop();
- cb->reset();
- }
- iter = mActiveSubmissions.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->getIntraQueueSemaphore();
- 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;
- }
- }}
|