From 2b83be1a62cbac48be9e317d020fd3541b6eaad6 Mon Sep 17 00:00:00 2001
From: Artur Wasmut <awasmut@uni-koblenz.de>
Date: Fri, 4 Jun 2021 14:10:56 +0200
Subject: [PATCH] Add proper resizing with dynamic pipeline configs. Refactor
 swapchain slightly.

---
 config/Sources.cmake             |   5 +-
 include/vkcv/Core.hpp            |  12 +--
 include/vkcv/SwapChain.hpp       |  43 +++++---
 projects/first_mesh/src/main.cpp |  22 ++--
 src/vkcv/Core.cpp                | 168 +++++++++++++++----------------
 src/vkcv/PipelineManager.cpp     |  21 +++-
 src/vkcv/Surface.cpp             |  27 -----
 src/vkcv/Surface.hpp             |   8 --
 src/vkcv/SwapChain.cpp           | 122 +++++++++++++---------
 9 files changed, 222 insertions(+), 206 deletions(-)
 delete mode 100644 src/vkcv/Surface.cpp
 delete mode 100644 src/vkcv/Surface.hpp

diff --git a/config/Sources.cmake b/config/Sources.cmake
index 8fc0aa9a..6fc477cc 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -50,10 +50,7 @@ set(vkcv_sources
         
         ${vkcv_include}/vkcv/QueueManager.hpp
         ${vkcv_source}/vkcv/QueueManager.cpp
-        
-        ${vkcv_source}/vkcv/Surface.hpp
-        ${vkcv_source}/vkcv/Surface.cpp
-        
+
         ${vkcv_source}/vkcv/ImageLayoutTransitions.hpp
         ${vkcv_source}/vkcv/ImageLayoutTransitions.cpp
 
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 2894b7a1..e102c266 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -62,7 +62,6 @@ namespace vkcv
         Core() = delete;
 
 		Result acquireSwapchainImage();
-		void destroyTemporaryFramebuffers();
 
         Context m_Context;
 
@@ -80,11 +79,10 @@ namespace vkcv
 		CommandResources				m_CommandResources;
 		SyncResources					m_SyncResources;
 		uint32_t						m_currentSwapchainImageIndex;
-		std::vector<vk::Framebuffer>	m_TemporaryFramebuffers;
-		
+
 		ImageHandle						m_DepthImage;
 
-        std::function<void(int, int)> m_resizeHandle;
+        std::function<void(int, int)> e_resizeHandle;
 
         /**
          * recreates the swapchain
@@ -234,14 +232,14 @@ namespace vkcv
 		 * @brief render a beautiful triangle
 		*/
 		void renderMesh(
-			const PassHandle						renderpassHandle, 
-			const PipelineHandle					pipelineHandle,
+			const PassHandle						&renderpassHandle,
+			const PipelineHandle					&pipelineHandle,
 			const uint32_t							width,
 			const uint32_t							height,
 			const size_t							pushConstantSize, 
 			const void*								pushConstantData, 
 			const std::vector<VertexBufferBinding>	&vertexBufferBindings, 
-			const BufferHandle						indexBuffer, 
+			const BufferHandle						&indexBuffer,
 			const size_t							indexCount,
 			const vkcv::ResourcesHandle				resourceHandle,
 			const size_t							resourceDescriptorSetIndex);
diff --git a/include/vkcv/SwapChain.hpp b/include/vkcv/SwapChain.hpp
index 852a907e..c4ffae63 100644
--- a/include/vkcv/SwapChain.hpp
+++ b/include/vkcv/SwapChain.hpp
@@ -3,16 +3,25 @@
 #include "Context.hpp"
 #include "vkcv/Window.hpp"
 
-namespace vkcv {
+namespace vkcv
+{
     class SwapChain final {
     private:
 
-        vk::SurfaceKHR m_surface;
-        vk::SwapchainKHR m_swapchain;
-        vk::SurfaceFormatKHR m_format;
-        vk::PresentModeKHR m_presentMode;
+        struct Surface
+        {
+            vk::SurfaceKHR handle;
+            std::vector<vk::SurfaceFormatKHR> formats;
+            vk::SurfaceCapabilitiesKHR capabilities;
+            std::vector<vk::PresentModeKHR> presentModes;
+        };
+        Surface m_Surface;
 
-		uint32_t m_ImageCount;
+        vk::SwapchainKHR m_Swapchain;
+        vk::Format m_SwapchainFormat;
+        vk::ColorSpaceKHR m_SwapchainColorSpace;
+        vk::PresentModeKHR m_SwapchainPresentMode;
+		uint32_t m_SwapchainImageCount;
 
         /**
          * Constructor of a SwapChain object
@@ -22,7 +31,13 @@ namespace vkcv {
          * @param swapchain to show images in the window
          * @param format
          */
-        SwapChain(vk::SurfaceKHR surface, vk::SwapchainKHR swapchain, vk::SurfaceFormatKHR format, uint32_t imageCount, vk::PresentModeKHR presentMode);
+         // TODO:
+        SwapChain(const Surface &surface,
+                  vk::SwapchainKHR swapchain,
+                  vk::Format format,
+                  vk::ColorSpaceKHR colorSpace,
+                  vk::PresentModeKHR presentMode,
+                  uint32_t imageCount) noexcept;
 
     public:
         SwapChain(const SwapChain &other) = default;
@@ -40,13 +55,14 @@ namespace vkcv {
          * @return current surface
          */
         [[nodiscard]]
-        vk::SurfaceKHR getSurface();
+        vk::SurfaceKHR getSurface() const;
+
         /**
-         * gets the current surface format
-         * @return gets the surface format
+         * gets the chosen swapchain format
+         * @return gets the chosen swapchain format
          */
         [[nodiscard]]
-        vk::SurfaceFormatKHR getSurfaceFormat();
+        vk::Format getSwapchainFormat() const;
 
         /**
          * creates a swap chain object out of the given window and the given context
@@ -54,7 +70,7 @@ namespace vkcv {
          * @param context of the application
          * @return returns an object of swapChain
          */
-        static SwapChain create(const Window &window, const Context &context, const vk::SurfaceKHR surface);
+        static SwapChain create(const Window &window, const Context &context);
 
         /**
          * Destructor of SwapChain
@@ -71,7 +87,6 @@ namespace vkcv {
 		 * @param width
 		 * @param height
 		 */
-        void recreateSwapchain( const Context &context, const Window &window, int width, int height);
+        void recreateSwapchain(const Context &context, const Window &window, int width, int height);
     };
-
 }
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index ec65f4dc..58c56dba 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -8,16 +8,14 @@
 int main(int argc, const char** argv) {
 	const char* applicationName = "First Mesh";
 
-	const int windowWidth = 800;
-	const int windowHeight = 600;
 	vkcv::Window window = vkcv::Window::create(
 		applicationName,
-		windowWidth,
-		windowHeight,
+        800,
+        600,
 		true
 	);
 
-	vkcv::CameraManager cameraManager(window, windowWidth, windowHeight);
+	vkcv::CameraManager cameraManager(window, window.getWidth(), window.getHeight());
 
 	window.initEvents();
 
@@ -112,9 +110,9 @@ int main(int argc, const char** argv) {
 	//end of exemplary code
 
 	const vkcv::PipelineConfig trianglePipelineDefinition(
-		triangleShaderProgram, 
-		windowWidth,
-		windowHeight,
+		triangleShaderProgram,
+        UINT32_MAX,
+        UINT32_MAX,
 		trianglePass,
 		mesh.vertexGroups[0].vertexBuffer.attributes,
 		{ core.getDescriptorSetLayout(set, 0) });
@@ -149,6 +147,10 @@ int main(int argc, const char** argv) {
 	auto start = std::chrono::system_clock::now();
 	while (window.isWindowOpen()) {
         window.pollEvents();
+
+        if(window.getHeight() == 0 || window.getWidth() == 0)
+            continue;
+
 		core.beginFrame();
 		auto end = std::chrono::system_clock::now();
 		auto deltatime = end - start;
@@ -159,8 +161,8 @@ int main(int argc, const char** argv) {
 		core.renderMesh(
 			trianglePass,
 			trianglePipeline,
-			windowWidth,
-			windowHeight,
+            window.getWidth(),
+            window.getHeight(),
 			sizeof(mvp),
 			&mvp,
 			vertexBufferBindings,
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index ad25e79a..ad6a8756 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -13,7 +13,6 @@
 #include "SamplerManager.hpp"
 #include "ImageManager.hpp"
 #include "DescriptorManager.hpp"
-#include "Surface.hpp"
 #include "ImageLayoutTransitions.hpp"
 
 namespace vkcv
@@ -32,14 +31,8 @@ namespace vkcv
         		instanceExtensions,
         		deviceExtensions
 		);
-	
-		const vk::SurfaceKHR surface = createSurface(
-				window.getWindow(),
-				context.getInstance(),
-				context.getPhysicalDevice()
-		);
 
-        SwapChain swapChain = SwapChain::create(window, context, surface);
+        SwapChain swapChain = SwapChain::create(window, context);
 
         std::vector<vk::ImageView> imageViews;
         imageViews = createImageViews( context, swapChain);
@@ -79,7 +72,7 @@ namespace vkcv
     	
     	m_ImageManager->m_core = this;
 
-        m_resizeHandle = window.e_resize.add( [&](int width, int height) { recreateSwapchain( width ,height ); });
+        e_resizeHandle = window.e_resize.add( [&](int width, int height) { recreateSwapchain( width ,height ); });
 	}
 
 	Core::~Core() noexcept {
@@ -90,7 +83,6 @@ namespace vkcv
 
 		destroyCommandResources(m_Context.getDevice(), m_CommandResources);
 		destroySyncResources(m_Context.getDevice(), m_SyncResources);
-		destroyTemporaryFramebuffers();
 
 		m_Context.m_Device.destroySwapchainKHR(m_swapchain.getSwapchain());
 		m_Context.m_Instance.destroySurfaceKHR(m_swapchain.getSurface());
@@ -126,37 +118,22 @@ namespace vkcv
 		return Result::SUCCESS;
 	}
 
-	void Core::destroyTemporaryFramebuffers() {
-		for (const vk::Framebuffer f : m_TemporaryFramebuffers) {
-			m_Context.getDevice().destroyFramebuffer(f);
-		}
-		m_TemporaryFramebuffers.clear();
-	}
-
 	void Core::beginFrame() {
     	if (acquireSwapchainImage() != Result::SUCCESS) {
     		return;
     	}
-		m_Context.getDevice().waitIdle();	// FIMXE: this is a sin against graphics programming, but its getting late - Alex
-		destroyTemporaryFramebuffers();
-	}
-	
-	vk::Framebuffer createFramebuffer(const vk::Device device, const vk::RenderPass& renderpass,
-									  const int width, const int height, const std::vector<vk::ImageView>& attachments) {
-		const vk::FramebufferCreateFlags flags = {};
-		const vk::FramebufferCreateInfo createInfo(flags, renderpass, attachments.size(), attachments.data(), width, height, 1);
-		return device.createFramebuffer(createInfo);
+		m_Context.getDevice().waitIdle();	// TODO: this is a sin against graphics programming, but its getting late - Alex
 	}
 
 	void Core::renderMesh(
-		const PassHandle						renderpassHandle, 
-		const PipelineHandle					pipelineHandle, 
+		const PassHandle						&renderpassHandle,
+		const PipelineHandle					&pipelineHandle,
 		const uint32_t 							width,
 		const uint32_t							height,
-		const size_t							pushConstantSize, 
+		const size_t							pushConstantSize,
 		const void								*pushConstantData,
 		const std::vector<VertexBufferBinding>& vertexBufferBindings, 
-		const BufferHandle						indexBuffer, 
+		const BufferHandle						&indexBuffer,
 		const size_t							indexCount,
 		const vkcv::ResourcesHandle				resourceHandle,
 		const size_t							resourceDescriptorSetIndex
@@ -197,15 +174,25 @@ namespace vkcv
 			attachments.push_back(m_ImageManager->getVulkanImageView(m_DepthImage));
 		}
 		
-		const vk::Framebuffer framebuffer = createFramebuffer(
-				m_Context.getDevice(),
-				renderpass,
-				width,
-				height,
-				attachments
-		);
-		
-		m_TemporaryFramebuffers.push_back(framebuffer);
+		vk::Framebuffer framebuffer = nullptr;
+        const vk::FramebufferCreateInfo createInfo({},
+                                                   renderpass,
+                                                   static_cast<uint32_t>(attachments.size()),
+                                                   attachments.data(),
+                                                   width,
+                                                   height,
+                                                   1);
+        if(m_Context.m_Device.createFramebuffer(&createInfo, nullptr, &framebuffer) != vk::Result::eSuccess)
+        {
+            std::cout << "FAILED TO CREATE TEMPORARY FRAMEBUFFER!" << std::endl;
+            return;
+        }
+
+        vk::Viewport dynamicViewport(0.0f, 0.0f,
+                                     static_cast<float>(width), static_cast<float>(height),
+                                     0.0f, 1.0f);
+
+        vk::Rect2D dynamicScissor({0, 0}, {width, height});
 
 		auto &bufferManager = m_BufferManager;
 
@@ -213,48 +200,58 @@ namespace vkcv
 		submitInfo.queueType = QueueType::Graphics;
 		submitInfo.signalSemaphores = { m_SyncResources.renderFinished };
 
-		submitCommands(submitInfo, [&](const vk::CommandBuffer& cmdBuffer) {
-			std::vector<vk::ClearValue> clearValues;
-			
-			for (const auto& attachment : passConfig.attachments) {
-				if (attachment.load_operation == AttachmentOperation::CLEAR) {
-					float clear = 0.0f;
-					
-					if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) {
-						clear = 1.0f;
-					}
-					
-					clearValues.emplace_back(std::array<float, 4>{
-							clear,
-							clear,
-							clear,
-							1.f
-					});
-				}
-			}
-
-			const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
-			const vk::SubpassContents subpassContents = {};
-			cmdBuffer.beginRenderPass(beginInfo, subpassContents, {});
+		auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
+            std::vector<vk::ClearValue> clearValues;
+
+            for (const auto& attachment : passConfig.attachments) {
+                if (attachment.load_operation == AttachmentOperation::CLEAR) {
+                    float clear = 0.0f;
+
+                    if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) {
+                        clear = 1.0f;
+                    }
+
+                    clearValues.emplace_back(std::array<float, 4>{
+                            clear,
+                            clear,
+                            clear,
+                            1.f
+                    });
+                }
+            }
+
+            const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
+            const vk::SubpassContents subpassContents = {};
+            cmdBuffer.beginRenderPass(beginInfo, subpassContents, {});
+
+            cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
+            cmdBuffer.setViewport(0, 1, &dynamicViewport);
+            cmdBuffer.setScissor(0, 1, &dynamicScissor);
+
+            for (uint32_t i = 0; i < vertexBufferBindings.size(); i++) {
+                const auto &vertexBinding = vertexBufferBindings[i];
+                const auto vertexBuffer = bufferManager->getBuffer(vertexBinding.buffer);
+                cmdBuffer.bindVertexBuffers(i, (vertexBuffer), (vertexBinding.offset));
+            }
+
+            if (resourceHandle) {
+                const vk::DescriptorSet descriptorSet = m_DescriptorManager->getDescriptorSet(resourceHandle, resourceDescriptorSetIndex);
+                cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, descriptorSet, nullptr);
+            }
+
+            cmdBuffer.bindIndexBuffer(vulkanIndexBuffer, 0, vk::IndexType::eUint16);	//FIXME: choose proper size
+            cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData);
+            cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {});
+            cmdBuffer.endRenderPass();
+        };
+
+        auto finishFunction = [&]()
+        {
+            m_Context.m_Device.destroy(framebuffer);
+        };
 
-			cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
+		submitCommands(submitInfo, submitFunction, finishFunction);
 
-			for (uint32_t i = 0; i < vertexBufferBindings.size(); i++) {
-				const auto &vertexBinding = vertexBufferBindings[i];
-				const auto vertexBuffer = bufferManager->getBuffer(vertexBinding.buffer);
-				cmdBuffer.bindVertexBuffers(i, (vertexBuffer), (vertexBinding.offset));
-			}
-			
-			if (resourceHandle) {
-				const vk::DescriptorSet descriptorSet = m_DescriptorManager->getDescriptorSet(resourceHandle, resourceDescriptorSetIndex);
-				cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, descriptorSet, nullptr);
-			}
-			
-			cmdBuffer.bindIndexBuffer(vulkanIndexBuffer, 0, vk::IndexType::eUint16);	//FIXME: choose proper size
-			cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData);
-			cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {});
-			cmdBuffer.endRenderPass();
-		}, nullptr);
 	}
 
 	void Core::endFrame() {
@@ -263,8 +260,7 @@ namespace vkcv
 		}
   
 		const auto swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain());
