From f9215657056786f4879ffbd65bf2a89c1d86a7de Mon Sep 17 00:00:00 2001
From: Tobias Frisch <tfrisch@uni-koblenz.de>
Date: Fri, 8 Jul 2022 11:29:05 +0200
Subject: [PATCH] Adjusted swapchain manager (still WIP)

Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de>
---
 config/Sources.cmake                      |   6 -
 include/vkcv/Core.hpp                     |  43 +--
 include/vkcv/Surface.hpp                  | 107 -------
 include/vkcv/Swapchain.hpp                | 136 ---------
 include/vkcv/Window.hpp                   |   3 +-
 modules/gui/src/vkcv/gui/GUI.cpp          |  19 +-
 projects/bindless_textures/src/main.cpp   |   9 +-
 projects/first_mesh/src/main.cpp          |   7 +-
 projects/first_scene/src/main.cpp         |   2 +-
 projects/first_triangle/src/main.cpp      |   2 +-
 projects/head_demo/src/main.cpp           |   2 +-
 projects/indirect_draw/src/main.cpp       |   7 +-
 projects/mesh_shader/src/main.cpp         |   2 +-
 projects/particle_simulation/src/main.cpp |   7 +-
 projects/saf_r/src/main.cpp               |   5 +-
 projects/sph/src/main.cpp                 |   7 +-
 projects/voxelization/src/main.cpp        |   2 +-
 projects/wobble_bobble/src/main.cpp       |   8 +-
 src/vkcv/Core.cpp                         | 155 ++++++-----
 src/vkcv/QueueManager.cpp                 |   1 -
 src/vkcv/Surface.cpp                      | 258 -----------------
 src/vkcv/Swapchain.cpp                    |  96 -------
 src/vkcv/SwapchainManager.cpp             | 322 +++++++++++++++++++---
 src/vkcv/SwapchainManager.hpp             | 141 ++++++++--
 src/vkcv/Window.cpp                       |   2 +-
 25 files changed, 549 insertions(+), 800 deletions(-)
 delete mode 100644 include/vkcv/Surface.hpp
 delete mode 100644 include/vkcv/Swapchain.hpp
 delete mode 100644 src/vkcv/Surface.cpp
 delete mode 100644 src/vkcv/Swapchain.cpp

diff --git a/config/Sources.cmake b/config/Sources.cmake
index f2c69d35..c3231e7a 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -49,12 +49,6 @@ set(vkcv_sources
 		
 		${vkcv_include}/vkcv/Logger.hpp
 		
-		${vkcv_include}/vkcv/Surface.hpp
-		${vkcv_source}/vkcv/Surface.cpp
-
-		${vkcv_include}/vkcv/Swapchain.hpp
-		${vkcv_source}/vkcv/Swapchain.cpp
-		
 		${vkcv_include}/vkcv/ShaderStage.hpp
 		
 		${vkcv_include}/vkcv/ShaderProgram.hpp
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index bf5cf40f..aaac77de 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -11,7 +11,6 @@
 
 #include "BufferTypes.hpp"
 #include "Context.hpp"
-#include "Swapchain.hpp"
 #include "Window.hpp"
 #include "PassConfig.hpp"
 #include "Handles.hpp"
@@ -380,30 +379,36 @@ namespace vkcv
 		 * @return the window
 		 */
 		[[nodiscard]]
-		Window& getWindow(const WindowHandle& handle );
-
+		Window& getWindow(const WindowHandle& handle);
+	
 		/**
-		 * Gets the swapchain of the current focused window
-		 * @return swapchain
-		 */
+         * @brief Returns the image format for the current surface
+         * of the swapchain.
+         *
+         * @param[in] handle Swapchain handle
+         * @return Swapchain image format
+         */
 		[[nodiscard]]
-		Swapchain& getSwapchainOfCurrentWindow();
-
+		vk::Format getSwapchainFormat(const SwapchainHandle& swapchain) const;
+	
 		/**
-		 * Returns the swapchain reference
-		 * @param handle of the swapchain
-		 * @return swapchain
-		 */
+		 * @brief Returns the amount of images for the swapchain.
+		 *
+		 * @param[in] handle Swapchain handle
+		 * @return Number of images
+		*/
 		[[nodiscard]]
-		Swapchain& getSwapchain(const SwapchainHandle &handle);
-
+		uint32_t getSwapchainImageCount(const SwapchainHandle& swapchain) const;
+	
 		/**
-		 * Gets the swapchain handle from the window
-		 * @param handle of the window
-		 * @return the swapchain from getSwapchain( SwapchainHandle )
-		 */
+         * @brief Returns the extent from the current surface of
+         * the swapchain.
+         *
+         * @param[in] handle Swapchain handle
+         * @return Extent of the swapchains surface
+         */
 		[[nodiscard]]
-		Swapchain& getSwapchain(const WindowHandle &handle);
+		vk::Extent2D getSwapchainExtent(const SwapchainHandle& swapchain) const;
 
 		/**
 		 * @brief Returns the image width.
diff --git a/include/vkcv/Surface.hpp b/include/vkcv/Surface.hpp
deleted file mode 100644
index 47862b9c..00000000
--- a/include/vkcv/Surface.hpp
+++ /dev/null
@@ -1,107 +0,0 @@
-#pragma once
-/**
- * @authors Tobias Frisch
- * @file vkcv/Surface.hpp
- * @brief Class to manage the surface used by a swapchain.
- */
-
-#include <vulkan/vulkan.hpp>
-
-#include "Context.hpp"
-#include "Window.hpp"
-
-namespace vkcv {
-	
-	const uint32_t MIN_SURFACE_SIZE = 2;
-
-    /**
-     * @brief Class to handle surfaces to use with a swapchain.
-     */
-	class Surface final {
-	private:
-		friend class Swapchain;
-		friend class SwapchainManager;
-		
-		const Context *m_Context;
-		vk::SurfaceKHR m_Handle;
-		uint32_t m_PresentQueueIndex;
-		vk::Extent2D m_Extent;
-		vk::Format m_Format;
-		vk::ColorSpaceKHR m_ColorSpace;
-		
-		Surface(const Context &context,
-				const vk::SurfaceKHR &handle,
-				uint32_t presentQueueIndex,
-				const vk::Extent2D &extent,
-				vk::Format format,
-				vk::ColorSpaceKHR colorSpace);
-		
-		vk::SwapchainKHR createVulkanSwapchain(const Window &window,
-											   const vk::SwapchainKHR &oldSwapchain);
-		
-	public:
-		Surface(const Surface& other) = default;
-		
-		Surface(Surface&& other) noexcept;
-		
-		Surface& operator=(const Surface& other) = default;
-		
-		Surface& operator=(Surface&& other) noexcept;
-		
-		~Surface();
-		
-		/**
-		 * @brief Creates a surface via a window and a current context.
-		 *
-		 * @param[in] window Window
-		 * @param[in] context Context
-		 * @return Created surface
-		 */
-		static Surface create(const Window &window,
-							  const Context &context);
-		
-		/**
-         * @brief Returns the Vulkan-Surface of the object.
-         *
-         * @return Current Vulkan-Surface
-         */
-		[[nodiscard]]
-		vk::SurfaceKHR getSurface() const;
-		
-		/**
-		 * @brief Returns the queue index of the present queue
-		 * for the surface.
-		 *
-		 * @return Present queue index
-		 */
-		[[nodiscard]]
-		uint32_t getPresentQueueIndex() const;
-		
-		/**
-		 * @brief Returns the extent of the surfaces resolution.
-		 *
-		 * @return Extent of surface
-		 */
-		[[nodiscard]]
-		const vk::Extent2D& getExtent() const;
-		
-		/**
-		 * @brief Returns the image format of the surface to
-		 * present an image.
-		 *
-		 * @return Vulkan image format
-		 */
-		[[nodiscard]]
-		vk::Format getFormat() const;
-		
-		/**
-		 * @brief Returns the color space of the surface.
-		 *
-		 * @return Color space
-		 */
-		[[nodiscard]]
-		vk::ColorSpaceKHR getColorSpace() const;
-		
-	};
-
-}
diff --git a/include/vkcv/Swapchain.hpp b/include/vkcv/Swapchain.hpp
deleted file mode 100644
index 9380b97c..00000000
--- a/include/vkcv/Swapchain.hpp
+++ /dev/null
@@ -1,136 +0,0 @@
-#pragma once
-/**
- * @authors Sebastian Gaida, Tobias Frisch
- * @file vkcv/Swapchain.hpp
- * @brief Class to manage the state of a swapchain and its transitions.
- */
-
-#include <atomic>
-#include <vulkan/vulkan.hpp>
-
-#include "Context.hpp"
-#include "Surface.hpp"
-#include "Window.hpp"
-
-namespace vkcv
-{
-
-    /**
-     * @brief Class to handle swapchains using a context.
-     */
-    class Swapchain final {
-    private:
-    	friend class Core;
-    	friend class Window;
-    	friend class SwapchainManager;
-     
-		const Context *m_Context;
-        Surface m_Surface;
-        vk::SwapchainKHR m_Swapchain;
-		std::atomic<bool> m_RecreationRequired;
-
-		/**
-		 * @brief Constructor of the swapchain with the current context,
-		 * a surface and a given vulkan swapchain object.
-		 *
-		 * @param[in,out] context Current context
-		 * @param[in] surface used by the swapchain
-		 * @param[in,out] swapchain to show images in the window
-		 */
-        Swapchain(const Context &context,
-				  const Surface &surface,
-                  vk::SwapchainKHR swapchain) noexcept;
-	
-		/**
-		 * @brief Checks whether the swapchain needs to be recreated.
-		 *
-		 * @return True, if the swapchain should be updated,
-		 * otherwise false.
-		 */
-		bool shouldUpdateSwapchain() const;
-	
-		/**
-		 * @brief Updates and recreates the swapchain.
-		 *
-		 * @param[in,out] context that holds the device to recreate the swapchain
-		 * @param[in] window that the new swapchain gets bound to
-		 */
-		void updateSwapchain(const Context &context, const Window &window);
-	
-		/**
-		 * @brief Signals the swapchain to be recreated.
-		 */
-		void signalSwapchainRecreation();
-
-    public:
-    	Swapchain(const Swapchain& other);
-
-        /**
-         * @brief Returns the vulkan swapchain object of the swapchain.
-         *
-         * @return The swapchain linked with the #SwapChain class
-         * @note The reference to our Swapchain variable is needed for the recreation step
-         */
-        [[nodiscard]]
-        const vk::SwapchainKHR& getSwapchain() const;
-
-        /**
-         * @brief Returns the current surface of the swapchain.
-         *
-         * @return Current surface
-         */
-        [[nodiscard]]
-        const Surface& getSurface() const;
-
-        /**
-         * @brief Returns the image format for the current surface
-         * of the swapchain.
-         *
-         * @return Swapchain image format
-         */
-        [[nodiscard]]
-        vk::Format getFormat() const;
-
-        /**
-         * @brief Creates a swapchain for a specific window and
-         * a given context.
-         *
-         * @param[in,out] window Window
-         * @param[in,out] context Context
-         * @return New created swapchain
-         */
-        static Swapchain create(const Window &window, const Context &context);
-
-        /**
-         * Destructor of thw swapchain.
-         */
-        virtual ~Swapchain();
-
-		/**
-		 * @brief Returns the amount of images for the swapchain.
-		 *
-		 * @return Number of images
-		*/
-		uint32_t getImageCount() const;
-	
-        /**
-         * @brief Returns the extent from the current surface of
-         * the swapchain.
-         *
-         * @return Extent of the swapchains surface
-         */
-        [[nodiscard]]
-		const vk::Extent2D& getExtent() const;
-
-		/**
-		 * @brief Returns the present queue index to be used with
-		 * the swapchain and its current surface.
-		 *
-		 * @return Present queue family index
-		 */
-		[[nodiscard]]
-		uint32_t getPresentQueueIndex() const;
-
-	};
-    
-}
diff --git a/include/vkcv/Window.hpp b/include/vkcv/Window.hpp
index d1db4bf4..e7a27730 100644
--- a/include/vkcv/Window.hpp
+++ b/include/vkcv/Window.hpp
@@ -169,7 +169,8 @@ namespace vkcv {
          *
          * @return Swapchain handle
          */
-        SwapchainHandle getSwapchainHandle() const;
+        SwapchainHandle getSwapchain() const;
+		
     };
 
 }
