diff --git a/config/Sources.cmake b/config/Sources.cmake
index e3f5c950ce0d7e5e7e697bda0047ec3da7a15e18..a5b2ddae5e0a194e4ee887da5f37097821e41d0f 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -72,4 +72,9 @@ set(vkcv_sources
         
         ${vkcv_include}/vkcv/DrawcallRecording.hpp
         ${vkcv_source}/vkcv/DrawcallRecording.cpp
+        
+        ${vkcv_include}/vkcv/CommandStreamManager.hpp
+        ${vkcv_source}/vkcv/CommandStreamManager.cpp
+        
+        ${vkcv_include}/vkcv/CommandRecordingFunctionTypes.hpp
 )
diff --git a/include/vkcv/CommandRecordingFunctionTypes.hpp b/include/vkcv/CommandRecordingFunctionTypes.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c236fb2c717afd2a3bafc4b3a22708cdac942ffe
--- /dev/null
+++ b/include/vkcv/CommandRecordingFunctionTypes.hpp
@@ -0,0 +1,8 @@
+#pragma once
+#include "vkcv/Event.hpp"
+#include <vulkan/vulkan.hpp>
+
+namespace vkcv {
+	typedef typename event_function<const vk::CommandBuffer&>::type RecordCommandFunction;
+	typedef typename event_function<>::type FinishCommandFunction;
+}
\ No newline at end of file
diff --git a/include/vkcv/CommandStreamManager.hpp b/include/vkcv/CommandStreamManager.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..60f7bbaab448b30818a2f9548d288ab6ebe022ce
--- /dev/null
+++ b/include/vkcv/CommandStreamManager.hpp
@@ -0,0 +1,53 @@
+#pragma once
+#include <vulkan/vulkan.hpp>
+#include <vector>
+#include "vkcv/Event.hpp"
+#include "vkcv/Handles.hpp"
+#include "vkcv/CommandRecordingFunctionTypes.hpp"
+
+namespace vkcv {
+
+	class CommandStreamManager
+	{
+		friend class Core;
+	private:
+		struct CommandStream {
+			inline CommandStream(vk::CommandBuffer cmdBuffer, vk::Queue queue, vk::CommandPool cmdPool) 
+				: cmdBuffer(cmdBuffer), cmdPool(cmdPool), queue(queue) {};
+			vk::CommandBuffer                   cmdBuffer;
+			vk::CommandPool                     cmdPool;
+			vk::Queue                           queue;
+			std::vector<FinishCommandFunction>  callbacks;
+		};
+
+		Core* m_core;
+		std::vector<CommandStream> m_commandStreams;
+
+		CommandStreamManager() noexcept;
+
+		void init(Core* core);
+
+	public:
+		~CommandStreamManager() noexcept;
+
+		CommandStreamManager(CommandStreamManager&& other) = delete;
+		CommandStreamManager(const CommandStreamManager& other) = delete;
+
+		CommandStreamManager& operator=(CommandStreamManager&& other) = delete;
+		CommandStreamManager& operator=(const CommandStreamManager& other) = delete;
+
+		CommandStreamHandle createCommandStream(
+			const vk::Queue queue,
+			vk::CommandPool cmdPool);
+
+		void recordCommandsToStream(const CommandStreamHandle handle, const RecordCommandFunction record);
+		void addFinishCallbackToStream(const CommandStreamHandle handle, const FinishCommandFunction finish);
+		void submitCommandStreamSynchronous(
+			const CommandStreamHandle   handle,
+			std::vector<vk::Semaphore>  &waitSemaphores,
+			std::vector<vk::Semaphore>  &signalSemaphores);
+
+		vk::CommandBuffer getStreamCommandBuffer(const CommandStreamHandle handle);
+	};
+
+}
\ No newline at end of file
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 02a58ae875f4a9341268e97e53530f9b2b34b446..0a45856e3754f45944f356cbc08bd51cd0549a06 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -23,6 +23,7 @@
 #include "DescriptorWrites.hpp"
 #include "Event.hpp"
 #include "DrawcallRecording.hpp"
+#include "CommandRecordingFunctionTypes.hpp"
 
 namespace vkcv
 {
@@ -34,15 +35,13 @@ namespace vkcv
     class BufferManager;
     class SamplerManager;
     class ImageManager;
+	class CommandStreamManager;
 
 	struct SubmitInfo {
 		QueueType queueType;
 		std::vector<vk::Semaphore> waitSemaphores;
 		std::vector<vk::Semaphore> signalSemaphores;
 	};
-	
-	typedef typename event_function<const vk::CommandBuffer&>::type RecordCommandFunction;
-	typedef typename event_function<>::type FinishCommandFunction;
 
     class Core final
     {
@@ -62,25 +61,30 @@ namespace vkcv
 
         Context m_Context;
 
-        SwapChain					m_swapchain;
-        std::vector<vk::ImageView>	m_swapchainImageViews;
-        const Window&				m_window;
+        SwapChain                       m_swapchain;
+        std::vector<vk::ImageView>      m_swapchainImageViews;
+        std::vector<vk::Image>          m_swapchainImages;
+		std::vector<vk::ImageLayout>    m_swapchainImageLayouts;
+        const Window&                   m_window;
 
-        std::unique_ptr<PassManager>		m_PassManager;
-        std::unique_ptr<PipelineManager>	m_PipelineManager;
-        std::unique_ptr<DescriptorManager>	m_DescriptorManager;
-        std::unique_ptr<BufferManager>		m_BufferManager;
-        std::unique_ptr<SamplerManager>		m_SamplerManager;
-        std::unique_ptr<ImageManager>		m_ImageManager;
+        std::unique_ptr<PassManager>            m_PassManager;
+        std::unique_ptr<PipelineManager>        m_PipelineManager;
+        std::unique_ptr<DescriptorManager>      m_DescriptorManager;
+        std::unique_ptr<BufferManager>          m_BufferManager;
+        std::unique_ptr<SamplerManager>         m_SamplerManager;
+        std::unique_ptr<ImageManager>           m_ImageManager;
+        std::unique_ptr<CommandStreamManager>   m_CommandStreamManager;
 
-		CommandResources				m_CommandResources;
-		SyncResources					m_SyncResources;
-		uint32_t						m_currentSwapchainImageIndex;
+		CommandResources    m_CommandResources;
+		SyncResources       m_SyncResources;
+		uint32_t            m_currentSwapchainImageIndex;
 
         std::function<void(int, int)> e_resizeHandle;
 
         static std::vector<vk::ImageView> createImageViews( Context &context, SwapChain& swapChain);
 
+		void recordSwapchainImageLayoutTransition(vk::CommandBuffer cmdBuffer, vk::ImageLayout newLayout);
+
     public:
         /**
          * Destructor of #Core destroys the Vulkan objects contained in the core's context.
@@ -216,10 +220,8 @@ namespace vkcv
 		*/
 		void beginFrame();
 
-		/**
-		 * @brief render a beautiful triangle
-		*/
-		void recordDrawcalls(
+		void recordDrawcallsToCmdStream(
+            const CommandStreamHandle       cmdStreamHandle,
 			const PassHandle                renderpassHandle, 
 			const PipelineHandle            pipelineHandle,
 			const PushConstantData          &pushConstantData,
@@ -242,6 +244,19 @@ namespace vkcv
 		 * @param record Record-command-function
 		 * @param finish Finish-command-function or nullptr
 		 */
-		void submitCommands(const SubmitInfo &submitInfo, const RecordCommandFunction& record, const FinishCommandFunction& finish);
+		void recordAndSubmitCommands(
+			const SubmitInfo            &submitInfo, 
+			const RecordCommandFunction &record, 
+			const FinishCommandFunction &finish);
+
+		CommandStreamHandle createCommandStream(QueueType queueType);
+
+		void Core::recordCommandsToStream(
+			const CommandStreamHandle   cmdStreamHandle,
+			const RecordCommandFunction &record,
+			const FinishCommandFunction &finish);
+
+		void submitCommandStream(const CommandStreamHandle handle);
+		void prepareSwapchainImageForPresent(const CommandStreamHandle handle);
     };
 }
diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp
index f2a0da0a6d9650ad22fff9a1e5ec2071eebf53e3..ea05bd212dd9314957e4771070bedb3963b1b2dc 100644
--- a/include/vkcv/Handles.hpp
+++ b/include/vkcv/Handles.hpp
@@ -101,5 +101,11 @@ namespace vkcv
 		static ImageHandle createSwapchainImageHandle(const HandleDestroyFunction& destroy = nullptr);
 		
 	};
+
+    class CommandStreamHandle : public Handle {
+        friend class CommandStreamManager;
+    private:
+        using Handle::Handle;
+    };
 	
 }
diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp
index d76bd12169f622f05f1731b0eb3065d6133a5f2f..a1219ce4147ebbb8ae0650da8a87766f8967874b 100644
--- a/include/vkcv/Image.hpp
+++ b/include/vkcv/Image.hpp
@@ -9,8 +9,12 @@
 #include "Handles.hpp"
 
 namespace vkcv {
-	
-	class ImageManager;
+
+    // forward declares
+    class ImageManager;
+
+	bool isDepthFormat(const vk::Format format);
+
 	class Image {
 		friend class Core;
 	public:
@@ -37,11 +41,9 @@ namespace vkcv {
 		void fill(void* data, size_t size = SIZE_MAX);
 	private:
 		ImageManager* const m_manager;
-		const ImageHandle m_handle;
-		const vk::Format m_format;
-		vk::ImageLayout m_layout;
+		const ImageHandle   m_handle;
 
-		Image(ImageManager* manager, const ImageHandle& handle, vk::Format format);
+		Image(ImageManager* manager, const ImageHandle& handle);
 		
 		static Image create(ImageManager* manager, vk::Format format, uint32_t width, uint32_t height, uint32_t depth);
 		
diff --git a/include/vkcv/PassConfig.hpp b/include/vkcv/PassConfig.hpp
index d9a5bcd83acca5f5ba86b4e6ce6973acbed89de6..8f3b516d4b4451c513366fbd8469908bccde6a5f 100644
--- a/include/vkcv/PassConfig.hpp
+++ b/include/vkcv/PassConfig.hpp
@@ -32,23 +32,15 @@ namespace vkcv
 
     struct AttachmentDescription
     {
-        AttachmentDescription() = delete;
         AttachmentDescription(
-			AttachmentLayout initial,
-			AttachmentLayout in_pass,
-			AttachmentLayout final,
-			AttachmentOperation store_op,
-			AttachmentOperation load_op,
-			vk::Format format) noexcept;
-
-        AttachmentLayout layout_initial;
-        AttachmentLayout layout_in_pass;
-        AttachmentLayout layout_final;
+            AttachmentOperation store_op,
+            AttachmentOperation load_op,
+            vk::Format format) noexcept;
 
         AttachmentOperation store_operation;
         AttachmentOperation load_operation;
 
-		vk::Format format;
+        vk::Format format;
     };
 
     struct PassConfig
diff --git a/include/vkcv/SwapChain.hpp b/include/vkcv/SwapChain.hpp
index 53f7b783051307c7d327f20f389d7bef0fb9a16c..089205d1633551b4ad9f11d0bdd5540b2bb61bbb 100644
--- a/include/vkcv/SwapChain.hpp
+++ b/include/vkcv/SwapChain.hpp
@@ -107,7 +107,7 @@ namespace vkcv
 		/**
 		 *
 		 */
-        void recreateSwapchain();
+        void signalSwapchainRecreation();
 	
         /**
          * TODO
diff --git a/projects/cmd_sync_test/src/main.cpp b/projects/cmd_sync_test/src/main.cpp
index 1f28626f5f532e2b2c6fc4653b02850055b4b4ef..4933c44fd3663cf537f11e843bbb9b4c381fc69a 100644
--- a/projects/cmd_sync_test/src/main.cpp
+++ b/projects/cmd_sync_test/src/main.cpp
@@ -70,18 +70,12 @@ int main(int argc, const char** argv) {
 
 	// an example attachment for passes that output to the window
 	const vkcv::AttachmentDescription present_color_attachment(
-		vkcv::AttachmentLayout::UNDEFINED,
-		vkcv::AttachmentLayout::COLOR_ATTACHMENT,
-		vkcv::AttachmentLayout::PRESENTATION,
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
 		core.getSwapchainImageFormat()
 	);
 	
 	const vkcv::AttachmentDescription depth_attachment(
-			vkcv::AttachmentLayout::UNDEFINED,
-			vkcv::AttachmentLayout::DEPTH_STENCIL_ATTACHMENT,
-			vkcv::AttachmentLayout::DEPTH_STENCIL_ATTACHMENT,
 			vkcv::AttachmentOperation::STORE,
 			vkcv::AttachmentOperation::CLEAR,
 			vk::Format::eD32Sfloat
@@ -185,12 +179,17 @@ int main(int argc, const char** argv) {
 		vkcv::PushConstantData pushConstantData((void*)mvpMatrices.data(), sizeof(glm::mat4));
         const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer };
 
-		core.recordDrawcalls(
+		auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
+
+		core.recordDrawcallsToCmdStream(
+			cmdStream,
 			trianglePass,
 			trianglePipeline,
 			pushConstantData,
 			drawcalls,
 			renderTargets);
+		core.prepareSwapchainImageForPresent(cmdStream);
+		core.submitCommandStream(cmdStream);
 
 		core.endFrame();
 	}
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index bf728391d090e44b441c3ee12b3c2a26f6dca60e..a93346cf08d17e96cfd32fef5e3f8cddabf19b61 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -170,7 +170,7 @@ int main(int argc, const char** argv) {
 		cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count());
 		const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView();
 
-		core.recordDrawcalls(
+		core.recordDrawcallsToCmdStream(
 			trianglePass,
 			trianglePipeline,
 			sizeof(mvp),
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 649a3f8748be1e05c2c5ee79b3734f5e6387dfc5..40e8a3e222419cd2ba823d6d7ef6f619e3cd20b8 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -147,7 +147,7 @@ int main(int argc, const char** argv) {
         cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count());
 		const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView();
 
-	    core.recordDrawcalls(
+	    core.recordDrawcallsToCmdStream(
 			trianglePass,
 			trianglePipeline,
 			sizeof(mvp),
diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp
index ef874606ed0f30f33e4b1e0720d4f3455a8e137e..6d494c4ec90726d46039007607464378624f1c75 100644
--- a/src/vkcv/BufferManager.cpp
+++ b/src/vkcv/BufferManager.cpp
@@ -158,7 +158,7 @@ namespace vkcv {
 		SubmitInfo submitInfo;
 		submitInfo.queueType = QueueType::Transfer;
 		
-		core->submitCommands(
+		core->recordAndSubmitCommands(
 				submitInfo,
 				[&info, &mapped_size](const vk::CommandBuffer& commandBuffer) {
 					const vk::BufferCopy region (
diff --git a/src/vkcv/CommandStreamManager.cpp b/src/vkcv/CommandStreamManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9d0a236a4eaa5a166be77d143370a018b9ea7e73
--- /dev/null
+++ b/src/vkcv/CommandStreamManager.cpp
@@ -0,0 +1,119 @@
+#include "vkcv/CommandStreamManager.hpp"
+#include "vkcv/Core.hpp"
+
+namespace vkcv {
+	CommandStreamManager::CommandStreamManager() noexcept : m_core(nullptr){}
+
+	CommandStreamManager::~CommandStreamManager() noexcept {
+		for (const auto& stream : m_commandStreams) {
+			if (stream.cmdBuffer && stream.cmdBuffer) {
+				m_core->getContext().getDevice().freeCommandBuffers(stream.cmdPool, stream.cmdBuffer);
+			}
+		}
+	}
+
+	void CommandStreamManager::init(Core* core) {
+		if (!core) {
+			std::cerr << "Error: CommandStreamManager::init requires valid core pointer" << std::endl;
+		}
+		m_core = core;
+	}
+
+	CommandStreamHandle CommandStreamManager::createCommandStream(
+		const vk::Queue queue, 
+		vk::CommandPool cmdPool) {
+
+		const vk::CommandBuffer cmdBuffer = allocateCommandBuffer(m_core->getContext().getDevice(), cmdPool);
+
+		CommandStream stream(cmdBuffer, queue, cmdPool);
+		beginCommandBuffer(stream.cmdBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
+
+		// find unused stream
+		int unusedStreamIndex = -1;
+		for (int i = 0; i < m_commandStreams.size(); i++) {
+			if (m_commandStreams[i].cmdBuffer) {
+				// still in use
+			}
+			else {
+				unusedStreamIndex = i;
+				break;
+			}
+		}
+
+        const bool foundUnusedStream = unusedStreamIndex >= 0;
+        if (foundUnusedStream) {
+            m_commandStreams[unusedStreamIndex] = stream;
+            return CommandStreamHandle(unusedStreamIndex);
+        }
+
+        CommandStreamHandle handle(m_commandStreams.size());
+        m_commandStreams.push_back(stream);
+        return handle;
+    }
+
+	void CommandStreamManager::recordCommandsToStream(
+		const CommandStreamHandle   handle, 
+		const RecordCommandFunction record) {
+
+		const size_t id = handle.getId();
+		if (id >= m_commandStreams.size()) {
+			std::cerr << "Error: CommandStreamManager::recordCommandsToStream requires valid handle" << std::endl;
+			return;
+		}
+
+		CommandStream& stream = m_commandStreams[id];
+		record(stream.cmdBuffer);
+	}
+
+	void CommandStreamManager::addFinishCallbackToStream(
+		const CommandStreamHandle   handle, 
+		const FinishCommandFunction finish) {
+
+		const size_t id = handle.getId();
+		if (id >= m_commandStreams.size()) {
+			std::cerr << "Error: CommandStreamManager::addFinishCallbackToStream requires valid handle" << std::endl;
+			return;
+		}
+
+		CommandStream& stream = m_commandStreams[id];
+		stream.callbacks.push_back(finish);
+	}
+
+	void CommandStreamManager::submitCommandStreamSynchronous(
+		const CommandStreamHandle   handle,
+		std::vector<vk::Semaphore>  &waitSemaphores,
+		std::vector<vk::Semaphore>  &signalSemaphores) {
+
+		const size_t id = handle.getId();
+		if (id >= m_commandStreams.size()) {
+			std::cerr << "Error: CommandStreamManager::submitCommandStreamSynchronous requires valid handle" << std::endl;
+			return;
+		}
+		CommandStream& stream = m_commandStreams[id];
+		stream.cmdBuffer.end();
+
+		const auto device = m_core->getContext().getDevice();
+		const vk::Fence waitFence = createFence(device);
+		submitCommandBufferToQueue(stream.queue, stream.cmdBuffer, waitFence, waitSemaphores, signalSemaphores);
+		waitForFence(device, waitFence);
+		device.destroyFence(waitFence);
+
+		device.freeCommandBuffers(stream.cmdPool, stream.cmdBuffer);
+		stream.cmdBuffer    = nullptr;
+		stream.cmdPool      = nullptr;
+		stream.queue        = nullptr;
+
+		for (const auto& finishCallback : stream.callbacks) {
+			finishCallback();
+		}
+	}
+
+	vk::CommandBuffer CommandStreamManager::getStreamCommandBuffer(const CommandStreamHandle handle) {
+		const size_t id = handle.getId();
+		if (id >= m_commandStreams.size()) {
+			std::cerr << "Error: CommandStreamManager::submitCommandStreamSynchronous requires valid handle" << std::endl;
+			return nullptr;
+		}
+		return m_commandStreams[id].cmdBuffer;
+	}
+}
\ No newline at end of file
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 08189af15111128aa51cd8619f0ba092d653eb17..c9ac4decbc5ae19d77fa33726566ecb5c8b31d3c 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -14,6 +14,7 @@
 #include "ImageManager.hpp"
 #include "DescriptorManager.hpp"
 #include "ImageLayoutTransitions.hpp"
+#include "vkcv/CommandStreamManager.hpp"
 
 namespace vkcv
 {
@@ -52,8 +53,8 @@ namespace vkcv
         return m_Context;
     }
 
-	Core::Core(Context &&context, Window &window, const SwapChain& swapChain,  std::vector<vk::ImageView> imageViews,
-		const CommandResources& commandResources, const SyncResources& syncResources) noexcept :
+    Core::Core(Context &&context, Window &window, const SwapChain& swapChain,  std::vector<vk::ImageView> imageViews,
+        const CommandResources& commandResources, const SyncResources& syncResources) noexcept :
             m_Context(std::move(context)),
             m_window(window),
             m_swapchain(swapChain),
@@ -61,20 +62,25 @@ namespace vkcv
             m_PassManager{std::make_unique<PassManager>(m_Context.m_Device)},
             m_PipelineManager{std::make_unique<PipelineManager>(m_Context.m_Device)},
             m_DescriptorManager(std::make_unique<DescriptorManager>(m_Context.m_Device)),
-			m_BufferManager{std::unique_ptr<BufferManager>(new BufferManager())},
-			m_SamplerManager(std::unique_ptr<SamplerManager>(new SamplerManager(m_Context.m_Device))),
-			m_ImageManager{std::unique_ptr<ImageManager>(new ImageManager(*m_BufferManager))},
+            m_BufferManager{std::unique_ptr<BufferManager>(new BufferManager())},
+            m_SamplerManager(std::unique_ptr<SamplerManager>(new SamplerManager(m_Context.m_Device))),
+            m_ImageManager{std::unique_ptr<ImageManager>(new ImageManager(*m_BufferManager))},
+            m_CommandStreamManager{std::unique_ptr<CommandStreamManager>(new CommandStreamManager)},
             m_CommandResources(commandResources),
             m_SyncResources(syncResources)
 	{
-    	m_BufferManager->m_core = this;
-    	m_BufferManager->init();
-    	
-    	m_ImageManager->m_core = this;
+		m_BufferManager->m_core = this;
+		m_BufferManager->init();
+		m_CommandStreamManager->init(this);
+
+		m_ImageManager->m_core = this;
+
+		e_resizeHandle = window.e_resize.add( [&](int width, int height) {
+			m_swapchain.signalSwapchainRecreation();
+		});
 
-        e_resizeHandle = window.e_resize.add( [&](int width, int height) {
-        	m_swapchain.recreateSwapchain();
-        });
+		m_swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain());
+		m_swapchainImageLayouts.resize(m_swapchainImages.size(), vk::ImageLayout::eUndefined);
 	}
 
 	Core::~Core() noexcept {
@@ -130,6 +136,10 @@ namespace vkcv
 			
 			m_swapchain.updateSwapchain(m_Context, m_window);
 			m_swapchainImageViews = createImageViews(m_Context, m_swapchain);
+			m_swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain());
+
+			m_swapchainImageLayouts.clear();
+			m_swapchainImageLayouts.resize(m_swapchainImages.size(), vk::ImageLayout::eUndefined);
 		}
 		
     	if (acquireSwapchainImage() != Result::SUCCESS) {
@@ -141,7 +151,8 @@ namespace vkcv
 		m_Context.getDevice().waitIdle(); // TODO: this is a sin against graphics programming, but its getting late - Alex
 	}
 
-	void Core::recordDrawcalls(
+	void Core::recordDrawcallsToCmdStream(
+		const CommandStreamHandle       cmdStreamHandle,
 		const PassHandle                renderpassHandle, 
 		const PipelineHandle            pipelineHandle, 
         const PushConstantData          &pushConstantData,
@@ -184,11 +195,17 @@ namespace vkcv
 		std::vector<vk::ImageView> attachmentsViews;
 		for (const ImageHandle handle : renderTargets) {
 			vk::ImageView targetHandle;
+			const auto cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle);
 			if (handle.isSwapchainImage()) {
+				recordSwapchainImageLayoutTransition(cmdBuffer, vk::ImageLayout::eColorAttachmentOptimal);
 				targetHandle = m_swapchainImageViews[m_currentSwapchainImageIndex];
 			}
 			else {
 				targetHandle = m_ImageManager->getVulkanImageView(handle);
+				const bool isDepthImage = isDepthFormat(m_ImageManager->getImageFormat(handle));
+				const vk::ImageLayout targetLayout = 
+					isDepthFormat ? vk::ImageLayout::eDepthStencilAttachmentOptimal : vk::ImageLayout::eColorAttachmentOptimal;
+				m_ImageManager->recordImageLayoutTransition(handle, targetLayout, cmdBuffer);
 			}
 			attachmentsViews.push_back(targetHandle);
 		}
@@ -227,7 +244,7 @@ namespace vkcv
                 if (attachment.load_operation == AttachmentOperation::CLEAR) {
                     float clear = 0.0f;
 
-                    if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) {
+                    if (isDepthFormat(attachment.format)) {
                         clear = 1.0f;
                     }
 
@@ -260,12 +277,12 @@ namespace vkcv
             cmdBuffer.endRenderPass();
         };
 
-        auto finishFunction = [&]()
+        auto finishFunction = [framebuffer, this]()
         {
             m_Context.m_Device.destroy(framebuffer);
         };
 
-		submitCommands(submitInfo, submitFunction, finishFunction);
+		recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction);
 	}
 
 	void Core::endFrame() {
@@ -297,7 +314,10 @@ namespace vkcv
 		return m_swapchain.getSwapchainFormat();
 	}
 	
-	void Core::submitCommands(const SubmitInfo &submitInfo, const RecordCommandFunction& record, const FinishCommandFunction& finish)
+	void Core::recordAndSubmitCommands(
+		const SubmitInfo &submitInfo, 
+		const RecordCommandFunction &record, 
+		const FinishCommandFunction &finish)
 	{
 		const vk::Device& device = m_Context.getDevice();
 
@@ -320,12 +340,37 @@ namespace vkcv
 			finish();
 		}
 	}
-	
+
+	CommandStreamHandle Core::createCommandStream(QueueType queueType) {
+
+		const vk::Device&       device  = m_Context.getDevice();
+		const vkcv::Queue       queue   = getQueueForSubmit(queueType, m_Context.getQueueManager());
+		const vk::CommandPool   cmdPool = chooseCmdPool(queue, m_CommandResources);
+
+		return m_CommandStreamManager->createCommandStream(queue.handle, cmdPool);
+	}
+
+    void Core::recordCommandsToStream(
+		const CommandStreamHandle   cmdStreamHandle,
+		const RecordCommandFunction &record, 
+		const FinishCommandFunction &finish) {
+
+		m_CommandStreamManager->recordCommandsToStream(cmdStreamHandle, record);
+		m_CommandStreamManager->addFinishCallbackToStream(cmdStreamHandle, finish);
+	}
+
+	void Core::submitCommandStream(const CommandStreamHandle handle) {
+		std::vector<vk::Semaphore> waitSemaphores;
+		// FIXME: add proper user controllable sync
+		std::vector<vk::Semaphore> signalSemaphores = { m_SyncResources.renderFinished };
+		m_CommandStreamManager->submitCommandStreamSynchronous(handle, waitSemaphores, signalSemaphores);
+	}
+
 	SamplerHandle Core::createSampler(SamplerFilterType magFilter, SamplerFilterType minFilter,
 									  SamplerMipmapMode mipmapMode, SamplerAddressMode addressMode) {
-    	return m_SamplerManager->createSampler(magFilter, minFilter, mipmapMode, addressMode);
-    }
-    
+		return m_SamplerManager->createSampler(magFilter, minFilter, mipmapMode, addressMode);
+	}
+
 	Image Core::createImage(vk::Format format, uint32_t width, uint32_t height, uint32_t depth)
 	{
     	return Image::create(m_ImageManager.get(), format, width, height, depth);
@@ -371,11 +416,26 @@ namespace vkcv
                     vk::ImageViewType::e2D,
                     swapChain.getSwapchainFormat(),
                     componentMapping,
-                    subResourceRange
-            );
+                    subResourceRange);
 
             imageViews.push_back(context.getDevice().createImageView(imageViewCreateInfo));
         }
         return imageViews;
     }
+
+	void Core::recordSwapchainImageLayoutTransition(vk::CommandBuffer cmdBuffer, vk::ImageLayout newLayout) {
+		auto& imageLayout = m_swapchainImageLayouts[m_currentSwapchainImageIndex];
+		const auto transitionBarrier = createSwapchainImageLayoutTransitionBarrier(
+			m_swapchainImages[m_currentSwapchainImageIndex],
+			imageLayout,
+			newLayout);
+		recordImageBarrier(cmdBuffer, transitionBarrier);
+		imageLayout = newLayout;
+	}
+
+	void Core::prepareSwapchainImageForPresent(const CommandStreamHandle handle) {
+		m_CommandStreamManager->recordCommandsToStream(handle, [&](vk::CommandBuffer cmdBuffer) {
+			recordSwapchainImageLayoutTransition(cmdBuffer, vk::ImageLayout::ePresentSrcKHR);
+		});
+	}
 }
diff --git a/src/vkcv/Image.cpp b/src/vkcv/Image.cpp
index 9ce5c25a01957ca43c75c14f6b37a7a3e82feee4..f861daeb1cd7de9697e2f649de444666b8b0e63c 100644
--- a/src/vkcv/Image.cpp
+++ b/src/vkcv/Image.cpp
@@ -8,13 +8,24 @@
 
 namespace vkcv{
 	
+	bool isDepthFormat(const vk::Format format) {
+		switch (format) {
+			case(vk::Format::eD16Unorm):        return true;
+			case(vk::Format::eD16UnormS8Uint):  return true;
+			case(vk::Format::eD24UnormS8Uint):  return true;
+			case(vk::Format::eD32Sfloat):       return true;
+			case(vk::Format::eD32SfloatS8Uint): return true;
+			default:                            return false;
+		}
+	}
+
 	Image Image::create(ImageManager* manager, vk::Format format, uint32_t width, uint32_t height, uint32_t depth)
 	{
-		return Image(manager, manager->createImage(width, height, depth, format), format);
+		return Image(manager, manager->createImage(width, height, depth, format));
 	}
 	
 	vk::Format Image::getFormat() const {
-		return m_format;
+		return m_manager->getImageFormat(m_handle);
 	}
 	
 	uint32_t Image::getWidth() const {
@@ -28,15 +39,10 @@ namespace vkcv{
 	uint32_t Image::getDepth() const {
 		return m_manager->getImageDepth(m_handle);
 	}
-	
-	vk::ImageLayout Image::getLayout() const {
-		return m_layout;
-	}
 
 	void Image::switchLayout(vk::ImageLayout newLayout)
 	{
-		m_manager->switchImageLayout(m_handle, m_layout, newLayout);
-		m_layout = newLayout;
+		m_manager->switchImageLayoutImmediate(m_handle, newLayout);
 	}
 
 	vkcv::ImageHandle Image::getHandle() const {
@@ -47,12 +53,9 @@ namespace vkcv{
 		m_manager->fillImage(m_handle, data, size);
 	}
 	
-	Image::Image(ImageManager* manager, const ImageHandle& handle, vk::Format format) :
+	Image::Image(ImageManager* manager, const ImageHandle& handle) :
 		m_manager(manager),
-		m_handle(handle),
-		m_format(format),
-		m_layout(vk::ImageLayout::eUndefined)
-	{
-	}
+		m_handle(handle)
+	{}
 
 }
diff --git a/src/vkcv/ImageLayoutTransitions.cpp b/src/vkcv/ImageLayoutTransitions.cpp
index 0b08819489c41c5cde3ceddbb0629a5d2ae3cd30..cb0f90a79d188cd80a5744d8c6ad7718e542d473 100644
--- a/src/vkcv/ImageLayoutTransitions.cpp
+++ b/src/vkcv/ImageLayoutTransitions.cpp
@@ -1,24 +1,68 @@
 #include "ImageLayoutTransitions.hpp"
+#include "vkcv/Image.hpp"
 
 namespace vkcv {
-	void transitionImageLayoutImmediate(const vk::CommandBuffer cmdBuffer, const vk::Image image,
-		const vk::ImageLayout oldLayout, const vk::ImageLayout newLayout) {
+	vk::ImageMemoryBarrier createImageLayoutTransitionBarrier(const ImageManager::Image &image, vk::ImageLayout newLayout) {
 
-		// TODO: proper src and dst masks
-		const vk::PipelineStageFlags srcStageMask = vk::PipelineStageFlagBits::eAllCommands;
-		const vk::PipelineStageFlags dstStageMask = vk::PipelineStageFlagBits::eAllCommands;
-		const vk::DependencyFlags dependecyFlags = {};
+		vk::ImageAspectFlags aspectFlags;
+		if (isDepthFormat(image.m_format)) {
+			aspectFlags = vk::ImageAspectFlagBits::eDepth;
+		}
+		else {
+			aspectFlags = vk::ImageAspectFlagBits::eColor;
+		}
 
-		// TODO: proper src and dst masks
-		const vk::AccessFlags srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
-		const vk::AccessFlags dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
+		vk::ImageSubresourceRange imageSubresourceRange(
+			aspectFlags,
+			0,
+			image.m_levels,
+			0,
+			image.m_layers
+		);
 
-		// TODO: proper aspect flags
-		const vk::ImageAspectFlags aspectFlags = vk::ImageAspectFlagBits::eColor;
+		// TODO: precise AccessFlagBits, will require a lot of context
+		return vk::ImageMemoryBarrier(
+			vk::AccessFlagBits::eMemoryWrite,
+			vk::AccessFlagBits::eMemoryRead,
+			image.m_layout,
+			newLayout,
+			VK_QUEUE_FAMILY_IGNORED,
+			VK_QUEUE_FAMILY_IGNORED,
+			image.m_handle,
+			imageSubresourceRange);
+	}
+
+	vk::ImageMemoryBarrier createSwapchainImageLayoutTransitionBarrier(
+		vk::Image       vulkanHandle, 
+		vk::ImageLayout oldLayout, 
+		vk::ImageLayout newLayout) {
 
-		const vk::ImageSubresourceRange subresourceRange(aspectFlags, 0, 1, 0, 1);
-		vk::ImageMemoryBarrier imageBarrier(srcAccessMask, dstAccessMask, oldLayout, newLayout, 0, 0, image, subresourceRange);
+		vk::ImageSubresourceRange imageSubresourceRange(
+			vk::ImageAspectFlagBits::eColor,
+			0,
+			1,
+			0,
+			1);
+
+		// TODO: precise AccessFlagBits, will require a lot of context
+		return vk::ImageMemoryBarrier(
+			vk::AccessFlagBits::eMemoryWrite,
+			vk::AccessFlagBits::eMemoryRead,
+			oldLayout,
+			newLayout,
+			VK_QUEUE_FAMILY_IGNORED,
+			VK_QUEUE_FAMILY_IGNORED,
+			vulkanHandle,
+			imageSubresourceRange);
+	}
 
-		cmdBuffer.pipelineBarrier(srcStageMask, dstStageMask, dependecyFlags, 0, nullptr, 0, nullptr, 1, &imageBarrier, {});
+	void recordImageBarrier(vk::CommandBuffer cmdBuffer, vk::ImageMemoryBarrier barrier) {
+		cmdBuffer.pipelineBarrier(
+			vk::PipelineStageFlagBits::eTopOfPipe,
+			vk::PipelineStageFlagBits::eBottomOfPipe,
+			{},
+			nullptr,
+			nullptr,
+			barrier);
 	}
 }
\ No newline at end of file
diff --git a/src/vkcv/ImageLayoutTransitions.hpp b/src/vkcv/ImageLayoutTransitions.hpp
index 3dbfbdf6690a0683b30a96f400e7e4b6ec25c379..5c147f133a6492746ad410367e5e627be000d7be 100644
--- a/src/vkcv/ImageLayoutTransitions.hpp
+++ b/src/vkcv/ImageLayoutTransitions.hpp
@@ -1,7 +1,13 @@
 #pragma once
 #include <vulkan/vulkan.hpp>
+#include "ImageManager.hpp"
 
 namespace vkcv {
-	void transitionImageLayoutImmediate(const vk::CommandBuffer cmdBuffer, const vk::Image image,
-		const vk::ImageLayout oldLayout, const vk::ImageLayout newLayout);
+	vk::ImageMemoryBarrier createImageLayoutTransitionBarrier(const ImageManager::Image& image, vk::ImageLayout newLayout);
+	vk::ImageMemoryBarrier createSwapchainImageLayoutTransitionBarrier(
+		vk::Image       vulkanHandle,
+		vk::ImageLayout oldLayout,
+		vk::ImageLayout newLayout);
+
+	void recordImageBarrier(vk::CommandBuffer cmdBuffer, vk::ImageMemoryBarrier barrier);
 }
\ No newline at end of file
diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp
index a3ca22b16b2c96962b188c8a8be51ebb9cd7314d..b732630a6f479ccc501e4250a7a7f8d1a5804b93 100644
--- a/src/vkcv/ImageManager.cpp
+++ b/src/vkcv/ImageManager.cpp
@@ -5,11 +5,34 @@
  */
 #include "ImageManager.hpp"
 #include "vkcv/Core.hpp"
+#include "ImageLayoutTransitions.hpp"
 
 #include <algorithm>
 
 namespace vkcv {
 
+	ImageManager::Image::Image(
+		vk::Image           handle,
+		vk::DeviceMemory    memory,
+		vk::ImageView       view,
+		uint32_t            width,
+		uint32_t            height,
+		uint32_t            depth,
+		vk::Format          format,
+		uint32_t            layers,
+		uint32_t            levels)
+		:
+		m_handle(handle),
+		m_memory(memory),
+		m_view(view),
+		m_width(width),
+		m_height(height),
+		m_depth(depth),
+		m_format(format),
+		m_layers(layers),
+		m_levels(levels)
+	{}
+
 	/**
 	 * @brief searches memory type index for image allocation, combines requirements of image and application
 	 * @param physicalMemoryProperties Memory Properties of physical device
@@ -166,7 +189,7 @@ namespace vkcv {
 		vk::ImageView view = device.createImageView(imageViewCreateInfo);
 		
 		const uint64_t id = m_images.size();
-		m_images.push_back({ image, memory, view, width, height, depth, format, arrayLayers, mipLevels });
+		m_images.push_back(Image(image, memory, view, width, height, depth, format, arrayLayers, mipLevels));
 		return ImageHandle(id, [&](uint64_t id) { destroyImageById(id); });
 	}
 	
@@ -213,7 +236,7 @@ namespace vkcv {
 		return image.m_view;
 	}
 	
-	void ImageManager::switchImageLayout(const ImageHandle& handle, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) {
+	void ImageManager::switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout) {
 		const uint64_t id = handle.getId();
 		
 		if (id >= m_images.size()) {
@@ -222,76 +245,43 @@ namespace vkcv {
 		}
 		
 		auto& image = m_images[id];
-		
-		//alternativly we could use switch case for every variable to set
-		vk::AccessFlags sourceAccessMask;
-		vk::PipelineStageFlags sourceStage;
-		
-		vk::AccessFlags destinationAccessMask;
-		vk::PipelineStageFlags destinationStage;
-		
-		if ((oldLayout == vk::ImageLayout::eUndefined) &&
-			(newLayout == vk::ImageLayout::eTransferDstOptimal))
-		{
-			destinationAccessMask = vk::AccessFlagBits::eTransferWrite;
-			
-			sourceStage = vk::PipelineStageFlagBits::eTopOfPipe;
-			destinationStage = vk::PipelineStageFlagBits::eTransfer;
-		}
-		else if ((oldLayout == vk::ImageLayout::eTransferDstOptimal) &&
-				 (newLayout == vk::ImageLayout::eShaderReadOnlyOptimal))
-		{
-			sourceAccessMask = vk::AccessFlagBits::eTransferWrite;
-			destinationAccessMask = vk::AccessFlagBits::eShaderRead;
-			
-			sourceStage = vk::PipelineStageFlagBits::eTransfer;
-			destinationStage = vk::PipelineStageFlagBits::eFragmentShader;
-		}
-		
-		vk::ImageAspectFlags aspectFlags;
-		
-		if (isDepthImageFormat(image.m_format)) {
-			aspectFlags = vk::ImageAspectFlagBits::eDepth;
-		} else {
-			aspectFlags = vk::ImageAspectFlagBits::eColor;
-		}
-		
-		vk::ImageSubresourceRange imageSubresourceRange(
-				aspectFlags,
-				0,
-				image.m_levels,
-				0,
-				image.m_layers
-		);
-		
-		vk::ImageMemoryBarrier imageMemoryBarrier(
-			sourceAccessMask,
-			destinationAccessMask,
-			oldLayout,
-			newLayout,
-			VK_QUEUE_FAMILY_IGNORED,
-			VK_QUEUE_FAMILY_IGNORED,
-			image.m_handle,
-			imageSubresourceRange
-		);
+		const auto transitionBarrier = createImageLayoutTransitionBarrier(image, newLayout);
 		
 		SubmitInfo submitInfo;
 		submitInfo.queueType = QueueType::Graphics;
 		
-		m_core->submitCommands(
+		m_core->recordAndSubmitCommands(
 			submitInfo,
-			[sourceStage, destinationStage, imageMemoryBarrier](const vk::CommandBuffer& commandBuffer) {
-				commandBuffer.pipelineBarrier(
-					sourceStage,
-					destinationStage,
-					{},
-					nullptr,
-					nullptr,
-					imageMemoryBarrier
+			[transitionBarrier](const vk::CommandBuffer& commandBuffer) {
+			// TODO: precise PipelineStageFlagBits, will require a lot of context
+			commandBuffer.pipelineBarrier(
+				vk::PipelineStageFlagBits::eTopOfPipe,
+				vk::PipelineStageFlagBits::eBottomOfPipe,
+				{},
+				nullptr,
+				nullptr,
+				transitionBarrier
 				);
 			},
-			nullptr
-		);
+			nullptr);
+		image.m_layout = newLayout;
+	}
+
+	void ImageManager::recordImageLayoutTransition(
+		const ImageHandle& handle, 
+		vk::ImageLayout newLayout, 
+		vk::CommandBuffer cmdBuffer) {
+
+		const uint64_t id = handle.getId();
+
+		if (id >= m_images.size()) {
+			std::cerr << "Error: ImageManager::switchImageLayout invalid handle" << std::endl;
+			return;
+		}
+
+		auto& image = m_images[id];
+		const auto transitionBarrier = createImageLayoutTransitionBarrier(image, newLayout);
+		recordImageBarrier(cmdBuffer, transitionBarrier);
 	}
 	
 	void ImageManager::fillImage(const ImageHandle& handle, void* data, size_t size)
@@ -305,11 +295,9 @@ namespace vkcv {
 		
 		auto& image = m_images[id];
 		
-		switchImageLayout(
+		switchImageLayoutImmediate(
 				handle,
-				vk::ImageLayout::eUndefined,
-				vk::ImageLayout::eTransferDstOptimal
-		);
+				vk::ImageLayout::eTransferDstOptimal);
 		
 		uint32_t channels = 4; // TODO: check image.m_format
 		const size_t image_size = (
@@ -329,7 +317,7 @@ namespace vkcv {
 		SubmitInfo submitInfo;
 		submitInfo.queueType = QueueType::Transfer;
 		
-		m_core->submitCommands(
+		m_core->recordAndSubmitCommands(
 				submitInfo,
 				[&image, &stagingBuffer](const vk::CommandBuffer& commandBuffer) {
 					vk::ImageAspectFlags aspectFlags;
@@ -363,9 +351,8 @@ namespace vkcv {
 					);
 				},
 				[&]() {
-					switchImageLayout(
+					switchImageLayoutImmediate(
 							handle,
-							vk::ImageLayout::eTransferDstOptimal,
 							vk::ImageLayout::eShaderReadOnlyOptimal
 					);
 				}
@@ -438,5 +425,16 @@ namespace vkcv {
 		}
 	}
 
+	vk::Format ImageManager::getImageFormat(const ImageHandle& handle) const {
+
+		const uint64_t id = handle.getId();
+
+		if (id >= m_images.size()) {
+			std::cerr << "Error: ImageManager::destroyImageById invalid handle" << std::endl;
+			return vk::Format::eUndefined;
+		}
+
+		return m_images[id].m_format;
+	}
 
 }
\ No newline at end of file
diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp
index f1bd9d0be774478f62098cbc2833b5c268be2eea..b9fccb25ec16bc1fd9569ab1a94627bd7ff06b18 100644
--- a/src/vkcv/ImageManager.hpp
+++ b/src/vkcv/ImageManager.hpp
@@ -11,23 +11,38 @@
 #include "vkcv/Handles.hpp"
 
 namespace vkcv {
-	
+
 	class ImageManager
 	{
 		friend class Core;
-	private:
+	public:
 		struct Image
 		{
-			vk::Image m_handle;
-			vk::DeviceMemory m_memory;
-			vk::ImageView m_view;
-			uint32_t m_width = 0;
-			uint32_t m_height = 0;
-			uint32_t m_depth = 0;
-			vk::Format m_format;
-			uint32_t m_layers = 1;
-			uint32_t m_levels = 1;
+			vk::Image           m_handle;
+			vk::DeviceMemory    m_memory;
+			vk::ImageView       m_view;
+			uint32_t            m_width = 0;
+			uint32_t            m_height = 0;
+			uint32_t            m_depth = 0;
+			vk::Format          m_format;
+			uint32_t            m_layers = 1;
+			uint32_t            m_levels = 1;
+			vk::ImageLayout     m_layout = vk::ImageLayout::eUndefined;
+		private:
+			// struct is public so utility functions can access members, but only ImageManager can create Image
+			friend ImageManager;
+			Image(
+				vk::Image           handle,
+				vk::DeviceMemory    memory,
+				vk::ImageView       view,
+				uint32_t            width,
+				uint32_t            height,
+				uint32_t            depth,
+				vk::Format          format,
+				uint32_t            layers,
+				uint32_t            levels);
 		};
+	private:
 		
 		Core* m_core;
 		BufferManager& m_bufferManager;
@@ -64,8 +79,13 @@ namespace vkcv {
 		
 		[[nodiscard]]
 		vk::ImageView getVulkanImageView(const ImageHandle& handle) const;
-		
-		void switchImageLayout(const ImageHandle& handle, vk::ImageLayout oldLayout, vk::ImageLayout newLayout);
+
+		void switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout);
+		void recordImageLayoutTransition(
+			const ImageHandle& handle, 
+			vk::ImageLayout newLayout, 
+			vk::CommandBuffer cmdBuffer);
+
 		void fillImage(const ImageHandle& handle, void* data, size_t size);
 		
 		[[nodiscard]]
@@ -77,5 +97,7 @@ namespace vkcv {
 		[[nodiscard]]
 		uint32_t getImageDepth(const ImageHandle& handle) const;
 		
+		[[nodiscard]]
+		vk::Format getImageFormat(const ImageHandle& handle) const;
 	};
 }
\ No newline at end of file
diff --git a/src/vkcv/PassConfig.cpp b/src/vkcv/PassConfig.cpp
index ef07d3ee8d6170ae893cd055eefcc971cd1b87a3..602f1d3e2a8100ebd9bbb83772312d3d659abe86 100644
--- a/src/vkcv/PassConfig.cpp
+++ b/src/vkcv/PassConfig.cpp
@@ -5,15 +5,9 @@
 namespace vkcv
 {
     AttachmentDescription::AttachmentDescription(
-		AttachmentLayout initial,
-		AttachmentLayout in_pass,
-		AttachmentLayout final,
 		AttachmentOperation store_op,
 		AttachmentOperation load_op,
 		vk::Format format) noexcept :
-	layout_initial{initial},
-	layout_in_pass{in_pass},
-	layout_final{final},
 	store_operation{store_op},
 	load_operation{load_op},
 	format(format)
diff --git a/src/vkcv/PassManager.cpp b/src/vkcv/PassManager.cpp
index 8b59495ae7eaa68b6f42ed2a4786ae688e4a6375..c34b0d3631c48561f42eb7f21ba5578156910f51 100644
--- a/src/vkcv/PassManager.cpp
+++ b/src/vkcv/PassManager.cpp
@@ -1,4 +1,5 @@
 #include "PassManager.hpp"
+#include "vkcv/Image.hpp"
 
 namespace vkcv
 {
@@ -73,63 +74,63 @@ namespace vkcv
         for (uint32_t i = 0; i < config.attachments.size(); i++)
         {
             // TODO: Renderpass struct should hold proper format information
-            vk::Format format = config.attachments[i].format;
+            vk::Format      format = config.attachments[i].format;
+            vk::ImageLayout layout;
 
-            if (config.attachments[i].layout_in_pass == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT)
+            if (isDepthFormat(config.attachments[i].format))
             {
+                layout                              = vk::ImageLayout::eDepthStencilAttachmentOptimal;
                 depthAttachmentReference.attachment = i;
-                depthAttachmentReference.layout = getVkLayoutFromAttachLayout(config.attachments[i].layout_in_pass);
-                pDepthAttachment = &depthAttachmentReference;
+                depthAttachmentReference.layout     = layout;
+                pDepthAttachment                    = &depthAttachmentReference;
             }
             else
             {
-                vk::AttachmentReference attachmentRef(i, getVkLayoutFromAttachLayout(config.attachments[i].layout_in_pass));
+                layout = vk::ImageLayout::eColorAttachmentOptimal;
+                vk::AttachmentReference attachmentRef(i, layout);
                 colorAttachmentReferences.push_back(attachmentRef);
             }
 
             vk::AttachmentDescription attachmentDesc(
-            		{},
-            		format,
-            		vk::SampleCountFlagBits::e1,
-            		getVKLoadOpFromAttachOp(config.attachments[i].load_operation),
-            		getVkStoreOpFromAttachOp(config.attachments[i].store_operation),
-            		vk::AttachmentLoadOp::eDontCare,
-            		vk::AttachmentStoreOp::eDontCare,
-            		getVkLayoutFromAttachLayout(config.attachments[i].layout_initial),
-            		getVkLayoutFromAttachLayout(config.attachments[i].layout_final)
-			);
-            
+                {},
+                format,
+                vk::SampleCountFlagBits::e1,
+                getVKLoadOpFromAttachOp(config.attachments[i].load_operation),
+                getVkStoreOpFromAttachOp(config.attachments[i].store_operation),
+                vk::AttachmentLoadOp::eDontCare,
+                vk::AttachmentStoreOp::eDontCare,
+                layout,
+                layout);
+
             attachmentDescriptions.push_back(attachmentDesc);
         }
         
         const vk::SubpassDescription subpassDescription(
-        		{},
-        		vk::PipelineBindPoint::eGraphics,
-        		0,
-        		{},
-        		static_cast<uint32_t>(colorAttachmentReferences.size()),
-        		colorAttachmentReferences.data(),
-        		{},
-        		pDepthAttachment,
-        		0,
-        		{}
-        );
+            {},
+            vk::PipelineBindPoint::eGraphics,
+            0,
+            {},
+            static_cast<uint32_t>(colorAttachmentReferences.size()),
+            colorAttachmentReferences.data(),
+            {},
+            pDepthAttachment,
+            0,
+            {});
 
         const vk::RenderPassCreateInfo passInfo(
-        		{},
-        		static_cast<uint32_t>(attachmentDescriptions.size()),
-        		attachmentDescriptions.data(),
-        		1,
-        		&subpassDescription,
-        		0,
-        		{}
-	  	);
+            {},
+            static_cast<uint32_t>(attachmentDescriptions.size()),
+            attachmentDescriptions.data(),
+            1,
+            &subpassDescription,
+            0,
+            {});
 
         vk::RenderPass renderPass = m_Device.createRenderPass(passInfo);
-	
+
         const uint64_t id = m_Passes.size();
-		m_Passes.push_back({ renderPass, config });
-		return PassHandle(id, [&](uint64_t id) { destroyPassById(id); });
+        m_Passes.push_back({ renderPass, config });
+        return PassHandle(id, [&](uint64_t id) { destroyPassById(id); });
     }
 
     vk::RenderPass PassManager::getVkPass(const PassHandle &handle) const
diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp
index e065033f1072e313f23c77e5218f8b85901cc3e4..9afa2bc90dc5bdbaf88deee9de8b4ff71d436641 100644
--- a/src/vkcv/PipelineManager.cpp
+++ b/src/vkcv/PipelineManager.cpp
@@ -1,4 +1,5 @@
 #include "PipelineManager.hpp"
+#include "vkcv/Image.hpp"
 
 namespace vkcv
 {
@@ -207,7 +208,7 @@ namespace vkcv
 		const PassConfig& passConfig = passManager.getPassConfig(config.m_PassHandle);
 		
 		for (const auto& attachment : passConfig.attachments) {
-			if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) {
+			if (isDepthFormat(attachment.format)) {
 				p_depthStencilCreateInfo = &depthStencilCreateInfo;
 				break;
 			}
diff --git a/src/vkcv/SwapChain.cpp b/src/vkcv/SwapChain.cpp
index 39c310de60db2c3678749f142c926a26ac127b58..b787536b66cfd802dfd435a773a584c875eeb391 100644
--- a/src/vkcv/SwapChain.cpp
+++ b/src/vkcv/SwapChain.cpp
@@ -244,7 +244,7 @@ namespace vkcv
 		m_Extent = extent2D;
     }
 
-    void SwapChain::recreateSwapchain() {
+    void SwapChain::signalSwapchainRecreation() {
 		m_RecreationRequired = true;
     }