From b8b0fa0528bf49ce050d05d01c45874b15bd4083 Mon Sep 17 00:00:00 2001
From: Tobias Frisch <tfrisch@uni-koblenz.de>
Date: Tue, 30 Aug 2022 22:39:52 +0200
Subject: [PATCH] Reduced code duplication in drawcall recording

Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de>
---
 include/vkcv/Core.hpp                         |  26 +-
 .../src/RTX/ASManager.cpp                     |   8 +-
 src/vkcv/Core.cpp                             | 467 +++++++++---------
 src/vkcv/PassManager.cpp                      |  11 +-
 src/vkcv/PassManager.hpp                      |   4 +
 5 files changed, 251 insertions(+), 265 deletions(-)

diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index a77d8b28..0278466a 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -356,22 +356,22 @@ namespace vkcv
 								Multisampling multisampling=Multisampling::None);
 		
 		/**
-		 * Fills the image with given data of a specified size
+		 * @brief Fills the image with given data of a specified size
 		 * in bytes.
 		 *
-		 * @param image Image handle
-		 * @param data Image data pointer
-		 * @param size Size of data
+		 * @param[in] image Image handle
+		 * @param[in] data Image data pointer
+		 * @param[in] size Size of data
 		 */
 		void fillImage(const ImageHandle& image,
 					   const void *data,
 					   size_t size);
 		
 		/**
-		 * Switches the images layout synchronously if possible.
+		 * @brief Switches the images layout synchronously if possible.
 		 *
-		 * @param image Image handle
-		 * @param layout New image layout
+		 * @param[in] image Image handle
+		 * @param[in] layout New image layout
 		 */
 		void switchImageLayout(const ImageHandle &image,
 							   vk::ImageLayout layout);
@@ -386,10 +386,10 @@ namespace vkcv
 
         /**
          * Creates a new window and returns it's handle
-         * @param applicationName window name
-         * @param windowWidth
-         * @param windowHeight
-         * @param resizeable resizeability bool
+         * @param[in] applicationName Window title
+         * @param[in] windowWidth Window width
+         * @param[in] windowHeight Window height
+         * @param[in] resizeable resizeability bool
          * @return windowHandle
          */
 		[[nodiscard]]
@@ -401,7 +401,7 @@ namespace vkcv
 
 		/**
 		 * Getter for window reference
-		 * @param handle of the window
+		 * @param[in] handle of the window
 		 * @return the window
 		 */
 		[[nodiscard]]
@@ -439,7 +439,7 @@ namespace vkcv
 		/**
 		 * @brief Returns the image width.
 		 *
-		 * @param image Image handle
+		 * @param[in] image Image handle
 		 * @return imageWidth
 		 */
         [[nodiscard]]
diff --git a/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp b/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp
index 8e19caae..fefd4680 100644
--- a/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp
+++ b/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp
@@ -67,8 +67,9 @@ namespace vkcv::rtx {
         if (result != vk::Result::eSuccess) {
             vkcv_log(LogLevel::ERROR, "ASManager: command buffer for Acceleration Strucutre Build could not be allocated! (%s)", vk::to_string(result).c_str());
         }
-
-        beginCommandBuffer(commandBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
+		
+		const vk::CommandBufferBeginInfo beginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
+		commandBuffer.begin(beginInfo);
         return commandBuffer;
     }
 
@@ -144,9 +145,6 @@ namespace vkcv::rtx {
     }
 
     void ASManager::copyFromCPUToGPU(RTXBuffer& cpuBuffer, RTXBuffer& gpuBuffer) {
-        SubmitInfo submitInfo;
-        submitInfo.queueType = QueueType::Graphics;
-
         vk::CommandPool commandPool= createCommandPool();
         vk::CommandBuffer commandBuffer= createAndBeginCommandBuffer(commandPool);
         vk::BufferCopy bufferCopy;
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 53730e97..7d4d9b59 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -321,11 +321,11 @@ namespace vkcv
 		return widthHeight;
 	}
 
-	static vk::Framebuffer createFramebuffer(const std::vector<ImageHandle>& renderTargets,
-											 const ImageManager& imageManager,
-											 const vk::Extent2D& renderExtent,
-											 vk::RenderPass renderpass,
-											 vk::Device device) {
+	static vk::Framebuffer createFramebuffer(const std::vector<ImageHandle> &renderTargets,
+											 const ImageManager &imageManager,
+											 const vk::Extent2D &renderExtent,
+											 const vk::RenderPass &renderpass,
+											 const vk::Device &device) {
 
 		std::vector<vk::ImageView> attachmentsViews;
 		for (const ImageHandle& handle : renderTargets) {
@@ -339,7 +339,8 @@ namespace vkcv
 			attachmentsViews.data(),
 			renderExtent.width,
 			renderExtent.height,
-			1);
+			1
+		);
 
 		return device.createFramebuffer(createInfo);
 	}
@@ -394,13 +395,12 @@ namespace vkcv
 		}
 	}
 	