diff --git a/modules/gui/src/vkcv/gui/GUI.cpp b/modules/gui/src/vkcv/gui/GUI.cpp
index 7ee33537..5ac03ce5 100644
--- a/modules/gui/src/vkcv/gui/GUI.cpp
+++ b/modules/gui/src/vkcv/gui/GUI.cpp
@@ -71,7 +71,8 @@ namespace vkcv::gui {
 		m_descriptor_pool = m_context.getDevice().createDescriptorPool(descriptorPoolCreateInfo);
 		
 		const vk::PhysicalDevice& physicalDevice = m_context.getPhysicalDevice();
-		const Swapchain& swapchain = m_core.getSwapchain(m_windowHandle);
+		const SwapchainHandle& swapchainHandle = m_core.getWindow(m_windowHandle).getSwapchain();
+		const uint32_t swapchainImageCount = m_core.getSwapchainImageCount(swapchainHandle);
 		
 		const uint32_t graphicsQueueFamilyIndex = (
 				m_context.getQueueManager().getGraphicsQueues()[0].familyIndex
@@ -86,13 +87,13 @@ namespace vkcv::gui {
 		init_info.PipelineCache = 0;
 		init_info.DescriptorPool = static_cast<VkDescriptorPool>(m_descriptor_pool);
 		init_info.Allocator = nullptr;
-		init_info.MinImageCount = swapchain.getImageCount();
-		init_info.ImageCount = swapchain.getImageCount();
+		init_info.MinImageCount = swapchainImageCount;
+		init_info.ImageCount = swapchainImageCount;
 		init_info.CheckVkResultFn = checkVulkanResult;
 		
 		const vk::AttachmentDescription attachment (
 				vk::AttachmentDescriptionFlags(),
-				swapchain.getFormat(),
+				m_core.getSwapchainFormat(swapchainHandle),
 				vk::SampleCountFlagBits::e1,
 				vk::AttachmentLoadOp::eLoad,
 				vk::AttachmentStoreOp::eStore,
@@ -177,11 +178,11 @@ namespace vkcv::gui {
 	}
 	
 	void GUI::beginGUI() {
-		const Swapchain& swapchain = m_core.getSwapchain(m_windowHandle);
-		const auto extent = swapchain.getExtent();
+		const auto swapchainHandle = m_core.getWindow(m_windowHandle).getSwapchain();
+		const auto& extent = m_core.getSwapchainExtent(swapchainHandle);
 		
 		if ((extent.width > 0) && (extent.height > 0)) {
-			ImGui_ImplVulkan_SetMinImageCount(swapchain.getImageCount());
+			ImGui_ImplVulkan_SetMinImageCount(m_core.getSwapchainImageCount(swapchainHandle));
 		}
 		
 		ImGui_ImplVulkan_NewFrame();
@@ -200,8 +201,8 @@ namespace vkcv::gui {
 			return;
 		}
 		
-		const Swapchain& swapchain = m_core.getSwapchain(m_windowHandle);
-		const auto extent = swapchain.getExtent();
+		const auto swapchainHandle = m_core.getWindow(m_windowHandle).getSwapchain();
+		const auto& extent = m_core.getSwapchainExtent(swapchainHandle);
 
 		const vk::ImageView swapchainImageView = m_core.getSwapchainImageView();
 
diff --git a/projects/bindless_textures/src/main.cpp b/projects/bindless_textures/src/main.cpp
index afc58330..e2f4c4ac 100644
--- a/projects/bindless_textures/src/main.cpp
+++ b/projects/bindless_textures/src/main.cpp
@@ -47,6 +47,7 @@ int main(int argc, const char** argv) {
 	);
 
 	vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 800, 600, true);
+	vkcv::Window& window = core.getWindow(windowHandle);
 
 	vkcv::asset::Scene mesh;
 
@@ -102,7 +103,7 @@ int main(int argc, const char** argv) {
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchain(windowHandle).getFormat()
+		core.getSwapchainFormat(window.getSwapchain())
 	);
 	
 	const vkcv::AttachmentDescription depth_attachment(
@@ -221,7 +222,7 @@ int main(int argc, const char** argv) {
 	vkcv::DescriptorSetUsage    descriptorUsage(0, descriptorSet);
 	vkcv::DrawcallInfo          drawcall(renderMesh, { descriptorUsage },1);
 
-    vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle));
+    vkcv::camera::CameraManager cameraManager(window);
     uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
 	cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL);
 	
@@ -232,11 +233,11 @@ int main(int argc, const char** argv) {
 	while (vkcv::Window::hasOpenWindow()) {
         vkcv::Window::pollEvents();
 		
-		if(core.getWindow(windowHandle).getHeight() == 0 || core.getWindow(windowHandle).getWidth() == 0)
+		if (window.getHeight() == 0 || window.getWidth() == 0)
 			continue;
 		
 		uint32_t swapchainWidth, swapchainHeight;
-		if (!core.beginFrame(swapchainWidth, swapchainHeight,windowHandle)) {
+		if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) {
 			continue;
 		}
 		
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index 40a16aed..1220b36e 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -17,6 +17,7 @@ int main(int argc, const char** argv) {
 	);
 
 	vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 800, 600, true);
+	vkcv::Window& window = core.getWindow(windowHandle);
 
 	vkcv::asset::Scene mesh;
 
@@ -53,7 +54,7 @@ int main(int argc, const char** argv) {
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchain(windowHandle).getFormat()
+		core.getSwapchainFormat(window.getSwapchain())
 	);
 	
 	const vkcv::AttachmentDescription depth_attachment(
@@ -162,7 +163,7 @@ int main(int argc, const char** argv) {
 	vkcv::DescriptorSetUsage    descriptorUsage(0, descriptorSet);
 	vkcv::DrawcallInfo          drawcall(renderMesh, { descriptorUsage },1);
 
-    vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle));
+    vkcv::camera::CameraManager cameraManager(window);
     uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
 	
 	cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -3));
@@ -172,7 +173,7 @@ int main(int argc, const char** argv) {
 	while (vkcv::Window::hasOpenWindow()) {
         vkcv::Window::pollEvents();
 		
-		if(core.getWindow(windowHandle).getHeight() == 0 || core.getWindow(windowHandle).getWidth() == 0)
+		if (window.getHeight() == 0 || window.getWidth() == 0)
 			continue;
 		
 		uint32_t swapchainWidth, swapchainHeight;
diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp
index c09d0121..dfa58d88 100644
--- a/projects/first_scene/src/main.cpp
+++ b/projects/first_scene/src/main.cpp
@@ -51,7 +51,7 @@ int main(int argc, const char** argv) {
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchain(windowHandle).getFormat()
+		core.getSwapchainFormat(window.getSwapchain())
 	);
 
 	const vkcv::AttachmentDescription depth_attachment(
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index d98ea8e7..c3824b49 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -32,7 +32,7 @@ int main(int argc, const char** argv) {
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchain(windowHandle).getFormat());
+		core.getSwapchainFormat(window.getSwapchain()));
 
 	vkcv::PassConfig trianglePassDefinition({ present_color_attachment }, vkcv::Multisampling::None);
 	vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition);
diff --git a/projects/head_demo/src/main.cpp b/projects/head_demo/src/main.cpp
index 5e3d0abc..fb3170d4 100644
--- a/projects/head_demo/src/main.cpp
+++ b/projects/head_demo/src/main.cpp
@@ -175,7 +175,7 @@ int main(int argc, const char** argv) {
 		return EXIT_FAILURE;
 	}
 	
-	auto swapchainExtent = core.getSwapchain(windowHandle).getExtent();
+	auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain());
 	
 	vkcv::ImageHandle depthBuffer = core.createImage(
 			vk::Format::eD32Sfloat,
diff --git a/projects/indirect_draw/src/main.cpp b/projects/indirect_draw/src/main.cpp
index 6c3c19df..cba4be9a 100644
--- a/projects/indirect_draw/src/main.cpp
+++ b/projects/indirect_draw/src/main.cpp
@@ -307,6 +307,7 @@ int main(int argc, const char** argv) {
 	);
 
 	vkcv::WindowHandle windowHandle = core.createWindow(applicationName,800,600,true);
+	vkcv::Window& window = core.getWindow(windowHandle);
 
     vkcv::gui::GUI gui (core, windowHandle);
 
@@ -330,7 +331,7 @@ int main(int argc, const char** argv) {
     const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchain(windowHandle).getFormat()
+		core.getSwapchainFormat(window.getSwapchain())
 	);
 	const vkcv::AttachmentDescription depth_attachment(
 			vkcv::AttachmentOperation::STORE,
@@ -507,7 +508,7 @@ int main(int argc, const char** argv) {
         return EXIT_FAILURE;
     }
 
-    vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle));
+    vkcv::camera::CameraManager cameraManager (window);
     uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
 	
 	cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -3));
