diff --git a/config/Sources.cmake b/config/Sources.cmake
index ac49dac1a030be3b3dff1c4f6dc3339b1baca422..1b35d798597d0c781d5c4e90679679a83fcedcb2 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -24,6 +24,12 @@ set(vkcv_sources
 		${vkcv_include}/vkcv/BufferManager.hpp
 		${vkcv_source}/vkcv/BufferManager.cpp
 
+		${vkcv_include}/vkcv/Image.hpp
+		${vkcv_source}/vkcv/Image.cpp
+
+		${vkcv_source}/vkcv/ImageManager.hpp
+		${vkcv_source}/vkcv/ImageManager.cpp
+
 		${vkcv_include}/vkcv/SwapChain.hpp
 		${vkcv_source}/vkcv/SwapChain.cpp
 
@@ -50,9 +56,6 @@ set(vkcv_sources
         
         ${vkcv_source}/vkcv/ImageLayoutTransitions.hpp
         ${vkcv_source}/vkcv/ImageLayoutTransitions.cpp
-        
-        ${vkcv_source}/vkcv/Framebuffer.hpp
-        ${vkcv_source}/vkcv/Framebuffer.cpp
 
 		${vkcv_include}/vkcv/VertexLayout.hpp
 		${vkcv_source}/vkcv/VertexLayout.cpp
diff --git a/include/vkcv/BufferManager.hpp b/include/vkcv/BufferManager.hpp
index 52e338483af7ddd01b6345b4ff1d0187ae4fbd8a..4b12f47ba8497bd09260d24523c28f207f64a98c 100644
--- a/include/vkcv/BufferManager.hpp
+++ b/include/vkcv/BufferManager.hpp
@@ -31,9 +31,9 @@ namespace vkcv
 		{
 			vk::Buffer m_handle;
 			vk::DeviceMemory m_memory;
-			size_t m_size;
+			size_t m_size = 0;
 			void* m_mapped = nullptr;
-			bool m_mappable;
+			bool m_mappable = false;
 		};
 		
 		Core* m_core;
@@ -55,7 +55,7 @@ namespace vkcv
 		
 		/**
 		 * Creates and allocates a new buffer and returns its
-		 * unique buffer handle id.
+		 * unique buffer handle.
 		 *
 		 * @param type Type of buffer
 		 * @param size Size of buffer in bytes
@@ -66,7 +66,7 @@ namespace vkcv
 		
 		/**
 		 * Returns the Vulkan buffer handle of a buffer
-		 * represented by a given buffer handle id.
+		 * represented by a given buffer handle.
 		 *
 		 * @param handle Buffer handle
 		 * @return Vulkan buffer handle
@@ -74,6 +74,16 @@ namespace vkcv
 		[[nodiscard]]
 		vk::Buffer getBuffer(const BufferHandle& handle) const;
 		
+		/**
+		 * Returns the size of a buffer represented
+		 * by a given buffer handle.
+		 *
+		 * @param handle Buffer handle
+		 * @return Size of the buffer
+		 */
+		[[nodiscard]]
+		size_t getBufferSize(const BufferHandle& handle) const;
+		
 		/**
 		 * Returns the Vulkan device memory handle of a buffer
 		 * represented by a given buffer handle id.
@@ -86,7 +96,7 @@ namespace vkcv
 		
 		/**
 		 * Fills a buffer represented by a given buffer
-		 * handle id with custom data.
+		 * handle with custom data.
 		 *
 		 * @param handle Buffer handle
 		 * @param data Pointer to data
@@ -97,7 +107,7 @@ namespace vkcv
 		
 		/**
 		 * Maps memory to a buffer represented by a given
-		 * buffer handle id and returns it.
+		 * buffer handle and returns it.
 		 *
 		 * @param handle Buffer handle
 		 * @param offset Offset of mapping in bytes
@@ -108,7 +118,7 @@ namespace vkcv
 		
 		/**
 		 * Unmaps memory from a buffer represented by a given
-		 * buffer handle id.
+		 * buffer handle.
 		 *
 		 * @param handle Buffer handle
 		 */
@@ -116,7 +126,7 @@ namespace vkcv
 	
 		/**
 		 * Destroys and deallocates buffer represented by a given
-		 * buffer handle id.
+		 * buffer handle.
 		 *
 		 * @param handle Buffer handle
 		 */
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index ab0d2aca0eccbd3c6adfea191cefa2c63623b0b9..388bc0ea40950f0e73a23a280af753b79ad00da7 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -13,6 +13,7 @@
 #include "vkcv/PassConfig.hpp"
 #include "vkcv/Handles.hpp"
 #include "vkcv/Buffer.hpp"
+#include "vkcv/Image.hpp"
 #include "vkcv/PipelineConfig.hpp"
 #include "CommandResources.hpp"
 #include "SyncResources.hpp"
@@ -26,6 +27,7 @@ namespace vkcv
     class PipelineManager;
     class DescriptorManager;
     class BufferManager;
+    class ImageManager;
 
 	struct SubmitInfo {
 		QueueType queueType;
@@ -63,6 +65,7 @@ namespace vkcv
         std::unique_ptr<PipelineManager> m_PipelineManager;
         std::unique_ptr<DescriptorManager> m_DescriptorManager;
         std::unique_ptr<BufferManager> m_BufferManager;
+        std::unique_ptr<ImageManager> m_ImageManager;
 
 		CommandResources m_CommandResources;
 		SyncResources m_SyncResources;
@@ -170,6 +173,18 @@ namespace vkcv
         Buffer<T> createBuffer(vkcv::BufferType type, size_t count, BufferMemoryType memoryType = BufferMemoryType::DEVICE_LOCAL) {
         	return Buffer<T>::create(m_BufferManager.get(), type, count, memoryType);
         }
+        
+        /**
+         * Creates an #Image with a given format, width, height and depth.
+         *
+         * @param format Image format
+         * @param width Image width
+         * @param height Image height
+         * @param depth Image depth
+         * @return Image-Object
+         */
+        [[nodiscard]]
+        Image createImage(vk::Format format, uint32_t width, uint32_t height, uint32_t depth = 1);
 
         /** TODO:
          *   @param setDescriptions
diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp
index 7b500ea514f1034e9822f9c12936b5e63ba3225e..1fd6573976b1f5aab572eb982cc0c61eff01a9e9 100644
--- a/include/vkcv/Handles.hpp
+++ b/include/vkcv/Handles.hpp
@@ -64,4 +64,10 @@ namespace vkcv
 		using Handle::Handle;
 	};
 	
+	class ImageHandle : public Handle {
+		friend class ImageManager;
+	private:
+		using Handle::Handle;
+	};
+	
 }
diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5050513b6fd612605b7c83d18d2d3beaaef9a8a0
--- /dev/null
+++ b/include/vkcv/Image.hpp
@@ -0,0 +1,50 @@
+#pragma once
+/**
+ * @authors Lars Hoerttrich
+ * @file vkcv/Buffer.hpp
+ * @brief class for image handles
+ */
+#include "vulkan/vulkan.hpp"
+
+#include "Handles.hpp"
+
+namespace vkcv {
+	
+	class ImageManager;
+	class Image {
+		friend class Core;
+	public:
+		[[nodiscard]]
+		vk::Format getFormat() const;
+		
+		[[nodiscard]]
+		uint32_t getWidth() const;
+		
+		[[nodiscard]]
+		uint32_t getHeight() const;
+		
+		[[nodiscard]]
+		uint32_t getDepth() const;
+		
+		[[nodiscard]]
+		vk::ImageLayout getLayout() const;
+		
+		void switchLayout(vk::ImageLayout newLayout);
+		
+		void fill(void* data, size_t size = SIZE_MAX);
+	private:
+		ImageManager* const m_manager;
+		const ImageHandle m_handle;
+		const vk::Format m_format;
+		const uint32_t m_width;
+		const uint32_t m_height;
+		const uint32_t m_depth;
+		vk::ImageLayout m_layout;
+
+		Image(ImageManager* manager, const ImageHandle& handle, vk::Format format, uint32_t width, uint32_t height, uint32_t depth);
+		
+		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 b8e80c67c2b70e3a0e6e2732b950ccaed38da3bf..d9a5bcd83acca5f5ba86b4e6ce6973acbed89de6 100644
--- a/include/vkcv/PassConfig.hpp
+++ b/include/vkcv/PassConfig.hpp
@@ -53,7 +53,6 @@ namespace vkcv
 
     struct PassConfig
     {
-        PassConfig() = delete;
         explicit PassConfig(std::vector<AttachmentDescription> attachments) noexcept;
         std::vector<AttachmentDescription> attachments{};
     };
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index e1cbc40e747f9f68e44db6ea9ca3dcd556148a4b..6ba3656f6c02077a868c5d99b1331fab5be0abe6 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -60,9 +60,19 @@ int main(int argc, const char** argv) {
 		vkcv::AttachmentLayout::PRESENTATION,
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchainImageFormat());
+		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
+	);
 
-	vkcv::PassConfig trianglePassDefinition({ present_color_attachment });
+	vkcv::PassConfig trianglePassDefinition({ present_color_attachment, depth_attachment });
 	vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition);
 
 	if (!trianglePass) {
@@ -83,6 +93,10 @@ int main(int argc, const char** argv) {
 		std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl;
 		return EXIT_FAILURE;
 	}
+	
+	vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, mesh.texture_hack.w, mesh.texture_hack.h);
+	
+	texture.fill(mesh.texture_hack.img);
 
 	auto start = std::chrono::system_clock::now();
 	while (window.isWindowOpen()) {
@@ -94,8 +108,20 @@ 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.renderMesh(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp, vertexBuffer.getHandle(), indexBuffer.getHandle(), mesh.vertexGroups[0].numIndices);
+		core.renderMesh(
+				trianglePass,
+				trianglePipeline,
+				windowWidth,
+				windowHeight,
+				sizeof(mvp),
+				&mvp,
+				vertexBuffer.getHandle(),
+				indexBuffer.getHandle(),
+				mesh.vertexGroups[0].numIndices
+		);
+		
 		core.endFrame();
 	}
+	
 	return 0;
 }
diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp
index e27338d837e89b5a9442c4ba2dff2061bf0e0f53..740e89993860a7f71ac78aedae5cf3ed946c7b49 100644
--- a/src/vkcv/BufferManager.cpp
+++ b/src/vkcv/BufferManager.cpp
@@ -28,28 +28,29 @@ namespace vkcv {
 	}
 	
 	/**
-	 * @brief searches memory type index for buffer allocation, inspired by vulkan tutorial and "https://github.com/KhronosGroup/Vulkan-Hpp/blob/master/samples/utils/utils.hpp"
+	 * @brief searches memory type index for buffer allocation, combines requirements of buffer and application
 	 * @param physicalMemoryProperties Memory Properties of physical device
-	 * @param typeBits
+	 * @param typeBits Bit field for suitable memory types
 	 * @param requirements Property flags that are required
 	 * @return memory type index for Buffer
 	 */
-	uint32_t searchMemoryType(const vk::PhysicalDeviceMemoryProperties& physicalMemoryProperties, uint32_t typeBits, vk::MemoryPropertyFlags requirements) {
-		uint32_t memoryTypeIndex = 0;
-		
-		for (uint32_t i = 0; i < physicalMemoryProperties.memoryTypeCount; i++)
-		{
-			if ((typeBits & 1) &&
-				((physicalMemoryProperties.memoryTypes[i].propertyFlags & requirements) == requirements))
-			{
-				memoryTypeIndex = i;
-				break;
-			}
-			
-			typeBits >>= 1;
+	uint32_t searchBufferMemoryType(const vk::PhysicalDeviceMemoryProperties& physicalMemoryProperties, uint32_t typeBits, vk::MemoryPropertyFlags requirements) {
+		const uint32_t memoryCount = physicalMemoryProperties.memoryTypeCount;
+		for (uint32_t memoryIndex = 0; memoryIndex < memoryCount; ++memoryIndex) {
+			const uint32_t memoryTypeBits = (1 << memoryIndex);
+			const bool isRequiredMemoryType = typeBits & memoryTypeBits;
+
+			const vk::MemoryPropertyFlags properties =
+				physicalMemoryProperties.memoryTypes[memoryIndex].propertyFlags;
+			const bool hasRequiredProperties =
+				(properties & requirements) == requirements;
+
+			if (isRequiredMemoryType && hasRequiredProperties)
+				return static_cast<int32_t>(memoryIndex);
 		}
-		
-		return memoryTypeIndex;
+
+		// failed to find memory type
+		return -1;
 	}
 	
 	BufferHandle BufferManager::createBuffer(BufferType type, size_t size, BufferMemoryType memoryType) {
@@ -106,7 +107,7 @@ namespace vkcv {
 				break;
 		}
 		
-		const uint32_t memoryTypeIndex = searchMemoryType(
+		const uint32_t memoryTypeIndex = searchBufferMemoryType(
 				physicalDevice.getMemoryProperties(),
 				requirements.memoryTypeBits,
 				memoryTypeFlags
@@ -193,6 +194,18 @@ namespace vkcv {
 		return buffer.m_handle;
 	}
 	
+	size_t BufferManager::getBufferSize(const BufferHandle &handle) const {
+		const uint64_t id = handle.getId();
+		
+		if (id >= m_buffers.size()) {
+			return 0;
+		}
+		
+		auto& buffer = m_buffers[id];
+		
+		return buffer.m_size;
+	}
+	
 	vk::DeviceMemory BufferManager::getDeviceMemory(const BufferHandle& handle) const {
 		const uint64_t id = handle.getId();
 		
@@ -315,10 +328,12 @@ namespace vkcv {
 		
 		if (buffer.m_memory) {
 			device.freeMemory(buffer.m_memory);
+			buffer.m_memory = nullptr;
 		}
 		
 		if (buffer.m_handle) {
 			device.destroyBuffer(buffer.m_handle);
+			buffer.m_handle = nullptr;
 		}
 	}
 
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 13800254d78cb679c81d58a003089aa961986937..d24282f194e79c36096677b7f13d4b218911c3a1 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -10,10 +10,10 @@
 #include "PassManager.hpp"
 #include "PipelineManager.hpp"
 #include "vkcv/BufferManager.hpp"
+#include "ImageManager.hpp"
 #include "DescriptorManager.hpp"
 #include "Surface.hpp"
 #include "ImageLayoutTransitions.hpp"
-#include "Framebuffer.hpp"
 
 namespace vkcv
 {
@@ -95,11 +95,14 @@ namespace vkcv
             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_ImageManager{std::unique_ptr<ImageManager>(new ImageManager(*m_BufferManager))},
             m_CommandResources(commandResources),
             m_SyncResources(syncResources)
 	{
     	m_BufferManager->m_core = this;
     	m_BufferManager->init();
+    	
+    	m_ImageManager->m_core = this;
 	}
 
 	Core::~Core() noexcept {
@@ -118,8 +121,7 @@ namespace vkcv
 
     PipelineHandle Core::createGraphicsPipeline(const PipelineConfig &config)
     {
-        const vk::RenderPass &pass = m_PassManager->getVkPass(config.m_PassHandle);
-        return m_PipelineManager->createPipeline(config, pass);
+        return m_PipelineManager->createPipeline(config, *m_PassManager);
     }
 
 
@@ -161,6 +163,13 @@ namespace vkcv
 		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);
+	}
 
 	void Core::renderMesh(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, 
 		const int width, const int height, const size_t pushConstantSize, const void *pushConstantData,
@@ -171,6 +180,17 @@ namespace vkcv
 		}
 
 		const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle);
+		const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle);
+		
+		ImageHandle depthImage;
+		
+		for (const auto& attachment : passConfig.attachments) {
+			if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) {
+				depthImage = m_ImageManager->createImage(width, height, 1, attachment.format);
+				break;
+			}
+		}
+		
 		const vk::ImageView imageView	= m_swapchainImageViews[m_currentSwapchainImageIndex];
 		const vk::Pipeline pipeline		= m_PipelineManager->getVkPipeline(pipelineHandle);
         const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle);
@@ -178,19 +198,47 @@ namespace vkcv
 		const vk::Buffer vulkanVertexBuffer	= m_BufferManager->getBuffer(vertexBuffer);
 		const vk::Buffer vulkanIndexBuffer	= m_BufferManager->getBuffer(indexBuffer);
 
-		const vk::Framebuffer framebuffer = createFramebuffer(m_Context.getDevice(), renderpass, width, height, imageView);
+		std::vector<vk::ImageView> attachments;
+		attachments.push_back(imageView);
+		
+		if (depthImage) {
+			attachments.push_back(m_ImageManager->getVulkanImageView(depthImage));
+		}
+		
+		const vk::Framebuffer framebuffer = createFramebuffer(
+				m_Context.getDevice(),
+				renderpass,
+				width,
+				height,
+				attachments
+		);
+		
 		m_TemporaryFramebuffers.push_back(framebuffer);
 
 		SubmitInfo submitInfo;
 		submitInfo.queueType = QueueType::Graphics;
 		submitInfo.signalSemaphores = { m_SyncResources.renderFinished };
-		submitCommands(submitInfo, [renderpass, renderArea, imageView, framebuffer, pipeline, pipelineLayout, 
-			pushConstantSize, pushConstantData, vulkanVertexBuffer, indexCount, vulkanIndexBuffer](const vk::CommandBuffer& cmdBuffer) {
-
-			const std::array<float, 4> clearColor = { 0.f, 0.f, 0.f, 1.f };
-			const vk::ClearValue clearValues(clearColor);
-
-			const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, 1, &clearValues);
+		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, {});
 
@@ -201,7 +249,9 @@ namespace vkcv
             cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData);
 			cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {});
 			cmdBuffer.endRenderPass();
-		}, nullptr);
+		}, [&]() {
+			m_ImageManager->destroyImage(depthImage);
+		});
 	}
 
 	void Core::endFrame() {
@@ -262,6 +312,11 @@ namespace vkcv
 			finish();
 		}
 	}
