From 1807c1a798d344652c19e2d910e5841f0c54d342 Mon Sep 17 00:00:00 2001
From: Tobias Frisch <tfrisch@uni-koblenz.de>
Date: Tue, 18 May 2021 16:21:47 +0200
Subject: [PATCH] Refactored context and core in structure

Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de>
---
 include/vkcv/Context.hpp      |  17 ++-
 include/vkcv/Core.hpp         |   4 +-
 include/vkcv/QueueManager.hpp |  37 +++--
 src/vkcv/Context.cpp          | 241 ++++++++++++++++++++++++++++++++-
 src/vkcv/Core.cpp             | 247 ++++------------------------------
 src/vkcv/QueueManager.cpp     |  42 +++---
 6 files changed, 327 insertions(+), 261 deletions(-)

diff --git a/include/vkcv/Context.hpp b/include/vkcv/Context.hpp
index 1352ce0c..1c01a613 100644
--- a/include/vkcv/Context.hpp
+++ b/include/vkcv/Context.hpp
@@ -2,6 +2,8 @@
 
 #include <vulkan/vulkan.hpp>
 
+#include "QueueManager.hpp"
+
 namespace vkcv
 {
     class Context
@@ -21,10 +23,21 @@ namespace vkcv
 
         [[nodiscard]]
         const vk::Instance &getInstance() const;
+        
         [[nodiscard]]
         const vk::PhysicalDevice &getPhysicalDevice() const;
+        
         [[nodiscard]]
         const vk::Device &getDevice() const;
+        
+        [[nodiscard]]
+        const QueueManager& getQueueManager() const;
+        
+        static Context create(const char *applicationName,
+							  uint32_t applicationVersion,
+							  std::vector<vk::QueueFlagBits> queueFlags,
+							  std::vector<const char *> instanceExtensions,
+							  std::vector<const char *> deviceExtensions);
 
     private:
         /**
@@ -34,9 +47,11 @@ namespace vkcv
          * @param physicalDevice Vulkan-PhysicalDevice
          * @param device Vulkan-Device
          */
-        Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device) noexcept;
+        Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device, QueueManager&& queueManager) noexcept;
+        
         vk::Instance        m_Instance;
         vk::PhysicalDevice  m_PhysicalDevice;
         vk::Device          m_Device;
+		QueueManager		m_QueueManager;
     };
 }
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 506e72f2..6d48e89b 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -15,7 +15,6 @@
 #include "vkcv/PipelineConfig.hpp"
 #include "CommandResources.hpp"
 #include "SyncResources.hpp"
-#include "vkcv/QueueManager.hpp"
 
 namespace vkcv
 {
@@ -36,7 +35,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 QueueManager &queues) noexcept;
+			const CommandResources& commandResources, const SyncResources& syncResources) noexcept;
         // explicit destruction of default constructor
         Core() = delete;
 
@@ -53,7 +52,6 @@ namespace vkcv
         std::unique_ptr<PipelineManager> m_PipelineManager;
 		CommandResources m_CommandResources;
 		SyncResources m_SyncResources;