@@ -532,7 +533,7 @@ int main(int argc, const char** argv) {
     while (vkcv::Window::hasOpenWindow()) {
         vkcv::Window::pollEvents();
 		
-		if(core.getWindow(windowHandle).getHeight() == 0 || core.getWindow(windowHandle).getWidth() == 0)
+		if (window.getHeight() == 0 || window.getWidth() == 0)
 			continue;
 		
 		uint32_t swapchainWidth, swapchainHeight;
diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp
index 287a925f..f369e42d 100644
--- a/projects/mesh_shader/src/main.cpp
+++ b/projects/mesh_shader/src/main.cpp
@@ -166,7 +166,7 @@ int main(int argc, const char** argv) {
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchain(windowHandle).getFormat());
+		core.getSwapchainFormat(window.getSwapchain()));
 
     const vkcv::AttachmentDescription depth_attachment(
             vkcv::AttachmentOperation::STORE,
diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp
index a281c393..764f3c06 100644
--- a/projects/particle_simulation/src/main.cpp
+++ b/projects/particle_simulation/src/main.cpp
@@ -43,10 +43,7 @@ int main(int argc, const char **argv) {
     vkcv::PassConfig particlePassDefinition({present_color_attachment}, vkcv::Multisampling::None);
     vkcv::PassHandle particlePass = core.createPass(particlePassDefinition);
 
-    vkcv::PassConfig computePassDefinition({});
-    vkcv::PassHandle computePass = core.createPass(computePassDefinition);
-
-    if (!particlePass || !computePass)
+    if (!particlePass)
     {
         std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
         return EXIT_FAILURE;
@@ -214,7 +211,7 @@ int main(int argc, const char **argv) {
     cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, -2.0f));
     cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, 0.0f));
 
-	const auto swapchainExtent = core.getSwapchain(windowHandle).getExtent();
+	const auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain());
 	
     vkcv::ImageHandle colorBuffer = core.createImage(
 			colorFormat,
diff --git a/projects/saf_r/src/main.cpp b/projects/saf_r/src/main.cpp
index cc6dd0d4..dd20e132 100644
--- a/projects/saf_r/src/main.cpp
+++ b/projects/saf_r/src/main.cpp
@@ -40,6 +40,7 @@ int main(int argc, const char** argv) {
 	);
 
 	vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true);
+	vkcv::Window& window = core.getWindow(windowHandle);
 
 	//configuring the compute Shader
 	vkcv::PassConfig computePassDefinition({});
@@ -164,7 +165,7 @@ int main(int argc, const char** argv) {
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchain(windowHandle).getFormat());
+		core.getSwapchainFormat(window.getSwapchain()));
 
 	vkcv::PassConfig safrPassDefinition({ present_color_attachment }, vkcv::Multisampling::None);
 	vkcv::PassHandle safrPass = core.createPass(safrPassDefinition);
@@ -205,7 +206,7 @@ int main(int argc, const char** argv) {
 	vkcv::DrawcallInfo drawcall(renderMesh, { descriptorUsage }, 1);
 
 	//create the camera
-	vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle));
+	vkcv::camera::CameraManager cameraManager(window);
 	uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
 	uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL);
 
diff --git a/projects/sph/src/main.cpp b/projects/sph/src/main.cpp
index 02d659eb..6955281c 100644
--- a/projects/sph/src/main.cpp
+++ b/projects/sph/src/main.cpp
@@ -41,9 +41,6 @@ int main(int argc, const char **argv) {
     vkcv::PassConfig particlePassDefinition({present_color_attachment}, vkcv::Multisampling::None);
     vkcv::PassHandle particlePass = core.createPass(particlePassDefinition);
 
-    vkcv::PassConfig computePassDefinition({});
-    vkcv::PassHandle computePass = core.createPass(computePassDefinition);
-
     //rotation
     float rotationx = 0;
     float rotationy = 0;
@@ -58,7 +55,7 @@ int main(int argc, const char **argv) {
     float param_ABSORBTION = 0.5;
     float param_dt = 0.0005;
 
-    if (!particlePass || !computePass)
+    if (!particlePass)
     {
         std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
         return EXIT_FAILURE;
@@ -231,7 +228,7 @@ int main(int argc, const char **argv) {
     cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, -2.5f));
     cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, 0.0f));
 