+	
+	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);
+	}
 
     ResourcesHandle Core::createResourceDescription(const std::vector<DescriptorSet> &descriptorSets)
     {
diff --git a/src/vkcv/Framebuffer.cpp b/src/vkcv/Framebuffer.cpp
deleted file mode 100644
index 3b3e8000668e460d476b211984e9e12249f066c0..0000000000000000000000000000000000000000
--- a/src/vkcv/Framebuffer.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "Framebuffer.hpp"
-
-namespace vkcv {
-	vk::Framebuffer createFramebuffer(const vk::Device device, const vk::RenderPass renderpass, 
-		const int width, const int height, const vk::ImageView imageView) {
-		const vk::FramebufferCreateFlags flags = {};
-		const uint32_t attachmentCount = 1;	// TODO: proper value
-		const vk::FramebufferCreateInfo createInfo(flags, renderpass, attachmentCount, &imageView, width, height, 1);
-		return device.createFramebuffer(createInfo, nullptr, {});
-	}
-}
\ No newline at end of file
diff --git a/src/vkcv/Framebuffer.hpp b/src/vkcv/Framebuffer.hpp
deleted file mode 100644
index 7d5d718adbde0c3f8eb8d97c539fb73f7771987f..0000000000000000000000000000000000000000
--- a/src/vkcv/Framebuffer.hpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-#include <vulkan/vulkan.hpp>
-
-namespace vkcv{
-	vk::Framebuffer createFramebuffer(const vk::Device device, const vk::RenderPass renderpass,
-		const int width, const int height, const vk::ImageView imageView);
-}
\ No newline at end of file
diff --git a/src/vkcv/Image.cpp b/src/vkcv/Image.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c4341b4f173028afa5dce98383b2ae34833ee2fa
--- /dev/null
+++ b/src/vkcv/Image.cpp
@@ -0,0 +1,58 @@
+/**
+ * @authors Lars Hoerttrich
+ * @file vkcv/Image.cpp
+ * @brief class for image handles
+ */
+#include "vkcv/Image.hpp"
+#include "ImageManager.hpp"
+
+namespace vkcv{
+	
+	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, width, height, depth);
+	}
+	
+	vk::Format Image::getFormat() const {
+		return m_format;
+	}
+	
+	uint32_t Image::getWidth() const {
+		return m_width;
+	}
+	
+	uint32_t Image::getHeight() const {
+		return m_height;
+	}
+	
+	uint32_t Image::getDepth() const {
+		return m_depth;
+	}
+	
+	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;
+	}
+	
+	void Image::fill(void *data, size_t size) {
+		m_manager->fillImage(m_handle, data, size);
+	}
+	
+	Image::Image(ImageManager* manager, const ImageHandle& handle,
+			  	 vk::Format format, uint32_t width, uint32_t height, uint32_t depth) :
+		m_manager(manager),
+		m_handle(handle),
+		m_format(format),
+		m_width(width),
+		m_height(height),
+		m_depth(depth),
+		m_layout(vk::ImageLayout::eUndefined)
+	{
+	}
+
+}
diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3896d6bc4abdd24264ad5d468b49ebf08bd20be7
--- /dev/null
+++ b/src/vkcv/ImageManager.cpp
@@ -0,0 +1,397 @@
+/**
+ * @authors Lars Hoerttrich
+ * @file vkcv/ImageManager.cpp
+ * @brief class creating and managing images
+ */
+#include "ImageManager.hpp"
+#include "vkcv/Core.hpp"
+
+#include <algorithm>
+
+namespace vkcv {
+
+	/**
+	 * @brief searches memory type index for image allocation, combines requirements of image and application
+	 * @param physicalMemoryProperties Memory Properties of physical device
+	 * @param typeBits Bit field for suitable memory types
+	 * @param requirements Property flags that are required
+	 * @return memory type index for image
+	 */
+	uint32_t searchImageMemoryType(const vk::PhysicalDeviceMemoryProperties& physicalMemoryProperties, uint32_t typeBits, vk::MemoryPropertyFlags requirements) {
+		const uint32_t memoryCount = physicalMemoryProperties.memoryTypeCount;
+		for (uint32_t memoryIndex = 0; memoryIndex < memoryCount; ++memoryIndex) {
+			const uint32_t memoryTypeBits = (1 << memoryIndex);
+			const bool isRequiredMemoryType = typeBits & memoryTypeBits;
+
+			const vk::MemoryPropertyFlags properties =
+				physicalMemoryProperties.memoryTypes[memoryIndex].propertyFlags;
+			const bool hasRequiredProperties =
+				(properties & requirements) == requirements;
+
+			if (isRequiredMemoryType && hasRequiredProperties)
+				return static_cast<int32_t>(memoryIndex);
+		}
+
+		// failed to find memory type
+		return -1;
+	}
+
+	ImageManager::ImageManager(BufferManager& bufferManager) noexcept :
+		m_core(nullptr), m_bufferManager(bufferManager), m_images()
+	{
+	}
+
+	ImageManager::~ImageManager() noexcept {
+		for (uint64_t id = 0; id < m_images.size(); id++) {
+			destroyImage(ImageHandle(id));
+		}
+	}
+	
+	bool isDepthImageFormat(vk::Format format) {
+		if ((format == vk::Format::eD16Unorm) || (format == vk::Format::eD16UnormS8Uint) ||
+			(format == vk::Format::eD24UnormS8Uint) || (format == vk::Format::eD32Sfloat) ||
+			(format == vk::Format::eD32SfloatS8Uint)) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	ImageHandle ImageManager::createImage(uint32_t width, uint32_t height, uint32_t depth, vk::Format format)
+	{
+		const vk::PhysicalDevice& physicalDevice = m_core->getContext().getPhysicalDevice();
+		
+		const vk::FormatProperties formatProperties = physicalDevice.getFormatProperties(format);
+		
+		vk::ImageCreateFlags createFlags;
+		vk::ImageUsageFlags imageUsageFlags = (
+				vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst
+		);
+		
+		const bool isDepthFormat = isDepthImageFormat(format);
+		
+		if (isDepthFormat) {
+			imageUsageFlags |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
+		}
+
+		const vk::Device& device = m_core->getContext().getDevice();
+
+		vk::ImageType imageType = vk::ImageType::e3D;
+		vk::ImageViewType imageViewType = vk::ImageViewType::e3D;
+		
+		if (depth <= 1) {
+			if (height <= 1) {
+				imageType = vk::ImageType::e1D;
+				imageViewType = vk::ImageViewType::e1D;
+			} else {
+				imageType = vk::ImageType::e2D;
+				imageViewType = vk::ImageViewType::e2D;
+			}
+		}
+		
+		vk::ImageTiling imageTiling = vk::ImageTiling::eOptimal;
+		
+		if (!formatProperties.optimalTilingFeatures) {
+			if (!formatProperties.linearTilingFeatures)
+				return ImageHandle();
+			
+			imageTiling = vk::ImageTiling::eLinear;
+		}
+		
+		const vk::ImageFormatProperties imageFormatProperties = physicalDevice.getImageFormatProperties(
+				format, imageType, imageTiling, imageUsageFlags
+		);
+		
+		const uint32_t mipLevels = std::min<uint32_t>(1, imageFormatProperties.maxMipLevels);
+		const uint32_t arrayLayers = std::min<uint32_t>(1, imageFormatProperties.maxArrayLayers);
+		
+		const vk::ImageCreateInfo imageCreateInfo(
+			createFlags,
+			imageType,
+			format,
+			vk::Extent3D(width, height, depth),
+			mipLevels,
+			arrayLayers,
+			vk::SampleCountFlagBits::e1,
+			imageTiling,
+			imageUsageFlags,
+			vk::SharingMode::eExclusive,
+			{},
+			vk::ImageLayout::eUndefined
+		);
+
+		vk::Image image = device.createImage(imageCreateInfo);
+		
+		const vk::MemoryRequirements requirements = device.getImageMemoryRequirements(image);
+
+		vk::MemoryPropertyFlags memoryTypeFlags = vk::MemoryPropertyFlagBits::eDeviceLocal;
+
+		const uint32_t memoryTypeIndex = searchImageMemoryType(
+			physicalDevice.getMemoryProperties(),
+			requirements.memoryTypeBits,
+			memoryTypeFlags
+		);
+
+		vk::DeviceMemory memory = device.allocateMemory(vk::MemoryAllocateInfo(requirements.size, memoryTypeIndex));
+		device.bindImageMemory(image, memory, 0);
+
+		vk::ImageAspectFlags aspectFlags;
+		
+		if (isDepthFormat) {
+			aspectFlags = vk::ImageAspectFlagBits::eDepth;
+		} else {
+			aspectFlags = vk::ImageAspectFlagBits::eColor;
+		}
+		
+		const vk::ImageViewCreateInfo imageViewCreateInfo (
+				{},
+				image,
+				imageViewType,
+				format,
+				vk::ComponentMapping(
+						vk::ComponentSwizzle::eIdentity,
+						vk::ComponentSwizzle::eIdentity,
+						vk::ComponentSwizzle::eIdentity,
+						vk::ComponentSwizzle::eIdentity
+				),
+				vk::ImageSubresourceRange(
+						aspectFlags,
+						0,
+						mipLevels,
+						0,
+						arrayLayers
+				)
+		);
+		
+		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 });
+		return ImageHandle(id);
+	}
+	
+	vk::Image ImageManager::getVulkanImage(const ImageHandle &handle) const {
+		const uint64_t id = handle.getId();
+		
+		if (id >= m_images.size()) {
+			return nullptr;
+		}
+		
+		auto& image = m_images[id];
+		
+		return image.m_handle;
+	}
+	
+	vk::DeviceMemory ImageManager::getVulkanDeviceMemory(const ImageHandle &handle) const {
+		const uint64_t id = handle.getId();
+		
+		if (id >= m_images.size()) {
+			return nullptr;
+		}
+		
+		auto& image = m_images[id];
+		
+		return image.m_memory;
+	}
+	
+	vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle) const {
+		const uint64_t id = handle.getId();
+		
+		if (id >= m_images.size()) {
+			return nullptr;
+		}
+		
+		auto& image = m_images[id];
+		
+		return image.m_view;
+	}
+	
+	void ImageManager::switchImageLayout(const ImageHandle& handle, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) {
+		const uint64_t id = handle.getId();
+		
+		if (id >= m_images.size()) {
+			return;
+		}
+		
+		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
+		);
+		
+		SubmitInfo submitInfo;
+		submitInfo.queueType = QueueType::Graphics;
+		
+		m_core->submitCommands(
+			submitInfo,
+			[sourceStage, destinationStage, imageMemoryBarrier](const vk::CommandBuffer& commandBuffer) {
+				commandBuffer.pipelineBarrier(
+					sourceStage,
+					destinationStage,
+					{},
+					nullptr,
+					nullptr,
+					imageMemoryBarrier
+				);
+			},
+			nullptr
+		);
+	}
+	
+	void ImageManager::fillImage(const ImageHandle& handle, void* data, size_t size)
+	{
+		const uint64_t id = handle.getId();
+		
+		if (id >= m_images.size()) {
+			return;
+		}
+		
+		auto& image = m_images[id];
+		
+		switchImageLayout(
+				handle,
+				vk::ImageLayout::eUndefined,
+				vk::ImageLayout::eTransferDstOptimal
+		);
+		
+		uint32_t channels = 4; // TODO: check image.m_format
+		const size_t image_size = (
+				image.m_width * image.m_height * image.m_depth * channels
+		);
+		
+		const size_t max_size = std::min(size, image_size);
+		
+		BufferHandle bufferHandle = m_bufferManager.createBuffer(
+				BufferType::STAGING, max_size, BufferMemoryType::HOST_VISIBLE
+		);
+		
+		m_bufferManager.fillBuffer(bufferHandle, data, max_size, 0);
+		
+		vk::Buffer stagingBuffer = m_bufferManager.getBuffer(bufferHandle);
+		
+		SubmitInfo submitInfo;
+		submitInfo.queueType = QueueType::Transfer;
+		
+		m_core->submitCommands(
+				submitInfo,
+				[&image, &stagingBuffer](const vk::CommandBuffer& commandBuffer) {
+					vk::ImageAspectFlags aspectFlags;
+					
+					if (isDepthImageFormat(image.m_format)) {
+						aspectFlags = vk::ImageAspectFlagBits::eDepth;
+					} else {
+						aspectFlags = vk::ImageAspectFlagBits::eColor;
+					}
+					
+					const vk::BufferImageCopy region (
+							0,
+							0,
+							0,
+							vk::ImageSubresourceLayers(
+									aspectFlags,
+									0,
+									0,
+									image.m_layers
+							),
+							vk::Offset3D(0, 0, 0),
+							vk::Extent3D(image.m_width, image.m_height, image.m_depth)
+					);
+					
+					commandBuffer.copyBufferToImage(
+							stagingBuffer,
+							image.m_handle,
+							vk::ImageLayout::eTransferDstOptimal,
+							1,
+							&region
+					);
+				},
+				[&]() {
+					switchImageLayout(
+							handle,
+							vk::ImageLayout::eTransferDstOptimal,
+							vk::ImageLayout::eShaderReadOnlyOptimal
+					);
+					
+					m_bufferManager.destroyBuffer(bufferHandle);
+				}
+		);
+	}
+
+	void ImageManager::destroyImage(const ImageHandle& handle)
+	{
+		const uint64_t id = handle.getId();
+		
+		if (id >= m_images.size()) {
+			return;
+		}
+		
+		auto& image = m_images[id];
+
+		const vk::Device& device = m_core->getContext().getDevice();
+		
+		if (image.m_view) {
+			device.destroyImageView(image.m_view);
+			image.m_view = nullptr;
+		}
+
+		if (image.m_memory) {
+			device.freeMemory(image.m_memory);
+			image.m_memory = nullptr;
+		}
+
+		if (image.m_handle) {
+			device.destroyImage(image.m_handle);
+			image.m_handle = nullptr;
+		}
+	}
+
+
+}
\ No newline at end of file
diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..7dc6746f37b7d03900302afbd0536b909f9e48fc
--- /dev/null
+++ b/src/vkcv/ImageManager.hpp
@@ -0,0 +1,70 @@
+#pragma once
+/**
+ * @authors Lars Hoerttrich
+ * @file vkcv/ImageManager.hpp
+ * @brief class creating and managing images
+ */
+#include <vector>
+#include <vulkan/vulkan.hpp>
+
+#include "vkcv/BufferManager.hpp"
+#include "vkcv/Handles.hpp"
+
+namespace vkcv {
+	
+	class ImageManager
+	{
+		friend class Core;
+	private:
+		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;
+		};
+		
+		Core* m_core;
+		BufferManager& m_bufferManager;
+		
+		std::vector<Image> m_images;
+		
+		ImageManager(BufferManager& bufferManager) noexcept;
+		
+	public:
+		~ImageManager() noexcept;
+		ImageManager(ImageManager&& other) = delete;
+		ImageManager(const ImageManager& other) = delete;
+
+		ImageManager& operator=(ImageManager&& other) = delete;
+		ImageManager& operator=(const ImageManager& other) = delete;
+		
+		ImageHandle createImage(uint32_t width, uint32_t height, uint32_t depth, vk::Format format);
+		
+		[[nodiscard]]
+		vk::Image getVulkanImage(const ImageHandle& handle) const;
+		
+		[[nodiscard]]
+		vk::DeviceMemory getVulkanDeviceMemory(const ImageHandle& handle) const;
+		
+		[[nodiscard]]
+		vk::ImageView getVulkanImageView(const ImageHandle& handle) const;
+		
+		void switchImageLayout(const ImageHandle& handle, vk::ImageLayout oldLayout, vk::ImageLayout newLayout);
+		void fillImage(const ImageHandle& handle, void* data, size_t size);
+
+		/**
+		 * Destroys and deallocates image represented by a given
+		 * buffer handle.
+		 *
+		 * @param handle Image handle
+		 */
+		void destroyImage(const ImageHandle& handle);
+		
+	};
+}
\ No newline at end of file
diff --git a/src/vkcv/PassManager.cpp b/src/vkcv/PassManager.cpp
index d69024a805f45cda549365c7cc97fc57f59ef926..26e5f290d04ebaf16940cd99386253b5ab3622cc 100644
--- a/src/vkcv/PassManager.cpp
+++ b/src/vkcv/PassManager.cpp
@@ -49,16 +49,16 @@ namespace vkcv
 
     PassManager::PassManager(vk::Device device) noexcept :
     m_Device{device},
