LCOV - code coverage report
Current view: top level - source/renderer/backend/vulkan - SubmitScheduler.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 1 93 1.1 %
Date: 2023-01-19 00:18:29 Functions: 2 9 22.2 %

          Line data    Source code
       1             : /* Copyright (C) 2023 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "SubmitScheduler.h"
      21             : 
      22             : #include "renderer/backend/vulkan/Device.h"
      23             : #include "renderer/backend/vulkan/RingCommandContext.h"
      24             : #include "renderer/backend/vulkan/SwapChain.h"
      25             : #include "renderer/backend/vulkan/Utilities.h"
      26             : 
      27             : namespace Renderer
      28             : {
      29             : 
      30             : namespace Backend
      31             : {
      32             : 
      33             : namespace Vulkan
      34             : {
      35             : 
      36           0 : CSubmitScheduler::CSubmitScheduler(
      37           0 :     CDevice* device, const uint32_t queueFamilyIndex, VkQueue queue)
      38           0 :     : m_Device(device), m_Queue(queue)
      39             : {
      40           0 :     constexpr size_t numberOfFences = NUMBER_OF_FRAMES_IN_FLIGHT;
      41           0 :     m_Fences.reserve(numberOfFences);
      42           0 :     for (size_t index = 0; index < numberOfFences; ++index)
      43             :     {
      44           0 :         VkFenceCreateInfo fenceCreateInfo{};
      45           0 :         fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
      46           0 :         VkFence fence = VK_NULL_HANDLE;
      47           0 :         ENSURE_VK_SUCCESS(vkCreateFence(
      48             :             m_Device->GetVkDevice(), &fenceCreateInfo, nullptr, &fence));
      49           0 :         m_Fences.push_back({fence, INVALID_SUBMIT_HANDLE});
      50             :     }
      51             : 
      52           0 :     for (FrameObject& frameObject : m_FrameObjects)
      53             :     {
      54           0 :         VkSemaphoreCreateInfo semaphoreCreateInfo{};
      55           0 :         semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
      56           0 :         ENSURE_VK_SUCCESS(vkCreateSemaphore(
      57             :             device->GetVkDevice(), &semaphoreCreateInfo, nullptr, &frameObject.acquireImageSemaphore));
      58             : 
      59           0 :         ENSURE_VK_SUCCESS(vkCreateSemaphore(
      60             :             device->GetVkDevice(), &semaphoreCreateInfo, nullptr, &frameObject.submitDone));
      61             :     }
      62             : 
      63           0 :     m_AcquireCommandContext = std::make_unique<CRingCommandContext>(
      64           0 :         device, NUMBER_OF_FRAMES_IN_FLIGHT, queueFamilyIndex, *this);
      65           0 :     m_PresentCommandContext = std::make_unique<CRingCommandContext>(
      66           0 :         device, NUMBER_OF_FRAMES_IN_FLIGHT, queueFamilyIndex, *this);
      67           0 : }
      68             : 
      69           0 : CSubmitScheduler::~CSubmitScheduler()
      70             : {
      71           0 :     VkDevice device = m_Device->GetVkDevice();
      72             : 
      73           0 :     for (Fence& fence : m_Fences)
      74           0 :         if (fence.value != VK_NULL_HANDLE)
      75           0 :             vkDestroyFence(device, fence.value, nullptr);
      76             : 
      77           0 :     for (FrameObject& frameObject : m_FrameObjects)
      78             :     {
      79           0 :         if (frameObject.acquireImageSemaphore != VK_NULL_HANDLE)
      80           0 :             vkDestroySemaphore(device, frameObject.acquireImageSemaphore, nullptr);
      81             : 
      82           0 :         if (frameObject.submitDone != VK_NULL_HANDLE)
      83           0 :             vkDestroySemaphore(device, frameObject.submitDone, nullptr);
      84             :     }
      85           0 : }
      86             : 
      87           0 : bool CSubmitScheduler::AcquireNextImage(CSwapChain& swapChain)
      88             : {
      89           0 :     FrameObject& frameObject = m_FrameObjects[m_FrameID % m_FrameObjects.size()];
      90           0 :     if (!swapChain.AcquireNextImage(frameObject.acquireImageSemaphore))
      91           0 :         return false;
      92           0 :     swapChain.SubmitCommandsAfterAcquireNextImage(*m_AcquireCommandContext);
      93             :     
      94           0 :     m_NextWaitSemaphore = frameObject.acquireImageSemaphore;
      95           0 :     m_NextWaitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
      96           0 :     m_AcquireCommandContext->Flush();
      97           0 :     return true;
      98             : }
      99             : 
     100           0 : void CSubmitScheduler::Present(CSwapChain& swapChain)
     101             : {
     102           0 :     FrameObject& frameObject = m_FrameObjects[m_FrameID % m_FrameObjects.size()];
     103           0 :     swapChain.SubmitCommandsBeforePresent(*m_PresentCommandContext);
     104           0 :     m_NextSubmitSignalSemaphore = frameObject.submitDone;
     105           0 :     m_PresentCommandContext->Flush();
     106           0 :     Flush();
     107           0 :     swapChain.Present(frameObject.submitDone, m_Queue);
     108           0 : }
     109             : 
     110           0 : CSubmitScheduler::SubmitHandle CSubmitScheduler::Submit(VkCommandBuffer commandBuffer)
     111             : {
     112           0 :     m_SubmittedCommandBuffers.emplace_back(commandBuffer);
     113           0 :     return m_CurrentHandle;
     114             : }
     115             : 
     116           0 : void CSubmitScheduler::WaitUntilFree(const SubmitHandle handle)
     117             : {
     118             :     // We haven't submitted the current handle.
     119           0 :     if (handle == m_CurrentHandle)
     120           0 :         Flush();
     121             : 
     122           0 :     VkDevice device = m_Device->GetVkDevice();
     123           0 :     while (!m_SubmittedHandles.empty() && handle >= m_SubmittedHandles.front().value)
     124             :     {
     125           0 :         Fence& fence = m_Fences[m_SubmittedHandles.front().fenceIndex];
     126           0 :         ENSURE(fence.inUse);
     127           0 :         m_SubmittedHandles.pop();
     128           0 :         ENSURE_VK_SUCCESS(vkWaitForFences(device, 1, &fence.value, VK_TRUE, std::numeric_limits<uint64_t>::max()));
     129           0 :         ENSURE_VK_SUCCESS(vkResetFences(device, 1, &fence.value));
     130           0 :         fence.inUse = false;
     131           0 :         fence.lastUsedHandle = INVALID_SUBMIT_HANDLE;
     132             :     }
     133           0 : }
     134             : 
     135           0 : void CSubmitScheduler::Flush()
     136             : {
     137           0 :     ENSURE(!m_SubmittedCommandBuffers.empty());
     138             : 
     139           0 :     Fence& fence = m_Fences[m_FenceIndex];
     140           0 :     if (fence.inUse)
     141           0 :         WaitUntilFree(fence.lastUsedHandle);
     142           0 :     fence.lastUsedHandle = m_CurrentHandle;
     143           0 :     fence.inUse = true;
     144           0 :     m_SubmittedHandles.push({m_CurrentHandle, m_FenceIndex});
     145           0 :     ++m_CurrentHandle;
     146           0 :     m_FenceIndex = (m_FenceIndex + 1) % m_Fences.size();
     147             : 
     148           0 :     VkSubmitInfo submitInfo{};
     149           0 :     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
     150           0 :     if (m_NextWaitSemaphore != VK_NULL_HANDLE)
     151             :     {
     152           0 :         submitInfo.waitSemaphoreCount = 1;
     153           0 :         submitInfo.pWaitSemaphores = &m_NextWaitSemaphore;
     154           0 :         submitInfo.pWaitDstStageMask = &m_NextWaitDstStageMask;
     155             :     }
     156           0 :     if (m_NextSubmitSignalSemaphore != VK_NULL_HANDLE)
     157             :     {
     158           0 :         submitInfo.signalSemaphoreCount = 1;
     159           0 :         submitInfo.pSignalSemaphores = &m_NextSubmitSignalSemaphore;
     160             :     }
     161           0 :     submitInfo.commandBufferCount = m_SubmittedCommandBuffers.size();
     162           0 :     submitInfo.pCommandBuffers = m_SubmittedCommandBuffers.data();
     163             : 
     164           0 :     ENSURE_VK_SUCCESS(vkQueueSubmit(m_Queue, 1, &submitInfo, fence.value));
     165             : 
     166           0 :     m_NextWaitSemaphore = VK_NULL_HANDLE;
     167           0 :     m_NextWaitDstStageMask = 0;
     168           0 :     m_NextSubmitSignalSemaphore = VK_NULL_HANDLE;
     169             : 
     170           0 :     m_SubmittedCommandBuffers.clear();
     171           0 : }
     172             : 
     173             : } // namespace Vulkan
     174             : 
     175             : } // namespace Backend
     176             : 
     177           3 : } // namespace Renderer

Generated by: LCOV version 1.13