-	const auto swapchainExtent = core.getSwapchain(window.getSwapchainHandle()).getExtent();
+	const auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain());
 	
     vkcv::ImageHandle colorBuffer = core.createImage(
 			colorFormat,
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index 995045d2..821cc1c2 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -333,7 +333,7 @@ int main(int argc, const char** argv) {
 	vkcv::DescriptorSetLayoutHandle prepassDescriptorSetLayout = core.createDescriptorSetLayout({});
 	vkcv::DescriptorSetHandle prepassDescriptorSet = core.createDescriptorSet(prepassDescriptorSetLayout);
 
-	auto swapchainExtent = core.getSwapchain(windowHandle).getExtent();
+	auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain());
 	
 	vkcv::GraphicsPipelineConfig prepassPipelineConfig (
 		depthPrepassShader,
diff --git a/projects/wobble_bobble/src/main.cpp b/projects/wobble_bobble/src/main.cpp
index 7a567c40..24c203f7 100644
--- a/projects/wobble_bobble/src/main.cpp
+++ b/projects/wobble_bobble/src/main.cpp
@@ -303,7 +303,7 @@ int main(int argc, const char **argv) {
 	cameraManager.getCamera(trackballIdx).setCenter(glm::vec3(0.5f, 0.5f, 0.5f));   // set camera to look at the center of the particle volume
 	cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
 	
-	auto swapchainExtent = core.getSwapchain(windowHandle).getExtent();
+	auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain());
 	
 	vkcv::ImageHandle depthBuffer = core.createImage(
 			vk::Format::eD32Sfloat,
@@ -458,7 +458,7 @@ int main(int argc, const char **argv) {
 		vkcv::AttachmentDescription(
 				vkcv::AttachmentOperation::STORE,
 				vkcv::AttachmentOperation::CLEAR,
-				core.getSwapchain(windowHandle).getFormat()
+				core.getSwapchainFormat(window.getSwapchain())
 		),
 		vkcv::AttachmentDescription(
 				vkcv::AttachmentOperation::STORE,
@@ -471,7 +471,7 @@ int main(int argc, const char **argv) {
 		vkcv::AttachmentDescription(
 				vkcv::AttachmentOperation::STORE,
 				vkcv::AttachmentOperation::CLEAR,
-				core.getSwapchain(windowHandle).getFormat()
+				core.getSwapchainFormat(window.getSwapchain())
 		),
 		vkcv::AttachmentDescription(
 				vkcv::AttachmentOperation::STORE,
@@ -484,7 +484,7 @@ int main(int argc, const char **argv) {
 		vkcv::AttachmentDescription(
 				vkcv::AttachmentOperation::STORE,
 				vkcv::AttachmentOperation::LOAD,
-				core.getSwapchain(windowHandle).getFormat()
+				core.getSwapchainFormat(window.getSwapchain())
 		),
 		vkcv::AttachmentDescription(
 				vkcv::AttachmentOperation::STORE,
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index d54e5c85..edccae45 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -73,9 +73,9 @@ namespace vkcv
 		m_DescriptorSetManager->init(*this, *m_DescriptorSetLayoutManager);
 		m_BufferManager->init(*this);
 		m_SamplerManager->init(*this);
-		m_CommandStreamManager->init(*this);
-		m_SwapchainManager->m_context = &m_Context;
 		m_ImageManager->init(*this, *m_BufferManager);
+		m_CommandStreamManager->init(*this);
+		m_SwapchainManager->init(*this);
 		m_downsampler = std::unique_ptr<Downsampler>(new BlitDownsampler(*this, *m_ImageManager));
 	}
 
@@ -172,7 +172,7 @@ namespace vkcv
     	
 		try {
 			result = m_Context.getDevice().acquireNextImageKHR(
-					m_SwapchainManager->getSwapchain(swapchainHandle).getSwapchain(),
+					m_SwapchainManager->getSwapchain(swapchainHandle).m_Swapchain,
 					std::numeric_limits<uint64_t>::max(),
 					m_SyncResources.swapchainImageAcquired,
 					nullptr,
@@ -191,7 +191,7 @@ namespace vkcv
 		} else
 		if (result == vk::Result::eSuboptimalKHR) {
 			vkcv_log(LogLevel::WARNING, "Acquired image is suboptimal");
-			m_SwapchainManager->getSwapchain(swapchainHandle).signalSwapchainRecreation();
+			m_SwapchainManager->signalRecreation(swapchainHandle);
 		}
 		
 		m_currentSwapchainImageIndex = imageIndex;
@@ -199,21 +199,22 @@ namespace vkcv
 	}
 
 	bool Core::beginFrame(uint32_t& width, uint32_t& height, const WindowHandle &windowHandle) {
-		const SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle();
+		const Window& window = m_WindowManager->getWindow(windowHandle);
+		const SwapchainHandle swapchainHandle = window.getSwapchain();
 
-		if (m_SwapchainManager->getSwapchain(swapchainHandle).shouldUpdateSwapchain()) {
+		if (m_SwapchainManager->shouldUpdateSwapchain(swapchainHandle)) {
 			m_Context.getDevice().waitIdle();
 
-			m_SwapchainManager->getSwapchain(swapchainHandle).updateSwapchain(m_Context, m_WindowManager->getWindow(windowHandle));
+			m_SwapchainManager->updateSwapchain(swapchainHandle, window);
 			
-			if (!m_SwapchainManager->getSwapchain(swapchainHandle).getSwapchain()) {
+			if (!m_SwapchainManager->getSwapchain(swapchainHandle).m_Swapchain) {
 				return false;
 			}
 
 			setSwapchainImages(swapchainHandle);
 		}
 		
-		const auto& extent = m_SwapchainManager->getSwapchain(swapchainHandle).getExtent();
+		const auto& extent = m_SwapchainManager->getExtent(swapchainHandle);
 		
 		width = extent.width;
 		height = extent.height;
@@ -235,21 +236,18 @@ namespace vkcv
 		return (m_currentSwapchainImageIndex != std::numeric_limits<uint32_t>::max());
 	}
 
-	std::array<uint32_t, 2> getWidthHeightFromRenderTargets(
-		const std::vector<ImageHandle>& renderTargets,
-		const Swapchain& swapchain,
-		const ImageManager& imageManager) {
+	static std::array<uint32_t, 2> getWidthHeightFromRenderTargets(const std::vector<ImageHandle>& renderTargets,
+																   const vk::Extent2D& swapchainExtent,
+																   const ImageManager& imageManager) {
 
 		std::array<uint32_t, 2> widthHeight;
 
 		if (renderTargets.size() > 0) {
 			const vkcv::ImageHandle firstImage = renderTargets[0];
 			if (firstImage.isSwapchainImage()) {
-				const auto& swapchainExtent = swapchain.getExtent();
 				widthHeight[0] = swapchainExtent.width;
 				widthHeight[1] = swapchainExtent.height;
-			}
-			else {
+			} else {
 				widthHeight[0] = imageManager.getImageWidth(firstImage);
 				widthHeight[1] = imageManager.getImageHeight(firstImage);
 			}
@@ -262,27 +260,24 @@ namespace vkcv
 		return widthHeight;
 	}
 
-	vk::Framebuffer createFramebuffer(
-		const std::vector<ImageHandle>& renderTargets,
-		const ImageManager&             imageManager,
-		const Swapchain&                swapchain,
-		vk::RenderPass                  renderpass,
-		vk::Device                      device) {
+	static vk::Framebuffer createFramebuffer(const std::vector<ImageHandle>& renderTargets,
+											 const ImageManager& imageManager,
+											 const vk::Extent2D& renderExtent,
+											 vk::RenderPass renderpass,
+											 vk::Device device) {
 
 		std::vector<vk::ImageView> attachmentsViews;
 		for (const ImageHandle& handle : renderTargets) {
 			attachmentsViews.push_back(imageManager.getVulkanImageView(handle));
 		}
 
-		const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, swapchain, imageManager);
-
 		const vk::FramebufferCreateInfo createInfo(
 			{},
 			renderpass,
 			static_cast<uint32_t>(attachmentsViews.size()),
 			attachmentsViews.data(),
-			widthHeight[0],
-			widthHeight[1],
+			renderExtent.width,
+			renderExtent.height,
 			1);
 
 		return device.createFramebuffer(createInfo);
@@ -397,13 +392,18 @@ namespace vkcv
 		const std::vector<ImageHandle>  &renderTargets,
 		const WindowHandle              &windowHandle) {
 
-		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle();
+		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchain();
 
 		if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
 			return;
 		}
 
-		const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, m_SwapchainManager->getSwapchain(swapchainHandle), *m_ImageManager);
+		const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(
+				renderTargets,
+				m_SwapchainManager->getExtent(swapchainHandle),
+				*m_ImageManager
+		);
+		
 		const auto width  = widthHeight[0];
 		const auto height = widthHeight[1];
 
@@ -412,12 +412,18 @@ namespace vkcv
 
 		const vk::Pipeline          pipeline        = m_GraphicsPipelineManager->getVkPipeline(pipelineHandle);
 		const vk::PipelineLayout    pipelineLayout  = m_GraphicsPipelineManager->getVkPipelineLayout(pipelineHandle);
-		const vk::Rect2D            renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height));
+		const vk::Rect2D            renderArea (vk::Offset2D(0, 0), vk::Extent2D(width, height));
 
 		vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle);
 		transitionRendertargetsToAttachmentLayout(renderTargets, *m_ImageManager, cmdBuffer);
 
-		const vk::Framebuffer framebuffer = createFramebuffer(renderTargets, *m_ImageManager, m_SwapchainManager->getSwapchain(swapchainHandle), renderpass, m_Context.m_Device);
+		const vk::Framebuffer framebuffer = createFramebuffer(
+				renderTargets,
+				*m_ImageManager,
+				renderArea.extent,
+				renderpass,
+				m_Context.m_Device
+		);
 
 		if (!framebuffer) {
 			vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer");
@@ -471,9 +477,11 @@ namespace vkcv
         if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
             return;
         }
-		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle();
-        const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, m_SwapchainManager->getSwapchain(swapchainHandle),
-                                                                                    *m_ImageManager);
+		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchain();
+        const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(
+				renderTargets,
+				m_SwapchainManager->getExtent(swapchainHandle),
+				*m_ImageManager);
         const auto width = widthHeight[0];
         const auto height = widthHeight[1];
 
@@ -482,13 +490,18 @@ namespace vkcv
 
         const vk::Pipeline          pipeline        = m_GraphicsPipelineManager->getVkPipeline(pipelineHandle);
         const vk::PipelineLayout    pipelineLayout  = m_GraphicsPipelineManager->getVkPipelineLayout(pipelineHandle);
-        const vk::Rect2D            renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height));
+        const vk::Rect2D            renderArea (vk::Offset2D(0, 0), vk::Extent2D(width, height));
 
         vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle);
         transitionRendertargetsToAttachmentLayout(renderTargets, *m_ImageManager, cmdBuffer);
 
-        const vk::Framebuffer framebuffer = createFramebuffer(renderTargets, *m_ImageManager, m_SwapchainManager->getSwapchain(swapchainHandle), renderpass,
-                                                              m_Context.m_Device);
+        const vk::Framebuffer framebuffer = createFramebuffer(
+				renderTargets,
+				*m_ImageManager,
+				renderArea.extent,
+				renderpass,
+				m_Context.m_Device
+		);
 
         if (!framebuffer) {
             vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer");
@@ -603,13 +616,16 @@ namespace vkcv
 		const std::vector<ImageHandle>&                     renderTargets,
 		const WindowHandle&                                 windowHandle) {
 
-		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle();
+		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchain();
 
 		if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
 			return;
 		}
 
-		const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, m_SwapchainManager->getSwapchain(swapchainHandle), *m_ImageManager);
+		const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(
+				renderTargets,
+				m_SwapchainManager->getExtent(swapchainHandle),
+				*m_ImageManager);
 		const auto width  = widthHeight[0];
 		const auto height = widthHeight[1];
 
@@ -618,12 +634,18 @@ namespace vkcv
 
 		const vk::Pipeline          pipeline = m_GraphicsPipelineManager->getVkPipeline(pipelineHandle);
 		const vk::PipelineLayout    pipelineLayout = m_GraphicsPipelineManager->getVkPipelineLayout(pipelineHandle);
-		const vk::Rect2D            renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height));
+		const vk::Rect2D            renderArea (vk::Offset2D(0, 0), vk::Extent2D(width, height));
 
 		vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle);
 		transitionRendertargetsToAttachmentLayout(renderTargets, *m_ImageManager, cmdBuffer);
 
-		const vk::Framebuffer framebuffer = createFramebuffer(renderTargets, *m_ImageManager, m_SwapchainManager->getSwapchain(swapchainHandle), renderpass, m_Context.m_Device);
+		const vk::Framebuffer framebuffer = createFramebuffer(
+				renderTargets,
+				*m_ImageManager,
+				renderArea.extent,
+				renderpass,
+				m_Context.m_Device
+		);
 
 		if (!framebuffer) {
 			vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer");
@@ -830,8 +852,7 @@ namespace vkcv
 	}
 
 	void Core::endFrame(const WindowHandle& windowHandle) {
-
-		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle();
+		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchain();
 
 		if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
 			return;
@@ -842,7 +863,7 @@ namespace vkcv
 			m_SyncResources.swapchainImageAcquired
 		};
 