-    m_RenderPasses{},
+    m_Passes{},
     m_NextPassId(0)
     {}
 
     PassManager::~PassManager() noexcept
     {
-        for(const auto &pass : m_RenderPasses)
-            m_Device.destroy(pass);
-
-        m_RenderPasses.clear();
+        for(const auto &pass : m_Passes)
+            m_Device.destroy(pass.m_Handle);
+	
+		m_Passes.clear();
         m_NextPassId = 0;
     }
 
@@ -90,46 +90,74 @@ namespace vkcv
                 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));
+            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)
+			);
+            
             attachmentDescriptions.push_back(attachmentDesc);
         }
-        vk::SubpassDescription subpassDescription({},
-                                                  vk::PipelineBindPoint::eGraphics,
-                                                  0,
-                                                  {},
-                                                  static_cast<uint32_t>(colorAttachmentReferences.size()),
-                                                  colorAttachmentReferences.data(),
-                                                  {},
-                                                  pDepthAttachment,
-                                                  0,
-                                                  {});
-
-        vk::RenderPassCreateInfo passInfo({},
-                                          static_cast<uint32_t>(attachmentDescriptions.size()),
-                                          attachmentDescriptions.data(),
-                                          1,
-                                          &subpassDescription,
-                                          0,
-                                          {});
+        
+        const vk::SubpassDescription subpassDescription(
+        		{},
+        		vk::PipelineBindPoint::eGraphics,
+        		0,
+        		{},
+        		static_cast<uint32_t>(colorAttachmentReferences.size()),
+        		colorAttachmentReferences.data(),
+        		{},
+        		pDepthAttachment,
+        		0,
+        		{}
+        );
 