-	static void recordDrawcall(
-			const DescriptorSetManager 	&descriptorSetManager,
-			const DrawcallInfo      	&drawcall,
-			vk::CommandBuffer       	cmdBuffer,
-			vk::PipelineLayout      	pipelineLayout,
-			const PushConstants     	&pushConstants,
-			const size_t            	drawcallIndex) {
+	static void recordDrawcall(const DescriptorSetManager &descriptorSetManager,
+							   const DrawcallInfo &drawcall,
+							   vk::CommandBuffer cmdBuffer,
+							   vk::PipelineLayout pipelineLayout,
+							   const PushConstants &pushConstants,
+							   size_t drawcallIndex) {
 		
 		for (uint32_t i = 0; i < drawcall.mesh.vertexBufferBindings.size(); i++) {
 			const auto& vertexBinding = drawcall.mesh.vertexBufferBindings[i];
@@ -413,7 +413,8 @@ namespace vkcv
 					pipelineLayout,
 					descriptorUsage.setLocation,
 					descriptorSetManager.getDescriptorSet(descriptorUsage.descriptorSet).vulkanHandle,
-					nullptr);
+					nullptr
+			);
 		}
 		
 		if (pushConstants.getSizePerDrawcall() > 0) {
@@ -422,7 +423,8 @@ namespace vkcv
 					vk::ShaderStageFlagBits::eAll,
 					0,
 					pushConstants.getSizePerDrawcall(),
-					pushConstants.getDrawcallData(drawcallIndex));
+					pushConstants.getDrawcallData(drawcallIndex)
+			);
 		}
 		
 		if (drawcall.mesh.indexBuffer) {
@@ -432,190 +434,207 @@ namespace vkcv
 			cmdBuffer.draw(drawcall.mesh.indexCount, drawcall.instanceCount, 0, 0, {});
 		}
 	}