-		const vk::SwapchainKHR& swapchain = m_SwapchainManager->getSwapchain(swapchainHandle).getSwapchain();
+		const vk::SwapchainKHR& swapchain = m_SwapchainManager->getSwapchain(swapchainHandle).m_Swapchain;
 		const vk::PresentInfoKHR presentInfo(
 			waitSemaphores,
 			swapchain,
@@ -852,7 +873,7 @@ namespace vkcv
 		vk::Result result;
 		
 		try {
-			result = m_Context.getDevice().getQueue(m_SwapchainManager->getSwapchain(swapchainHandle).getPresentQueueIndex(),0).presentKHR(presentInfo);
+			result = m_Context.getDevice().getQueue(m_SwapchainManager->getPresentQueueIndex(swapchainHandle),0).presentKHR(presentInfo);
 		} catch (const vk::OutOfDateKHRError& e) {
 			result = vk::Result::eErrorOutOfDateKHR;
 		} catch (const vk::DeviceLostError& e) {
@@ -970,14 +991,13 @@ namespace vkcv
 		return *m_downsampler;
 	}
 
-	WindowHandle Core::createWindow(
-			const char *applicationName,
-			uint32_t windowWidth,
-			uint32_t windowHeight,
-			bool resizeable) {
+	WindowHandle Core::createWindow(const char *applicationName,
+									uint32_t windowWidth,
+									uint32_t windowHeight,
+									bool resizeable) {
 
 		WindowHandle windowHandle = m_WindowManager->createWindow(*m_SwapchainManager ,applicationName, windowWidth, windowHeight, resizeable);
-		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle();
+		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchain();
 		setSwapchainImages( swapchainHandle );
 		return windowHandle;
 	}
@@ -985,7 +1005,19 @@ namespace vkcv
 	Window& Core::getWindow(const WindowHandle& handle) {
 		return m_WindowManager->getWindow(handle);
 	}
-
+	
+	vk::Format Core::getSwapchainFormat(const SwapchainHandle &swapchain) const {
+		return m_SwapchainManager->getFormat(swapchain);
+	}
+	
+	uint32_t Core::getSwapchainImageCount(const SwapchainHandle &swapchain) const {
+		return m_SwapchainManager->getImageCount(swapchain);
+	}
+	
+	vk::Extent2D Core::getSwapchainExtent(const SwapchainHandle& swapchain) const {
+		return m_SwapchainManager->getExtent(swapchain);
+	}
+	
 	uint32_t Core::getImageWidth(const ImageHandle& image)
 	{
 		return m_ImageManager->getImageWidth(image);
@@ -1017,19 +1049,6 @@ namespace vkcv
 		return m_ImageManager->getImageArrayLayers(image);
 	}
 
-	Swapchain& Core::getSwapchainOfCurrentWindow() {
-		return m_SwapchainManager->getSwapchain(Window::getFocusedWindow().getSwapchainHandle());
-	}
-
-	Swapchain& Core::getSwapchain(const SwapchainHandle& handle) {
-		return m_SwapchainManager->getSwapchain(handle);
-	}
-
-	Swapchain& Core::getSwapchain(const WindowHandle& handle) {
-		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(handle).getSwapchainHandle();
-		return getSwapchain(swapchainHandle);
-	}
-
 	DescriptorSetLayoutHandle Core::createDescriptorSetLayout(const DescriptorBindings &bindings) {
 	    return m_DescriptorSetLayoutManager->createDescriptorSetLayout(bindings);
 	}
@@ -1202,16 +1221,16 @@ namespace vkcv
 	}
 
 	void Core::setSwapchainImages( SwapchainHandle handle ) {
-		Swapchain swapchain = m_SwapchainManager->getSwapchain(handle);
+		const auto& swapchain = m_SwapchainManager->getSwapchain(handle);
 		const auto swapchainImages = m_SwapchainManager->getSwapchainImages(handle);
 		const auto swapchainImageViews = m_SwapchainManager->createSwapchainImageViews(handle);
 
 		m_ImageManager->setSwapchainImages(
 				swapchainImages,
 				swapchainImageViews,
-				swapchain.getExtent().width,
-				swapchain.getExtent().height,
-				swapchain.getFormat()
+				swapchain.m_Extent.width,
+				swapchain.m_Extent.height,
+				swapchain.m_Format
 		);
 	}
 	
diff --git a/src/vkcv/QueueManager.cpp b/src/vkcv/QueueManager.cpp
index d2a4d593..c818769e 100644
--- a/src/vkcv/QueueManager.cpp
+++ b/src/vkcv/QueueManager.cpp
@@ -5,7 +5,6 @@
 
 #include "vkcv/QueueManager.hpp"
 #include "vkcv/Logger.hpp"
-#include "vkcv/Swapchain.hpp"
 
 namespace vkcv {
 
diff --git a/src/vkcv/Surface.cpp b/src/vkcv/Surface.cpp
deleted file mode 100644
index 3fa601b7..00000000
--- a/src/vkcv/Surface.cpp
+++ /dev/null
@@ -1,258 +0,0 @@
-
-#include <vkcv/Surface.hpp>
-#include <vkcv/Logger.hpp>
-
-#include <GLFW/glfw3.h>
-
-namespace vkcv {
-	
-	/**
-    * @brief Creates vulkan surface and checks availability.
-    *
-    * @param[in,out] window Current window for the surface
-    * @param[in,out] instance Vulkan-Instance
-    * @param[in,out] physicalDevice Vulkan-PhysicalDevice
-    * @param[out] surface Vulkan-Surface
-    * @return Created vulkan surface
-    */
-	bool createVulkanSurface(GLFWwindow* window,
-							 const vk::Instance& instance,
-							 const vk::PhysicalDevice& physicalDevice,
-							 vk::SurfaceKHR& surface) {
-		VkSurfaceKHR api_surface;
-		
-		if (glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &api_surface) != VK_SUCCESS) {
-			vkcv_log(LogLevel::ERROR, "Failed to create a window surface");
-			return false;
-		}
-		
-		vk::Bool32 surfaceSupport = false;
-		surface = vk::SurfaceKHR(api_surface);
-		
-		if ((physicalDevice.getSurfaceSupportKHR(0, surface, &surfaceSupport) != vk::Result::eSuccess) ||
-			(!surfaceSupport)) {
-			vkcv_log(LogLevel::ERROR, "Surface is not supported by the device");
-			instance.destroy(surface);
-			surface = nullptr;
-			return false;
-		}
-		
-		return true;
-	}
-	
-	/**
-     * @brief Chooses an Extent and clamps values to the available capabilities.
-     *
-     * @param physicalDevice Vulkan-PhysicalDevice
-     * @param surface Vulkan-Surface of the swapchain
-     * @param window Window of the current application
-     * @return Chosen Extent for the surface
-     */
-	vk::Extent2D chooseExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, const Window &window) {
-		int fb_width, fb_height;
-		window.getFramebufferSize(fb_width, fb_height);
-		
-		VkExtent2D extent2D = {
-				static_cast<uint32_t>(fb_width),
-				static_cast<uint32_t>(fb_height)
-		};
-		
-		vk::SurfaceCapabilitiesKHR surfaceCapabilities;
-		if(physicalDevice.getSurfaceCapabilitiesKHR(surface, &surfaceCapabilities) != vk::Result::eSuccess) {
-			vkcv_log(LogLevel::WARNING, "The capabilities of the surface can not be retrieved");
-			
-			extent2D.width = std::max(MIN_SURFACE_SIZE, extent2D.width);
-			extent2D.height = std::max(MIN_SURFACE_SIZE, extent2D.height);
-		} else {
-			extent2D.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, extent2D.width));
-			extent2D.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, extent2D.height));
-		}
-		
-		return extent2D;
-	}
-	
-	/**
-     * @brief Chooses Surface Format for the current surface
-     *
-     * @param physicalDevice Vulkan-PhysicalDevice
-     * @param surface Vulkan-Surface of the swapchain
-     * @return Available Format
-     */
-	vk::SurfaceFormatKHR chooseSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
-		std::vector<vk::SurfaceFormatKHR> availableFormats = physicalDevice.getSurfaceFormatsKHR(surface);
-		
-		for (const auto& availableFormat : availableFormats) {
-			if (availableFormat.format == vk::Format::eB8G8R8A8Unorm  && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
-				return availableFormat;
-			}
-		}
-		
-		return availableFormats[0];
-	}
-	
-	/**
-     * @brief Returns vk::PresentModeKHR::eMailbox if available or
-     * vk::PresentModeKHR::eFifo otherwise
-     *
-     * @param physicalDevice Vulkan-PhysicalDevice
-     * @param surface Vulkan-Surface of the swapchain
-     * @return Available PresentationMode
-     */
-	vk::PresentModeKHR choosePresentMode(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
-		std::vector<vk::PresentModeKHR> availablePresentModes = physicalDevice.getSurfacePresentModesKHR(surface);
-		
-		for (const auto& availablePresentMode : availablePresentModes) {
-			if (availablePresentMode == vk::PresentModeKHR::eMailbox) {
-				return availablePresentMode;
-			}
-		}
-		// The FIFO present mode is guaranteed by the spec to be supported
-		return vk::PresentModeKHR::eFifo;
-	}
-	
-	/**
-	* @brief Returns the minImageCount +1 for at least double buffering,
-	* if it's greater than maxImageCount return maxImageCount
-	*
-	* @param physicalDevice Vulkan-PhysicalDevice
-	* @param surface Vulkan-Surface of the swapchain
-	* @return Available image count
-	*/
-	uint32_t chooseImageCount(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
-		vk::SurfaceCapabilitiesKHR surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface);
-		
-		// minImageCount should always be at least 2; set to 3 for triple buffering
-		uint32_t imageCount = surfaceCapabilities.minImageCount + 1;
-		
-		// check if requested image count is supported
-		if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount) {
-			imageCount = surfaceCapabilities.maxImageCount;
-		}
-		
-		return imageCount;
-	}
-	
-	Surface::Surface(const Context &context,
-					 const vk::SurfaceKHR &handle,
-					 uint32_t presentQueueIndex,
-					 const vk::Extent2D &extent,
-					 vk::Format format,
-					 vk::ColorSpaceKHR colorSpace)
-					 : m_Context(&context),
-					   m_Handle(handle),
-					   m_PresentQueueIndex(presentQueueIndex),
-					   m_Extent(extent),
-					   m_Format(format),
-					   m_ColorSpace(colorSpace) {
-	}
-	
-	vk::SwapchainKHR Surface::createVulkanSwapchain(const Window &window,
-													const vk::SwapchainKHR &oldSwapchain) {
-		if ((!m_Context) || (!m_Handle))
-			return nullptr;
-		
-		const vk::PhysicalDevice& physicalDevice = m_Context->getPhysicalDevice();
-		const vk::Device& device = m_Context->getDevice();
-		
-		m_Extent = chooseExtent(physicalDevice, m_Handle, window);
-		
-		if ((m_Extent.width < MIN_SURFACE_SIZE) || (m_Extent.height < MIN_SURFACE_SIZE)) {
-			return nullptr;
-		}
-		
-		vk::SurfaceFormatKHR chosenSurfaceFormat = chooseSurfaceFormat(physicalDevice, m_Handle);
-		vk::PresentModeKHR chosenPresentMode = choosePresentMode(physicalDevice, m_Handle);
-		uint32_t chosenImageCount = chooseImageCount(physicalDevice, m_Handle);
-		
-		m_Format = chosenSurfaceFormat.format;
-		m_ColorSpace = chosenSurfaceFormat.colorSpace;
-		
-		vk::SwapchainCreateInfoKHR swapchainCreateInfo (
-				vk::SwapchainCreateFlagsKHR(),
-				m_Handle,
-				chosenImageCount,
-				m_Format,
-				m_ColorSpace,
-				m_Extent,
-				1,
-				vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage,
-				vk::SharingMode::eExclusive,
-				0,
-				nullptr,
-				vk::SurfaceTransformFlagBitsKHR::eIdentity,
-				vk::CompositeAlphaFlagBitsKHR::eOpaque,
-				chosenPresentMode,
-				true,
-				oldSwapchain
-		);
-		
-		return device.createSwapchainKHR(swapchainCreateInfo);
-	}
-	
-	Surface::Surface(Surface &&other) noexcept
-	: m_Context(other.m_Context),
-	  m_Handle(other.m_Handle),
-	  m_PresentQueueIndex(other.m_PresentQueueIndex),
-	  m_Extent(other.m_Extent),
-	  m_Format(other.m_Format),
-	  m_ColorSpace(other.m_ColorSpace) {
-		other.m_Context = nullptr;
-		other.m_Handle = nullptr;
-	}
-	
-	Surface &Surface::operator=(Surface &&other) noexcept {
-		m_Context = other.m_Context;
-		m_Handle = other.m_Handle;
-		m_PresentQueueIndex = other.m_PresentQueueIndex;
-		m_Extent = other.m_Extent;
-		m_Format = other.m_Format;
-		m_ColorSpace = other.m_ColorSpace;
-		
-		other.m_Context = nullptr;
-		other.m_Handle = nullptr;
-		return *this;
-	}
-	
-	Surface::~Surface() {
-		// needs to be destroyed by creator
-	}
-	
-	Surface Surface::create(const Window &window, const Context &context) {
-		const vk::Instance& instance = context.getInstance();
-		const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice();
-		
-		uint32_t presentQueueIndex = 0;
-		
-		vk::SurfaceKHR surfaceHandle;
-		if (!createVulkanSurface(window.getWindow(), instance, physicalDevice, surfaceHandle))
-			surfaceHandle = nullptr;
-		else
-			presentQueueIndex = QueueManager::checkSurfaceSupport(physicalDevice, surfaceHandle);
-		
-		const vk::Extent2D extent = chooseExtent(physicalDevice, surfaceHandle, window);
-		const vk::SurfaceFormatKHR format = chooseSurfaceFormat(physicalDevice, surfaceHandle);
-		
-		return { context, surfaceHandle, presentQueueIndex, extent, format.format, format.colorSpace };
-	}
-	
-	vk::SurfaceKHR Surface::getSurface() const {
-		return m_Handle;
-	}
-	
-	uint32_t Surface::getPresentQueueIndex() const {
-		return m_PresentQueueIndex;
-	}
-	
-	const vk::Extent2D& Surface::getExtent() const {
-		return m_Extent;
-	}
-	
-	vk::Format Surface::getFormat() const {
-		return m_Format;
-	}
-	
-	vk::ColorSpaceKHR Surface::getColorSpace() const {
-		return m_ColorSpace;
-	}
-
-}
diff --git a/src/vkcv/Swapchain.cpp b/src/vkcv/Swapchain.cpp
deleted file mode 100644
index 2ca69e7d..00000000
--- a/src/vkcv/Swapchain.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-#include <vkcv/Swapchain.hpp>
-#include <utility>
-
-#include <GLFW/glfw3.h>
-
-namespace vkcv
-{
-
-    Swapchain::Swapchain(const Context &context,
-						 const Surface &surface,
-                         vk::SwapchainKHR swapchain) noexcept
-						 : m_Context(&context),
-						   m_Surface(surface),
-						   m_Swapchain(swapchain),
-						   m_RecreationRequired(false) {
-	}
-    
-    Swapchain::Swapchain(const Swapchain &other) :
-	m_Context(other.m_Context),
-	m_Surface(other.m_Surface),
-	m_Swapchain(other.m_Swapchain),
-	m_RecreationRequired(other.m_RecreationRequired.load()) {
-	}
-
-    const vk::SwapchainKHR& Swapchain::getSwapchain() const {
-        return m_Swapchain;
-    }
-
-    const Surface& Swapchain::getSurface() const {
-        return m_Surface;
-    }
-
-    vk::Format Swapchain::getFormat() const{
-        return m_Surface.getFormat();
-    }
-
-    Swapchain Swapchain::create(const Window &window, const Context &context) {
-        Surface surface = Surface::create(window, context);
-
-        vk::SwapchainKHR swapchain = surface.createVulkanSwapchain(
-				window, nullptr
-		);
-
-        return { context, surface, swapchain };
-    }
-    
-    bool Swapchain::shouldUpdateSwapchain() const {
-    	return m_RecreationRequired;
-    }
-    
-    void Swapchain::updateSwapchain(const Context &context, const Window &window) {
-    	if (!m_RecreationRequired.exchange(false)) {
-			return;
-		}
-    	
-		vk::SwapchainKHR oldSwapchain = m_Swapchain;
-	
-		m_Swapchain = m_Surface.createVulkanSwapchain(
-				window, oldSwapchain
-		);
-		
-		if (!m_Swapchain) {
-			signalSwapchainRecreation();
-		}
-		
-		if (oldSwapchain) {
-			context.getDevice().destroySwapchainKHR(oldSwapchain);
-		}
-    }
-
-    void Swapchain::signalSwapchainRecreation() {
-		m_RecreationRequired = true;
-    }
-    
-    const vk::Extent2D& Swapchain::getExtent() const {
-    	return m_Surface.getExtent();
-    }
-
-    Swapchain::~Swapchain() {
-        // needs to be destroyed by creator
-    }
-
-	uint32_t Swapchain::getImageCount() const {
-		uint32_t imageCount = 0;
-		
-		if (vk::Result::eSuccess != m_Context->getDevice().getSwapchainImagesKHR(m_Swapchain, &imageCount, nullptr))
-			return 0;
-		else
-			return imageCount;
-	}
-
-	uint32_t Swapchain::getPresentQueueIndex() const {
-		return m_Surface.getPresentQueueIndex();
-	}
-	
-}
diff --git a/src/vkcv/SwapchainManager.cpp b/src/vkcv/SwapchainManager.cpp
index 369e077a..f16a4c30 100644
--- a/src/vkcv/SwapchainManager.cpp
+++ b/src/vkcv/SwapchainManager.cpp
@@ -1,62 +1,309 @@
 #include "SwapchainManager.hpp"
 
