From bd8cbbb1ce7fc172bb11463bd2a76fdd5096f408 Mon Sep 17 00:00:00 2001
From: Tobias Frisch <tfrisch@uni-koblenz.de>
Date: Tue, 30 Aug 2022 12:23:11 +0200
Subject: [PATCH] Added support functions for passes and abstracted them in
 class

Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de>
---
 config/Sources.cmake                        |  3 +
 include/vkcv/Core.hpp                       | 10 ++++
 include/vkcv/Pass.hpp                       | 31 +++++++++++
 include/vkcv/PassConfig.hpp                 | 42 ++++++++++++--
 projects/bindless_textures/src/main.cpp     | 19 ++-----
 projects/fire_works/src/main.cpp            | 12 +---
 projects/first_mesh/src/main.cpp            | 23 ++------
 projects/first_scene/src/main.cpp           | 24 ++------
 projects/first_triangle/src/main.cpp        | 13 ++---
 projects/head_demo/src/main.cpp             | 40 +-------------
 projects/indirect_draw/src/main.cpp         | 17 ++----
 projects/mesh_shader/src/main.cpp           | 25 ++-------
 projects/particle_simulation/src/main.cpp   | 12 +---
 projects/path_tracer/src/main.cpp           |  1 +
 projects/saf_r/src/main.cpp                 | 29 +++-------
 projects/sph/src/main.cpp                   | 11 +---
 projects/voxelization/src/ShadowMapping.cpp | 12 +---
 projects/voxelization/src/Voxelization.cpp  | 26 +++------
 projects/voxelization/src/main.cpp          | 32 +++--------
 projects/wobble_bobble/src/main.cpp         | 61 +++++++--------------
 src/vkcv/Core.cpp                           | 16 +++++-
 src/vkcv/GraphicsPipelineManager.cpp        |  4 +-
 src/vkcv/Pass.cpp                           | 47 ++++++++++++++++
 src/vkcv/PassConfig.cpp                     | 23 ++++++++
 src/vkcv/PassManager.cpp                    | 16 +++---
 25 files changed, 262 insertions(+), 287 deletions(-)
 create mode 100644 include/vkcv/Pass.hpp
 create mode 100644 src/vkcv/Pass.cpp

diff --git a/config/Sources.cmake b/config/Sources.cmake
index 45dc8bc8..764ea2e7 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -15,6 +15,9 @@ set(vkcv_sources
 		
 		${vkcv_include}/vkcv/File.hpp
 		${vkcv_source}/vkcv/File.cpp
+		
+		${vkcv_include}/vkcv/Pass.hpp
+		${vkcv_source}/vkcv/Pass.cpp
 
 		${vkcv_include}/vkcv/PassConfig.hpp
 		${vkcv_source}/vkcv/PassConfig.cpp
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index bf944a61..e6c61cbb 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -189,6 +189,16 @@ namespace vkcv
          */
         [[nodiscard]]
         PassHandle createPass(const PassConfig &config);
+		
+		/**
+		 * Returns the used configuration for a created render pass which is
+		 * represented by the given handle.
+		 *
+		 * @param[in] pass Pass handle
+		 * @return Pass configuration
+		 */
+		[[nodiscard]]
+		const PassConfig& getPassConfiguration(const PassHandle &pass);
 	
 		/**
 		 * @brief Creates a buffer with given parameters and returns its handle.
diff --git a/include/vkcv/Pass.hpp b/include/vkcv/Pass.hpp
new file mode 100644
index 00000000..f931eef5
--- /dev/null
+++ b/include/vkcv/Pass.hpp
@@ -0,0 +1,31 @@
+#pragma once
+/**
+ * @authors Tobias Frisch
+ * @file vkcv/Pass.hpp
+ * @brief Support functions for basic pass creation.
+ */
+
+#include "Core.hpp"
+#include "Handles.hpp"
+#include "PassConfig.hpp"
+
+namespace vkcv
+{
+
+	PassHandle passFormats(Core &core,
+						   const std::vector<vk::Format> formats,
+						   bool clear = true,
+						   Multisampling multisampling = Multisampling::None);
+	
+	PassHandle passFormat(Core &core,
+						  vk::Format format,
+						  bool clear = true,
+						  Multisampling multisampling = Multisampling::None);
+	
+	PassHandle passSwapchain(Core &core,
+							 const SwapchainHandle &swapchain,
+							 const std::vector<vk::Format> formats,
+							 bool clear = true,
+							 Multisampling multisampling = Multisampling::None);
+	
+}
diff --git a/include/vkcv/PassConfig.hpp b/include/vkcv/PassConfig.hpp
index 7f06ab14..849a6e83 100644
--- a/include/vkcv/PassConfig.hpp
+++ b/include/vkcv/PassConfig.hpp
@@ -24,7 +24,7 @@ namespace vkcv
     };
 
 	/**
-	 * @brief Structure to store details about an attachment of a pass.
+	 * @brief Class to store details about an attachment of a pass.
 	 */
     class AttachmentDescription {
 	private:
@@ -51,25 +51,55 @@ namespace vkcv
 	
 		AttachmentDescription& operator=(const AttachmentDescription &other) = default;
 		AttachmentDescription& operator=(AttachmentDescription &&other) = default;
-		
+	
+		[[nodiscard]]
 		vk::Format getFormat() const;
 	
+		[[nodiscard]]
 		AttachmentOperation getLoadOperation() const;
 	
+		[[nodiscard]]
 		AttachmentOperation getStoreOperation() const;
 		
 		void setClearValue(const vk::ClearValue &clear);
 	
+		[[nodiscard]]
 		const vk::ClearValue& getClearValue() const;
 		
     };