-
-	void Core::recordDrawcallsToCmdStream(
-		const CommandStreamHandle&      cmdStreamHandle,
-		const GraphicsPipelineHandle    &pipelineHandle,
-        const PushConstants             &pushConstantData,
-        const std::vector<DrawcallInfo> &drawcalls,
-		const std::vector<ImageHandle>  &renderTargets,
-		const WindowHandle              &windowHandle) {
-
-		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchain();
-
-		if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
-			return;
-		}
-
-		const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(
+	
+	static void recordGraphicsPipeline(Core& core,
+									   CommandStreamManager &cmdStreamManager,
+									   GraphicsPipelineManager &pipelineManager,
+									   PassManager &passManager,
+									   ImageManager &imageManager,
+									   const CommandStreamHandle &cmdStreamHandle,
+									   const GraphicsPipelineHandle &pipelineHandle,
+									   const PushConstants &pushConstants,
+									   const std::vector<ImageHandle> &renderTargets,
+									   const WindowHandle &windowHandle,
+									   const RecordCommandFunction &record) {
+		
+		const SwapchainHandle swapchainHandle = core.getWindow(windowHandle).getSwapchain();
+		
+		const std::array<uint32_t, 2> extent = getWidthHeightFromRenderTargets(
 				renderTargets,
-				m_SwapchainManager->getExtent(swapchainHandle),
-				*m_ImageManager
+				core.getSwapchainExtent(swapchainHandle),
+				imageManager
 		);
 		
-		const auto width  = widthHeight[0];
-		const auto height = widthHeight[1];
+		const auto width = extent[0];
+		const auto height = extent[1];
+		
+		const PassHandle &passHandle = pipelineManager.getPipelineConfig(pipelineHandle).getPass();
+		
+		const vk::RenderPass renderPass = passManager.getVkPass(passHandle);
+		const PassConfig passConfig = passManager.getPassConfig(passHandle);
+		
+		const auto& attachments = passConfig.getAttachments();
+		const auto& layouts = passManager.getLayouts(passHandle);
+		
+		if (renderTargets.size() != layouts.size()) {
+			vkcv_log(LogLevel::ERROR, "Amount of render targets does not match specified pipeline");
+			return;
+		}
+		
+		const vk::Pipeline pipeline = pipelineManager.getVkPipeline(pipelineHandle);
+		const vk::Rect2D renderArea (vk::Offset2D(0, 0), vk::Extent2D(width, height));
+		
+		vk::CommandBuffer cmdBuffer = cmdStreamManager.getStreamCommandBuffer(cmdStreamHandle);
+		transitionRendertargetsToAttachmentLayout(renderTargets, imageManager, cmdBuffer);
+		
+		for (size_t i = 0; i < layouts.size(); i++) {
+			imageManager.recordImageLayoutTransition(renderTargets[i], 0, 0, layouts[i], cmdBuffer);
+		}
 		
-		const PassHandle &renderpassHandle = m_GraphicsPipelineManager->getPipelineConfig(
-				pipelineHandle
-		).getPass();
-
-		const vk::RenderPass        renderpass      = m_PassManager->getVkPass(renderpassHandle);
-		const PassConfig            passConfig      = m_PassManager->getPassConfig(renderpassHandle);
-
-		const vk::Pipeline          pipeline        = m_GraphicsPipelineManager->getVkPipeline(pipelineHandle);
-		const vk::PipelineLayout    pipelineLayout  = m_GraphicsPipelineManager->getVkPipelineLayout(pipelineHandle);
-		const vk::Rect2D            renderArea (vk::Offset2D(0, 0), vk::Extent2D(width, height));
-
-		vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle);
-		transitionRendertargetsToAttachmentLayout(renderTargets, *m_ImageManager, cmdBuffer);
-
 		const vk::Framebuffer framebuffer = createFramebuffer(
 				renderTargets,
-				*m_ImageManager,
+				imageManager,
 				renderArea.extent,
-				renderpass,
-				m_Context.m_Device
+				renderPass,
+				core.getContext().getDevice()
 		);
-
+		
 		if (!framebuffer) {
 			vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer");
 			return;
 		}
-
-		auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
-			const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(
-					passConfig.getAttachments()
+		
+		auto submitFunction = [&](const vk::CommandBuffer &cmdBuffer) {
+			const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(attachments);
+			
+			const vk::RenderPassBeginInfo beginInfo(
+					renderPass,
+					framebuffer,
+					renderArea,
+					clearValues.size(),
+					clearValues.data()
 			);
-
-			const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
+			
 			cmdBuffer.beginRenderPass(beginInfo, {}, {});
-
 			cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
-
-			const GraphicsPipelineConfig &pipeConfig = m_GraphicsPipelineManager->getPipelineConfig(pipelineHandle);
+			
+			const GraphicsPipelineConfig &pipeConfig = pipelineManager.getPipelineConfig(pipelineHandle);
+			
 			if (pipeConfig.isViewportDynamic()) {
 				recordDynamicViewport(cmdBuffer, width, height);
 			}
-
-			for (size_t i = 0; i < drawcalls.size(); i++) {
-				recordDrawcall(*m_DescriptorSetManager, drawcalls[i], cmdBuffer, pipelineLayout, pushConstantData, i);
+			
+			if (record) {
+				record(cmdBuffer);
 			}
-
+			
 			cmdBuffer.endRenderPass();
 		};
+		
+		auto finishFunction = [framebuffer, &core]() {
+			core.getContext().getDevice().destroy(framebuffer);
+		};
+		
+		core.recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction);
+	}
+
+	void Core::recordDrawcallsToCmdStream(const CommandStreamHandle &cmdStreamHandle,
+										  const GraphicsPipelineHandle &pipelineHandle,
+										  const PushConstants &pushConstantData,
+										  const std::vector<DrawcallInfo> &drawcalls,
+										  const std::vector<ImageHandle> &renderTargets,
+										  const WindowHandle &windowHandle) {
+		
+		if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
+			return;
+		}
+		
+		const vk::PipelineLayout pipelineLayout = m_GraphicsPipelineManager->getVkPipelineLayout(
+				pipelineHandle
+		);
 
-		auto finishFunction = [framebuffer, this]()
-		{
-			m_Context.m_Device.destroy(framebuffer);
+		auto recordFunction = [&](const vk::CommandBuffer& cmdBuffer) {
+			for (size_t i = 0; i < drawcalls.size(); i++) {
+				recordDrawcall(
+						*m_DescriptorSetManager,
+						drawcalls[i],
+						cmdBuffer,
+						pipelineLayout,
+						pushConstantData,
+						i
+				);
+			}
 		};
 
-		recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction);
+		recordGraphicsPipeline(
+				*this,
+				*m_CommandStreamManager,
+				*m_GraphicsPipelineManager,
+				*m_PassManager,
+				*m_ImageManager,
+				cmdStreamHandle,
+				pipelineHandle,
+				pushConstantData,
+				renderTargets,
+				windowHandle,
+				recordFunction
+		);
 	}
 