-namespace vkcv {
+#include <GLFW/glfw3.h>
+
+#include "vkcv/Core.hpp"
 
-	SwapchainManager::SwapchainManager() noexcept {
+namespace vkcv {
+	
+	uint64_t SwapchainManager::getIdFrom(const SwapchainHandle &handle) const {
+		return handle.getId();
+	}
+	
+	SwapchainHandle SwapchainManager::createById(uint64_t id, const HandleDestroyFunction &destroy) {
+		return SwapchainHandle(id, destroy);
+	}
+	
+	void SwapchainManager::destroyById(uint64_t id) {
+		auto& swapchain = getById(id);
+		
+		if (swapchain.m_Swapchain) {
+			getCore().getContext().getDevice().destroySwapchainKHR(swapchain.m_Swapchain);
+			swapchain.m_Swapchain = nullptr;
+		}
+		
+		if (swapchain.m_Surface) {
+			getCore().getContext().getInstance().destroySurfaceKHR(swapchain.m_Surface);
+			swapchain.m_Surface = nullptr;
+		}
 	}
+	
+	SwapchainManager::SwapchainManager() noexcept : HandleManager<SwapchainEntry, SwapchainHandle>() {}
 
 	SwapchainManager::~SwapchainManager() noexcept {
-		for (uint64_t id = 0; id < m_swapchains.size(); id++) {
-			destroySwapchainById(id);
+		clear();
+	}
+	
+	/**
+    * @brief Creates vulkan surface and checks availability.
+    *
+    * @param[in,out] window Current window for the surface
+    * @param[in,out] instance Vulkan-Instance
+    * @param[in,out] physicalDevice Vulkan-PhysicalDevice
+    * @param[out] surface Vulkan-Surface
+    * @return Created vulkan surface
+    */
+	static bool createVulkanSurface(GLFWwindow* window,
+									const vk::Instance& instance,
+									const vk::PhysicalDevice& physicalDevice,
+									vk::SurfaceKHR& surface) {
+		VkSurfaceKHR api_surface;
+		
+		if (glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &api_surface) != VK_SUCCESS) {
+			vkcv_log(LogLevel::ERROR, "Failed to create a window surface");
+			return false;
+		}
+		
+		vk::Bool32 surfaceSupport = false;
+		surface = vk::SurfaceKHR(api_surface);
+		
+		if ((physicalDevice.getSurfaceSupportKHR(0, surface, &surfaceSupport) != vk::Result::eSuccess) ||
+			(!surfaceSupport)) {
+			vkcv_log(LogLevel::ERROR, "Surface is not supported by the device");
+			instance.destroy(surface);
+			surface = nullptr;
+			return false;
+		}
+		
+		return true;
+	}
+	
+	/**
+     * @brief Chooses an Extent and clamps values to the available capabilities.
+     *
+     * @param physicalDevice Vulkan-PhysicalDevice
+     * @param surface Vulkan-Surface of the swapchain
+     * @param window Window of the current application
+     * @return Chosen Extent for the surface
+     */
+	static vk::Extent2D chooseExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, const Window &window) {
+		int fb_width, fb_height;
+		window.getFramebufferSize(fb_width, fb_height);
+		
+		VkExtent2D extent2D = {
+				static_cast<uint32_t>(fb_width),
+				static_cast<uint32_t>(fb_height)
+		};
+		
+		vk::SurfaceCapabilitiesKHR surfaceCapabilities;
+		if(physicalDevice.getSurfaceCapabilitiesKHR(surface, &surfaceCapabilities) != vk::Result::eSuccess) {
+			vkcv_log(LogLevel::WARNING, "The capabilities of the surface can not be retrieved");
+			
+			extent2D.width = std::max(MIN_SURFACE_SIZE, extent2D.width);
+			extent2D.height = std::max(MIN_SURFACE_SIZE, extent2D.height);
+		} else {
+			extent2D.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, extent2D.width));
+			extent2D.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, extent2D.height));
+		}
+		
+		return extent2D;
+	}
+	
+	/**
+     * @brief Chooses Surface Format for the current surface
+     *
+     * @param physicalDevice Vulkan-PhysicalDevice
+     * @param surface Vulkan-Surface of the swapchain
+     * @return Available Format
+     */
+	static vk::SurfaceFormatKHR chooseSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
+		std::vector<vk::SurfaceFormatKHR> availableFormats = physicalDevice.getSurfaceFormatsKHR(surface);
+		
+		for (const auto& availableFormat : availableFormats) {
+			if (availableFormat.format == vk::Format::eB8G8R8A8Unorm && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
+				return availableFormat;
+			}
+		}
+		
+		return availableFormats[0];
+	}
+	
+	/**
+     * @brief Returns vk::PresentModeKHR::eMailbox if available or
+     * vk::PresentModeKHR::eFifo otherwise
+     *
+     * @param physicalDevice Vulkan-PhysicalDevice
+     * @param surface Vulkan-Surface of the swapchain
+     * @return Available PresentationMode
+     */
+	static vk::PresentModeKHR choosePresentMode(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
+		std::vector<vk::PresentModeKHR> availablePresentModes = physicalDevice.getSurfacePresentModesKHR(surface);
+		
+		for (const auto& availablePresentMode : availablePresentModes) {
+			if (availablePresentMode == vk::PresentModeKHR::eMailbox) {
+				return availablePresentMode;
+			}
 		}
-		m_swapchains.clear();
+		// The FIFO present mode is guaranteed by the spec to be supported
+		return vk::PresentModeKHR::eFifo;
+	}
+	
+	/**
+	* @brief Returns the minImageCount +1 for at least double buffering,
+	* if it's greater than maxImageCount return maxImageCount
+	*
+	* @param physicalDevice Vulkan-PhysicalDevice
+	* @param surface Vulkan-Surface of the swapchain
+	* @return Available image count
+	*/
+	static uint32_t chooseImageCount(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
+		vk::SurfaceCapabilitiesKHR surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface);
+		
+		// minImageCount should always be at least 2; set to 3 for triple buffering
+		uint32_t imageCount = surfaceCapabilities.minImageCount + 1;
+		
+		// check if requested image count is supported
+		if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount) {
+			imageCount = surfaceCapabilities.maxImageCount;
+		}
+		
+		return imageCount;
+	}
+	
+	static bool createVulkanSwapchain(const Context& context,
+									  const Window &window,
+									  SwapchainEntry& entry) {
+		const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice();
+		const vk::Device& device = context.getDevice();
+		
+		entry.m_Extent = chooseExtent(physicalDevice, entry.m_Surface, window);
+		
+		if ((entry.m_Extent.width < MIN_SURFACE_SIZE) || (entry.m_Extent.height < MIN_SURFACE_SIZE)) {
+			return false;
+		}
+		
+		vk::SurfaceFormatKHR chosenSurfaceFormat = chooseSurfaceFormat(physicalDevice, entry.m_Surface);
+		vk::PresentModeKHR chosenPresentMode = choosePresentMode(physicalDevice, entry.m_Surface);
+		uint32_t chosenImageCount = chooseImageCount(physicalDevice, entry.m_Surface);
+		
+		entry.m_Format = chosenSurfaceFormat.format;
+		entry.m_ColorSpace = chosenSurfaceFormat.colorSpace;
+		
+		vk::SwapchainCreateInfoKHR swapchainCreateInfo (
+				vk::SwapchainCreateFlagsKHR(),
+				entry.m_Surface,
+				chosenImageCount,
+				entry.m_Format,
+				entry.m_ColorSpace,
+				entry.m_Extent,
+				1,
+				vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage,
+				vk::SharingMode::eExclusive,
+				0,
+				nullptr,
+				vk::SurfaceTransformFlagBitsKHR::eIdentity,
+				vk::CompositeAlphaFlagBitsKHR::eOpaque,
+				chosenPresentMode,
+				true,
+				entry.m_Swapchain
+		);
+		
+		entry.m_Swapchain = device.createSwapchainKHR(swapchainCreateInfo);
+		return true;
 	}
 
 	SwapchainHandle SwapchainManager::createSwapchain(Window &window) {
-		const uint64_t id = m_swapchains.size();
-
-		Swapchain swapchain = Swapchain::create(window, *m_context);
-
-		m_swapchains.push_back(swapchain);
-		SwapchainHandle swapchainHandle = SwapchainHandle(id, [&](uint64_t id) { destroySwapchainById(id); });
-		window.m_swapchainHandle = swapchainHandle;
-		return swapchainHandle;
+		const vk::Instance& instance = getCore().getContext().getInstance();
+		const vk::PhysicalDevice& physicalDevice = getCore().getContext().getPhysicalDevice();
+		
+		vk::SurfaceKHR surfaceHandle;
+		if (!createVulkanSurface(window.getWindow(), instance, physicalDevice, surfaceHandle)) {
+			return {};
+		}
+		
+		uint32_t presentQueueIndex = QueueManager::checkSurfaceSupport(physicalDevice, surfaceHandle);
+		
+		const vk::Extent2D extent = chooseExtent(physicalDevice, surfaceHandle, window);
+		const vk::SurfaceFormatKHR format = chooseSurfaceFormat(physicalDevice, surfaceHandle);
+		
+		SwapchainEntry entry {
+			nullptr,
+			false,
+			
+			surfaceHandle,
+			presentQueueIndex,
+			extent,
+			format.format,
+			format.colorSpace
+		};
+		
+		if (!createVulkanSwapchain(getCore().getContext(), window, entry)) {
+			instance.destroySurfaceKHR(surfaceHandle);
+			return {};
+		}
+		
+		window.m_swapchainHandle = add(entry);
+		return window.m_swapchainHandle;
 	}
 