-        vk::RenderPass vkObject{nullptr};
-        if(m_Device.createRenderPass(&passInfo, nullptr, &vkObject) != vk::Result::eSuccess)
-            return PassHandle();
+        const vk::RenderPassCreateInfo passInfo(
+        		{},
+        		static_cast<uint32_t>(attachmentDescriptions.size()),
+        		attachmentDescriptions.data(),
+        		1,
+        		&subpassDescription,
+        		0,
+        		{}
+	  	);
 
-        m_RenderPasses.push_back(vkObject);
+        vk::RenderPass renderPass = m_Device.createRenderPass(passInfo);
+	
+		m_Passes.push_back({ renderPass, config });
 		return PassHandle(m_NextPassId++);
     }
 
     vk::RenderPass PassManager::getVkPass(const PassHandle &handle) const
     {
-        return m_RenderPasses[handle.getId()];
+    	const uint64_t id = handle.getId();
+    	
+    	if (id >= m_Passes.size()) {
+    		return nullptr;
+    	}
+    	
+    	auto& pass = m_Passes[id];
+    	
+        return pass.m_Handle;
+    }
+    
+    const PassConfig& PassManager::getPassConfig(const PassHandle &handle) const {
+		const uint64_t id = handle.getId();
+	
+		if (id >= m_Passes.size()) {
+			static PassConfig emptyConfig = PassConfig({});
+			return emptyConfig;
+		}
+	
+		auto& pass = m_Passes[id];
+	
+		return pass.m_Config;
     }