+	
+	using AttachmentDescriptions = std::vector<AttachmentDescription>;
 
 	/**
-	 * @brief Structure to configure a pass for usage.
+	 * @brief Class to configure a pass for usage.
 	 */
-    struct PassConfig {
-		std::vector<AttachmentDescription> attachments;
-        Multisampling msaa;
+    class PassConfig {
+	private:
+		AttachmentDescriptions m_attachments;
+        Multisampling m_multisampling;
+		
+	public:
+		PassConfig();
+		
+		explicit PassConfig(const AttachmentDescriptions &attachments,
+							Multisampling multisampling = Multisampling::None);
+		
+		PassConfig(const PassConfig &other) = default;
+		PassConfig(PassConfig &&other) = default;
+		
+		~PassConfig() = default;
+	
+		PassConfig& operator=(const PassConfig &other) = default;
+		PassConfig& operator=(PassConfig &&other) = default;
+		
+		[[nodiscard]]
+		const AttachmentDescriptions& getAttachments() const;
+		
+		void setMultisampling(Multisampling multisampling);
+	
+		[[nodiscard]]
+		Multisampling getMultisampling() const;
+		
     };
 	
 }
\ No newline at end of file
diff --git a/projects/bindless_textures/src/main.cpp b/projects/bindless_textures/src/main.cpp
index f196db2e..8f594e59 100644
--- a/projects/bindless_textures/src/main.cpp
+++ b/projects/bindless_textures/src/main.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <vkcv/Buffer.hpp>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <GLFW/glfw3.h>
 #include <vkcv/camera/CameraManager.hpp>
 #include <chrono>
@@ -98,23 +99,13 @@ int main(int argc, const char** argv) {
 	);
 	
 	indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data);
-
-	// an example attachment for passes that output to the window
-	const vkcv::AttachmentDescription present_color_attachment(
-			core.getSwapchainFormat(window.getSwapchain()),
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
-	);
 	