-    void Core::recordIndexedIndirectDrawcallsToCmdStream(
-            const CommandStreamHandle                           cmdStreamHandle,
-            const GraphicsPipelineHandle                        &pipelineHandle,
-            const PushConstants                                 &pushConstantData,
-            const vkcv::DescriptorSetHandle                     &compiledDescriptorSet,
-            const vkcv::Mesh                                    &compiledMesh,
-            const std::vector<ImageHandle>                      &renderTargets,
-            const BufferHandle  								&indirectBuffer,
-            const uint32_t                                      drawCount,
-			const WindowHandle                                  &windowHandle) {
+    void Core::recordIndexedIndirectDrawcallsToCmdStream(const CommandStreamHandle cmdStreamHandle,
+														 const GraphicsPipelineHandle &pipelineHandle,
+														 const PushConstants &pushConstantData,
+														 const vkcv::DescriptorSetHandle &compiledDescriptorSet,
+														 const vkcv::Mesh &compiledMesh,
+														 const std::vector<ImageHandle> &renderTargets,
+														 const BufferHandle &indirectBuffer,
+														 const uint32_t drawCount,
+														 const WindowHandle &windowHandle) {
 
         if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
             return;
         }
-		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchain();
-        const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(
-				renderTargets,
-				m_SwapchainManager->getExtent(swapchainHandle),
-				*m_ImageManager);
-        const auto width = widthHeight[0];
-        const auto height = widthHeight[1];
 	
-		const PassHandle &renderpassHandle = m_GraphicsPipelineManager->getPipelineConfig(
+		const vk::PipelineLayout pipelineLayout = m_GraphicsPipelineManager->getVkPipelineLayout(
 				pipelineHandle
-		).getPass();
-
-        const vk::RenderPass        renderpass      = m_PassManager->getVkPass(renderpassHandle);
-        const PassConfig            passConfig      = m_PassManager->getPassConfig(renderpassHandle);
-
-        const vk::Pipeline          pipeline        = m_GraphicsPipelineManager->getVkPipeline(pipelineHandle);
-        const vk::PipelineLayout    pipelineLayout  = m_GraphicsPipelineManager->getVkPipelineLayout(pipelineHandle);
-        const vk::Rect2D            renderArea (vk::Offset2D(0, 0), vk::Extent2D(width, height));
-
-        vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle);
-        transitionRendertargetsToAttachmentLayout(renderTargets, *m_ImageManager, cmdBuffer);
-
-        const vk::Framebuffer framebuffer = createFramebuffer(
-				renderTargets,
-				*m_ImageManager,
-				renderArea.extent,
-				renderpass,
-				m_Context.m_Device
 		);
-
-        if (!framebuffer) {
-            vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer");
-            return;
-        }
-
-        auto submitFunction = [&](const vk::CommandBuffer &cmdBuffer) {
-
-            const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(
-					passConfig.getAttachments()
-			);
-
-            const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(),
-                                                    clearValues.data());
-            cmdBuffer.beginRenderPass(beginInfo, {}, {});
-
-            cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
-
-            const GraphicsPipelineConfig &pipeConfig = m_GraphicsPipelineManager->getPipelineConfig(pipelineHandle);
-            if (pipeConfig.isViewportDynamic()) {
-                recordDynamicViewport(cmdBuffer, width, height);
-            }
-
-			if (pushConstantData.getSizePerDrawcall() > 0)
-			{
-				cmdBuffer.pushConstants(
+	
+		auto recordFunction = [&](const vk::CommandBuffer& cmdBuffer) {
+			const auto& descSet = m_DescriptorSetManager->getDescriptorSet(compiledDescriptorSet);
+			
+			cmdBuffer.bindDescriptorSets(
+					vk::PipelineBindPoint::eGraphics,
 					pipelineLayout,
-					vk::ShaderStageFlagBits::eAll,
 					0,
-					pushConstantData.getSizePerDrawcall(),
-					pushConstantData.getDrawcallData(0));
+					descSet.vulkanHandle,
+					nullptr
+			);
+			
+			if (pushConstantData.getSizePerDrawcall() > 0) {
+				cmdBuffer.pushConstants(
+						pipelineLayout,
+						vk::ShaderStageFlagBits::eAll,
+						0,
+						pushConstantData.getSizePerDrawcall(),
+						pushConstantData.getDrawcallData(0)
+				);
 			}
-
-            const auto& descSet = m_DescriptorSetManager->getDescriptorSet(compiledDescriptorSet);
-
-            cmdBuffer.bindDescriptorSets(
-                    vk::PipelineBindPoint::eGraphics,
-                    pipelineLayout,
-                    0,
-                    descSet.vulkanHandle,
-                    nullptr);
-
+			
 			vk::DeviceSize deviceSize = 0;
 			cmdBuffer.bindVertexBuffers(0, 1, &compiledMesh.vertexBufferBindings[0].buffer,&deviceSize);
-            cmdBuffer.bindIndexBuffer(compiledMesh.indexBuffer, 0, getIndexType(compiledMesh.indexBitCount));
-
-            cmdBuffer.drawIndexedIndirect(
-                    m_BufferManager->getBuffer(indirectBuffer),
-                    0,
-                    drawCount,
-                    sizeof(vk::DrawIndexedIndirectCommand));
-
-            cmdBuffer.endRenderPass();
-        };
-
-        auto finishFunction = [framebuffer, this]() {
-            m_Context.m_Device.destroy(framebuffer);
-        };
-
-        recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction);
+			cmdBuffer.bindIndexBuffer(compiledMesh.indexBuffer, 0, getIndexType(compiledMesh.indexBitCount));
+			
+			cmdBuffer.drawIndexedIndirect(
+					m_BufferManager->getBuffer(indirectBuffer),
+					0,
+					drawCount,
+					sizeof(vk::DrawIndexedIndirectCommand)
+			);
+		};
+	
+		recordGraphicsPipeline(
+				*this,
+				*m_CommandStreamManager,
+				*m_GraphicsPipelineManager,
+				*m_PassManager,
+				*m_ImageManager,
+				cmdStreamHandle,
+				pipelineHandle,
+				pushConstantData,
+				renderTargets,
+				windowHandle,
+				recordFunction
+		);
     }
 	
 	static void recordMeshShaderDrawcall(const Core& core,
@@ -623,9 +642,9 @@ namespace vkcv
 										 vk::CommandBuffer cmdBuffer,
 										 vk::PipelineLayout pipelineLayout,
 										 const PushConstants& pushConstantData,
-										 uint32_t pushConstantOffset,
-										 const MeshShaderDrawcall& drawcall,
-										 uint32_t firstTask) {
+										 size_t drawcallIndex,
+										 const MeshShaderDrawcall& drawcall) {
+		
 		static PFN_vkCmdDrawMeshTasksNV cmdDrawMeshTasks = reinterpret_cast<PFN_vkCmdDrawMeshTasksNV>(
 				core.getContext().getDevice().getProcAddr("vkCmdDrawMeshTasksNV")
 		);
@@ -644,120 +663,76 @@ namespace vkcv
 					nullptr);
 		}
 		