-		const vk::Image presentImage = swapchainImages[m_currentSwapchainImageIndex];
-		
+
 		const auto& queueManager = m_Context.getQueueManager();
 		std::array<vk::Semaphore, 2> waitSemaphores{ 
 			m_SyncResources.renderFinished, 
@@ -284,17 +280,17 @@ namespace vkcv
 	}
 
 	vk::Format Core::getSwapchainImageFormat() {
-		return m_swapchain.getSurfaceFormat().format;
+		return m_swapchain.getSwapchainFormat();
 	}
 
     void Core::recreateSwapchain( int width, int height) {
         m_Context.getDevice().waitIdle();
 
-        destroyTemporaryFramebuffers();
+        if(width == 0 || height == 0)
+            return;
 
-        for (auto image : m_swapchainImageViews) {
+        for (auto image : m_swapchainImageViews)
             m_Context.m_Device.destroyImageView(image);
-        }
 
         m_swapchain.recreateSwapchain(m_Context, m_window, width, height);
         m_swapchainImageViews = createImageViews(m_Context, m_swapchain);
@@ -372,7 +368,7 @@ namespace vkcv
                     vk::ImageViewCreateFlags(),
                     image,
                     vk::ImageViewType::e2D,
-                    swapChain.getSurfaceFormat().format,
+                    swapChain.getSwapchainFormat(),
                     componentMapping,
                     subResourceRange
             );
diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp
index 1b866c05..344e541c 100644
--- a/src/vkcv/PipelineManager.cpp
+++ b/src/vkcv/PipelineManager.cpp
@@ -94,8 +94,8 @@ namespace vkcv
 			//FIXME: hoping that order is the same and compatible: add explicit mapping and validation
 			const VertexAttribute attribute = config.m_vertexAttributes[i];
 
-            vertexAttributeDescriptions.push_back({location, binding, vertexFormatToVulkanFormat(attachment.format), 0});
-			vertexBindingDescriptions.push_back(vk::VertexInputBindingDescription(
+            vertexAttributeDescriptions.emplace_back(location, binding, vertexFormatToVulkanFormat(attachment.format), 0);
+			vertexBindingDescriptions.emplace_back(vk::VertexInputBindingDescription(
 				binding,
 				attribute.stride + getFormatSize(attachment.format),
 				vk::VertexInputRate::eVertex));
@@ -211,8 +211,19 @@ namespace vkcv
 				break;
 			}
 		}
-	
-		// graphics pipeline create
+
+		std::vector<vk::DynamicState> dynamicStates = {};
+		if(config.m_Width == UINT32_MAX && config.m_Height == UINT32_MAX)
+        {
+		    dynamicStates.push_back(vk::DynamicState::eViewport);
+		    dynamicStates.push_back(vk::DynamicState::eScissor);
+        }
+
+        vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo({},
+                                                            static_cast<uint32_t>(dynamicStates.size()),
+                                                            dynamicStates.data());
+
+        // graphics pipeline create
         std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = { pipelineVertexShaderStageInfo, pipelineFragmentShaderStageInfo };
         const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo(
                 {},
@@ -226,7 +237,7 @@ namespace vkcv
                 &pipelineMultisampleStateCreateInfo,
 				p_depthStencilCreateInfo,
                 &pipelineColorBlendStateCreateInfo,
-                nullptr,
+                &dynamicStateCreateInfo,
                 vkPipelineLayout,
                 pass,
                 0,
diff --git a/src/vkcv/Surface.cpp b/src/vkcv/Surface.cpp
deleted file mode 100644
index 29b6c646..00000000
--- a/src/vkcv/Surface.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#include "Surface.hpp"
-
-#define GLFW_INCLUDE_VULKAN
-#include <GLFW/glfw3.h>
-
-namespace vkcv {
-	/**
-	* creates surface and checks availability
-	* @param window current window for the surface
-	* @param instance Vulkan-Instance
-	* @param physicalDevice Vulkan-PhysicalDevice
-	* @return created surface
-	*/
-	vk::SurfaceKHR createSurface(GLFWwindow* window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice) {
-		//create surface
-		VkSurfaceKHR surface;
-		if (glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &surface) != VK_SUCCESS) {
-			throw std::runtime_error("failed to create a window surface!");
-		}
-		vk::Bool32 surfaceSupport = false;
-		if (physicalDevice.getSurfaceSupportKHR(0, vk::SurfaceKHR(surface), &surfaceSupport) != vk::Result::eSuccess && surfaceSupport != true) {
-			throw std::runtime_error("surface is not supported by the device!");
-		}
-
-		return vk::SurfaceKHR(surface);
-	}
-}
diff --git a/src/vkcv/Surface.hpp b/src/vkcv/Surface.hpp
deleted file mode 100644
index 74aafeba..00000000
--- a/src/vkcv/Surface.hpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#pragma once
-#include <vulkan/vulkan.hpp>
-
-struct GLFWwindow;
-
-namespace vkcv {	
-	vk::SurfaceKHR createSurface(GLFWwindow* window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice);
-}
\ No newline at end of file
diff --git a/src/vkcv/SwapChain.cpp b/src/vkcv/SwapChain.cpp
index ce874c86..2a40eba4 100644
--- a/src/vkcv/SwapChain.cpp
+++ b/src/vkcv/SwapChain.cpp
@@ -1,29 +1,56 @@
 #include <vkcv/SwapChain.hpp>