-	const vkcv::AttachmentDescription depth_attachment(
-			vk::Format::eD32Sfloat,
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
+	vkcv::PassHandle firstMeshPass = vkcv::passSwapchain(
+			core,
+			window.getSwapchain(),
+			{ vk::Format::eUndefined, vk::Format::eD32Sfloat }
 	);
 
-	vkcv::PassConfig firstMeshPassDefinition({ present_color_attachment, depth_attachment }, vkcv::Multisampling::None);
-	vkcv::PassHandle firstMeshPass = core.createPass(firstMeshPassDefinition);
-
 	if (!firstMeshPass) {
 		std::cerr << "Error. Could not create renderpass. Exiting." << std::endl;
 		return EXIT_FAILURE;
diff --git a/projects/fire_works/src/main.cpp b/projects/fire_works/src/main.cpp
index 500f5f5e..a657d8bf 100644
--- a/projects/fire_works/src/main.cpp
+++ b/projects/fire_works/src/main.cpp
@@ -3,6 +3,7 @@
 
 #include <vkcv/Buffer.hpp>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <vkcv/DrawcallRecording.hpp>
 
 #include <vkcv/camera/CameraManager.hpp>
@@ -587,16 +588,7 @@ int main(int argc, const char **argv) {
 	
 	const vkcv::VertexLayout smokeLayout { vbSmoke };
 	
-	vkcv::PassHandle renderPass = core.createPass(vkcv::PassConfig(
-		{
-			vkcv::AttachmentDescription(
-				colorFormat,
-				vkcv::AttachmentOperation::CLEAR,
-				vkcv::AttachmentOperation::STORE
-			)
-		},
-		vkcv::Multisampling::None
-	));
+	vkcv::PassHandle renderPass = vkcv::passFormat(core, colorFormat);
 	
 	vkcv::GraphicsPipelineConfig smokePipelineDefinition (
 		smokeShaderProgram,
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index 356fd9f1..27e0630e 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <vkcv/Buffer.hpp>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <vkcv/camera/CameraManager.hpp>
 #include <chrono>
 #include <vkcv/asset/asset_loader.hpp>
@@ -50,26 +51,12 @@ int main(int argc, const char** argv) {
 	
 	indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data);
 
-	// an example attachment for passes that output to the window
-	const vkcv::AttachmentDescription present_color_attachment(
-			core.getSwapchainFormat(window.getSwapchain()),
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
-	);
-	
-	const vkcv::AttachmentDescription depth_attachment(
-			vk::Format::eD32Sfloat,
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
-	);
-
-	vkcv::PassConfig firstMeshPassDefinition(
-			{ present_color_attachment, depth_attachment },
-			vkcv::Multisampling::None
+	vkcv::PassHandle firstMeshPass = vkcv::passSwapchain(
+			core,
+			window.getSwapchain(),
+			{ vk::Format::eUndefined, vk::Format::eD32Sfloat }
 	);
 
-	vkcv::PassHandle firstMeshPass = core.createPass(firstMeshPassDefinition);
-
 	if (!firstMeshPass) {
 		std::cerr << "Error. Could not create renderpass. Exiting." << std::endl;
 		return EXIT_FAILURE;
diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp
index bd3b2ac7..17b41378 100644
--- a/projects/first_scene/src/main.cpp
+++ b/projects/first_scene/src/main.cpp
@@ -1,5 +1,6 @@
 #include <iostream>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <GLFW/glfw3.h>
 #include <vkcv/camera/CameraManager.hpp>
 #include <vkcv/gui/GUI.hpp>
@@ -47,25 +48,12 @@ int main(int argc, const char** argv) {
 	vkcv::scene::Scene scene = vkcv::scene::Scene::load(core, std::filesystem::path(
 			argc > 1 ? argv[1] : "assets/Sponza/Sponza.gltf"
 	));
-
-	const vkcv::AttachmentDescription present_color_attachment(
-			core.getSwapchainFormat(window.getSwapchain()),
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
-	);
-
-	const vkcv::AttachmentDescription depth_attachment(
-			vk::Format::eD32Sfloat,
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
-	);
-
-	vkcv::PassConfig scenePassDefinition(
-			{ present_color_attachment, depth_attachment },
-			vkcv::Multisampling::None
-	);
 	
-	vkcv::PassHandle scenePass = core.createPass(scenePassDefinition);
+	vkcv::PassHandle scenePass = vkcv::passSwapchain(
+			core,
+			window.getSwapchain(),
+			{ vk::Format::eUndefined, vk::Format::eD32Sfloat }
+	);
 
 	if (!scenePass) {
 		std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index edf8fa8f..5ad87a57 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <vkcv/Buffer.hpp>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <GLFW/glfw3.h>
 #include <vkcv/camera/CameraManager.hpp>
 #include <vkcv/shader/GLSLCompiler.hpp>
@@ -28,16 +29,12 @@ int main(int argc, const char** argv) {
 
 	core.setDebugLabel(triangleIndexBuffer.getHandle(), "Triangle Index Buffer");
 	
-	// an example attachment for passes that output to the window
-	const vkcv::AttachmentDescription present_color_attachment(
-			core.getSwapchainFormat(window.getSwapchain()),
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
+	vkcv::PassHandle trianglePass = vkcv::passSwapchain(
+			core,
+			window.getSwapchain(),
+			{ vk::Format::eUndefined }
 	);
 
-	vkcv::PassConfig trianglePassDefinition({ present_color_attachment }, vkcv::Multisampling::None);
-	vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition);
-
 	if (!trianglePass)
 	{
 		std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
diff --git a/projects/head_demo/src/main.cpp b/projects/head_demo/src/main.cpp
index 9c92128f..905c333f 100644
--- a/projects/head_demo/src/main.cpp
+++ b/projects/head_demo/src/main.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <vkcv/Buffer.hpp>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <GLFW/glfw3.h>
 #include <vkcv/camera/CameraManager.hpp>
 #include <vkcv/gui/GUI.hpp>
@@ -43,43 +44,8 @@ int main(int argc, const char** argv) {
 	
 	vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat;
 	
-	const vkcv::AttachmentDescription color_attachment0(
-			colorFormat,
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
-	);
-	
-	const vkcv::AttachmentDescription depth_attachment0(
-			vk::Format::eD32Sfloat,
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
-	);
-	
-	const vkcv::AttachmentDescription color_attachment1(
-			colorFormat,
-			vkcv::AttachmentOperation::LOAD,
-			vkcv::AttachmentOperation::STORE
-	);
-	
-	const vkcv::AttachmentDescription depth_attachment1(
-			vk::Format::eD32Sfloat,
-			vkcv::AttachmentOperation::LOAD,
-			vkcv::AttachmentOperation::STORE
-	);
-	
-	vkcv::PassConfig linePassDefinition(
-			{ color_attachment0, depth_attachment0 },
-			vkcv::Multisampling::None
-	);
-	
-	vkcv::PassHandle linePass = core.createPass(linePassDefinition);
-	
-	vkcv::PassConfig scenePassDefinition(
-			{ color_attachment1, depth_attachment1 },
-			vkcv::Multisampling::None
-	);
-	
-	vkcv::PassHandle scenePass = core.createPass(scenePassDefinition);
+	vkcv::PassHandle linePass = vkcv::passFormats(core, { colorFormat, vk::Format::eD32Sfloat });
+	vkcv::PassHandle scenePass = vkcv::passFormats(core, { colorFormat, vk::Format::eD32Sfloat }, false);
 	
 	if ((!scenePass) || (!linePass)) {
 		std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
diff --git a/projects/indirect_draw/src/main.cpp b/projects/indirect_draw/src/main.cpp
index f3fa7f8d..733469fd 100644
--- a/projects/indirect_draw/src/main.cpp
+++ b/projects/indirect_draw/src/main.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <vkcv/Buffer.hpp>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <vkcv/camera/CameraManager.hpp>
 #include <chrono>
 #include <vkcv/gui/GUI.hpp>
@@ -328,20 +329,12 @@ int main(int argc, const char** argv) {
         return EXIT_FAILURE;
     }
 
-    const vkcv::AttachmentDescription present_color_attachment (
-			core.getSwapchainFormat(window.getSwapchain()),
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
+    vkcv::PassHandle passHandle = vkcv::passSwapchain(
+			core,
+			window.getSwapchain(),
+			{ vk::Format::eUndefined, vk::Format::eD32Sfloat }
 	);
 	
-	const vkcv::AttachmentDescription depth_attachment (
-			vk::Format::eD32Sfloat,
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
-	);
-
-	vkcv::PassConfig passDefinition({ present_color_attachment, depth_attachment }, vkcv::Multisampling::None);
-	vkcv::PassHandle passHandle = core.createPass(passDefinition);
 	if (!passHandle) {
 		std::cerr << "Error. Could not create renderpass. Exiting." << std::endl;
 		return EXIT_FAILURE;
diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp
index 77df9f4e..f80c47ff 100644
--- a/projects/mesh_shader/src/main.cpp
+++ b/projects/mesh_shader/src/main.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <vkcv/Buffer.hpp>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <GLFW/glfw3.h>
 #include <vkcv/camera/CameraManager.hpp>
 #include <chrono>
@@ -161,26 +162,12 @@ int main(int argc, const char** argv) {
 		vkcv::BufferMemoryType::DEVICE_LOCAL
 		);
 	meshletBuffer.fill(meshShaderModelData.meshlets);
-
-	// attachments
-	const vkcv::AttachmentDescription present_color_attachment(
-			core.getSwapchainFormat(window.getSwapchain()),
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
-	);
-
-    const vkcv::AttachmentDescription depth_attachment(
-			vk::Format::eD32Sfloat,
-			vkcv::AttachmentOperation::CLEAR,
-            vkcv::AttachmentOperation::STORE
-    );
-
-	vkcv::PassConfig bunnyPassDefinition(
-			{ present_color_attachment, depth_attachment },
-			vkcv::Multisampling::None
-	);
 	
-	vkcv::PassHandle renderPass = core.createPass(bunnyPassDefinition);
+	vkcv::PassHandle renderPass = vkcv::passSwapchain(
+			core,
+			window.getSwapchain(),
+			{ vk::Format::eUndefined, vk::Format::eD32Sfloat }
+	);
 
 	if (!renderPass)
 	{
diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp
index a1e40221..5ade2185 100644
--- a/projects/particle_simulation/src/main.cpp
+++ b/projects/particle_simulation/src/main.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <vkcv/Buffer.hpp>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <GLFW/glfw3.h>
 #include <vkcv/camera/CameraManager.hpp>
 #include <chrono>
@@ -33,16 +34,7 @@ int main(int argc, const char **argv) {
     particleIndexBuffer.fill(&indices[0], sizeof(indices));
 
     vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat;
-    // an example attachment for passes that output to the window
-    const vkcv::AttachmentDescription present_color_attachment(
-			colorFormat,
-			vkcv::AttachmentOperation::CLEAR,
-            vkcv::AttachmentOperation::STORE
-	);
-
-
-    vkcv::PassConfig particlePassDefinition({present_color_attachment}, vkcv::Multisampling::None);
-    vkcv::PassHandle particlePass = core.createPass(particlePassDefinition);
+    vkcv::PassHandle particlePass = vkcv::passFormat(core, colorFormat);
 
     if (!particlePass)
     {
diff --git a/projects/path_tracer/src/main.cpp b/projects/path_tracer/src/main.cpp
index 3b9d8ab4..6c34f51a 100644
--- a/projects/path_tracer/src/main.cpp
+++ b/projects/path_tracer/src/main.cpp
@@ -1,5 +1,6 @@
 #include <vkcv/Buffer.hpp>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <vkcv/camera/CameraManager.hpp>
 #include <vkcv/asset/asset_loader.hpp>
 #include <vkcv/shader/GLSLCompiler.hpp>
diff --git a/projects/saf_r/src/main.cpp b/projects/saf_r/src/main.cpp
index 19ecf20d..d514eb2f 100644
--- a/projects/saf_r/src/main.cpp
+++ b/projects/saf_r/src/main.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <vkcv/Core.hpp>
 #include <vkcv/Buffer.hpp>
+#include <vkcv/Pass.hpp>
 #include <GLFW/glfw3.h>
 #include <vkcv/camera/CameraManager.hpp>
 #include <vkcv/asset/asset_loader.hpp>
@@ -11,7 +12,6 @@
 #include <cstring>
 #include "safrScene.hpp"
 
-
 void createQuadraticLightCluster(std::vector<safrScene::Light>& lights, int countPerDimension, float dimension, float height, float intensity) {
     float distance = dimension/countPerDimension;
 
@@ -42,16 +42,6 @@ int main(int argc, const char** argv) {
 	vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true);
 	vkcv::Window& window = core.getWindow(windowHandle);
 
-	//configuring the compute Shader
-	vkcv::PassConfig computePassDefinition({});
-	vkcv::PassHandle computePass = core.createPass(computePassDefinition);
-
-	if (!computePass)
-	{
-		std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
-		return EXIT_FAILURE;
-	}
-
 	std::string shaderPathCompute = "shaders/raytracing.comp";
 
 	//creating the shader programs
@@ -160,19 +150,14 @@ int main(int argc, const char** argv) {
 	auto safrIndexBuffer = vkcv::buffer<uint16_t>(core, vkcv::BufferType::INDEX, 3);
 	uint16_t indices[3] = { 0, 1, 2 };
 	safrIndexBuffer.fill(&indices[0], sizeof(indices));
-
-	// an example attachment for passes that output to the window
-	const vkcv::AttachmentDescription present_color_attachment(
-			core.getSwapchainFormat(window.getSwapchain()),
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
+	
+	vkcv::PassHandle safrPass = vkcv::passSwapchain(
+			core,
+			window.getSwapchain(),
+			{ vk::Format::eUndefined }
 	);
 
-	vkcv::PassConfig safrPassDefinition({ present_color_attachment }, vkcv::Multisampling::None);
-	vkcv::PassHandle safrPass = core.createPass(safrPassDefinition);
-
-	if (!safrPass)
-	{
+	if (!safrPass) {
 		std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
 		return EXIT_FAILURE;
 	}
diff --git a/projects/sph/src/main.cpp b/projects/sph/src/main.cpp
index f6ed0505..ab02c4a0 100644
--- a/projects/sph/src/main.cpp
+++ b/projects/sph/src/main.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include <vkcv/Core.hpp>
 #include <vkcv/Buffer.hpp>
+#include <vkcv/Pass.hpp>
 #include <vkcv/camera/CameraManager.hpp>
 #include <chrono>
 #include <random>
@@ -31,15 +32,7 @@ int main(int argc, const char **argv) {
     particleIndexBuffer.fill(&indices[0], sizeof(indices));
 
     vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat;
-    // an example attachment for passes that output to the window
-    const vkcv::AttachmentDescription present_color_attachment(
-			colorFormat,
-			vkcv::AttachmentOperation::CLEAR,
-            vkcv::AttachmentOperation::STORE
-	);
-
-    vkcv::PassConfig particlePassDefinition({present_color_attachment}, vkcv::Multisampling::None);
-    vkcv::PassHandle particlePass = core.createPass(particlePassDefinition);
+    vkcv::PassHandle particlePass = vkcv::passFormat(core, colorFormat);
 
     //rotation
     float rotationx = 0;
diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp
index 990007cb..c0f7ed2a 100644
--- a/projects/voxelization/src/ShadowMapping.cpp
+++ b/projects/voxelization/src/ShadowMapping.cpp
@@ -1,4 +1,6 @@
 #include "ShadowMapping.hpp"
+
+#include <vkcv/Pass.hpp>
 #include <vkcv/shader/GLSLCompiler.hpp>
 
 const vk::Format            shadowMapFormat         = vk::Format::eR16G16B16A16Unorm;
@@ -159,15 +161,7 @@ ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vert
 	vkcv::ShaderProgram shadowShader = loadShadowShader();
 
 	// pass
-	const std::vector<vkcv::AttachmentDescription> shadowAttachments = {
-		vkcv::AttachmentDescription(
-				shadowMapDepthFormat,
-				vkcv::AttachmentOperation::CLEAR,
-				vkcv::AttachmentOperation::STORE
-		)
-	};
-	vkcv::PassConfig shadowPassConfig(shadowAttachments, msaa);
-	m_shadowMapPass = corePtr->createPass(shadowPassConfig);
+	m_shadowMapPass = vkcv::passFormat(*corePtr, shadowMapDepthFormat, true, msaa);
 
 	// pipeline
 	vkcv::GraphicsPipelineConfig shadowPipeConfig (
diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp
index 63316208..f8d7fa4f 100644
--- a/projects/voxelization/src/Voxelization.cpp
+++ b/projects/voxelization/src/Voxelization.cpp
@@ -1,4 +1,6 @@
 #include "Voxelization.hpp"
+
+#include <vkcv/Pass.hpp>
 #include <vkcv/shader/GLSLCompiler.hpp>
 #include <glm/gtc/matrix_transform.hpp>
 #include <algorithm>
@@ -136,25 +138,13 @@ Voxelization::Voxelization(
 
 	m_visualisationDescriptorSetLayout = m_corePtr->createDescriptorSetLayout(voxelVisualisationShader.getReflectedDescriptors().at(0));
 	m_visualisationDescriptorSet = m_corePtr->createDescriptorSet(m_visualisationDescriptorSetLayout);
-
-	const vkcv::AttachmentDescription voxelVisualisationColorAttachments (
-			dependencies.colorBufferFormat,
-			vkcv::AttachmentOperation::LOAD,
-			vkcv::AttachmentOperation::STORE
-	);
-
-	const vkcv::AttachmentDescription voxelVisualisationDepthAttachments (
-			dependencies.depthBufferFormat,
-			vkcv::AttachmentOperation::LOAD,
-			vkcv::AttachmentOperation::STORE
-	);
-
-	vkcv::PassConfig voxelVisualisationPassDefinition{
-		{ voxelVisualisationColorAttachments, voxelVisualisationDepthAttachments },
-		msaa
-	};
 	
-	m_visualisationPass = m_corePtr->createPass(voxelVisualisationPassDefinition);
+	m_visualisationPass = vkcv::passFormats(
+			*m_corePtr,
+			{ dependencies.colorBufferFormat, dependencies.depthBufferFormat },
+			false,
+			msaa
+	);
 
 	vkcv::GraphicsPipelineConfig voxelVisualisationPipeConfig (
 		voxelVisualisationShader,
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index e2e1f0ee..8f568407 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -1,5 +1,6 @@
 #include <iostream>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <GLFW/glfw3.h>
 #include <vkcv/camera/CameraManager.hpp>
 #include <chrono>
@@ -239,15 +240,8 @@ int main(int argc, const char** argv) {
 		prepassVertexBindings.push_back(vkcv::createVertexBinding(i, { prepassVertexAttachments[i] }));
 	}
 	const vkcv::VertexLayout prepassVertexLayout { prepassVertexBindings };
-
-	const vkcv::AttachmentDescription prepassAttachment(
-			depthBufferFormat,
-			vkcv::AttachmentOperation::CLEAR,
-			vkcv::AttachmentOperation::STORE
-	);
-
-	vkcv::PassConfig prepassPassDefinition({ prepassAttachment }, msaa);
-	vkcv::PassHandle prepassPass = core.createPass(prepassPassDefinition);
+	
+	vkcv::PassHandle prepassPass = vkcv::passFormat(core, depthBufferFormat, true, msaa);
 
 	// create descriptor sets
 	vkcv::SamplerHandle colorSampler = core.createSampler(
@@ -376,22 +370,14 @@ int main(int argc, const char** argv) {
 	SkySettings skySettings;
 	skySettings.color       = glm::vec3(0.15, 0.65, 1);
 	skySettings.strength    = 5;
-
-	const vkcv::AttachmentDescription skyColorAttachment (
-			colorBufferFormat,
-			vkcv::AttachmentOperation::LOAD,
-			vkcv::AttachmentOperation::STORE
-	);
-
-	const vkcv::AttachmentDescription skyDepthAttachments (
-			depthBufferFormat,
-			vkcv::AttachmentOperation::LOAD,
-			vkcv::AttachmentOperation::STORE
+	
+	vkcv::PassHandle skyPass = vkcv::passFormats(
+			core,
+			{ colorBufferFormat, depthBufferFormat },
+			false,
+			msaa
 	);
 
-	vkcv::PassConfig skyPassConfig({ skyColorAttachment, skyDepthAttachments }, msaa);
-	vkcv::PassHandle skyPass = core.createPass(skyPassConfig);
-
 	vkcv::ShaderProgram skyShader;
 	compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("assets/shaders/sky.vert"),
 		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
diff --git a/projects/wobble_bobble/src/main.cpp b/projects/wobble_bobble/src/main.cpp
index 23ab97c5..da02ed38 100644
--- a/projects/wobble_bobble/src/main.cpp
+++ b/projects/wobble_bobble/src/main.cpp
@@ -1,6 +1,7 @@
 
 #include <vkcv/Buffer.hpp>
 #include <vkcv/Core.hpp>
+#include <vkcv/Pass.hpp>
 #include <vkcv/camera/CameraManager.hpp>
 #include <vkcv/gui/GUI.hpp>
 #include <vkcv/shader/GLSLCompiler.hpp>
@@ -454,45 +455,6 @@ int main(int argc, const char **argv) {
 			{ vkcv::ShaderStage::FRAGMENT, "shaders/lines.frag" }
 	}, nullptr);
 	
-	vkcv::PassConfig passConfigGrid {{
-		vkcv::AttachmentDescription(
-				core.getSwapchainFormat(window.getSwapchain()),
-				vkcv::AttachmentOperation::CLEAR,
-				vkcv::AttachmentOperation::STORE
-		),
-		vkcv::AttachmentDescription(
-				vk::Format::eD32Sfloat,
-				vkcv::AttachmentOperation::CLEAR,
-				vkcv::AttachmentOperation::STORE
-		)
-	}, vkcv::Multisampling::None };
-	
-	vkcv::PassConfig passConfigParticles {{
-		vkcv::AttachmentDescription(
-				core.getSwapchainFormat(window.getSwapchain()),
-				vkcv::AttachmentOperation::CLEAR,
-				vkcv::AttachmentOperation::STORE
-		),
-		vkcv::AttachmentDescription(
-				vk::Format::eD32Sfloat,
-				vkcv::AttachmentOperation::CLEAR,
-				vkcv::AttachmentOperation::STORE
-		)
-	}, vkcv::Multisampling::None };
-	
-	vkcv::PassConfig passConfigLines {{
-		vkcv::AttachmentDescription(
-				core.getSwapchainFormat(window.getSwapchain()),
-				vkcv::AttachmentOperation::LOAD,
-				vkcv::AttachmentOperation::STORE
-		),
-		vkcv::AttachmentDescription(
-				vk::Format::eD32Sfloat,
-				vkcv::AttachmentOperation::LOAD,
-				vkcv::AttachmentOperation::STORE
-		)
-	}, vkcv::Multisampling::None };
-	
 	vkcv::DescriptorSetLayoutHandle gfxSetLayoutGrid = core.createDescriptorSetLayout(
 			gfxProgramGrid.getReflectedDescriptors().at(0)
 	);
@@ -519,9 +481,24 @@ int main(int argc, const char **argv) {
 		core.writeDescriptorSet(gfxSetParticles, writes);
 	}
 	
-	vkcv::PassHandle gfxPassGrid = core.createPass(passConfigGrid);
-	vkcv::PassHandle gfxPassParticles = core.createPass(passConfigParticles);
-	vkcv::PassHandle gfxPassLines = core.createPass(passConfigLines);
+	vkcv::PassHandle gfxPassGrid = vkcv::passSwapchain(
+			core,
+			window.getSwapchain(),
+			{ vk::Format::eUndefined, vk::Format::eD32Sfloat }
+	);
+	
+	vkcv::PassHandle gfxPassParticles = vkcv::passSwapchain(
+			core,
+			window.getSwapchain(),
+			{ vk::Format::eUndefined, vk::Format::eD32Sfloat }
+	);
+	
+	vkcv::PassHandle gfxPassLines = vkcv::passSwapchain(
+			core,
+			window.getSwapchain(),
+			{ vk::Format::eUndefined, vk::Format::eD32Sfloat },
+			false
+	);
 	
 	vkcv::VertexLayout vertexLayoutGrid ({
 		vkcv::createVertexBinding(0, gfxProgramGrid.getVertexAttachments())
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 9cbba197..2382aff1 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -163,6 +163,10 @@ namespace vkcv
         return m_PassManager->createPass(config);
     }
 	
+	const PassConfig &Core::getPassConfiguration(const vkcv::PassHandle &pass) {
+		return m_PassManager->getPassConfig(pass);
+	}
+	
 	BufferHandle Core::createBuffer(BufferType type,
 									const TypeGuard &typeGuard,
 									size_t count,
@@ -479,7 +483,9 @@ namespace vkcv
 		}
 
 		auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
-			const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments);
+			const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(
+					passConfig.getAttachments()
+			);
 
 			const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
 			cmdBuffer.beginRenderPass(beginInfo, {}, {});
@@ -557,7 +563,9 @@ namespace vkcv
 
         auto submitFunction = [&](const vk::CommandBuffer &cmdBuffer) {
 
-            const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments);
+            const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(
+					passConfig.getAttachments()
+			);
 
             const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(),
                                                     clearValues.data());
@@ -699,7 +707,9 @@ namespace vkcv
 		}
 
 		auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
-			const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments);
+			const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(
+					passConfig.getAttachments()
+			);
 
 			const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
 			cmdBuffer.beginRenderPass(beginInfo, {}, {});
diff --git a/src/vkcv/GraphicsPipelineManager.cpp b/src/vkcv/GraphicsPipelineManager.cpp
index 57eedcac..2a495fa1 100644
--- a/src/vkcv/GraphicsPipelineManager.cpp
+++ b/src/vkcv/GraphicsPipelineManager.cpp
@@ -330,7 +330,7 @@ namespace vkcv {
 																					const PassConfig &passConfig) {
 		vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo(
 				{},
-				msaaToSampleCountFlagBits(passConfig.msaa),
+				msaaToSampleCountFlagBits(passConfig.getMultisampling()),
 				false,
 				0.f,
 				nullptr,
@@ -670,7 +670,7 @@ namespace vkcv {
 
         const vk::PipelineDepthStencilStateCreateInfo* p_depthStencilCreateInfo = nullptr;
 
-        for (const auto& attachment : passConfig.attachments) {
+        for (const auto& attachment : passConfig.getAttachments()) {
             if ((isDepthFormat(attachment.getFormat())) ||
 				(isStencilFormat(attachment.getFormat()))) {
                 p_depthStencilCreateInfo = &depthStencilCreateInfo;
diff --git a/src/vkcv/Pass.cpp b/src/vkcv/Pass.cpp
new file mode 100644
index 00000000..54482cd9
--- /dev/null
+++ b/src/vkcv/Pass.cpp
@@ -0,0 +1,47 @@
+
+#include "vkcv/Pass.hpp"
+
+namespace vkcv {
+	
+	PassHandle passFormats(Core &core,
+						   const std::vector<vk::Format> formats,
+						   bool clear,
+						   Multisampling multisampling) {
+		AttachmentDescriptions attachments;
+		
+		for (const auto format : formats) {
+			attachments.emplace_back(
+					format,
+					clear? AttachmentOperation::CLEAR : AttachmentOperation::LOAD,
+					AttachmentOperation::STORE
+			);
+		}
+		
+		const PassConfig config (attachments, multisampling);
+		return core.createPass(config);
+	}
+	
+	PassHandle passFormat(Core &core,
+						  vk::Format format,
+						  bool clear,
+						  Multisampling multisampling) {
+		return passFormats(core, { format }, clear, multisampling);
+	}
+	
+	PassHandle passSwapchain(Core &core,
+							 const SwapchainHandle &swapchain,
+							 const std::vector<vk::Format> formats,
+							 bool clear,
+							 Multisampling multisampling) {
+		std::vector<vk::Format> swapchainFormats (formats);
+		
+		for (auto& format : swapchainFormats) {
+			if (vk::Format::eUndefined == format) {
+				format = core.getSwapchainFormat(swapchain);
+			}
+		}
+		
+		return passFormats(core, swapchainFormats, clear, multisampling);
+	}
+	
+}
diff --git a/src/vkcv/PassConfig.cpp b/src/vkcv/PassConfig.cpp
index bfb93c87..54f3f17f 100644
--- a/src/vkcv/PassConfig.cpp
+++ b/src/vkcv/PassConfig.cpp
@@ -56,4 +56,27 @@ namespace vkcv
 		return m_clear_value;
 	}
 	
+	PassConfig::PassConfig()
+	: m_attachments(),
+	  m_multisampling(Multisampling::None)
+	{}
+	
+	PassConfig::PassConfig(const AttachmentDescriptions &attachments,
+						   Multisampling multisampling)
+	: m_attachments(attachments),
+	  m_multisampling(multisampling)
+	{}
+	
+	const AttachmentDescriptions &PassConfig::getAttachments() const {
+		return m_attachments;
+	}
+	
+	void PassConfig::setMultisampling(Multisampling multisampling) {
+		m_multisampling = multisampling;
+	}
+	
+	Multisampling PassConfig::getMultisampling() const {
+		return m_multisampling;
+	}
+	
 }
diff --git a/src/vkcv/PassManager.cpp b/src/vkcv/PassManager.cpp
index 71fa8006..3677fc83 100644
--- a/src/vkcv/PassManager.cpp
+++ b/src/vkcv/PassManager.cpp
@@ -74,13 +74,15 @@ namespace vkcv
 				}
 			)
 		);
+		
+		const auto& attachments = config.getAttachments();
 
-        for (uint32_t i = 0; i < config.attachments.size(); i++) {
-            vk::Format format = config.attachments[i].getFormat();
+        for (uint32_t i = 0; i < attachments.size(); i++) {
+            vk::Format format = attachments[i].getFormat();
             vk::ImageLayout layout;
 			
-			bool depthFormat = isDepthFormat(config.attachments[i].getFormat());
-			bool stencilFormat = isStencilFormat(config.attachments[i].getFormat());
+			bool depthFormat = isDepthFormat(attachments[i].getFormat());
+			bool stencilFormat = isStencilFormat(attachments[i].getFormat());
 			
             if ((separateDepthStencil) && (depthFormat) && (!stencilFormat)) {
 				layout = vk::ImageLayout::eDepthAttachmentOptimal;
@@ -105,9 +107,9 @@ namespace vkcv
             vk::AttachmentDescription attachmentDesc (
 					{},
 					format,
-					msaaToSampleCountFlagBits(config.msaa),
-					getVKLoadOpFromAttachOp(config.attachments[i].getLoadOperation()),
-					getVkStoreOpFromAttachOp(config.attachments[i].getStoreOperation()),
+					msaaToSampleCountFlagBits(config.getMultisampling()),
+					getVKLoadOpFromAttachOp(attachments[i].getLoadOperation()),
+					getVkStoreOpFromAttachOp(attachments[i].getStoreOperation()),
 					vk::AttachmentLoadOp::eDontCare,
 					vk::AttachmentStoreOp::eDontCare,
 					layout,
-- 
GitLab