-		// char* cast because void* does not support pointer arithmetic
-		const void* drawcallPushConstantData = pushConstantOffset + (char*)pushConstantData.getData();
-		
 		if (pushConstantData.getData()) {
 			cmdBuffer.pushConstants(
 					pipelineLayout,
 					vk::ShaderStageFlagBits::eAll,
 					0,
 					pushConstantData.getSizePerDrawcall(),
-					drawcallPushConstantData);
+					pushConstantData.getDrawcallData(drawcallIndex)
+			);
 		}
 		
-		cmdDrawMeshTasks(VkCommandBuffer(cmdBuffer), drawcall.taskCount, firstTask);
+		cmdDrawMeshTasks(VkCommandBuffer(cmdBuffer), drawcall.taskCount, 0);
 	}
 
-	void Core::recordMeshShaderDrawcalls(
-		const CommandStreamHandle&                          cmdStreamHandle,
-		const GraphicsPipelineHandle                        &pipelineHandle,
-		const PushConstants&                                pushConstantData,
-		const std::vector<MeshShaderDrawcall>&              drawcalls,
-		const std::vector<ImageHandle>&                     renderTargets,
-		const WindowHandle&                                 windowHandle) {
-
-		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchain();
-
+	void Core::recordMeshShaderDrawcalls(const CommandStreamHandle &cmdStreamHandle,
+										 const GraphicsPipelineHandle &pipelineHandle,
+										 const PushConstants &pushConstantData,
+										 const std::vector<MeshShaderDrawcall> &drawcalls,
+										 const std::vector<ImageHandle> &renderTargets,
+										 const WindowHandle &windowHandle) {
+		
 		if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
 			return;
 		}
-
-		const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(
-				renderTargets,
-				m_SwapchainManager->getExtent(swapchainHandle),
-				*m_ImageManager);
-		const auto width  = widthHeight[0];
-		const auto height = widthHeight[1];
 		
-		const PassHandle &renderpassHandle = m_GraphicsPipelineManager->getPipelineConfig(
+		const vk::PipelineLayout pipelineLayout = m_GraphicsPipelineManager->getVkPipelineLayout(
 				pipelineHandle
-		).getPass();
-
-		const vk::RenderPass        renderpass = m_PassManager->getVkPass(renderpassHandle);
-		const PassConfig            passConfig = m_PassManager->getPassConfig(renderpassHandle);
-
-		const vk::Pipeline          pipeline = m_GraphicsPipelineManager->getVkPipeline(pipelineHandle);
-		const vk::PipelineLayout    pipelineLayout = m_GraphicsPipelineManager->getVkPipelineLayout(pipelineHandle);
-		const vk::Rect2D            renderArea (vk::Offset2D(0, 0), vk::Extent2D(width, height));
-
-		vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle);
-		transitionRendertargetsToAttachmentLayout(renderTargets, *m_ImageManager, cmdBuffer);
-
-		const vk::Framebuffer framebuffer = createFramebuffer(
-				renderTargets,
-				*m_ImageManager,
-				renderArea.extent,
-				renderpass,
-				m_Context.m_Device
 		);
 
-		if (!framebuffer) {
-			vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer");
-			return;
-		}
-
-		auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
-			const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(
-					passConfig.getAttachments()
-			);
-
-			const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
-			cmdBuffer.beginRenderPass(beginInfo, {}, {});
-
-			cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
-
-			const GraphicsPipelineConfig& pipeConfig = m_GraphicsPipelineManager->getPipelineConfig(pipelineHandle);
-			if (pipeConfig.isViewportDynamic()) {
-				recordDynamicViewport(cmdBuffer, width, height);
-			}
-
+		auto recordFunction = [&](const vk::CommandBuffer& cmdBuffer) {
 			for (size_t i = 0; i < drawcalls.size(); i++) {
-                const uint32_t pushConstantOffset = i * pushConstantData.getSizePerDrawcall();
                 recordMeshShaderDrawcall(
 					*this,
 					*m_DescriptorSetManager,
                     cmdBuffer,
                     pipelineLayout,
                     pushConstantData,
-                    pushConstantOffset,
-                    drawcalls[i],
-                    0
+                    i,
+                    drawcalls[i]
 				);
 			}
 
 			cmdBuffer.endRenderPass();
 		};
-
-		auto finishFunction = [framebuffer, this]() {
-			m_Context.m_Device.destroy(framebuffer);
-		};
-
-		recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction);
+		
+		recordGraphicsPipeline(
+				*this,
+				*m_CommandStreamManager,
+				*m_GraphicsPipelineManager,
+				*m_PassManager,
+				*m_ImageManager,
+				cmdStreamHandle,
+				pipelineHandle,
+				pushConstantData,
+				renderTargets,
+				windowHandle,
+				recordFunction
+		);
 	}
 
 