+    
 }
diff --git a/src/vkcv/PassManager.hpp b/src/vkcv/PassManager.hpp
index b6be2cb13d8d24bdb9759f8878917f99e31afbec..bfc20fe25ace95bd8d94832b953b6b14ab9cadee 100644
--- a/src/vkcv/PassManager.hpp
+++ b/src/vkcv/PassManager.hpp
@@ -10,8 +10,13 @@ namespace vkcv
     class PassManager
     {
     private:
+    	struct Pass {
+			vk::RenderPass m_Handle;
+			PassConfig m_Config;
+    	};
+    	
         vk::Device m_Device;
-        std::vector<vk::RenderPass> m_RenderPasses;
+        std::vector<Pass> m_Passes;
         uint64_t m_NextPassId;
     public:
         PassManager() = delete; // no default ctor
@@ -28,5 +33,9 @@ namespace vkcv
 
         [[nodiscard]]
         vk::RenderPass getVkPass(const PassHandle &handle) const;
+        
+        [[nodiscard]]
+        const PassConfig& getPassConfig(const PassHandle &handle) const;
+        
     };
 }
diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp
index 8b6202eb901f26c84585597e327c297902e54b03..f9c56b41fb60841f19edf294bd9adb739dd19691 100644
--- a/src/vkcv/PipelineManager.cpp
+++ b/src/vkcv/PipelineManager.cpp
@@ -23,8 +23,10 @@ namespace vkcv
         m_NextPipelineId = 0;
     }
 