+#include <utility>
 
-namespace vkcv {
+#define GLFW_INCLUDE_VULKAN
+#include <GLFW/glfw3.h>
 
-    SwapChain::SwapChain(vk::SurfaceKHR surface, vk::SwapchainKHR swapchain, vk::SurfaceFormatKHR format, uint32_t imageCount, vk::PresentModeKHR presentMode)
-        : m_surface(surface), m_swapchain(swapchain), m_format( format), m_ImageCount(imageCount), m_presentMode(presentMode)
+namespace vkcv
+{
+    /**
+    * creates surface and checks availability
+    * @param window current window for the surface
+    * @param instance Vulkan-Instance
+    * @param physicalDevice Vulkan-PhysicalDevice
+    * @return created surface
+    */
+    vk::SurfaceKHR createSurface(GLFWwindow* window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice) {
+        //create surface
+        VkSurfaceKHR surface;
+        if (glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &surface) != VK_SUCCESS) {
+            throw std::runtime_error("failed to create a window surface!");
+        }
+        vk::Bool32 surfaceSupport = false;
+        if (physicalDevice.getSurfaceSupportKHR(0, vk::SurfaceKHR(surface), &surfaceSupport) != vk::Result::eSuccess && surfaceSupport != true) {
+            throw std::runtime_error("surface is not supported by the device!");
+        }
+
+        return vk::SurfaceKHR(surface);
+    }
+
+    SwapChain::SwapChain(const Surface &surface,
+                         vk::SwapchainKHR swapchain,
+                         vk::Format format,
+                         vk::ColorSpaceKHR colorSpace,
+                         vk::PresentModeKHR presentMode,
+                         uint32_t imageCount) noexcept :
+    m_Surface(surface),
+    m_Swapchain(swapchain),
+    m_SwapchainFormat(format),
+    m_SwapchainColorSpace(colorSpace),
+    m_SwapchainPresentMode(presentMode),
+    m_SwapchainImageCount(imageCount)
     {}
 
     const vk::SwapchainKHR& SwapChain::getSwapchain() const {
-        return m_swapchain;
+        return m_Swapchain;
     }
 
-    /**
-     * gets surface of the swapchain
-     * @return current surface
-     */
-    vk::SurfaceKHR SwapChain::getSurface() {
-        return m_surface;
+    vk::SurfaceKHR SwapChain::getSurface() const {
+        return m_Surface.handle;
     }
 
-    /**
-     * gets the surface of the swapchain
-     * @return chosen format
-     */
-    vk::SurfaceFormatKHR SwapChain::getSurfaceFormat(){
-        return m_format;
+    vk::Format SwapChain::getSwapchainFormat() const{
+        return m_SwapchainFormat;
     }
 
     /**
@@ -33,7 +60,7 @@ namespace vkcv {
      * @param window of the current application
      * @return chosen Extent for the surface
      */
-    vk::Extent2D chooseSwapExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, const Window &window){
+    vk::Extent2D chooseExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, const Window &window){
         vk::SurfaceCapabilitiesKHR surfaceCapabilities;
         if(physicalDevice.getSurfaceCapabilitiesKHR(surface,&surfaceCapabilities) != vk::Result::eSuccess){
             throw std::runtime_error("cannot get surface capabilities. There is an issue with the surface.");
@@ -46,12 +73,6 @@ namespace vkcv {
         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));
 
-        if (extent2D.width > surfaceCapabilities.maxImageExtent.width ||
-            extent2D.width < surfaceCapabilities.minImageExtent.width ||
-            extent2D.height > surfaceCapabilities.maxImageExtent.height ||
-            extent2D.height < surfaceCapabilities.minImageExtent.height) {
-            std::printf("Surface size not matching. Resizing to allowed value.");
-        }
         return extent2D;
     }
 
@@ -61,7 +82,7 @@ namespace vkcv {
      * @param surface of the swapchain
      * @return available Format
      */
-    vk::SurfaceFormatKHR chooseSwapSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
+    vk::SurfaceFormatKHR chooseSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
         uint32_t formatCount;
         physicalDevice.getSurfaceFormatsKHR(surface, &formatCount, nullptr);
         std::vector<vk::SurfaceFormatKHR> availableFormats(formatCount);
@@ -126,23 +147,29 @@ namespace vkcv {
      * @param context that keeps instance, physicalDevice and a device.
      * @return swapchain
      */
-    SwapChain SwapChain::create(const Window &window, const Context &context, const vk::SurfaceKHR surface) {
+    SwapChain SwapChain::create(const Window &window, const Context &context) {
         const vk::Instance& instance = context.getInstance();
         const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice();
         const vk::Device& device = context.getDevice();
 
-        vk::Extent2D extent2D = chooseSwapExtent(physicalDevice, surface, window);
-        vk::SurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(physicalDevice, surface);
-        vk::PresentModeKHR presentMode = choosePresentMode(physicalDevice, surface);
-        uint32_t imageCount = chooseImageCount(physicalDevice, surface);
+        Surface surface;
+        surface.handle       = createSurface(window.getWindow(), instance, physicalDevice);
+        surface.formats      = physicalDevice.getSurfaceFormatsKHR(surface.handle);
+        surface.capabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface.handle);
+        surface.presentModes = physicalDevice.getSurfacePresentModesKHR(surface.handle);
+
+        vk::Extent2D chosenExtent = chooseExtent(physicalDevice, surface.handle, window);
+        vk::SurfaceFormatKHR chosenSurfaceFormat = chooseSurfaceFormat(physicalDevice, surface.handle);
+        vk::PresentModeKHR chosenPresentMode = choosePresentMode(physicalDevice, surface.handle);
+        uint32_t chosenImageCount = chooseImageCount(physicalDevice, surface.handle);
 
         vk::SwapchainCreateInfoKHR swapchainCreateInfo(
                 vk::SwapchainCreateFlagsKHR(),  //flags
-                surface,    // surface
-                imageCount,  // minImageCount TODO: how many do we need for our application?? "must be less than or equal to the value returned in maxImageCount" -> 3 for Triple Buffering, else 2 for Double Buffering (should be the standard)
-                surfaceFormat.format,   // imageFormat
-                surfaceFormat.colorSpace,   // imageColorSpace
-                extent2D,   // imageExtent
+                surface.handle,    // surface
+                chosenImageCount,  // minImageCount TODO: how many do we need for our application?? "must be less than or equal to the value returned in maxImageCount" -> 3 for Triple Buffering, else 2 for Double Buffering (should be the standard)
+                chosenSurfaceFormat.format,   // imageFormat
+                chosenSurfaceFormat.colorSpace,   // imageColorSpace
+                chosenExtent,   // imageExtent
                 1,  // imageArrayLayers TODO: should we only allow non-stereoscopic applications? yes -> 1, no -> ? "must be greater than 0, less or equal to maxImageArrayLayers"
                 vk::ImageUsageFlagBits::eColorAttachment,  // imageUsage TODO: what attachments? only color? depth?
                 vk::SharingMode::eExclusive,    // imageSharingMode TODO: which sharing mode? "VK_SHARING_MODE_EXCLUSIV access exclusive to a single queue family, better performance", "VK_SHARING_MODE_CONCURRENT access from multiple queues"
@@ -150,26 +177,31 @@ namespace vkcv {
                 nullptr,    // pQueueFamilyIndices, the pointer to an array of queue family indices having access to the images(s) of the swapchain when imageSharingMode is VK_SHARING_MODE_CONCURRENT
                 vk::SurfaceTransformFlagBitsKHR::eIdentity, // preTransform, transformations applied onto the image before display
                 vk::CompositeAlphaFlagBitsKHR::eOpaque, // compositeAlpha, TODO: how to handle transparent pixels? do we need transparency? If no -> opaque
-                presentMode,    // presentMode
+                chosenPresentMode,    // presentMode
                 true,   // clipped
                 nullptr // oldSwapchain
         );
 
         vk::SwapchainKHR swapchain = device.createSwapchainKHR(swapchainCreateInfo);
 
-        return SwapChain(surface, swapchain, surfaceFormat, imageCount, presentMode);
+        return SwapChain(surface,
+                         swapchain,
+                         chosenSurfaceFormat.format,
+                         chosenSurfaceFormat.colorSpace,
+                         chosenPresentMode,
+                         chosenImageCount);
     }
 
     void SwapChain::recreateSwapchain( const Context &context, const Window &window, int width, int height){
-        vk::SwapchainKHR oldSwapchain = m_swapchain;
-        vk::Extent2D extent2D = chooseSwapExtent(context.getPhysicalDevice(), m_surface, window);
+        vk::SwapchainKHR oldSwapchain = m_Swapchain;
+        vk::Extent2D extent2D = chooseExtent(context.getPhysicalDevice(), m_Surface.handle, window);
 
         vk::SwapchainCreateInfoKHR swapchainCreateInfo(
                 vk::SwapchainCreateFlagsKHR(),
-                m_surface,
-                m_ImageCount,
-                m_format.format,
-                m_format.colorSpace,
+                m_Surface.handle,
+                m_SwapchainImageCount,
+                m_SwapchainFormat,
+                m_SwapchainColorSpace,
                 extent2D,
                 1,
                 vk::ImageUsageFlagBits::eColorAttachment,
@@ -178,11 +210,11 @@ namespace vkcv {
                 nullptr,
                 vk::SurfaceTransformFlagBitsKHR::eIdentity,
                 vk::CompositeAlphaFlagBitsKHR::eOpaque,
-                m_presentMode,
+                m_SwapchainPresentMode,
                 true,
                 oldSwapchain
         );
-        m_swapchain = context.getDevice().createSwapchainKHR(swapchainCreateInfo);
+        m_Swapchain = context.getDevice().createSwapchainKHR(swapchainCreateInfo);
     }
 
 
@@ -191,6 +223,6 @@ namespace vkcv {
     }
 
 	uint32_t SwapChain::getImageCount() {
-		return m_ImageCount;
+		return m_SwapchainImageCount;
 	}
 }
-- 
GitLab