diff --git a/config/Sources.cmake b/config/Sources.cmake index 23d9df0ff764daf64b37e9e2637fb4b1c5877421..9c86a9d56282a4a5f533f320f5b0ecf96a6489a2 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -64,12 +64,6 @@ set(vkcv_sources ${vkcv_source}/vkcv/GraphicsPipelineManager.hpp ${vkcv_source}/vkcv/GraphicsPipelineManager.cpp - - ${vkcv_include}/vkcv/CommandResources.hpp - ${vkcv_source}/vkcv/CommandResources.cpp - - ${vkcv_include}/vkcv/SyncResources.hpp - ${vkcv_source}/vkcv/SyncResources.cpp ${vkcv_include}/vkcv/QueueManager.hpp ${vkcv_source}/vkcv/QueueManager.cpp diff --git a/include/vkcv/CommandResources.hpp b/include/vkcv/CommandResources.hpp deleted file mode 100644 index 8ec868c0a5a353cba2efb2313d4168450f30844b..0000000000000000000000000000000000000000 --- a/include/vkcv/CommandResources.hpp +++ /dev/null @@ -1,113 +0,0 @@ -#pragma once -/** - * @authors Alexander Gauggel, Tobias Frisch - * @file vkcv/CommandResources.hpp - * @brief Support functions to deal with command resources. - */ - -#include <vulkan/vulkan.hpp> -#include <unordered_set> - -#include "QueueManager.hpp" - -namespace vkcv { - - /** - * @brief Structure to store command pools for given queue families - * of a device. - */ - struct CommandResources { - std::vector<vk::CommandPool> cmdPoolPerQueueFamily; - }; - - /** - * @brief Generates a set of the family indices for all different kinds of - * queues a given queue manager provides. - * - * @param[in] queueManager Queue manager - * @return Set of queue family indices - */ - std::unordered_set<int> generateQueueFamilyIndexSet(const QueueManager &queueManager); - - /** - * @brief Creates and returns a new command resources instance containing - * a vector of newly allocated command pools for each different queue family - * index in a given set. - * - * @param[in,out] device Vulkan device - * @param[in] familyIndexSet Set of queue family indices - * @return New command resources - */ - CommandResources createCommandResources(const vk::Device &device, - const std::unordered_set<int> &familyIndexSet); - - /** - * @brief Destroys a command resources instance and deallocates its command - * pools. The command resources will be invalid to use afterwards. - * - * @param[in,out] device Vulkan device - * @param[in,out] resources Command resources - */ - void destroyCommandResources(const vk::Device &device, - const CommandResources &resources); - - /** - * @brief Allocates and returns a new primary command buffer of a given - * command pool. - * - * @param[in,out] device Vulkan device - * @param[in,out] cmdPool Vulkan command pool - * @return New vulkan command buffer - */ - vk::CommandBuffer allocateCommandBuffer(const vk::Device &device, - const vk::CommandPool &cmdPool); - - /** - * @brief Returns the matching command pool of given command resources for - * a specific queue. - * - * @param[in] queue Queue - * @param[in] cmdResources Command resources - * @return Command pool for a given queue - */ - vk::CommandPool chooseCmdPool(const Queue &queue, - const CommandResources &cmdResources); - - /** - * @brief Returns a queue of a given type from a queue manager. - * - * @param[in] type Type of queue - * @param[in] queueManager Queue manager - * @return Queue of a given type - */ - Queue getQueueForSubmit(QueueType type, - const QueueManager &queueManager); - - /** - * @brief Begins the usage of a command buffer with given command buffer - * usage flags. - * - * @param[in] cmdBuffer Vulkan command buffer - * @param[in] flags Command buffer usage flags - */ - void beginCommandBuffer(const vk::CommandBuffer &cmdBuffer, - vk::CommandBufferUsageFlags flags); - - /** - * @brief Submits a command buffer into a queue with given fence and - * semaphores to wait for or to signal after processing the command - * buffer. - * - * @param[in,out] queue Vulkan queue - * @param[in] cmdBuffer Vulkan command buffer - * @param[in] fence Vulkan fence to wait for - * @param[in] waitSemaphores Vector of semaphores to wait for - * @param[in] signalSemaphores Vector of semaphores to signal - */ - void submitCommandBufferToQueue(vk::Queue queue, - const vk::CommandBuffer &cmdBuffer, - const vk::Fence &fence, - const std::vector<vk::Semaphore>& waitSemaphores, - const std::vector<vk::Semaphore>& signalSemaphores); - -} \ No newline at end of file diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 2ab8785943d7d4237789fff6c509f9daae26c5ad..e6529ce85507112485522a5650710086fb5aa5a2 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -18,8 +18,6 @@ #include "BlitDownsampler.hpp" #include "GraphicsPipelineConfig.hpp" #include "ComputePipelineConfig.hpp" -#include "CommandResources.hpp" -#include "SyncResources.hpp" #include "Result.hpp" #include "Sampler.hpp" #include "DescriptorWrites.hpp" @@ -46,15 +44,6 @@ namespace vkcv class WindowManager; class SwapchainManager; - /** - * @brief Structure to store details about a queue submission. - */ - struct SubmitInfo { - QueueType queueType; - std::vector<vk::Semaphore> waitSemaphores; - std::vector<vk::Semaphore> signalSemaphores; - }; - /** * @brief Class to handle the core functionality of the framework. * @@ -70,7 +59,8 @@ namespace vkcv * * @param context encapsulates various Vulkan objects */ - Core(Context &&context, const CommandResources& commandResources, const SyncResources& syncResources) noexcept; + explicit Core(Context &&context) noexcept; + // explicit destruction of default constructor Core() = delete; @@ -89,10 +79,11 @@ namespace vkcv std::unique_ptr<CommandStreamManager> m_CommandStreamManager; std::unique_ptr<WindowManager> m_WindowManager; std::unique_ptr<SwapchainManager> m_SwapchainManager; - - CommandResources m_CommandResources; - SyncResources m_SyncResources; - uint32_t m_currentSwapchainImageIndex; + + std::vector<vk::CommandPool> m_CommandPools; + vk::Semaphore m_RenderFinished; + vk::Semaphore m_SwapchainImageAcquired; + uint32_t m_currentSwapchainImageIndex; std::unique_ptr<Downsampler> m_downsampler; diff --git a/include/vkcv/SyncResources.hpp b/include/vkcv/SyncResources.hpp deleted file mode 100644 index 1683855b6b4f9046b0af5fb2df65f3bca895da2a..0000000000000000000000000000000000000000 --- a/include/vkcv/SyncResources.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once -/** - * @authors Alexander Gauggel, Tobias Frisch - * @file vkcv/SyncResources.hpp - * @brief Support functions to deal with synchronization resources. - */ - -#include <vulkan/vulkan.hpp> - -namespace vkcv { - - /** - * @brief Structure to store vulkan resources for presenting - * with a pipeline. - */ - struct SyncResources { - vk::Semaphore renderFinished; - vk::Semaphore swapchainImageAcquired; - vk::Fence presentFinished; - }; - - /** - * @brief Creates new synchronization resources for drawing - * and presenting with a swapchain. - * - * @param[in,out] device Vulkan-Device - * @return New created synchronization resources - */ - SyncResources createSyncResources(const vk::Device &device); - - /** - * @brief Destroys the synchronization resources with a - * given device. - * - * @param[in,out] device Vulkan-Device - * @param[in,out] resources Synchronizazion resources - */ - void destroySyncResources(const vk::Device &device, - const SyncResources &resources); - - /** - * @brief Creates a new fence with a given device and - * returns it. - * - * @param[in,out] device Vulkan-Device - * @return New created fence - */ - vk::Fence createFence(const vk::Device &device); - - /** - * @brief Calls a given device to wait for a specific fence. - * - * @param[in,out] device Vulkan-Device - * @param[in] fence Vulkan-Fence - */ - void waitForFence(const vk::Device& device, - const vk::Fence& fence); - -} \ No newline at end of file diff --git a/src/vkcv/CommandResources.cpp b/src/vkcv/CommandResources.cpp deleted file mode 100644 index d5c97946aa97ba897710dda412b6f71bd2ed54c8..0000000000000000000000000000000000000000 --- a/src/vkcv/CommandResources.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "vkcv/CommandResources.hpp" -#include <iostream> - -#include "vkcv/Logger.hpp" - -namespace vkcv { - - std::unordered_set<int> generateQueueFamilyIndexSet(const QueueManager &queueManager) { - std::unordered_set<int> indexSet; - for (const auto& queue : queueManager.getGraphicsQueues()) { - indexSet.insert(queue.familyIndex); - } - for (const auto& queue : queueManager.getComputeQueues()) { - indexSet.insert(queue.familyIndex); - } - for (const auto& queue : queueManager.getTransferQueues()) { - indexSet.insert(queue.familyIndex); - } - indexSet.insert(queueManager.getPresentQueue().familyIndex); - return indexSet; - } - - CommandResources createCommandResources(const vk::Device& device, const std::unordered_set<int>& familyIndexSet) { - CommandResources resources; - const size_t queueFamiliesCount = familyIndexSet.size(); - resources.cmdPoolPerQueueFamily.resize(queueFamiliesCount); - - const vk::CommandPoolCreateFlags poolFlags = vk::CommandPoolCreateFlagBits::eTransient; - for (const int familyIndex : familyIndexSet) { - const vk::CommandPoolCreateInfo poolCreateInfo(poolFlags, familyIndex); - resources.cmdPoolPerQueueFamily[familyIndex] = device.createCommandPool(poolCreateInfo, nullptr, {}); - } - - return resources; - } - - void destroyCommandResources(const vk::Device& device, const CommandResources& resources) { - for (const vk::CommandPool &pool : resources.cmdPoolPerQueueFamily) { - device.destroyCommandPool(pool); - } - } - - vk::CommandBuffer allocateCommandBuffer(const vk::Device& device, const vk::CommandPool &cmdPool) { - const vk::CommandBufferAllocateInfo info(cmdPool, vk::CommandBufferLevel::ePrimary, 1); - return device.allocateCommandBuffers(info).front(); - } - - vk::CommandPool chooseCmdPool(const Queue& queue, const CommandResources& cmdResources) { - return cmdResources.cmdPoolPerQueueFamily[queue.familyIndex]; - } - - Queue getQueueForSubmit(QueueType type, const QueueManager& queueManager) { - if (type == QueueType::Graphics) { - return queueManager.getGraphicsQueues().front(); - } - else if (type == QueueType::Compute) { - return queueManager.getComputeQueues().front(); - } - else if (type == QueueType::Transfer) { - return queueManager.getTransferQueues().front(); - } - else if (type == QueueType::Present) { - return queueManager.getPresentQueue(); - } - else { - vkcv_log(LogLevel::ERROR, "Unknown queue type"); - return queueManager.getGraphicsQueues().front(); // graphics is the most general queue - } - } - - void beginCommandBuffer(const vk::CommandBuffer &cmdBuffer, vk::CommandBufferUsageFlags flags) { - const vk::CommandBufferBeginInfo beginInfo(flags); - cmdBuffer.begin(beginInfo); - } - - void submitCommandBufferToQueue( - vk::Queue queue, - const vk::CommandBuffer &cmdBuffer, - const vk::Fence &fence, - const std::vector<vk::Semaphore> &waitSemaphores, - const std::vector<vk::Semaphore> &signalSemaphores) { - - const std::vector<vk::PipelineStageFlags> waitDstStageMasks(waitSemaphores.size(), vk::PipelineStageFlagBits::eAllCommands); - const vk::SubmitInfo queueSubmitInfo(waitSemaphores, waitDstStageMasks, cmdBuffer, signalSemaphores); - queue.submit(queueSubmitInfo, fence); - } -} \ No newline at end of file diff --git a/src/vkcv/CommandStreamManager.cpp b/src/vkcv/CommandStreamManager.cpp index 9f85eea38298d31dfa8fa48be2966de11dbefc2e..5086d0248f87f91778aa7fcbb6f6a22326666227 100644 --- a/src/vkcv/CommandStreamManager.cpp +++ b/src/vkcv/CommandStreamManager.cpp @@ -32,8 +32,13 @@ namespace vkcv { CommandStreamHandle CommandStreamManager::createCommandStream(const vk::Queue &queue, vk::CommandPool cmdPool) { - const vk::CommandBuffer cmdBuffer = allocateCommandBuffer(getCore().getContext().getDevice(), cmdPool); - beginCommandBuffer(cmdBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit); + const vk::CommandBufferAllocateInfo info (cmdPool, vk::CommandBufferLevel::ePrimary, 1); + auto& device = getCore().getContext().getDevice(); + + const vk::CommandBuffer cmdBuffer = device.allocateCommandBuffers(info).front(); + + const vk::CommandBufferBeginInfo beginInfo (vk::CommandBufferUsageFlagBits::eOneTimeSubmit); + cmdBuffer.begin(beginInfo); for (uint64_t id = 0; id < getCount(); id++) { auto& stream = getById(id); @@ -69,10 +74,22 @@ namespace vkcv { stream.cmdBuffer.end(); const auto device = getCore().getContext().getDevice(); + const vk::Fence waitFence = device.createFence({}); + + const std::vector<vk::PipelineStageFlags> waitDstStageMasks ( + waitSemaphores.size(), + vk::PipelineStageFlagBits::eAllCommands + ); + + const vk::SubmitInfo queueSubmitInfo( + waitSemaphores, + waitDstStageMasks, + stream.cmdBuffer, + signalSemaphores + ); - const vk::Fence waitFence = createFence(device); - submitCommandBufferToQueue(stream.queue, stream.cmdBuffer, waitFence, waitSemaphores, signalSemaphores); - waitForFence(device, waitFence); + stream.queue.submit(queueSubmitInfo, waitFence); + assert(device.waitForFences(waitFence, true, UINT64_MAX) == vk::Result::eSuccess); device.destroyFence(waitFence); stream.queue = nullptr; diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 761dd66dd26698dd4666a17df23d31d313149661..8454ae9a39a8bf006e9aaa528ec76e9be9792d7e 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -23,6 +23,55 @@ namespace vkcv { + + /** + * @brief Generates a set of the family indices for all different kinds of + * queues a given queue manager provides. + * + * @param[in] queueManager Queue manager + * @return Set of queue family indices + */ + static std::unordered_set<int> generateQueueFamilyIndexSet(const QueueManager &queueManager) { + std::unordered_set<int> indexSet; + + for (const auto& queue : queueManager.getGraphicsQueues()) { + indexSet.insert(queue.familyIndex); + } + + for (const auto& queue : queueManager.getComputeQueues()) { + indexSet.insert(queue.familyIndex); + } + + for (const auto& queue : queueManager.getTransferQueues()) { + indexSet.insert(queue.familyIndex); + } + + indexSet.insert(queueManager.getPresentQueue().familyIndex); + return indexSet; + } + + /** + * @brief Creates and returns a vector of newly allocated command pools + * for each different queue family index in a given set. + * + * @param[in,out] device Vulkan device + * @param[in] familyIndexSet Set of queue family indices + * @return New command pools + */ + static std::vector<vk::CommandPool> createCommandPools(const vk::Device& device, + const std::unordered_set<int>& familyIndexSet) { + std::vector<vk::CommandPool> commandPoolsPerQueueFamily; + commandPoolsPerQueueFamily.resize(familyIndexSet.size()); + + const vk::CommandPoolCreateFlags poolFlags = vk::CommandPoolCreateFlagBits::eTransient; + for (const int familyIndex : familyIndexSet) { + const vk::CommandPoolCreateInfo poolCreateInfo(poolFlags, familyIndex); + commandPoolsPerQueueFamily[familyIndex] = device.createCommandPool(poolCreateInfo, nullptr, {}); + } + + return commandPoolsPerQueueFamily; + } + Core Core::create(const char *applicationName, uint32_t applicationVersion, const std::vector<vk::QueueFlagBits>& queueFlags, @@ -36,20 +85,14 @@ namespace vkcv instanceExtensions ); - const auto& queueManager = context.getQueueManager(); - - const std::unordered_set<int> queueFamilySet = generateQueueFamilyIndexSet(queueManager); - const auto commandResources = createCommandResources(context.getDevice(), queueFamilySet); - const auto defaultSyncResources = createSyncResources(context.getDevice()); - - return Core(std::move(context) , commandResources, defaultSyncResources); + return Core(std::move(context)); } const Context &Core::getContext() const { return m_Context; } - Core::Core(Context &&context, const CommandResources& commandResources, const SyncResources& syncResources) noexcept : + Core::Core(Context &&context) noexcept : m_Context(std::move(context)), m_PassManager(std::make_unique<PassManager>()), m_GraphicsPipelineManager(std::make_unique<GraphicsPipelineManager>()), @@ -62,10 +105,19 @@ namespace vkcv m_CommandStreamManager{std::make_unique<CommandStreamManager>()}, m_WindowManager(std::make_unique<WindowManager>()), m_SwapchainManager(std::make_unique<SwapchainManager>()), - m_CommandResources(commandResources), - m_SyncResources(syncResources), + m_CommandPools(), + m_RenderFinished(), + m_SwapchainImageAcquired(), m_downsampler(nullptr) { + m_CommandPools = createCommandPools( + m_Context.getDevice(), + generateQueueFamilyIndexSet(m_Context.getQueueManager()) + ); + + m_RenderFinished = m_Context.getDevice().createSemaphore({}); + m_SwapchainImageAcquired = m_Context.getDevice().createSemaphore({}); + m_PassManager->init(*this); m_GraphicsPipelineManager->init(*this); m_ComputePipelineManager->init(*this); @@ -81,9 +133,13 @@ namespace vkcv Core::~Core() noexcept { m_Context.getDevice().waitIdle(); - - destroyCommandResources(m_Context.getDevice(), m_CommandResources); - destroySyncResources(m_Context.getDevice(), m_SyncResources); + + for (const vk::CommandPool &pool : m_CommandPools) { + m_Context.getDevice().destroyCommandPool(pool); + } + + m_Context.getDevice().destroySemaphore(m_RenderFinished); + m_Context.getDevice().destroySemaphore(m_SwapchainImageAcquired); } GraphicsPipelineHandle Core::createGraphicsPipeline(const GraphicsPipelineConfig &config) { @@ -174,7 +230,7 @@ namespace vkcv result = m_Context.getDevice().acquireNextImageKHR( m_SwapchainManager->getSwapchain(swapchainHandle).m_Swapchain, std::numeric_limits<uint64_t>::max(), - m_SyncResources.swapchainImageAcquired, + m_SwapchainImageAcquired, nullptr, &imageIndex, {} ); @@ -430,10 +486,6 @@ namespace vkcv return; } - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Graphics; - submitInfo.signalSemaphores = { m_SyncResources.renderFinished }; - auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments); @@ -508,10 +560,6 @@ namespace vkcv return; } - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Graphics; - submitInfo.signalSemaphores = {m_SyncResources.renderFinished}; - auto submitFunction = [&](const vk::CommandBuffer &cmdBuffer) { const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments); @@ -652,10 +700,6 @@ namespace vkcv return; } - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Graphics; - submitInfo.signalSemaphores = { m_SyncResources.renderFinished }; - auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments); @@ -858,9 +902,9 @@ namespace vkcv return; } - std::array<vk::Semaphore, 2> waitSemaphores{ - m_SyncResources.renderFinished, - m_SyncResources.swapchainImageAcquired + const std::array<vk::Semaphore, 2> waitSemaphores { + m_RenderFinished, + m_SwapchainImageAcquired }; const vk::SwapchainKHR& swapchain = m_SwapchainManager->getSwapchain(swapchainHandle).m_Swapchain; @@ -889,10 +933,34 @@ namespace vkcv m_SwapchainManager->signalRecreation(swapchainHandle); } } - + + /** + * @brief Returns a queue of a given type from a queue manager. + * + * @param[in] type Type of queue + * @param[in] queueManager Queue manager + * @return Queue of a given type + */ + static Queue getQueueForSubmit(QueueType type, const QueueManager& queueManager) { + switch (type) { + case QueueType::Graphics: + return queueManager.getGraphicsQueues().front(); + case QueueType::Compute: + return queueManager.getComputeQueues().front(); + case QueueType::Transfer: + return queueManager.getTransferQueues().front(); + case QueueType::Present: + return queueManager.getPresentQueue(); + default: { + vkcv_log(LogLevel::ERROR, "Unknown queue type"); + return queueManager.getGraphicsQueues().front(); // graphics is the most general queue + } + } + } + CommandStreamHandle Core::createCommandStream(QueueType queueType) { - const vkcv::Queue queue = getQueueForSubmit(queueType, m_Context.getQueueManager()); - const vk::CommandPool cmdPool = chooseCmdPool(queue, m_CommandResources); + const vkcv::Queue queue = getQueueForSubmit(queueType, m_Context.getQueueManager()); + const vk::CommandPool cmdPool = m_CommandPools[queue.familyIndex]; return m_CommandStreamManager->createCommandStream(queue.handle, cmdPool); } @@ -916,7 +984,7 @@ namespace vkcv // FIXME: add proper user controllable sync std::vector<vk::Semaphore> signalSemaphores; if (signalRendering) { - signalSemaphores.push_back(m_SyncResources.renderFinished); + signalSemaphores.push_back(m_RenderFinished); } m_CommandStreamManager->submitCommandStreamSynchronous(stream, waitSemaphores, signalSemaphores); diff --git a/src/vkcv/SyncResources.cpp b/src/vkcv/SyncResources.cpp deleted file mode 100644 index 8bd53c85e8cdede55d5b1db71d44bf483e24acb1..0000000000000000000000000000000000000000 --- a/src/vkcv/SyncResources.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "vkcv/SyncResources.hpp" - -namespace vkcv { - SyncResources createSyncResources(const vk::Device& device) { - SyncResources resources; - - const vk::SemaphoreCreateFlags semaphoreFlags = vk::SemaphoreCreateFlagBits(); - const vk::SemaphoreCreateInfo semaphoreInfo(semaphoreFlags); - resources.renderFinished = device.createSemaphore(semaphoreInfo, nullptr, {}); - resources.swapchainImageAcquired = device.createSemaphore(semaphoreInfo); - - resources.presentFinished = createFence(device); - - return resources; - } - - void destroySyncResources(const vk::Device& device, const SyncResources& resources) { - device.destroySemaphore(resources.renderFinished); - device.destroySemaphore(resources.swapchainImageAcquired); - device.destroyFence(resources.presentFinished); - } - - vk::Fence createFence(const vk::Device& device) { - const vk::FenceCreateFlags fenceFlags = vk::FenceCreateFlagBits(); - vk::FenceCreateInfo fenceInfo(fenceFlags); - return device.createFence(fenceInfo, nullptr, {}); - } - - void waitForFence(const vk::Device& device, const vk::Fence& fence) { - const auto result = device.waitForFences(fence, true, UINT64_MAX); - assert(result == vk::Result::eSuccess); - } -} \ No newline at end of file