-    PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, const vk::RenderPass &pass)
+    PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, PassManager& passManager)
     {
+		const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle);
+    	
         const bool existsVertexShader = config.m_ShaderProgram.existsShader(ShaderStage::VERTEX);
         const bool existsFragmentShader = config.m_ShaderProgram.existsShader(ShaderStage::FRAGMENT);
         if (!(existsVertexShader && existsFragmentShader))
@@ -170,10 +172,34 @@ namespace vkcv
             m_Device.destroy(fragmentModule);
             return PipelineHandle();
         }
-
-        // graphics pipeline create
+	
+		const vk::PipelineDepthStencilStateCreateInfo depthStencilCreateInfo(
+				vk::PipelineDepthStencilStateCreateFlags(),
+				true,
+				true,
+				vk::CompareOp::eLessOrEqual,
+				false,
+				false,
+				{},
+				{},
+				0.0f,
+				1.0f
+		);
+	
+		const vk::PipelineDepthStencilStateCreateInfo* p_depthStencilCreateInfo = nullptr;
+		
+		const PassConfig& passConfig = passManager.getPassConfig(config.m_PassHandle);
+		
+		for (const auto& attachment : passConfig.attachments) {
+			if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) {
+				p_depthStencilCreateInfo = &depthStencilCreateInfo;
+				break;
+			}
+		}
+	
+		// graphics pipeline create
         std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = { pipelineVertexShaderStageInfo, pipelineFragmentShaderStageInfo };