-	void Core::recordRayGenerationToCmdStream(
-		CommandStreamHandle cmdStreamHandle,
-		vk::Pipeline rtxPipeline,
-		vk::PipelineLayout rtxPipelineLayout,
-		vk::StridedDeviceAddressRegionKHR rgenRegion,
-		vk::StridedDeviceAddressRegionKHR rmissRegion,
-		vk::StridedDeviceAddressRegionKHR rchitRegion,
-		vk::StridedDeviceAddressRegionKHR rcallRegion,
-		const std::vector<DescriptorSetUsage>& descriptorSetUsages,
-        const PushConstants& pushConstants,
-		const WindowHandle windowHandle) {
+	void Core::recordRayGenerationToCmdStream(CommandStreamHandle cmdStreamHandle,
+											  vk::Pipeline rtxPipeline,
+											  vk::PipelineLayout rtxPipelineLayout,
+											  vk::StridedDeviceAddressRegionKHR rgenRegion,
+											  vk::StridedDeviceAddressRegionKHR rmissRegion,
+											  vk::StridedDeviceAddressRegionKHR rchitRegion,
+											  vk::StridedDeviceAddressRegionKHR rcallRegion,
+											  const std::vector<DescriptorSetUsage>& descriptorSetUsages,
+											  const PushConstants& pushConstants,
+											  const WindowHandle windowHandle) {
 
 		auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
 			cmdBuffer.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, rtxPipeline);
diff --git a/src/vkcv/PassManager.cpp b/src/vkcv/PassManager.cpp
index 3677fc83..75343f4c 100644
--- a/src/vkcv/PassManager.cpp
+++ b/src/vkcv/PassManager.cpp
@@ -76,6 +76,9 @@ namespace vkcv
 		);
 		
 		const auto& attachments = config.getAttachments();