-	Swapchain& SwapchainManager::getSwapchain(const SwapchainHandle& handle) {
-		return m_swapchains[handle.getId()];
+	SwapchainEntry& SwapchainManager::getSwapchain(const SwapchainHandle& handle) {
+		return (*this)[handle];
 	}
-
-	void SwapchainManager::destroySwapchainById(uint64_t id) {
-
-		if (id >= m_swapchains.size()) {
-			vkcv_log(LogLevel::ERROR, "Invalid id");
+	
+	bool SwapchainManager::shouldUpdateSwapchain(const SwapchainHandle &handle) const {
+		return (*this)[handle].m_RecreationRequired;
+	}
+	
+	void SwapchainManager::updateSwapchain(const SwapchainHandle &handle, const Window &window) {
+		auto& swapchain = (*this)[handle];
+		
+		if (!swapchain.m_RecreationRequired) {
 			return;
+		} else {
+			swapchain.m_RecreationRequired = false;
 		}
-		Swapchain &swapchain = m_swapchains[id];
-
-		if (swapchain.m_Swapchain) {
-			m_context->getDevice().destroySwapchainKHR(swapchain.m_Swapchain);
-			swapchain.m_Swapchain = nullptr;
-		}
 		
-		if (swapchain.m_Surface.m_Handle) {
-			m_context->getInstance().destroySurfaceKHR(swapchain.m_Surface.m_Handle);
-			swapchain.m_Surface.m_Handle = nullptr;
+		vk::SwapchainKHR oldSwapchain = swapchain.m_Swapchain;
+		
+		if (createVulkanSwapchain(getCore().getContext(), window, swapchain)) {
+			if (oldSwapchain) {
+				getCore().getContext().getDevice().destroySwapchainKHR(oldSwapchain);
+			}
+		} else {
+			signalRecreation(handle);
 		}
 	}
-
+	
 	void SwapchainManager::signalRecreation(const SwapchainHandle& handle) {
-		m_swapchains[handle.getId()].signalSwapchainRecreation();
+		(*this)[handle].m_RecreationRequired = true;
 	}
-
-	std::vector<vk::Image> SwapchainManager::getSwapchainImages(const SwapchainHandle& handle) {
-		return m_context->getDevice().getSwapchainImagesKHR(m_swapchains[handle.getId()].getSwapchain());
+	
+	vk::Format SwapchainManager::getFormat(const SwapchainHandle &handle) const {
+		return (*this)[handle].m_Format;
+	}
+	
+	uint32_t SwapchainManager::getImageCount(const SwapchainHandle &handle) const {
+		auto& swapchain = (*this)[handle];
+		
+		uint32_t imageCount;
+		if (vk::Result::eSuccess != getCore().getContext().getDevice().getSwapchainImagesKHR(swapchain.m_Swapchain,
+																							 &imageCount,
+																							 nullptr)) {
+			return 0;
+		} else {
+			return imageCount;
+		}
+	}
+	
+	const vk::Extent2D &SwapchainManager::getExtent(const SwapchainHandle &handle) const {
+		return (*this)[handle].m_Extent;
+	}
+	
+	uint32_t SwapchainManager::getPresentQueueIndex(const SwapchainHandle &handle) const {
+		return (*this)[handle].m_PresentQueueIndex;
+	}
+	
+	vk::ColorSpaceKHR SwapchainManager::getSurfaceColorSpace(const SwapchainHandle &handle) const {
+		return (*this)[handle].m_ColorSpace;
+	}
+	
+	std::vector<vk::Image> SwapchainManager::getSwapchainImages(const SwapchainHandle& handle) const {
+		return getCore().getContext().getDevice().getSwapchainImagesKHR((*this)[handle].m_Swapchain);
 	}
 
 	std::vector<vk::ImageView> SwapchainManager::createSwapchainImageViews(SwapchainHandle& handle) {
 		std::vector<vk::Image> images = getSwapchainImages(handle);
-		Swapchain &swapchain = m_swapchains[handle.getId()];
+		auto& swapchain = (*this)[handle];
 
 		std::vector<vk::ImageView> imageViews;
 		imageViews.reserve(images.size());
@@ -74,12 +321,13 @@ namespace vkcv {
 					vk::ImageViewCreateFlags(),
 					image,
 					vk::ImageViewType::e2D,
-					swapchain.getFormat(),
+					swapchain.m_Format,
 					componentMapping,
 					subResourceRange);
 
-			imageViews.push_back(m_context->getDevice().createImageView(imageViewCreateInfo));
+			imageViews.push_back(getCore().getContext().getDevice().createImageView(imageViewCreateInfo));
 		}
+		
 		return imageViews;
 	}
 }
\ No newline at end of file
diff --git a/src/vkcv/SwapchainManager.hpp b/src/vkcv/SwapchainManager.hpp
index 285641db..d9ba37aa 100644
--- a/src/vkcv/SwapchainManager.hpp
+++ b/src/vkcv/SwapchainManager.hpp
@@ -1,35 +1,55 @@
 #pragma once
+/**
+ * @authors Tobias Frisch
+ * @file vkcv/SwapchainManager.hpp
+ * @brief Class to manage the swapchains and their surfaces.
+ */
 
+#include <atomic>
 #include <vector>
-#include <GLFW/glfw3.h>
+#include <vulkan/vulkan.hpp>
 
-#include "WindowManager.hpp"
-#include "vkcv/Swapchain.hpp"
-#include "vkcv/Handles.hpp"
+#include "vkcv/Window.hpp"
+
+#include "HandleManager.hpp"
 
 namespace vkcv {
 	
-	class Core;
+	const uint32_t MIN_SURFACE_SIZE = 2;
+	
+	/**
+     * @brief Structure to handle swapchains.
+     */
+	struct SwapchainEntry {
+		vk::SwapchainKHR m_Swapchain;
+		bool m_RecreationRequired;
+		
+		vk::SurfaceKHR m_Surface;
+		uint32_t m_PresentQueueIndex;
+		vk::Extent2D m_Extent;
+		vk::Format m_Format;
+		vk::ColorSpaceKHR m_ColorSpace;
+	};
 	
 	/**
 	 * @brief Class to manage the creation, destruction and
 	 * allocation of swapchains.
 	 */
-	class SwapchainManager {
+	class SwapchainManager : public HandleManager<SwapchainEntry, SwapchainHandle> {
 		friend class Core;
-
-		friend class WindowManager;
-
 	private:
-		std::vector<Swapchain> m_swapchains;
-
-		Context *m_context;
-
+		[[nodiscard]]
+		uint64_t getIdFrom(const SwapchainHandle& handle) const override;
+		
+		[[nodiscard]]
+		SwapchainHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override;
+		
 		/**
-		 * destroys a specific swapchain by a given id
-		 * @param id of the swapchain to be destroyed
+		 * @brief Destroys a specific swapchain by a given id
+		 *
+		 * @param[in] id ID of the swapchain to be destroyed
 		 */
-		void destroySwapchainById(uint64_t id);
+		void destroyById(uint64_t id) override;
 
 	public:
 		SwapchainManager() noexcept;
@@ -37,15 +57,7 @@ namespace vkcv {
 		/**
 		 * destroys every swapchain
 		 */
-		~SwapchainManager() noexcept;
-
-		SwapchainManager(SwapchainManager &&other) = delete;
-
-		SwapchainManager(const SwapchainManager &other) = delete;
-
-		SwapchainManager &operator=(SwapchainManager &&other) = delete;
-
-		SwapchainManager &operator=(const SwapchainManager &other) = delete;
+		~SwapchainManager() noexcept override;
 
 		/**
 		 * creates a swapchain and returns the handle
@@ -59,27 +71,96 @@ namespace vkcv {
 		 * @return the reference of the swapchain
 		 */
 		[[nodiscard]]
-		Swapchain &getSwapchain(const SwapchainHandle& handle);
-
+		SwapchainEntry& getSwapchain(const SwapchainHandle& handle);
+		
+		/**
+		 * @brief Checks whether the swapchain needs to be recreated.
+		 *
+		 * @param[in] handle Swapchain handle
+		 * @return True, if the swapchain should be updated,
+		 * otherwise false.
+		 */
+		bool shouldUpdateSwapchain(const SwapchainHandle& handle) const;
+		
+		/**
+		 * @brief Updates and recreates the swapchain.
+		 *
+		 * @param[in] handle Swapchain handle
+		 * @param[in] window that the new swapchain gets bound to
+		 */
+		void updateSwapchain(const SwapchainHandle& handle, const Window &window);
+		
 		/**
-		 * sets  the recreation  flag fot the swapchain
-		 * @param handle of the swapchain that should be recreated
+		 * @brief Signals the swapchain to be recreated.
+		 *
+		 * @param[in] handle Swapchain handle
 		 */
 		void signalRecreation(const SwapchainHandle& handle);
+		
+		/**
+         * @brief Returns the image format for the current surface
+         * of the swapchain.
+         *
+         * @param[in] handle Swapchain handle
+         * @return Swapchain image format
+         */
+		[[nodiscard]]
+		vk::Format getFormat(const SwapchainHandle& handle) const;
+		
+		/**
+		 * @brief Returns the amount of images for the swapchain.
+		 *
+		 * @param[in] handle Swapchain handle
+		 * @return Number of images
+		*/
+		uint32_t getImageCount(const SwapchainHandle& handle) const;
+		
+		/**
+         * @brief Returns the extent from the current surface of
+         * the swapchain.
+         *
+         * @param[in] handle Swapchain handle
+         * @return Extent of the swapchains surface
+         */
+		[[nodiscard]]
+		const vk::Extent2D& getExtent(const SwapchainHandle& handle) const;
+		
+		/**
+		 * @brief Returns the present queue index to be used with
+		 * the swapchain and its current surface.
+		 *
+		 * @param[in] handle Swapchain handle
+		 * @return Present queue family index
+		 */
+		[[nodiscard]]
+		uint32_t getPresentQueueIndex(const SwapchainHandle& handle) const;
+		
+		/**
+		 * @brief Returns the color space of the surface from
+		 * a swapchain.
+		 *
+		 * @param[in] handle Swapchain handle
+		 * @return Color space
+		 */
+		[[nodiscard]]
+		vk::ColorSpaceKHR getSurfaceColorSpace(const SwapchainHandle& handle) const;
 
 		/**
 		 * gets the swapchain images
 		 * @param handle of the swapchain
 		 * @return a vector of the swapchain images
 		 */
-		std::vector<vk::Image> getSwapchainImages(const SwapchainHandle& handle);
+		[[nodiscard]]
+		std::vector<vk::Image> getSwapchainImages(const SwapchainHandle& handle) const;
 
 		/**
 		 * creates the swapchain imageViews for the swapchain
 		 * @param handle of the swapchain which ImageViews should be created
 		 * @return a ov ImageViews of the swapchain
 		 */
+		[[nodiscard]]
 		std::vector<vk::ImageView> createSwapchainImageViews(SwapchainHandle& handle);
+		
 	};
 	
 }
\ No newline at end of file
diff --git a/src/vkcv/Window.cpp b/src/vkcv/Window.cpp
index f6f9aa69..8787053d 100644
--- a/src/vkcv/Window.cpp
+++ b/src/vkcv/Window.cpp
@@ -284,7 +284,7 @@ namespace vkcv {
 		return window;
 	}
 
-	SwapchainHandle Window::getSwapchainHandle() const {
+	SwapchainHandle Window::getSwapchain() const {
 		return m_swapchainHandle;
 	}
 }
-- 
GitLab