From 96561f3e4f8b9647d78d1abab208b2cfa2d720f5 Mon Sep 17 00:00:00 2001
From: Sebastian Gaida <gaida@ca-digit.com>
Date: Tue, 18 May 2021 14:58:53 +0200
Subject: [PATCH] [#16] changed temp queueSetup

Changed the temp queueSetup and moved the core functions into QueueManager
---
 config/Sources.cmake          |   4 +-
 include/vkcv/Core.hpp         |   6 +-
 include/vkcv/QueueManager.hpp |  36 +++++++
 include/vkcv/Queues.hpp       |  27 -----
 src/vkcv/Core.cpp             | 187 ++++++---------------------------
 src/vkcv/QueueManager.cpp     | 189 ++++++++++++++++++++++++++++++++++
 src/vkcv/Queues.cpp           |  71 -------------
 7 files changed, 260 insertions(+), 260 deletions(-)
 create mode 100644 include/vkcv/QueueManager.hpp
 delete mode 100644 include/vkcv/Queues.hpp
 create mode 100644 src/vkcv/QueueManager.cpp
 delete mode 100644 src/vkcv/Queues.cpp

diff --git a/config/Sources.cmake b/config/Sources.cmake
index dce76b39..b8c2dcbd 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -37,8 +37,8 @@ set(vkcv_sources
         ${vkcv_include}/vkcv/SyncResources.hpp
         ${vkcv_source}/vkcv/SyncResources.cpp
         
-        ${vkcv_include}/vkcv/Queues.hpp
-        ${vkcv_source}/vkcv/Queues.cpp
+        ${vkcv_include}/vkcv/QueueManager.hpp
+        ${vkcv_source}/vkcv/QueueManager.cpp
         
         ${vkcv_source}/vkcv/Surface.hpp
         ${vkcv_source}/vkcv/Surface.cpp
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index b7b553d7..506e72f2 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -15,7 +15,7 @@
 #include "vkcv/PipelineConfig.hpp"
 #include "CommandResources.hpp"
 #include "SyncResources.hpp"
-#include "vkcv/Queues.hpp"
+#include "vkcv/QueueManager.hpp"
 
 namespace vkcv
 {
@@ -36,7 +36,7 @@ namespace vkcv
          * @param context encapsulates various Vulkan objects
          */
         Core(Context &&context, const Window &window, SwapChain swapChain,  std::vector<vk::ImageView> imageViews, 
-			const CommandResources& commandResources, const SyncResources& syncResources, const VulkanQueues &queues) noexcept;
+			const CommandResources& commandResources, const SyncResources& syncResources, const QueueManager &queues) noexcept;
         // explicit destruction of default constructor
         Core() = delete;
 
@@ -53,7 +53,7 @@ namespace vkcv
         std::unique_ptr<PipelineManager> m_PipelineManager;
 		CommandResources m_CommandResources;
 		SyncResources m_SyncResources;
-		VulkanQueues m_Queues;
+		QueueManager m_QueueManager;
 		uint32_t m_currentSwapchainImageIndex;
 		std::vector<vk::Framebuffer> m_TemporaryFramebuffers;
     public:
diff --git a/include/vkcv/QueueManager.hpp b/include/vkcv/QueueManager.hpp
new file mode 100644
index 00000000..1779fb66
--- /dev/null
+++ b/include/vkcv/QueueManager.hpp
@@ -0,0 +1,36 @@
+#pragma once
+#include <vulkan/vulkan.hpp>
+
+namespace vkcv {
+	class QueueManager {
+	public:
+		static QueueManager create(vk::Device device,
+                            std::vector<std::pair<int, int>> &queuePairsGraphics,
+                            std::vector<std::pair<int, int>> &queuePairsCompute,
+                            std::vector<std::pair<int, int>> &queuePairsTransfer);
+
+        const vk::Queue &getPresentQueue() const;
+
+		const std::vector<vk::Queue> &getGraphicsQueues() const;
+
+        const std::vector<vk::Queue> &getComputeQueues() const;
+
+        const std::vector<vk::Queue> &getTransferQueues() const;
+
+        static void queueCreateInfosQueueHandles(vk::PhysicalDevice &physicalDevice,
+                std::vector<float> &queuePriorities,
+                std::vector<vk::QueueFlagBits> &queueFlags,
+                std::vector<vk::DeviceQueueCreateInfo> &queueCreateInfos,
+                std::vector<std::pair<int, int>> &queuePairsGraphics,
+                std::vector<std::pair<int, int>> &queuePairsCompute,
+                std::vector<std::pair<int, int>> &queuePairsTransfer);
+
+    private:
+        vk::Queue m_presentQueue;
+        std::vector<vk::Queue> m_graphicsQueues;
+        std::vector<vk::Queue> m_computeQueues;
+        std::vector<vk::Queue> m_transferQueues;
+
+        QueueManager(std::vector<vk::Queue> graphicsQueues, std::vector<vk::Queue> computeQueues, std::vector<vk::Queue> transferQueues, vk::Queue presentQueue);
+	};
+}
diff --git a/include/vkcv/Queues.hpp b/include/vkcv/Queues.hpp
deleted file mode 100644
index c1cca709..00000000
--- a/include/vkcv/Queues.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-#include <vulkan/vulkan.hpp>
-
-namespace vkcv {
-	struct VulkanQueues {
-		vk::Queue graphicsQueue;
-		vk::Queue computeQueue;
-		vk::Queue transferQueue;
-		vk::Queue presentQueue;
-	};
-
-	struct QueueFamilyIndices {
-		int graphicsIndex = -1;
-		int computeIndex = -1;
-		int transferIndex = -1;
-		int presentIndex = -1;
-	};
-
-	VulkanQueues getDeviceQueues(const vk::Device& device, const QueueFamilyIndices& familyIndices);
-
-	QueueFamilyIndices getQueueFamilyIndices(const vk::PhysicalDevice& physicalDevice, const vk::SurfaceKHR surface);
-
-	// TODO: try to use specialised queues
-	std::vector<vk::DeviceQueueCreateInfo> createDeviceQueueCreateInfo(const QueueFamilyIndices& indices, 
-		std::vector<float> *outQueuePriorities);
-
-}
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 9cc5da70..7e6d87ca 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -82,141 +82,6 @@ namespace vkcv
         return phyDevice;
     }
 
-
-    /**
-     * Given the @p physicalDevice and the @p queuePriorities, the @p queueCreateInfos are computed. First, the requested
-     * queues are sorted by priority depending on the availability of queues in the queue families of the given
-     * @p physicalDevice. Then check, if all requested queues are creatable. If so, the @p queueCreateInfos will be computed.
-     * Furthermore, lists of index pairs (queueFamilyIndex, queueIndex) for later referencing of the separate queues will
-     * be computed.
-     * @param[in] physicalDevice The physical device
-     * @param[in] queuePriorities The queue priorities used for the computation of @p queueCreateInfos
-     * @param[in] queueFlags The queue flags requesting the queues
-     * @param[in,out] queueCreateInfos The queue create info structures to be created
-     * @param[in,out] queuePairsGraphics The list of index pairs (queueFamilyIndex, queueIndex) of queues of type
-     *      vk::QueueFlagBits::eGraphics
-     * @param[in,out] queuePairsCompute The list of index pairs (queueFamilyIndex, queueIndex) of queues of type
-     *      vk::QueueFlagBits::eCompute
-     * @param[in,out] queuePairsTransfer The list of index pairs (queueFamilyIndex, queueIndex) of queues of type
-     *      vk::QueueFlagBits::eTransfer
-     * @throws std::runtime_error If the requested queues from @p queueFlags are not creatable due to insufficient availability.
-     */
-    void queueCreateInfosQueueHandles(vk::PhysicalDevice &physicalDevice,
-                                                           std::vector<float> &queuePriorities,
-                                                           std::vector<vk::QueueFlagBits> &queueFlags,
-                                                           std::vector<vk::DeviceQueueCreateInfo> &queueCreateInfos,
-                                                           std::vector<std::pair<int, int>> &queuePairsGraphics,
-                                                           std::vector<std::pair<int, int>> &queuePairsCompute,
-                                                           std::vector<std::pair<int, int>> &queuePairsTransfer)
-    {
-        queueCreateInfos = {};
-        queuePairsGraphics = {};
-        queuePairsCompute = {};
-        queuePairsTransfer = {};
-        std::vector<vk::QueueFamilyProperties> qFamilyProperties = physicalDevice.getQueueFamilyProperties();
-
-        //check priorities of flags -> the lower prioCount the higher the priority
-        std::vector<int> prios;
-        for(auto flag: queueFlags){
-            int prioCount = 0;
-            for (int i = 0; i < qFamilyProperties.size(); i++) {
-                prioCount += (static_cast<uint32_t>(flag & qFamilyProperties[i].queueFlags) != 0) * qFamilyProperties[i].queueCount;
-            }
-            prios.push_back(prioCount);
-        }
-        //resort flags with heighest priority before allocating the queues
-        std::vector<vk::QueueFlagBits> newFlags;
-        for(int i = 0; i < prios.size(); i++){
-            auto minElem = std::min_element(prios.begin(), prios.end());
-            int index = minElem - prios.begin();
-            newFlags.push_back(queueFlags[index]);
-            prios[index] = std::numeric_limits<int>::max();
-        }
-
-        // create requested queues and check if more requested queues are supported
-        // herefore: create vector that updates available queues in each queue family
-        // structure: [qFamily_0, ..., qFamily_n] where
-        // - qFamily_i = [GraphicsCount, ComputeCount, TransferCount], 0 <= i <= n
-        std::vector<std::vector<int>> queueFamilyStatus, initialQueueFamilyStatus;
-
-        for (auto qFamily : qFamilyProperties) {
-            int graphicsCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0) * qFamily.queueCount;
-            int computeCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0) * qFamily.queueCount;
-            int transferCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0) * qFamily.queueCount;
-            queueFamilyStatus.push_back({graphicsCount, computeCount, transferCount});
-        }
-
-        initialQueueFamilyStatus = queueFamilyStatus;
-        // check if every queue with the specified queue flag can be created
-        // this automatically checks for queue flag support!
-        for (auto qFlag : newFlags) {
-            bool found;
-            switch (qFlag) {
-                case vk::QueueFlagBits::eGraphics:
-                    found = false;
-                    for (int i = 0; i < queueFamilyStatus.size() && !found; i++) {
-                        if (queueFamilyStatus[i][0] > 0) {
-                            queuePairsGraphics.push_back(std::pair(i, initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0]));
-                            queueFamilyStatus[i][0]--;
-                            queueFamilyStatus[i][1]--;
-                            queueFamilyStatus[i][2]--;
-                            found = true;
-                        }
-                    }
-                    if (!found) {
-                        throw std::runtime_error("Too many graphics queues were requested than being available!");
-                    }
-                    break;
-                case vk::QueueFlagBits::eCompute:
-                    found = false;
-                    for (int i = 0; i < queueFamilyStatus.size() && !found; i++) {
-                        if (queueFamilyStatus[i][1] > 0) {
-                            queuePairsCompute.push_back(std::pair(i, initialQueueFamilyStatus[i][1] - queueFamilyStatus[i][1]));
-                            queueFamilyStatus[i][0]--;
-                            queueFamilyStatus[i][1]--;
-                            queueFamilyStatus[i][2]--;
-                            found = true;
-                        }
-                    }
-                    if (!found) {
-                        throw std::runtime_error("Too many compute queues were requested than being available!");
-                    }
-                    break;
-                case vk::QueueFlagBits::eTransfer:
-                    found = false;
-                    for (int i = 0; i < queueFamilyStatus.size() && !found; i++) {
-                        if (queueFamilyStatus[i][2] > 0) {
-                            queuePairsTransfer.push_back(std::pair(i, initialQueueFamilyStatus[i][2] - queueFamilyStatus[i][2]));
-                            queueFamilyStatus[i][0]--;
-                            queueFamilyStatus[i][1]--;
-                            queueFamilyStatus[i][2]--;
-                            found = true;
-                        }
-                    }
-                    if (!found) {
-                        throw std::runtime_error("Too many transfer queues were requested than being available!");
-                    }
-                    break;
-                default:
-                    throw std::runtime_error("Invalid input for queue flag bits. Valid inputs are 'vk::QueueFlagBits::eGraphics', 'vk::QueueFlagBits::eCompute' and 'vk::QueueFlagBits::eTransfer'.");
-            }
-        }
-
-        // create all requested queues
-        for (int i = 0; i < qFamilyProperties.size(); i++) {
-            uint32_t create = std::abs(initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0]);
-            if (create > 0) {
-                vk::DeviceQueueCreateInfo qCreateInfo(
-                        vk::DeviceQueueCreateFlags(),
-                        i,
-                        create,
-                        queuePriorities.data()
-                );
-                queueCreateInfos.push_back(qCreateInfo);
-            }
-        }
-    }
-
     /**
      * @brief With the help of the reference "supported" all elements in "check" checked,
      * if they are supported by the physical device.
@@ -338,9 +203,13 @@ namespace vkcv
         }
 
 		const vk::SurfaceKHR surface = createSurface(window.getWindow(), instance, physicalDevice);
-		const QueueFamilyIndices queueFamilyIndices = getQueueFamilyIndices(physicalDevice, surface);
-		std::vector<float> queuePriorities;
-		const std::vector<vk::DeviceQueueCreateInfo> qCreateInfos = createDeviceQueueCreateInfo(queueFamilyIndices, &queuePriorities);
+		std::vector<vk::DeviceQueueCreateInfo> qCreateInfos;
+
+        // create required queues
+        std::vector<float> qPriorities;
+        qPriorities.resize(queueFlags.size(), 1.f);
+        std::vector<std::pair<int, int>> queuePairsGraphics, queuePairsCompute, queuePairsTransfer;
+        QueueManager::queueCreateInfosQueueHandles(physicalDevice, qPriorities, queueFlags, qCreateInfos, queuePairsGraphics, queuePairsCompute, queuePairsTransfer);
 
 		vk::DeviceCreateInfo deviceCreateInfo(
 			vk::DeviceCreateFlags(),
@@ -353,17 +222,21 @@ namespace vkcv
 			nullptr		// Should our device use some features??? If yes: TODO
 		);
 
-
-
 #ifndef NDEBUG
         deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
         deviceCreateInfo.ppEnabledLayerNames = validationLayers.data();
 #endif
 
+        // Ablauf
+        // qCreateInfos erstellen --> braucht das Device
+        // device erstellen
+        // jetzt koennen wir mit dem device die queues erstellen
+
         vk::Device device = physicalDevice.createDevice(deviceCreateInfo);
-        Context context(instance, physicalDevice, device);
 
-		const VulkanQueues queues = getDeviceQueues(device, queueFamilyIndices);
+        QueueManager queueManager = QueueManager::create(device, queuePairsGraphics, queuePairsCompute, queuePairsTransfer);
+
+        Context context (instance, physicalDevice, device);
 
         SwapChain swapChain = SwapChain::create(window, context, surface);
 
@@ -390,14 +263,14 @@ namespace vkcv
                     subResourceRange
             );
 
-            imageViews.push_back( device.createImageView( imageViewCreateInfo ) );
+            imageViews.push_back( device.createImageView( imageViewCreateInfo ));
         }
 
-		const int graphicQueueFamilyIndex = queueFamilyIndices.graphicsIndex;
+		const int graphicQueueFamilyIndex = queuePairsGraphics[0].first;
 		const auto defaultCommandResources = createDefaultCommandResources(context.getDevice(), graphicQueueFamilyIndex);
 		const auto defaultSyncResources = createDefaultSyncResources(context.getDevice());
 
-        return Core(std::move(context) , window, swapChain, imageViews, defaultCommandResources, defaultSyncResources, queues);
+        return Core(std::move(context) , window, swapChain, imageViews, defaultCommandResources, defaultSyncResources, queueManager);
     }
 
     const Context &Core::getContext() const
@@ -406,16 +279,16 @@ namespace vkcv
     }
 
 	Core::Core(Context &&context, const Window &window , SwapChain swapChain,  std::vector<vk::ImageView> imageViews, 
-		const CommandResources& commandResources, const SyncResources& syncResources, const VulkanQueues& queues) noexcept :
-			m_Context(std::move(context)),
-			m_window(window),
-			m_swapchain(swapChain),
-			m_swapchainImageViews(imageViews),
-			m_PassManager{std::make_unique<PassManager>(m_Context.m_Device)},
-			m_PipelineManager{std::make_unique<PipelineManager>(m_Context.m_Device)},
-			m_CommandResources(commandResources),
-			m_SyncResources(syncResources),
-			m_Queues(queues)
+		const CommandResources& commandResources, const SyncResources& syncResources, const QueueManager& queueManager) noexcept :
+            m_Context(std::move(context)),
+            m_window(window),
+            m_swapchain(swapChain),
+            m_swapchainImageViews(imageViews),
+            m_PassManager{std::make_unique<PassManager>(m_Context.m_Device)},
+            m_PipelineManager{std::make_unique<PipelineManager>(m_Context.m_Device)},
+            m_CommandResources(commandResources),
+            m_SyncResources(syncResources),
+            m_QueueManager(queueManager)
 	{}
 
 	Core::~Core() noexcept {
@@ -515,13 +388,13 @@ namespace vkcv
 		m_CommandResources.commandBuffer.end();
 		
 		const vk::SubmitInfo submitInfo(0, nullptr, 0, 1, &(m_CommandResources.commandBuffer), 1, &m_SyncResources.renderFinished);
-		m_Queues.graphicsQueue.submit(submitInfo);
+		m_QueueManager.getGraphicsQueues()[0].submit(submitInfo);
 
 		vk::Result presentResult;
 		const vk::SwapchainKHR& swapchain = m_swapchain.getSwapchain();
 		const vk::PresentInfoKHR presentInfo(1, &m_SyncResources.renderFinished, 1, &swapchain, 
 			&m_currentSwapchainImageIndex, &presentResult);
-		m_Queues.presentQueue.presentKHR(presentInfo);
+        m_QueueManager.getPresentQueue().presentKHR(presentInfo);
 		if (presentResult != vk::Result::eSuccess) {
 			std::cout << "Error: swapchain present failed" << std::endl;
 		}
diff --git a/src/vkcv/QueueManager.cpp b/src/vkcv/QueueManager.cpp
new file mode 100644
index 00000000..c6c9dda4
--- /dev/null
+++ b/src/vkcv/QueueManager.cpp
@@ -0,0 +1,189 @@
+#include "vkcv/QueueManager.hpp"
+#include <unordered_set>
+
+namespace vkcv {
+
+    /**
+     * Given the @p physicalDevice and the @p queuePriorities, the @p queueCreateInfos are computed. First, the requested
+     * queues are sorted by priority depending on the availability of queues in the queue families of the given
+     * @p physicalDevice. Then check, if all requested queues are creatable. If so, the @p queueCreateInfos will be computed.
+     * Furthermore, lists of index pairs (queueFamilyIndex, queueIndex) for later referencing of the separate queues will
+     * be computed.
+     * @param[in] physicalDevice The physical device
+     * @param[in] queuePriorities The queue priorities used for the computation of @p queueCreateInfos
+     * @param[in] queueFlags The queue flags requesting the queues
+     * @param[in,out] queueCreateInfos The queue create info structures to be created
+     * @param[in,out] queuePairsGraphics The list of index pairs (queueFamilyIndex, queueIndex) of queues of type
+     *      vk::QueueFlagBits::eGraphics
+     * @param[in,out] queuePairsCompute The list of index pairs (queueFamilyIndex, queueIndex) of queues of type
+     *      vk::QueueFlagBits::eCompute
+     * @param[in,out] queuePairsTransfer The list of index pairs (queueFamilyIndex, queueIndex) of queues of type
+     *      vk::QueueFlagBits::eTransfer
+     * @throws std::runtime_error If the requested queues from @p queueFlags are not creatable due to insufficient availability.
+     */
+    void QueueManager::queueCreateInfosQueueHandles(vk::PhysicalDevice &physicalDevice,
+                                      std::vector<float> &queuePriorities,
+                                      std::vector<vk::QueueFlagBits> &queueFlags,
+                                      std::vector<vk::DeviceQueueCreateInfo> &queueCreateInfos,
+                                      std::vector<std::pair<int, int>> &queuePairsGraphics,
+                                      std::vector<std::pair<int, int>> &queuePairsCompute,
+                                      std::vector<std::pair<int, int>> &queuePairsTransfer)
+    {
+        queueCreateInfos = {};
+        queuePairsGraphics = {};
+        queuePairsCompute = {};
+        queuePairsTransfer = {};
+        std::vector<vk::QueueFamilyProperties> qFamilyProperties = physicalDevice.getQueueFamilyProperties();
+
+        //check priorities of flags -> the lower prioCount the higher the priority
+        std::vector<int> prios;
+        for(auto flag: queueFlags) {
+            int prioCount = 0;
+            for (int i = 0; i < qFamilyProperties.size(); i++) {
+                prioCount += (static_cast<uint32_t>(flag & qFamilyProperties[i].queueFlags) != 0) * qFamilyProperties[i].queueCount;
+            }
+            prios.push_back(prioCount);
+        }
+        //resort flags with heighest priority before allocating the queues
+        std::vector<vk::QueueFlagBits> newFlags;
+        for(int i = 0; i < prios.size(); i++) {
+            auto minElem = std::min_element(prios.begin(), prios.end());
+            int index = minElem - prios.begin();
+            newFlags.push_back(queueFlags[index]);
+            prios[index] = std::numeric_limits<int>::max();
+        }
+
+        // create requested queues and check if more requested queues are supported
+        // herefore: create vector that updates available queues in each queue family
+        // structure: [qFamily_0, ..., qFamily_n] where
+        // - qFamily_i = [GraphicsCount, ComputeCount, TransferCount], 0 <= i <= n
+        std::vector<std::vector<int>> queueFamilyStatus, initialQueueFamilyStatus;
+
+        for (auto qFamily : qFamilyProperties) {
+            int graphicsCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0) * qFamily.queueCount;
+            int computeCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0) * qFamily.queueCount;
+            int transferCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0) * qFamily.queueCount;
+            queueFamilyStatus.push_back({graphicsCount, computeCount, transferCount});
+        }
+
+        initialQueueFamilyStatus = queueFamilyStatus;
+        // check if every queue with the specified queue flag can be created
+        // this automatically checks for queue flag support!
+        for (auto qFlag : newFlags) {
+            bool found;
+            switch (qFlag) {
+                case vk::QueueFlagBits::eGraphics:
+                    found = false;
+                    for (int i = 0; i < queueFamilyStatus.size() && !found; i++) {
+                        if (queueFamilyStatus[i][0] > 0) {
+                            queuePairsGraphics.push_back(std::pair(i, initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0]));
+                            queueFamilyStatus[i][0]--;
+                            queueFamilyStatus[i][1]--;
+                            queueFamilyStatus[i][2]--;
+                            found = true;
+                        }
+                    }
+                    if (!found) {
+                        throw std::runtime_error("Too many graphics queues were requested than being available!");
+                    }
+                    break;
+                case vk::QueueFlagBits::eCompute:
+                    found = false;
+                    for (int i = 0; i < queueFamilyStatus.size() && !found; i++) {
+                        if (queueFamilyStatus[i][1] > 0) {
+                            queuePairsCompute.push_back(std::pair(i, initialQueueFamilyStatus[i][1] - queueFamilyStatus[i][1]));
+                            queueFamilyStatus[i][0]--;
+                            queueFamilyStatus[i][1]--;
+                            queueFamilyStatus[i][2]--;
+                            found = true;
+                        }
+                    }
+                    if (!found) {
+                        throw std::runtime_error("Too many compute queues were requested than being available!");
+                    }
+                    break;
+                case vk::QueueFlagBits::eTransfer:
+                    found = false;
+                    for (int i = 0; i < queueFamilyStatus.size() && !found; i++) {
+                        if (queueFamilyStatus[i][2] > 0) {
+                            queuePairsTransfer.push_back(std::pair(i, initialQueueFamilyStatus[i][2] - queueFamilyStatus[i][2]));
+                            queueFamilyStatus[i][0]--;
+                            queueFamilyStatus[i][1]--;
+                            queueFamilyStatus[i][2]--;
+                            found = true;
+                        }
+                    }
+                    if (!found) {
+                        throw std::runtime_error("Too many transfer queues were requested than being available!");
+                    }
+                    break;
+                default:
+                    throw std::runtime_error("Invalid input for queue flag bits. Valid inputs are 'vk::QueueFlagBits::eGraphics', 'vk::QueueFlagBits::eCompute' and 'vk::QueueFlagBits::eTransfer'.");
+            }
+        }
+
+        // create all requested queues
+        for (int i = 0; i < qFamilyProperties.size(); i++) {
+            uint32_t create = std::abs(initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0]);
+            if (create > 0) {
+                vk::DeviceQueueCreateInfo qCreateInfo(
+                        vk::DeviceQueueCreateFlags(),
+                        i,
+                        create,
+                        queuePriorities.data()
+                );
+                queueCreateInfos.push_back(qCreateInfo);
+            }
+        }
+    }
+
+    /**
+     * Computes the queue handles from @p queuePairs
+     * @param device The device
+     * @param queuePairs The queuePairs that were created separately for each queue type (e.g., vk::QueueFlagBits::eGraphics)
+     * @return An array of queue handles based on the @p queuePairs
+     */
+    std::vector<vk::Queue> getQueueHandles(const vk::Device device, const std::vector<std::pair<int, int>> queuePairs) {
+        std::vector<vk::Queue> queueHandles;
+        for (auto q : queuePairs) {
+            int queueFamilyIndex = q.first; // the queueIndex of the queue family
+            int queueIndex = q.second;   // the queueIndex within a queue family
+            queueHandles.push_back(device.getQueue(queueFamilyIndex, queueIndex));
+        }
+        return queueHandles;
+    }
+
+
+    QueueManager QueueManager::create(vk::Device device,
+                                      std::vector<std::pair<int, int>> &queuePairsGraphics,
+                                      std::vector<std::pair<int, int>> &queuePairsCompute,
+                                      std::vector<std::pair<int, int>> &queuePairsTransfer) {
+
+        std::vector<vk::Queue> graphicsQueues = getQueueHandles(device, queuePairsGraphics);
+        std::vector<vk::Queue> computeQueues = getQueueHandles(device, queuePairsCompute );
+        std::vector<vk::Queue> transferQueues = getQueueHandles(device, queuePairsTransfer);
+
+    return QueueManager( graphicsQueues, computeQueues, transferQueues, graphicsQueues[0]);
+	}
+
+	QueueManager::QueueManager(std::vector<vk::Queue> graphicsQueues, std::vector<vk::Queue> computeQueues, std::vector<vk::Queue> transferQueues,  vk::Queue presentQueue)
+	: m_graphicsQueues(graphicsQueues), m_computeQueues(computeQueues), m_transferQueues(transferQueues), m_presentQueue(presentQueue)
+    {}
+
+    const vk::Queue &QueueManager::getPresentQueue() const {
+        return m_presentQueue;
+    }
+
+    const std::vector<vk::Queue> &QueueManager::getGraphicsQueues() const {
+        return m_graphicsQueues;
+    }
+
+    const std::vector<vk::Queue> &QueueManager::getComputeQueues() const {
+        return m_computeQueues;
+    }
+
+    const std::vector<vk::Queue> &QueueManager::getTransferQueues() const {
+        return m_transferQueues;
+    }
+
+}
\ No newline at end of file
diff --git a/src/vkcv/Queues.cpp b/src/vkcv/Queues.cpp
deleted file mode 100644
index 49e992ff..00000000
--- a/src/vkcv/Queues.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#include "vkcv/Queues.hpp"
-#include <unordered_set>
-
-namespace vkcv {
-
-	VulkanQueues getDeviceQueues(const vk::Device& device, const QueueFamilyIndices& familyIndices) {
-		VulkanQueues queues;
-		queues.graphicsQueue = device.getQueue(familyIndices.graphicsIndex, 0);
-		queues.computeQueue = device.getQueue(familyIndices.computeIndex, 0);
-		queues.transferQueue = device.getQueue(familyIndices.transferIndex, 0);
-		queues.presentQueue = device.getQueue(familyIndices.presentIndex, 0);
-		return queues;
-	}
-
-	QueueFamilyIndices getQueueFamilyIndices(const vk::PhysicalDevice& physicalDevice, const vk::SurfaceKHR surface) {
-		const std::vector<vk::QueueFamilyProperties> familyProps = physicalDevice.getQueueFamilyProperties();
-
-		QueueFamilyIndices indices;
-
-		for (int i = 0; i < familyProps.size(); i++) {
-			const auto& property = familyProps[i];
-
-			const bool hasQueues = property.queueCount >= 1;
-			if (!hasQueues) {
-				continue;
-			}
-
-			if (property.queueFlags & vk::QueueFlagBits::eGraphics) {
-				indices.graphicsIndex = i;
-			}
-			if (property.queueFlags & vk::QueueFlagBits::eCompute) {
-				indices.computeIndex = i;
-			}
-			if (property.queueFlags & vk::QueueFlagBits::eTransfer) {
-				indices.transferIndex = i;
-			}
-			if (physicalDevice.getSurfaceSupportKHR(i, surface)) {
-				indices.presentIndex = i;
-			}
-		}
-		assert(indices.graphicsIndex != -1);
-		assert(indices.computeIndex  != -1);
-		assert(indices.transferIndex != -1);
-		assert(indices.presentIndex  != -1);
-		return indices;
-	}
-
-	std::vector<vk::DeviceQueueCreateInfo> createDeviceQueueCreateInfo(const QueueFamilyIndices& indices,
-		std::vector<float>* outQueuePriorities) {
-
-		// use set to avoid duplicate queues
-		std::unordered_set<int> familyIndexSet;
-		familyIndexSet.insert(indices.graphicsIndex);
-		familyIndexSet.insert(indices.computeIndex);
-		familyIndexSet.insert(indices.transferIndex);
-		familyIndexSet.insert(indices.presentIndex);
-
-		const vk::DeviceQueueCreateFlagBits flags = {};
-		std::vector<vk::DeviceQueueCreateInfo> createInfos;
-
-		outQueuePriorities->resize(familyIndexSet.size(), 1.f);
-		int priorityIndex = 0;
-
-		for (const auto index : familyIndexSet) {
-			const vk::DeviceQueueCreateInfo graphicsCreateInfo(flags, index, 1, &outQueuePriorities->at(priorityIndex));
-			createInfos.push_back(graphicsCreateInfo);
-			priorityIndex++;
-		}
-		return createInfos;
-	}
-}
\ No newline at end of file
-- 
GitLab