-		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
index 1779fb66..9dc5fa16 100644
--- a/include/vkcv/QueueManager.hpp
+++ b/include/vkcv/QueueManager.hpp
@@ -2,6 +2,14 @@
 #include <vulkan/vulkan.hpp>
 
 namespace vkcv {
+	
+	struct Queue {
+		int familyIndex;
+		int queueIndex;
+		
+		vk::Queue handle;
+	};
+	
 	class QueueManager {
 	public:
 		static QueueManager create(vk::Device device,
@@ -9,13 +17,17 @@ namespace vkcv {
                             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;
+        [[nodiscard]]
+        const Queue &getPresentQueue() const;
+		
+		[[nodiscard]]
+		const std::vector<Queue> &getGraphicsQueues() const;
+		
+		[[nodiscard]]
+        const std::vector<Queue> &getComputeQueues() const;
+		
+		[[nodiscard]]
+        const std::vector<Queue> &getTransferQueues() const;
 
         static void queueCreateInfosQueueHandles(vk::PhysicalDevice &physicalDevice,
                 std::vector<float> &queuePriorities,
@@ -26,11 +38,12 @@ namespace vkcv {
                 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;
+        std::vector<Queue> m_graphicsQueues;
+        std::vector<Queue> m_computeQueues;
+        std::vector<Queue> m_transferQueues;
+		
+		size_t m_presentIndex;
 
-        QueueManager(std::vector<vk::Queue> graphicsQueues, std::vector<vk::Queue> computeQueues, std::vector<vk::Queue> transferQueues, vk::Queue presentQueue);
+        QueueManager(std::vector<Queue>&& graphicsQueues, std::vector<Queue>&& computeQueues, std::vector<Queue>&& transferQueues, size_t presentIndex);
 	};
 }
diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp
index d5261285..b53a1a2c 100644
--- a/src/vkcv/Context.cpp
+++ b/src/vkcv/Context.cpp
@@ -1,3 +1,6 @@
+
+#include <GLFW/glfw3.h>
+
 #include "vkcv/Context.hpp"
 
 namespace vkcv
@@ -5,7 +8,8 @@ namespace vkcv
     Context::Context(Context &&other) noexcept:
             m_Instance(other.m_Instance),
             m_PhysicalDevice(other.m_PhysicalDevice),
-            m_Device(other.m_Device)
+            m_Device(other.m_Device),
+            m_QueueManager(other.m_QueueManager)
     {
         other.m_Instance        = nullptr;
         other.m_PhysicalDevice  = nullptr;
@@ -17,6 +21,7 @@ namespace vkcv
         m_Instance          = other.m_Instance;
         m_PhysicalDevice    = other.m_PhysicalDevice;
         m_Device            = other.m_Device;
+        m_QueueManager		= other.m_QueueManager;
 
         other.m_Instance        = nullptr;
         other.m_PhysicalDevice  = nullptr;
@@ -27,10 +32,12 @@ namespace vkcv
 
     Context::Context(vk::Instance instance,
                      vk::PhysicalDevice physicalDevice,
-                     vk::Device device) noexcept :
+                     vk::Device device,
+					 QueueManager&& queueManager) noexcept :
     m_Instance{instance},
     m_PhysicalDevice{physicalDevice},
-    m_Device{device}
+    m_Device{device},
+    m_QueueManager{queueManager}
     {}
 
     Context::~Context() noexcept
@@ -53,4 +60,232 @@ namespace vkcv
     {
         return m_Device;
     }
+    
+    const QueueManager& Context::getQueueManager() const {
+    	return m_QueueManager;
+    }
+	
+	/**
+	 * @brief The physical device is evaluated by three categories:
+	 * discrete GPU vs. integrated GPU, amount of queues and its abilities, and VRAM.physicalDevice.
+	 * @param physicalDevice The physical device
+	 * @return Device score as integer
+	*/
+	int deviceScore(const vk::PhysicalDevice& physicalDevice)
+	{
+		int score = 0;
+		vk::PhysicalDeviceProperties properties = physicalDevice.getProperties();
+		std::vector<vk::QueueFamilyProperties> qFamilyProperties = physicalDevice.getQueueFamilyProperties();
+		
+		// for every queue family compute queue flag bits and the amount of queues
+		for (const auto& qFamily : qFamilyProperties) {
+			uint32_t qCount = qFamily.queueCount;
+			uint32_t bitCount = (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0)
+								+ (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0)
+								+ (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0)
+								+ (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eSparseBinding) != 0);
+			score += static_cast<int>(qCount * bitCount);
+		}
+		
+		// compute the VRAM of the physical device
+		vk::PhysicalDeviceMemoryProperties memoryProperties = physicalDevice.getMemoryProperties();
+		auto vram = static_cast<int>(memoryProperties.memoryHeaps[0].size / static_cast<uint32_t>(1E9));
+		score *= vram;
+		
+		if (properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) {
+			score *= 2;
+		}
+		else if (properties.deviceType != vk::PhysicalDeviceType::eIntegratedGpu) {
+			score = -1;
+		}
+		
+		return score;
+	}
+	
+	/**
+	 * @brief All existing physical devices will be evaluated by deviceScore.
+	 * @param instance The instance
+	 * @return The optimal physical device
+	 * @see Context.deviceScore
+	*/
+	vk::PhysicalDevice pickPhysicalDevice(vk::Instance& instance)
+	{
+		vk::PhysicalDevice phyDevice;
+		std::vector<vk::PhysicalDevice> devices = instance.enumeratePhysicalDevices();
+		
+		if (devices.empty()) {
+			throw std::runtime_error("failed to find GPUs with Vulkan support!");
+		}
+		
+		int max_score = -1;
+		for (const auto& device : devices) {
+			int score = deviceScore(device);
+			if (score > max_score) {
+				max_score = score;
+				phyDevice = device;
+			}
+		}
+		
+		if (max_score == -1) {
+			throw std::runtime_error("failed to find a suitable GPU!");
+		}
+		
+		return phyDevice;
+	}
+	
+	/**
+	 * @brief With the help of the reference "supported" all elements in "check" checked,
+	 * if they are supported by the physical device.
+	 * @param supported The reference that can be used to check "check"
+	 * @param check The elements to be checked
+	 * @return True, if all elements in "check" are supported
+	*/
+	bool checkSupport(std::vector<const char*>& supported, std::vector<const char*>& check)
+	{
+		for (auto checkElem : check) {
+			bool found = false;
+			for (auto supportedElem : supported) {
+				if (strcmp(supportedElem, checkElem) == 0) {
+					found = true;
+					break;
+				}
+			}
+			if (!found)
+				return false;
+		}
+		return true;
+	}
+	
+	
+	std::vector<const char*> getRequiredExtensions() {
+		uint32_t glfwExtensionCount = 0;
+		const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
+		std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
+
+#ifndef NDEBUG
+		extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+#endif
+		
+		return extensions;
+	}
+	
+	Context Context::create(const char *applicationName,
+							uint32_t applicationVersion,
+							std::vector<vk::QueueFlagBits> queueFlags,
+							std::vector<const char *> instanceExtensions,
+							std::vector<const char *> deviceExtensions) {
+		// check for layer support
+		
+		const std::vector<vk::LayerProperties>& layerProperties = vk::enumerateInstanceLayerProperties();
+		
+		std::vector<const char*> supportedLayers;
+		supportedLayers.reserve(layerProperties.size());
+		
+		for (auto& elem : layerProperties) {
+			supportedLayers.push_back(elem.layerName);
+		}
+
+// if in debug mode, check if validation layers are supported. Enable them if supported
+#ifndef NDEBUG
+		std::vector<const char*> validationLayers = {
+				"VK_LAYER_KHRONOS_validation"
+		};
+		
+		if (!checkSupport(supportedLayers, validationLayers)) {
+			throw std::runtime_error("Validation layers requested but not available!");
+		}
+#endif
+		
+		// check for extension support
+		std::vector<vk::ExtensionProperties> instanceExtensionProperties = vk::enumerateInstanceExtensionProperties();
+		
+		std::vector<const char*> supportedExtensions;
+		supportedExtensions.reserve(instanceExtensionProperties.size());
+		
+		for (auto& elem : instanceExtensionProperties) {
+			supportedExtensions.push_back(elem.extensionName);
+		}
+		
+		if (!checkSupport(supportedExtensions, instanceExtensions)) {
+			throw std::runtime_error("The requested instance extensions are not supported!");
+		}
+		
+		// for GLFW: get all required extensions
+		std::vector<const char*> requiredExtensions = getRequiredExtensions();
+		instanceExtensions.insert(instanceExtensions.end(), requiredExtensions.begin(), requiredExtensions.end());
+		
+		const vk::ApplicationInfo applicationInfo(
+				applicationName,
+				applicationVersion,
+				"vkCV",
+				VK_MAKE_VERSION(0, 0, 1),
+				VK_HEADER_VERSION_COMPLETE
+		);
+		
+		vk::InstanceCreateInfo instanceCreateInfo(
+				vk::InstanceCreateFlags(),
+				&applicationInfo,
+				0,
+				nullptr,
+				static_cast<uint32_t>(instanceExtensions.size()),
+				instanceExtensions.data()
+		);
+
+#ifndef NDEBUG
+		instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
+		instanceCreateInfo.ppEnabledLayerNames = validationLayers.data();
+#endif
+		
+		vk::Instance instance = vk::createInstance(instanceCreateInfo);
+		
+		std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
+		vk::PhysicalDevice physicalDevice = pickPhysicalDevice(instance);
+		
+		// check for physical device extension support
+		std::vector<vk::ExtensionProperties> deviceExtensionProperties = physicalDevice.enumerateDeviceExtensionProperties();
+		supportedExtensions.clear();
+		for (auto& elem : deviceExtensionProperties) {
+			supportedExtensions.push_back(elem.extensionName);
+		}
+		if (!checkSupport(supportedExtensions, deviceExtensions)) {
+			throw std::runtime_error("The requested device extensions are not supported by the physical device!");
+		}
+		
+		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(),
+				qCreateInfos.size(),
+				qCreateInfos.data(),
+				0,
+				nullptr,
+				deviceExtensions.size(),
+				deviceExtensions.data(),
+				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);
+		
+		QueueManager queueManager = QueueManager::create(device, queuePairsGraphics, queuePairsCompute, queuePairsTransfer);
+		
+		return Context(instance, physicalDevice, device, std::move(queueManager));
+	}
+ 
 }
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 7e6d87ca..0cfbaa24 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -14,110 +14,6 @@
 namespace vkcv
 {
 
-    /**
-     * @brief The physical device is evaluated by three categories:
-     * discrete GPU vs. integrated GPU, amount of queues and its abilities, and VRAM.physicalDevice.
-     * @param physicalDevice The physical device
-     * @return Device score as integer
-    */
-    int deviceScore(const vk::PhysicalDevice& physicalDevice)
-    {
-        int score = 0;
-        vk::PhysicalDeviceProperties properties = physicalDevice.getProperties();
-        std::vector<vk::QueueFamilyProperties> qFamilyProperties = physicalDevice.getQueueFamilyProperties();
-
-        // for every queue family compute queue flag bits and the amount of queues
-        for (const auto& qFamily : qFamilyProperties) {
-            uint32_t qCount = qFamily.queueCount;
-            uint32_t bitCount = (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0)
-                                + (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0)
-                                + (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0)
-                                + (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eSparseBinding) != 0);
-            score += static_cast<int>(qCount * bitCount);
-        }
-
-        // compute the VRAM of the physical device
-        vk::PhysicalDeviceMemoryProperties memoryProperties = physicalDevice.getMemoryProperties();
-        auto vram = static_cast<int>(memoryProperties.memoryHeaps[0].size / static_cast<uint32_t>(1E9));
-        score *= vram;
-
-        if (properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) {
-            score *= 2;
-        }
-        else if (properties.deviceType != vk::PhysicalDeviceType::eIntegratedGpu) {
-            score = -1;
-        }
-
-        return score;
-    }
-
-    /**
-     * @brief All existing physical devices will be evaluated by deviceScore.
-     * @param instance The instance
-     * @return The optimal physical device
-     * @see Context.deviceScore
-    */
-    vk::PhysicalDevice pickPhysicalDevice(vk::Instance& instance)
-    {
-        vk::PhysicalDevice phyDevice;
-        std::vector<vk::PhysicalDevice> devices = instance.enumeratePhysicalDevices();
-
-        if (devices.empty()) {
-            throw std::runtime_error("failed to find GPUs with Vulkan support!");
-        }
-
-        int max_score = -1;
-        for (const auto& device : devices) {
-            int score = deviceScore(device);
-            if (score > max_score) {
-                max_score = score;
-                phyDevice = device;
-            }
-        }
-
-        if (max_score == -1) {
-            throw std::runtime_error("failed to find a suitable GPU!");
-        }
-
-        return phyDevice;
-    }
-
-    /**
-     * @brief With the help of the reference "supported" all elements in "check" checked,
-     * if they are supported by the physical device.
-     * @param supported The reference that can be used to check "check"
-     * @param check The elements to be checked
-     * @return True, if all elements in "check" are supported
-    */
-    bool checkSupport(std::vector<const char*>& supported, std::vector<const char*>& check)
-    {
-        for (auto checkElem : check) {
-            bool found = false;
-            for (auto supportedElem : supported) {
-                if (strcmp(supportedElem, checkElem) == 0) {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found)
-                return false;
-        }
-        return true;
-    }
-
-
-    std::vector<const char*> getRequiredExtensions() {
-        uint32_t glfwExtensionCount = 0;
-        const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
-        std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
-
-#ifndef NDEBUG
-        extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
-#endif
-
-        return extensions;
-    }
-
     Core Core::create(const Window &window,
                       const char *applicationName,
                       uint32_t applicationVersion,
@@ -125,122 +21,22 @@ namespace vkcv
                       std::vector<const char *> instanceExtensions,
                       std::vector<const char *> deviceExtensions)
     {
-        // check for layer support
-
-        const std::vector<vk::LayerProperties>& layerProperties = vk::enumerateInstanceLayerProperties();
-
-        std::vector<const char*> supportedLayers;
-        supportedLayers.reserve(layerProperties.size());
-
-        for (auto& elem : layerProperties) {
-            supportedLayers.push_back(elem.layerName);
-        }
-
-// if in debug mode, check if validation layers are supported. Enable them if supported
-#ifndef NDEBUG
-        std::vector<const char*> validationLayers = {
-                "VK_LAYER_KHRONOS_validation"
-        };
-
-        if (!checkSupport(supportedLayers, validationLayers)) {
-            throw std::runtime_error("Validation layers requested but not available!");
-        }
-#endif
-
-        // check for extension support
-        std::vector<vk::ExtensionProperties> instanceExtensionProperties = vk::enumerateInstanceExtensionProperties();
-
-        std::vector<const char*> supportedExtensions;
-        supportedExtensions.reserve(instanceExtensionProperties.size());
-
-        for (auto& elem : instanceExtensionProperties) {
-            supportedExtensions.push_back(elem.extensionName);
-        }
-
-        if (!checkSupport(supportedExtensions, instanceExtensions)) {
-            throw std::runtime_error("The requested instance extensions are not supported!");
-        }
-
-        // for GLFW: get all required extensions
-        std::vector<const char*> requiredExtensions = getRequiredExtensions();
-        instanceExtensions.insert(instanceExtensions.end(), requiredExtensions.begin(), requiredExtensions.end());
-
-        const vk::ApplicationInfo applicationInfo(
-                applicationName,
-                applicationVersion,
-                "vkCV",
-                VK_MAKE_VERSION(0, 0, 1),
-                VK_HEADER_VERSION_COMPLETE
-        );
-
-        vk::InstanceCreateInfo instanceCreateInfo(
-                vk::InstanceCreateFlags(),
-                &applicationInfo,
-                0,
-                nullptr,
-                static_cast<uint32_t>(instanceExtensions.size()),
-                instanceExtensions.data()
-        );
-
-#ifndef NDEBUG
-        instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
-        instanceCreateInfo.ppEnabledLayerNames = validationLayers.data();
-#endif
-
-        vk::Instance instance = vk::createInstance(instanceCreateInfo);
-
-        std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
-        vk::PhysicalDevice physicalDevice = pickPhysicalDevice(instance);
-
-        // check for physical device extension support
-        std::vector<vk::ExtensionProperties> deviceExtensionProperties = physicalDevice.enumerateDeviceExtensionProperties();
-        supportedExtensions.clear();
-        for (auto& elem : deviceExtensionProperties) {
-            supportedExtensions.push_back(elem.extensionName);
-        }
-        if (!checkSupport(supportedExtensions, deviceExtensions)) {
-            throw std::runtime_error("The requested device extensions are not supported by the physical device!");
-        }
-
-		const vk::SurfaceKHR surface = createSurface(window.getWindow(), instance, physicalDevice);
-		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(),
-			qCreateInfos.size(),
-			qCreateInfos.data(),
-			0,
-			nullptr,
-			deviceExtensions.size(),
-			deviceExtensions.data(),
-			nullptr		// Should our device use some features??? If yes: TODO
+        Context context = Context::create(
+        		applicationName, applicationVersion,
+        		queueFlags,
+        		instanceExtensions,
+        		deviceExtensions
+		);
+	
+		const vk::SurfaceKHR surface = createSurface(
+				window.getWindow(),
+				context.getInstance(),
+				context.getPhysicalDevice()
 		);
-
-#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);
-
-        QueueManager queueManager = QueueManager::create(device, queuePairsGraphics, queuePairsCompute, queuePairsTransfer);
-
-        Context context (instance, physicalDevice, device);
 
         SwapChain swapChain = SwapChain::create(window, context, surface);
 
-        std::vector<vk::Image> swapChainImages = device.getSwapchainImagesKHR(swapChain.getSwapchain());
+        std::vector<vk::Image> swapChainImages = context.getDevice().getSwapchainImagesKHR(swapChain.getSwapchain());
         std::vector<vk::ImageView> imageViews;
         imageViews.reserve( swapChainImages.size() );
         //here can be swizzled with vk::ComponentSwizzle if needed
@@ -263,14 +59,16 @@ namespace vkcv
                     subResourceRange
             );
 
-            imageViews.push_back( device.createImageView( imageViewCreateInfo ));
+            imageViews.push_back(context.getDevice().createImageView(imageViewCreateInfo));
         }
 
-		const int graphicQueueFamilyIndex = queuePairsGraphics[0].first;
+        const auto& queueManager = context.getQueueManager();
+        
+		const int graphicQueueFamilyIndex = queueManager.getGraphicsQueues()[0].familyIndex;
 		const auto defaultCommandResources = createDefaultCommandResources(context.getDevice(), graphicQueueFamilyIndex);
 		const auto defaultSyncResources = createDefaultSyncResources(context.getDevice());
 
-        return Core(std::move(context) , window, swapChain, imageViews, defaultCommandResources, defaultSyncResources, queueManager);
+        return Core(std::move(context) , window, swapChain, imageViews, defaultCommandResources, defaultSyncResources);
     }
 
     const Context &Core::getContext() const