-        vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo(
+        const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo(
                 {},
                 static_cast<uint32_t>(shaderStages.size()),
                 shaderStages.data(),
@@ -183,7 +209,7 @@ namespace vkcv
                 &pipelineViewportStateCreateInfo,
                 &pipelineRasterizationStateCreateInfo,
                 &pipelineMultisampleStateCreateInfo,
-                nullptr,
+				p_depthStencilCreateInfo,
                 &pipelineColorBlendStateCreateInfo,
                 nullptr,
                 vkPipelineLayout,
diff --git a/src/vkcv/PipelineManager.hpp b/src/vkcv/PipelineManager.hpp
index b5c0948efa13a4021f424cc576f1403a1ec26ebe..896d0df1ce10f56d291ef1accf93f9783cdd9db4 100644
--- a/src/vkcv/PipelineManager.hpp
+++ b/src/vkcv/PipelineManager.hpp
@@ -4,6 +4,7 @@
 #include <vector>
 #include "vkcv/Handles.hpp"
 #include "vkcv/PipelineConfig.hpp"
+#include "PassManager.hpp"
 
 namespace vkcv
 {
@@ -25,7 +26,7 @@ namespace vkcv
         PipelineManager & operator=(const PipelineManager &other) = delete; // copy-assign op
         PipelineManager & operator=(PipelineManager &&other) = delete; // move-assign op
 
-        PipelineHandle createPipeline(const PipelineConfig &config, const vk::RenderPass &pass);
+        PipelineHandle createPipeline(const PipelineConfig &config, PassManager& passManager);
 
         [[nodiscard]]
         vk::Pipeline getVkPipeline(const PipelineHandle &handle) const;