+		
+		std::vector<vk::ImageLayout> layouts;
+		layouts.reserve(attachments.size());
 
         for (uint32_t i = 0; i < attachments.size(); i++) {
             vk::Format format = attachments[i].getFormat();
@@ -122,6 +125,7 @@ namespace vkcv
 			}
 
             attachmentDescriptions.push_back(attachmentDesc);
+			layouts.push_back(layout);
         }
         
         const vk::SubpassDescription subpassDescription (
@@ -149,7 +153,7 @@ namespace vkcv
 
         vk::RenderPass renderPass = getCore().getContext().getDevice().createRenderPass(passInfo);
 
-        return add({ renderPass, config });
+        return add({ renderPass, config, layouts });
     }
 
     vk::RenderPass PassManager::getVkPass(const PassHandle &handle) const {
@@ -161,5 +165,10 @@ namespace vkcv
 		auto& pass = (*this)[handle];
 		return pass.m_Config;
     }
+	
+	const std::vector<vk::ImageLayout>& PassManager::getLayouts(const PassHandle &handle) const {
+		auto& pass = (*this)[handle];
+		return pass.m_Layouts;
+	}
     
 }
diff --git a/src/vkcv/PassManager.hpp b/src/vkcv/PassManager.hpp
index 3ab69b0c..f8dc653c 100644
--- a/src/vkcv/PassManager.hpp
+++ b/src/vkcv/PassManager.hpp
@@ -12,6 +12,7 @@ namespace vkcv
 	struct PassEntry {
 		vk::RenderPass m_Handle;
 		PassConfig m_Config;
+		std::vector<vk::ImageLayout> m_Layouts;
 	};
 	
 	/**
@@ -47,6 +48,9 @@ namespace vkcv
         
         [[nodiscard]]
         const PassConfig& getPassConfig(const PassHandle &handle) const;
+	
+		[[nodiscard]]
+		const std::vector<vk::ImageLayout>& getLayouts(const PassHandle &handle) const;
         
     };
 	
-- 
GitLab