@@ -279,7 +77,7 @@ namespace vkcv
     }
 
 	Core::Core(Context &&context, const Window &window , SwapChain swapChain,  std::vector<vk::ImageView> imageViews, 
-		const CommandResources& commandResources, const SyncResources& syncResources, const QueueManager& queueManager) noexcept :
+		const CommandResources& commandResources, const SyncResources& syncResources) noexcept :
             m_Context(std::move(context)),
             m_window(window),
             m_swapchain(swapChain),
@@ -287,8 +85,7 @@ namespace vkcv
             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)
+            m_SyncResources(syncResources)
 	{}
 
 	Core::~Core() noexcept {
@@ -387,14 +184,16 @@ namespace vkcv
 
 		m_CommandResources.commandBuffer.end();
 		
+		const auto& queueManager = m_Context.getQueueManager();
+		
 		const vk::SubmitInfo submitInfo(0, nullptr, 0, 1, &(m_CommandResources.commandBuffer), 1, &m_SyncResources.renderFinished);
-		m_QueueManager.getGraphicsQueues()[0].submit(submitInfo);
+		queueManager.getGraphicsQueues()[0].handle.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_QueueManager.getPresentQueue().presentKHR(presentInfo);
+        queueManager.getPresentQueue().handle.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
index c6c9dda4..ef34643e 100644
--- a/src/vkcv/QueueManager.cpp
+++ b/src/vkcv/QueueManager.cpp
@@ -1,6 +1,9 @@
-#include "vkcv/QueueManager.hpp"
+
+#include <limits>
 #include <unordered_set>
 
+#include "vkcv/QueueManager.hpp"
+
 namespace vkcv {
 
     /**
@@ -143,14 +146,17 @@ namespace vkcv {
      * @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;
+    std::vector<Queue> getQueues(const vk::Device& device, const std::vector<std::pair<int, int>>& queuePairs) {
+        std::vector<Queue> queues;
+        
         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));
+            const int queueFamilyIndex = q.first; // the queueIndex of the queue family
+            const int queueIndex = q.second;   // the queueIndex within a queue family
+            
+			queues.push_back({ queueFamilyIndex, queueIndex, device.getQueue(queueFamilyIndex, queueIndex) });
         }
-        return queueHandles;
+        
+        return queues;
     }
 
 
@@ -159,30 +165,30 @@ namespace vkcv {
                                       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);
+        std::vector<Queue> graphicsQueues = getQueues(device, queuePairsGraphics);
+        std::vector<Queue> computeQueues = getQueues(device, queuePairsCompute );
+        std::vector<Queue> transferQueues = getQueues(device, queuePairsTransfer);
 
-    return QueueManager( graphicsQueues, computeQueues, transferQueues, graphicsQueues[0]);
+    	return QueueManager( std::move(graphicsQueues), std::move(computeQueues), std::move(transferQueues), 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)
+	QueueManager::QueueManager(std::vector<Queue>&& graphicsQueues, std::vector<Queue>&& computeQueues, std::vector<Queue>&& transferQueues, size_t presentIndex)
+	: m_graphicsQueues(graphicsQueues), m_computeQueues(computeQueues), m_transferQueues(transferQueues), m_presentIndex(presentIndex)
     {}
 
-    const vk::Queue &QueueManager::getPresentQueue() const {
-        return m_presentQueue;
+    const Queue &QueueManager::getPresentQueue() const {
+        return m_graphicsQueues[m_presentIndex];
     }
 
-    const std::vector<vk::Queue> &QueueManager::getGraphicsQueues() const {
+    const std::vector<Queue> &QueueManager::getGraphicsQueues() const {
         return m_graphicsQueues;
     }
 
-    const std::vector<vk::Queue> &QueueManager::getComputeQueues() const {
+    const std::vector<Queue> &QueueManager::getComputeQueues() const {
         return m_computeQueues;
     }
 
-    const std::vector<vk::Queue> &QueueManager::getTransferQueues() const {
+    const std::vector<Queue> &QueueManager::getTransferQueues() const {
         return m_transferQueues;
     }
 
-- 
GitLab