From 65c2b3f97597840602600b8832596ea74b44858f Mon Sep 17 00:00:00 2001
From: Tobias Frisch <tfrisch@uni-koblenz.de>
Date: Mon, 5 Sep 2022 14:08:11 +0200
Subject: [PATCH] Abstracted drawcalls and increased consistency with drawcall
 recording

Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de>
---
 config/Sources.cmake                          |  13 +-
 include/vkcv/Context.hpp                      |   1 -
 include/vkcv/Core.hpp                         |  42 ++---
 include/vkcv/DescriptorSetUsage.hpp           |  27 +++
 include/vkcv/Drawcall.hpp                     | 103 +++++++++++
 include/vkcv/DrawcallRecording.hpp            |  94 ----------
 include/vkcv/VertexData.hpp                   |  71 +++++++
 .../src/vkcv/effects/BloomAndFlaresEffect.cpp |   1 -
 modules/scene/include/vkcv/scene/Mesh.hpp     |   6 +-
 modules/scene/include/vkcv/scene/MeshPart.hpp |   2 +-
 modules/scene/include/vkcv/scene/Node.hpp     |   2 +-
 modules/scene/src/vkcv/scene/Mesh.cpp         |   4 +-
 modules/scene/src/vkcv/scene/MeshPart.cpp     |  16 +-
 modules/scene/src/vkcv/scene/Node.cpp         |   2 +-
 modules/scene/src/vkcv/scene/Scene.cpp        |   2 +-
 projects/bindless_textures/src/main.cpp       |  20 +-
 projects/fire_works/src/main.cpp              | 114 +++++-------
 projects/first_mesh/src/main.cpp              |  18 +-
 projects/first_scene/src/main.cpp             |  20 +-
 projects/first_triangle/src/main.cpp          |   7 +-
 projects/head_demo/src/main.cpp               |  42 +++--
 projects/indirect_dispatch/src/App.cpp        |  24 +--
 projects/indirect_dispatch/src/AppSetup.cpp   |  13 +-
 projects/indirect_dispatch/src/AppSetup.hpp   |   2 +-
 projects/indirect_dispatch/src/MotionBlur.cpp |  18 +-
 projects/indirect_draw/src/main.cpp           |  24 ++-
 projects/mesh_shader/src/main.cpp             |  23 ++-
 projects/particle_simulation/src/main.cpp     |  21 ++-
 projects/path_tracer/src/main.cpp             |   8 +-
 projects/rtx_ambient_occlusion/src/main.cpp   |   2 +-
 projects/saf_r/src/main.cpp                   |  11 +-
 projects/sph/src/main.cpp                     |  27 +--
 projects/voxelization/src/ShadowMapping.cpp   |  34 ++--
 projects/voxelization/src/ShadowMapping.hpp   |  24 +--
 projects/voxelization/src/Voxelization.cpp    |  24 +--
 projects/voxelization/src/Voxelization.hpp    |   2 +-
 projects/voxelization/src/main.cpp            |  43 +++--
 projects/wobble_bobble/src/main.cpp           |  69 +++----
 src/vkcv/Core.cpp                             | 174 ++++++++++++------
 src/vkcv/DescriptorSetUsage.cpp               |  12 ++
 src/vkcv/Drawcall.cpp                         |  60 ++++++
 src/vkcv/VertexData.cpp                       |  42 +++++
 42 files changed, 768 insertions(+), 496 deletions(-)
 create mode 100644 include/vkcv/DescriptorSetUsage.hpp
 create mode 100644 include/vkcv/Drawcall.hpp
 delete mode 100644 include/vkcv/DrawcallRecording.hpp
 create mode 100644 include/vkcv/VertexData.hpp
 create mode 100644 src/vkcv/DescriptorSetUsage.cpp
 create mode 100644 src/vkcv/Drawcall.cpp
 create mode 100644 src/vkcv/VertexData.cpp

diff --git a/config/Sources.cmake b/config/Sources.cmake
index d714857c..db4b200f 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -106,10 +106,6 @@ set(vkcv_sources
 		${vkcv_source}/vkcv/SwapchainManager.hpp
 		${vkcv_source}/vkcv/SwapchainManager.cpp
         
-        ${vkcv_include}/vkcv/DescriptorWrites.hpp
-        
-        ${vkcv_include}/vkcv/DrawcallRecording.hpp
-        
         ${vkcv_source}/vkcv/CommandStreamManager.hpp
         ${vkcv_source}/vkcv/CommandStreamManager.cpp
         
@@ -129,6 +125,15 @@ set(vkcv_sources
 		${vkcv_include}/vkcv/Sampler.hpp
 		${vkcv_source}/vkcv/Sampler.cpp
 		
+		${vkcv_include}/vkcv/DescriptorSetUsage.hpp
+		${vkcv_source}/vkcv/DescriptorSetUsage.cpp
+		
+		${vkcv_include}/vkcv/Drawcall.hpp
+		${vkcv_source}/vkcv/Drawcall.cpp
+		
+		${vkcv_include}/vkcv/VertexData.hpp
+		${vkcv_source}/vkcv/VertexData.cpp
+		
 		${vkcv_include}/vkcv/Result.hpp
 )
 
diff --git a/include/vkcv/Context.hpp b/include/vkcv/Context.hpp
index bb2255c6..5bdd354d 100644
--- a/include/vkcv/Context.hpp
+++ b/include/vkcv/Context.hpp
@@ -10,7 +10,6 @@
 
 #include "Handles.hpp"
 #include "QueueManager.hpp"
-#include "DrawcallRecording.hpp"
 #include "Features.hpp"
 
 namespace vkcv
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 39addd72..2f158b4b 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -21,7 +21,8 @@
 #include "SamplerTypes.hpp"
 #include "DescriptorWrites.hpp"
 #include "Event.hpp"
-#include "DrawcallRecording.hpp"
+#include "Drawcall.hpp"
+#include "PushConstants.hpp"
 #include "EventFunctionTypes.hpp"
 #include "DispatchSize.hpp"
 
@@ -542,12 +543,12 @@ namespace vkcv
 		 * @param windowHandle Window handle that is used to retrieve the corresponding swapchain
 		*/
 		void recordDrawcallsToCmdStream(
-			const CommandStreamHandle&      cmdStreamHandle,
-			const GraphicsPipelineHandle    &pipelineHandle,
-			const PushConstants             &pushConstants,
-			const std::vector<DrawcallInfo> &drawcalls,
-			const std::vector<ImageHandle>  &renderTargets,
-			const WindowHandle              &windowHandle);
+			const CommandStreamHandle							&cmdStreamHandle,
+			const GraphicsPipelineHandle    					&pipelineHandle,
+			const PushConstants             					&pushConstants,
+			const std::vector<InstanceDrawcall>					&drawcalls,
+			const std::vector<ImageHandle>  					&renderTargets,
+			const WindowHandle              					&windowHandle);
 	
 		/**
 		 * @brief Records indirect drawcalls to a command stream
@@ -555,23 +556,16 @@ namespace vkcv
 		 * @param cmdStreamHandle Handle of the command stream that the drawcalls are recorded into
 		 * @param pipelineHandle Handle of the pipeline that is used for the drawcalls
 		 * @param pushConstantData Push constants that are used for the drawcalls, ignored if constant size is set to 0
-		 * @param descriptorSetUsages Descriptor set usages of the drawcalls
-		 * @param compiledMesh TODO
-		 * @param drawcalls Information about each drawcall, consisting of mesh handle, descriptor set bindings and instance count
+		 * @param drawcalls Information about each drawcall, consisting of mesh handle, descriptor set bindings and draw count
 		 * @param renderTargets Image handles that are used as render targets
-		 * @param indirectBuffer TODO
-		 * @param drawCount TODO
 		 * @param windowHandle Window handle that is used to retrieve the corresponding swapchain
 		*/
-		void recordIndexedIndirectDrawcallsToCmdStream(
+		void recordIndirectDrawcallsToCmdStream(
 				const CommandStreamHandle                           cmdStreamHandle,
 				const GraphicsPipelineHandle                        &pipelineHandle,
 				const PushConstants                                 &pushConstantData,
-				const std::vector<DescriptorSetUsage> 				&descriptorSetUsages,
-				const vkcv::Mesh                                    &compiledMesh,
+				const std::vector<IndirectDrawcall>					&drawcalls,
 				const std::vector<ImageHandle>                      &renderTargets,
-				const BufferHandle  								&indirectBuffer,
-				const uint32_t                                      drawCount,
 				const WindowHandle                                  &windowHandle);
 		
 		/**
@@ -580,17 +574,17 @@ namespace vkcv
 		 * @param cmdStreamHandle Handle of the command stream that the drawcalls are recorded into
 		 * @param pipelineHandle Handle of the pipeline that is used for the drawcalls
 		 * @param pushConstantData Push constants that are used for the drawcalls, ignored if constant size is set to 0
-		 * @param drawcalls Information about each drawcall, consisting of descriptor set bindings and task shader dispatch count
+		 * @param drawcalls Information about each drawcall, consisting of descriptor set bindings and task shader task count
 		 * @param renderTargets Image handles that are used as render targets
 		 * @param windowHandle Window handle that is used to retrieve the corresponding swapchain
 		*/
 		void recordMeshShaderDrawcalls(
-			const CommandStreamHandle&              cmdStreamHandle,
+			const CommandStreamHandle				&cmdStreamHandle,
 			const GraphicsPipelineHandle            &pipelineHandle,
-			const PushConstants&                    pushConstantData,
-            const std::vector<MeshShaderDrawcall>&  drawcalls,
-			const std::vector<ImageHandle>&         renderTargets,
-			const WindowHandle&                     windowHandle);
+			const PushConstants						&pushConstantData,
+            const std::vector<TaskDrawcall>			&drawcalls,
+			const std::vector<ImageHandle>			&renderTargets,
+			const WindowHandle						&windowHandle);
 		
         /**
          * Records the rtx ray generation to the @p cmdStreamHandle.
@@ -617,7 +611,7 @@ namespace vkcv
             vk::StridedDeviceAddressRegionKHR rcallRegion,
             const std::vector<DescriptorSetUsage>& descriptorSetUsages,
             const PushConstants& pushConstants,
-            const WindowHandle windowHandle);
+            const WindowHandle& windowHandle);
 
 		/**
 		 * @brief Record a compute shader dispatch into a command stream
diff --git a/include/vkcv/DescriptorSetUsage.hpp b/include/vkcv/DescriptorSetUsage.hpp
new file mode 100644
index 00000000..8bbf2c96
--- /dev/null
+++ b/include/vkcv/DescriptorSetUsage.hpp
@@ -0,0 +1,27 @@
+#pragma once
+/**
+ * @authors Tobias Frisch
+ * @file vkcv/DescriptorUsage.hpp
+ * @brief Structures to handle descriptor usages.
+ */
+
+#include <vector>
+
+#include "Handles.hpp"
+
+namespace vkcv {
+	
+	/**
+	 * @brief Structure to configure a descriptor set usage.
+	 */
+	struct DescriptorSetUsage {
+		uint32_t location;
+		DescriptorSetHandle descriptorSet;
+		std::vector<uint32_t> dynamicOffsets;
+	};
+	
+	DescriptorSetUsage useDescriptorSet(uint32_t location,
+										const DescriptorSetHandle &descriptorSet,
+										const std::vector<uint32_t> &dynamicOffsets = {});
+	
+}
diff --git a/include/vkcv/Drawcall.hpp b/include/vkcv/Drawcall.hpp
new file mode 100644
index 00000000..50ba78d2
--- /dev/null
+++ b/include/vkcv/Drawcall.hpp
@@ -0,0 +1,103 @@
+#pragma once
+/**
+ * @authors Tobias Frisch
+ * @file vkcv/Drawcall.hpp
+ * @brief Classes to define different drawcalls.
+ */
+
+#include <vector>
+
+#include "DescriptorSetUsage.hpp"
+#include "Handles.hpp"
+#include "VertexData.hpp"
+
+namespace vkcv {
+	
+	/**
+	 * @brief Base class to store details for a general drawcall.
+	 */
+	class Drawcall {
+	private:
+		std::vector<DescriptorSetUsage> m_usages;
+	
+	public:
+		Drawcall() = default;
+		
+		Drawcall(const Drawcall& other) = default;
+		Drawcall(Drawcall&& other) noexcept = default;
+		
+		~Drawcall() = default;
+		
+		Drawcall& operator=(const Drawcall& other) = default;
+		Drawcall& operator=(Drawcall&& other) noexcept = default;
+		
+		[[nodiscard]]
+		const std::vector<DescriptorSetUsage>& getDescriptorSetUsages() const;
+		
+		void useDescriptorSet(uint32_t location,
+							  const DescriptorSetHandle &descriptorSet,
+							  const std::vector<uint32_t> &dynamicOffsets = {});
+		
+	};
+	
+	/**
+	 * @brief Class to store details for an instance drawcall.
+	 */
+	class InstanceDrawcall : public Drawcall {
+	private:
+		VertexData m_vertexData;
+		uint32_t m_instanceCount;
+		
+	public:
+		explicit InstanceDrawcall(const VertexData& vertexData,
+								  uint32_t instanceCount = 1);
+		
+		[[nodiscard]]
+		const VertexData& getVertexData() const;
+		
+		[[nodiscard]]
+		uint32_t getInstanceCount() const;
+	
+	};
+	
+	/**
+	 * @brief Class to store details for an indirect drawcall.
+	 */
+	class IndirectDrawcall : public Drawcall {
+	private:
+		BufferHandle m_indirectDrawBuffer;
+		VertexData m_vertexData;
+		uint32_t m_drawCount;
+	
+	public:
+		explicit IndirectDrawcall(const BufferHandle &indirectDrawBuffer,
+								  const VertexData& vertexData,
+								  uint32_t drawCount = 1);
+		
+		[[nodiscard]]
+		BufferHandle getIndirectDrawBuffer() const;
+		
+		[[nodiscard]]
+		const VertexData& getVertexData() const;
+		
+		[[nodiscard]]
+		uint32_t getDrawCount() const;
+		
+	};
+	
+	/**
+	 * @brief Class to store details for a task drawcall.
+	 */
+	class TaskDrawcall : public Drawcall {
+	private:
+		uint32_t m_taskCount;
+		
+	public:
+		explicit TaskDrawcall(uint32_t taskCount = 1);
+		
+		[[nodiscard]]
+		uint32_t getTaskCount() const;
+		
+	};
+	
+}
diff --git a/include/vkcv/DrawcallRecording.hpp b/include/vkcv/DrawcallRecording.hpp
deleted file mode 100644
index 217614c1..00000000
--- a/include/vkcv/DrawcallRecording.hpp
+++ /dev/null
@@ -1,94 +0,0 @@
-#pragma once
-/**
- * @authors Sebastian Gaida, Alexander Gauggel, Artur Wasmut, Tobias Frisch
- * @file vkcv/DrawcallRecording.hpp
- * @brief Structures and functions to record drawcalls.
- */
-
-#include <vector>
-#include <vulkan/vulkan.hpp>
-
-#include "Handles.hpp"
-#include "PushConstants.hpp"
-
-namespace vkcv {
-	
-	/**
-	 * @brief Structure to store details about a vertex buffer binding.
-	 */
-    struct VertexBufferBinding {
-        vk::DeviceSize offset;
-        vk::Buffer buffer;
-    };
-
-	/**
-	 * @brief Enum class to specify the size of indexes.
-	 */
-    enum class IndexBitCount {
-		Bit8,
-        Bit16,
-        Bit32
-    };
-	
-	/**
-	 * @brief Structure to configure a descriptor set usage.
-	 */
-    struct DescriptorSetUsage {
-        inline DescriptorSetUsage(uint32_t setLocation, DescriptorSetHandle descriptorSet,
-								  const std::vector<uint32_t>& dynamicOffsets = {}) noexcept :
-			setLocation(setLocation),
-			descriptorSet(descriptorSet),
-			dynamicOffsets(dynamicOffsets) {}
-
-        const uint32_t          	setLocation;
-        const DescriptorSetHandle 	descriptorSet;
-        const std::vector<uint32_t> dynamicOffsets;
-    };
-	
-	/**
-	 * @brief Structure to store details of a mesh to draw.
-	 */
-    struct Mesh {
-        inline Mesh() {}
-
-        inline Mesh(std::vector<VertexBufferBinding> vertexBufferBindings,
-					vk::Buffer indexBuffer,
-					size_t indexCount,
-					IndexBitCount indexBitCount = IndexBitCount::Bit16) noexcept :
-			vertexBufferBindings(vertexBufferBindings),
-			indexBuffer(indexBuffer),
-            indexCount(indexCount),
-            indexBitCount(indexBitCount) {}
-
-        std::vector<VertexBufferBinding> vertexBufferBindings;
-        vk::Buffer indexBuffer;
-        size_t indexCount;
-        IndexBitCount indexBitCount;
-
-    };
-	
-	/**
-	 * @brief Structure to store details for a drawcall.
-	 */
-    struct DrawcallInfo {
-        inline DrawcallInfo(const Mesh& mesh,
-							const std::vector<DescriptorSetUsage>& descriptorSets,
-							const uint32_t instanceCount = 1) :
-			mesh(mesh),
-			descriptorSets(descriptorSets),
-			instanceCount(instanceCount){}
-
-        Mesh mesh;
-        std::vector<DescriptorSetUsage> descriptorSets;
-        uint32_t instanceCount;
-    };
-	
-	/**
-	 * @brief Structure to store details for a mesh shader drawcall.
-	 */
-    struct MeshShaderDrawcall {
-        std::vector<DescriptorSetUsage> descriptorSets;
-        uint32_t taskCount;
-    };
-	
-}
diff --git a/include/vkcv/VertexData.hpp b/include/vkcv/VertexData.hpp
new file mode 100644
index 00000000..8e69c85e
--- /dev/null
+++ b/include/vkcv/VertexData.hpp
@@ -0,0 +1,71 @@
+#pragma once
+/**
+ * @authors Sebastian Gaida, Alexander Gauggel, Artur Wasmut, Tobias Frisch
+ * @file vkcv/VertexData.hpp
+ * @brief Types to configure vertex data for drawcalls.
+ */
+
+#include <vector>
+
+#include "Handles.hpp"
+
+namespace vkcv {
+	
+	/**
+	 * @brief Structure to store details about a vertex buffer binding.
+	 */
+	struct VertexBufferBinding {
+		BufferHandle buffer;
+		size_t offset;
+	};
+	
+	VertexBufferBinding vertexBufferBinding(const BufferHandle &buffer,
+											size_t offset = 0);
+	
+	/**
+	 * @brief Enum class to specify the size of indexes.
+	 */
+	enum class IndexBitCount {
+		Bit8,
+		Bit16,
+		Bit32
+	};
+	
+	class VertexData {
+	private:
+		std::vector<VertexBufferBinding> m_bindings;
+		BufferHandle m_indices;
+		IndexBitCount m_indexBitCount;
+		size_t m_count;
+	
+	public:
+		explicit VertexData(const std::vector<VertexBufferBinding> &bindings = {});
+		
+		VertexData(const VertexData& other) = default;
+		VertexData(VertexData&& other) noexcept = default;
+		
+		~VertexData() = default;
+		
+		VertexData& operator=(const VertexData& other) = default;
+		VertexData& operator=(VertexData&& other) noexcept = default;
+		
+		[[nodiscard]]
+		const std::vector<VertexBufferBinding>& getVertexBufferBindings() const;
+		
+		void setIndexBuffer(const BufferHandle& indices,
+							IndexBitCount indexBitCount = IndexBitCount::Bit16);
+		
+		[[nodiscard]]
+		const BufferHandle& getIndexBuffer() const;
+		
+		[[nodiscard]]
+		IndexBitCount getIndexBitCount() const;
+		
+		void setCount(size_t count);
+		
+		[[nodiscard]]
+		size_t getCount() const;
+	
+	};
+
+}
diff --git a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp
index 07987c13..f31596ae 100644
--- a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp
+++ b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp
@@ -1,7 +1,6 @@
 
 #include "vkcv/effects/BloomAndFlaresEffect.hpp"
 
-#include <vkcv/DrawcallRecording.hpp>
 #include <vkcv/PushConstants.hpp>
 #include <vkcv/Image.hpp>
 #include <vkcv/Sampler.hpp>
diff --git a/modules/scene/include/vkcv/scene/Mesh.hpp b/modules/scene/include/vkcv/scene/Mesh.hpp
index 3118696b..6235fa01 100644
--- a/modules/scene/include/vkcv/scene/Mesh.hpp
+++ b/modules/scene/include/vkcv/scene/Mesh.hpp
@@ -17,7 +17,7 @@ namespace vkcv::scene {
      * An event function type to be called on per drawcall recording level to adjust data
      * like push constants with provided matrices.
      */
-	typedef typename event_function<const glm::mat4&, const glm::mat4&, PushConstants&, vkcv::DrawcallInfo&>::type RecordMeshDrawcallFunction;
+	typedef typename event_function<const glm::mat4&, const glm::mat4&, PushConstants&, vkcv::Drawcall&>::type RecordMeshDrawcallFunction;
 	
 	class Node;
 
@@ -41,7 +41,7 @@ namespace vkcv::scene {
         /**
          * List of the meshes drawcalls to render.
          */
-		std::vector<DrawcallInfo> m_drawcalls;
+		std::vector<InstanceDrawcall> m_drawcalls;
 
         /**
          * Local transformation matrix of the mesh.
@@ -77,7 +77,7 @@ namespace vkcv::scene {
          */
 		void recordDrawcalls(const glm::mat4& viewProjection,
 							 PushConstants& pushConstants,
-							 std::vector<DrawcallInfo>& drawcalls,
+							 std::vector<InstanceDrawcall>& drawcalls,
 							 const RecordMeshDrawcallFunction& record);
 
         /**
diff --git a/modules/scene/include/vkcv/scene/MeshPart.hpp b/modules/scene/include/vkcv/scene/MeshPart.hpp
index 8d77efd7..eef68a00 100644
--- a/modules/scene/include/vkcv/scene/MeshPart.hpp
+++ b/modules/scene/include/vkcv/scene/MeshPart.hpp
@@ -77,7 +77,7 @@ namespace vkcv::scene {
          */
 		void load(const asset::Scene& scene,
 				  const asset::VertexGroup& vertexGroup,
-				  std::vector<DrawcallInfo>& drawcalls);
+				  std::vector<InstanceDrawcall>& drawcalls);
 	
 	public:
         /**
diff --git a/modules/scene/include/vkcv/scene/Node.hpp b/modules/scene/include/vkcv/scene/Node.hpp
index 51088f25..3cd5083c 100644
--- a/modules/scene/include/vkcv/scene/Node.hpp
+++ b/modules/scene/include/vkcv/scene/Node.hpp
@@ -71,7 +71,7 @@ namespace vkcv::scene {
          */
 		void recordDrawcalls(const glm::mat4& viewProjection,
 							 PushConstants& pushConstants,
-							 std::vector<DrawcallInfo>& drawcalls,
+							 std::vector<InstanceDrawcall>& drawcalls,
 							 const RecordMeshDrawcallFunction& record);
 
         /**
diff --git a/modules/scene/src/vkcv/scene/Mesh.cpp b/modules/scene/src/vkcv/scene/Mesh.cpp
index af02aedb..5729ed6c 100644
--- a/modules/scene/src/vkcv/scene/Mesh.cpp
+++ b/modules/scene/src/vkcv/scene/Mesh.cpp
@@ -67,7 +67,7 @@ namespace vkcv::scene {
 			m_parts[i] = other.m_parts[i];
 		}
 		
-		m_drawcalls = std::vector<DrawcallInfo>(other.m_drawcalls);
+		m_drawcalls = std::vector<InstanceDrawcall>(other.m_drawcalls);
 		m_transform = other.m_transform;
 		m_bounds = other.m_bounds;
 		
@@ -90,7 +90,7 @@ namespace vkcv::scene {
 	
 	void Mesh::recordDrawcalls(const glm::mat4& viewProjection,
 							   PushConstants& pushConstants,
-							   std::vector<DrawcallInfo>& drawcalls,
+							   std::vector<InstanceDrawcall>& drawcalls,
 							   const RecordMeshDrawcallFunction& record) {
 		const glm::mat4 transform = viewProjection * m_transform;
 		
diff --git a/modules/scene/src/vkcv/scene/MeshPart.cpp b/modules/scene/src/vkcv/scene/MeshPart.cpp
index adb611f0..a3fc117f 100644
--- a/modules/scene/src/vkcv/scene/MeshPart.cpp
+++ b/modules/scene/src/vkcv/scene/MeshPart.cpp
@@ -17,7 +17,7 @@ namespace vkcv::scene {
 	
 	void MeshPart::load(const asset::Scene& scene,
 						const asset::VertexGroup &vertexGroup,
-						std::vector<DrawcallInfo>& drawcalls) {
+						std::vector<InstanceDrawcall>& drawcalls) {
 		Core& core = *(m_scene.m_core);
 		
 		auto vertexBuffer = buffer<uint8_t>(
@@ -34,7 +34,7 @@ namespace vkcv::scene {
 		});
 		
 		for (const auto& attribute : attributes) {
-			m_vertexBindings.emplace_back(attribute.offset, vertexBuffer.getVulkanHandle());
+			m_vertexBindings.emplace_back(vertexBuffer.getHandle(), attribute.offset);
 		}
 		
 		auto indexBuffer = buffer<uint8_t>(
@@ -88,10 +88,14 @@ namespace vkcv::scene {
 					break;
 			}
 			
-			drawcalls.push_back(DrawcallInfo(
-					vkcv::Mesh(m_vertexBindings, indexBuffer.getVulkanHandle(), m_indexCount, indexBitCount),
-					{ DescriptorSetUsage(0, material.getDescriptorSet()) }
-			));
+			VertexData vertexData (m_vertexBindings);
+			vertexData.setIndexBuffer(indexBuffer.getHandle(), indexBitCount);
+			vertexData.setCount(m_indexCount);
+			
+			InstanceDrawcall drawcall (vertexData);
+			drawcall.useDescriptorSet(0, material.getDescriptorSet());
+			
+			drawcalls.push_back(drawcall);
 		}
 	}
 	
diff --git a/modules/scene/src/vkcv/scene/Node.cpp b/modules/scene/src/vkcv/scene/Node.cpp
index 24f62d18..746fe180 100644
--- a/modules/scene/src/vkcv/scene/Node.cpp
+++ b/modules/scene/src/vkcv/scene/Node.cpp
@@ -92,7 +92,7 @@ namespace vkcv::scene {
 	
 	void Node::recordDrawcalls(const glm::mat4& viewProjection,
 							   PushConstants& pushConstants,
-							   std::vector<DrawcallInfo>& drawcalls,
+							   std::vector<InstanceDrawcall>& drawcalls,
 							   const RecordMeshDrawcallFunction& record) {
 		if (!checkFrustum(viewProjection, m_bounds)) {
 			return;
diff --git a/modules/scene/src/vkcv/scene/Scene.cpp b/modules/scene/src/vkcv/scene/Scene.cpp
index 6ecfe34a..e68de653 100644
--- a/modules/scene/src/vkcv/scene/Scene.cpp
+++ b/modules/scene/src/vkcv/scene/Scene.cpp
@@ -126,7 +126,7 @@ namespace vkcv::scene {
 		});
 		
 		PushConstants pushConstants (pushConstantsSizePerDrawcall);
-		std::vector<DrawcallInfo> drawcalls;
+		std::vector<InstanceDrawcall> drawcalls;
 		size_t count = 0;
 		
 		const glm::mat4 viewProjection = camera.getMVP();
diff --git a/projects/bindless_textures/src/main.cpp b/projects/bindless_textures/src/main.cpp
index c4e18699..0a34bcb7 100644
--- a/projects/bindless_textures/src/main.cpp
+++ b/projects/bindless_textures/src/main.cpp
@@ -182,11 +182,11 @@ int main(int argc, const char** argv) {
 	core.submitCommandStream(downsampleStream, false);
 
 	vkcv::SamplerHandle sampler = vkcv::samplerLinear(core);
-
+	
 	const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = {
-		vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()),
-		vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()),
-		vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle())
+			vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[0].offset),
+			vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[1].offset),
+			vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[2].offset)
 	};
 
 	vkcv::DescriptorWrites setWrites;
@@ -210,11 +210,13 @@ int main(int argc, const char** argv) {
 	vkcv::ImageHandle depthBuffer;
 
 	const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
-
-	const vkcv::Mesh renderMesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), mesh.vertexGroups[0].numIndices);
-
-	vkcv::DescriptorSetUsage    descriptorUsage(0, descriptorSet);
-	vkcv::DrawcallInfo          drawcall(renderMesh, { descriptorUsage },1);
+	
+	vkcv::VertexData vertexData (vertexBufferBindings);
+	vertexData.setIndexBuffer(indexBuffer.getHandle());
+	vertexData.setCount(mesh.vertexGroups[0].numIndices);
+	
+	vkcv::InstanceDrawcall drawcall (vertexData);
+	drawcall.useDescriptorSet(0, descriptorSet);
 
     vkcv::camera::CameraManager cameraManager(window);
     uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
diff --git a/projects/fire_works/src/main.cpp b/projects/fire_works/src/main.cpp
index ffef4cd4..738723ff 100644
--- a/projects/fire_works/src/main.cpp
+++ b/projects/fire_works/src/main.cpp
@@ -6,7 +6,6 @@
 #include <vkcv/Image.hpp>
 #include <vkcv/Pass.hpp>
 #include <vkcv/Sampler.hpp>
-#include <vkcv/DrawcallRecording.hpp>
 
 #include <vkcv/camera/CameraManager.hpp>
 #include <vkcv/shader/GLSLCompiler.hpp>
@@ -575,11 +574,9 @@ int main(int argc, const char **argv) {
 		1, 4, 0
 	});
 	
-	vkcv::Mesh cubeMesh (
-		{ vkcv::VertexBufferBinding(0, cubePositions.getVulkanHandle()) },
-		cubeIndices.getVulkanHandle(),
-		cubeIndices.getCount()
-	);
+	vkcv::VertexData cubeData ({ vkcv::vertexBufferBinding(cubePositions.getHandle()) });
+	cubeData.setIndexBuffer(cubeIndices.getHandle());
+	cubeData.setCount(cubeIndices.getCount());
 	
 	const std::vector<vkcv::VertexAttachment> vaSmoke = smokeShaderProgram.getVertexAttachments();
 	
@@ -624,16 +621,9 @@ int main(int argc, const char **argv) {
 	
 	vkcv::GraphicsPipelineHandle trailPipeline = core.createGraphicsPipeline(trailPipelineDefinition);
 	
-	std::vector<vkcv::DrawcallInfo> drawcallsSmokes;
-	
-	drawcallsSmokes.push_back(vkcv::DrawcallInfo(
-		cubeMesh,
-		{
-			vkcv::DescriptorSetUsage(0, smokeDescriptorSet),
-			vkcv::DescriptorSetUsage(1, generationDescriptorSet),
-		},
-		smokeBuffer.getCount()
-	));
+	vkcv::InstanceDrawcall drawcallSmoke (cubeData, smokeBuffer.getCount());
+	drawcallSmoke.useDescriptorSet(0, smokeDescriptorSet);
+	drawcallSmoke.useDescriptorSet(1, generationDescriptorSet);
 	
 	auto trianglePositions = vkcv::buffer<glm::vec2>(
 			core,
@@ -657,29 +647,18 @@ int main(int argc, const char **argv) {
 		0, 1, 2
 	});
 	
-	vkcv::Mesh triangleMesh (
-		{ vkcv::VertexBufferBinding(0, trianglePositions.getVulkanHandle()) },
-		triangleIndices.getVulkanHandle(),
-		triangleIndices.getCount()
-	);
-	
-	vkcv::Mesh trailMesh (
-		{},
-		triangleIndices.getVulkanHandle(),
-		1
-	);
+	vkcv::VertexData triangleData ({ vkcv::vertexBufferBinding(trianglePositions.getHandle()) });
+	triangleData.setIndexBuffer(triangleIndices.getHandle());
+	triangleData.setCount(triangleIndices.getCount());
 	
-	std::vector<vkcv::DrawcallInfo> drawcallsTrails;
+	vkcv::VertexData trailData;
+	triangleData.setIndexBuffer(triangleIndices.getHandle());
+	trailData.setCount(1);
 	
-	drawcallsTrails.push_back(vkcv::DrawcallInfo(
-		trailMesh,
-		{
-			vkcv::DescriptorSetUsage(0, trailDescriptorSet),
-			vkcv::DescriptorSetUsage(1, generationDescriptorSet),
-			vkcv::DescriptorSetUsage(2, descriptorSet)
-		},
-		trailBuffer.getCount()
-	));
+	vkcv::InstanceDrawcall drawcallTrail (trailData, trailBuffer.getCount());
+	drawcallTrail.useDescriptorSet(0, trailDescriptorSet);
+	drawcallTrail.useDescriptorSet(1, generationDescriptorSet);
+	drawcallTrail.useDescriptorSet(2, descriptorSet);
 	
 	const std::vector<vkcv::VertexAttachment> vaParticles = particleShaderProgram.getVertexAttachments();
 	
@@ -701,13 +680,8 @@ int main(int argc, const char **argv) {
 	
 	vkcv::GraphicsPipelineHandle particlePipeline = core.createGraphicsPipeline(particlePipelineDefinition);
 	
-	std::vector<vkcv::DrawcallInfo> drawcallsParticles;
-	
-	drawcallsParticles.push_back(vkcv::DrawcallInfo(
-		triangleMesh,
-		{ vkcv::DescriptorSetUsage(0, descriptorSet) },
-		particleBuffer.getCount()
-	));
+	vkcv::InstanceDrawcall drawcallParticle (triangleData, particleBuffer.getCount());
+	drawcallParticle.useDescriptorSet(0, descriptorSet);
 	
 	vkcv::ShaderProgram motionShader;
 	compiler.compile(vkcv::ShaderStage::COMPUTE, "shaders/motion.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
@@ -1002,7 +976,7 @@ int main(int argc, const char **argv) {
 			cmdStream,
 			voxelClearPipeline,
 			voxelDispatchCount,
-			{ vkcv::DescriptorSetUsage(0, voxelDescriptorSet) },
+			{ vkcv::useDescriptorSet(0, voxelDescriptorSet) },
 			vkcv::PushConstants(0)
 		);
 		core.recordEndDebugLabel(cmdStream);
@@ -1025,10 +999,10 @@ int main(int argc, const char **argv) {
 			generationPipeline,
 			particleDispatchCount,
 			{
-				vkcv::DescriptorSetUsage(0, descriptorSet),
-				vkcv::DescriptorSetUsage(1, generationDescriptorSet),
-				vkcv::DescriptorSetUsage(2, smokeDescriptorSet),
-				vkcv::DescriptorSetUsage(3, trailDescriptorSet)
+				vkcv::useDescriptorSet(0, descriptorSet),
+				vkcv::useDescriptorSet(1, generationDescriptorSet),
+				vkcv::useDescriptorSet(2, smokeDescriptorSet),
+				vkcv::useDescriptorSet(3, trailDescriptorSet)
 			},
 			pushConstantsTime
 		);
@@ -1043,7 +1017,7 @@ int main(int argc, const char **argv) {
 			cmdStream,
 			scalePipeline,
 			smokeDispatchCount,
-			{ vkcv::DescriptorSetUsage(0, smokeDescriptorSet) },
+			{ vkcv::useDescriptorSet(0, smokeDescriptorSet) },
 			pushConstantsTime
 		);
 		core.recordEndDebugLabel(cmdStream);
@@ -1055,7 +1029,7 @@ int main(int argc, const char **argv) {
 			cmdStream,
 			motionPipeline,
 			particleDispatchCount,
-			{ vkcv::DescriptorSetUsage(0, descriptorSet) },
+			{ vkcv::useDescriptorSet(0, descriptorSet) },
 			pushConstantsTime
 		);
 		core.recordEndDebugLabel(cmdStream);
@@ -1072,8 +1046,8 @@ int main(int argc, const char **argv) {
 			trailComputePipeline,
 			trailDispatchCount,
 			{
-				vkcv::DescriptorSetUsage(0, descriptorSet),
-				vkcv::DescriptorSetUsage(1, trailDescriptorSet)
+				vkcv::useDescriptorSet(0, descriptorSet),
+				vkcv::useDescriptorSet(1, trailDescriptorSet)
 			},
 			pushConstantsTime
 		);
@@ -1099,7 +1073,7 @@ int main(int argc, const char **argv) {
 			cmdStream,
 			particlePipeline,
 			pushConstantsDraw0,
-			{ drawcallsParticles },
+			{ drawcallParticle },
 			{ colorBuffers[0] },
 			windowHandle
 		);
@@ -1119,8 +1093,8 @@ int main(int argc, const char **argv) {
 			voxelParticlePipeline,
 			particleDispatchCount,
 			{
-				vkcv::DescriptorSetUsage(0, descriptorSet),
-				vkcv::DescriptorSetUsage(1, voxelDescriptorSet)
+				vkcv::useDescriptorSet(0, descriptorSet),
+				vkcv::useDescriptorSet(1, voxelDescriptorSet)
 			},
 			pushConstantsVoxel
 		);
@@ -1141,7 +1115,7 @@ int main(int argc, const char **argv) {
 			cmdStream,
 			smokePipeline,
 			pushConstantsDraw1,
-			{ drawcallsSmokes },
+			{ drawcallSmoke },
 			{ colorBuffers[1] },
 			windowHandle
 		);
@@ -1158,8 +1132,8 @@ int main(int argc, const char **argv) {
 			voxelSmokePipeline,
 			smokeDispatchCount,
 			{
-				vkcv::DescriptorSetUsage(0, smokeDescriptorSet),
-				vkcv::DescriptorSetUsage(1, voxelDescriptorSet)
+				vkcv::useDescriptorSet(0, smokeDescriptorSet),
+				vkcv::useDescriptorSet(1, voxelDescriptorSet)
 			},
 			pushConstantsVoxel
 		);
@@ -1173,7 +1147,7 @@ int main(int argc, const char **argv) {
 			cmdStream,
 			trailPipeline,
 			pushConstantsDraw1,
-			{ drawcallsTrails },
+			{ drawcallTrail },
 			{ colorBuffers[2] },
 			windowHandle
 		);
@@ -1190,8 +1164,8 @@ int main(int argc, const char **argv) {
 			voxelTrailPipeline,
 			trailDispatchCount,
 			{
-				vkcv::DescriptorSetUsage(0, trailDescriptorSet),
-				vkcv::DescriptorSetUsage(1, voxelDescriptorSet)
+				vkcv::useDescriptorSet(0, trailDescriptorSet),
+				vkcv::useDescriptorSet(1, voxelDescriptorSet)
 			},
 			pushConstantsVoxel
 		);
@@ -1211,8 +1185,8 @@ int main(int argc, const char **argv) {
 			voxelPipeline,
 			voxelDispatchCount,
 			{
-				vkcv::DescriptorSetUsage(0, voxelDescriptorSet),
-				vkcv::DescriptorSetUsage(1, voxelOutDescriptorSet)
+				vkcv::useDescriptorSet(0, voxelDescriptorSet),
+				vkcv::useDescriptorSet(1, voxelOutDescriptorSet)
 			},
 			vkcv::PushConstants(0)
 		);
@@ -1229,7 +1203,7 @@ int main(int argc, const char **argv) {
 				cmdStream,
 				fluidPipeline,
 				voxelDispatchCount,
-				{ vkcv::DescriptorSetUsage(0, fluidDescriptorSet[i % 2]) },
+				{ vkcv::useDescriptorSet(0, fluidDescriptorSet[i % 2]) },
 				vkcv::PushConstants(0)
 			);
 		}
@@ -1251,8 +1225,8 @@ int main(int argc, const char **argv) {
 			voxelSamplePipeline,
 			sampleDispatchCount,
 			{
-				vkcv::DescriptorSetUsage(0, voxelOutDescriptorSet),
-				vkcv::DescriptorSetUsage(1, samplesDescriptorSet)
+				vkcv::useDescriptorSet(0, voxelOutDescriptorSet),
+				vkcv::useDescriptorSet(1, samplesDescriptorSet)
 			},
 			vkcv::PushConstants(0)
 		);
@@ -1283,8 +1257,8 @@ int main(int argc, const char **argv) {
 			addPipe,
 			colorDispatchCount,
 			{
-				vkcv::DescriptorSetUsage(0, addDescriptor),
-				vkcv::DescriptorSetUsage(1, generationDescriptorSet)
+				vkcv::useDescriptorSet(0, addDescriptor),
+				vkcv::useDescriptorSet(1, generationDescriptorSet)
 			},
 			vkcv::PushConstants(0)
 		);
@@ -1310,7 +1284,7 @@ int main(int argc, const char **argv) {
 			cmdStream,
 			tonemappingPipe,
 			colorDispatchCount,
-			{vkcv::DescriptorSetUsage(0, tonemappingDescriptor) },
+			{ vkcv::useDescriptorSet(0, tonemappingDescriptor) },
 			vkcv::PushConstants(0)
 		);
 		
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index 489fe0ad..2e28bd0f 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -127,9 +127,9 @@ int main(int argc, const char** argv) {
 	vkcv::SamplerHandle sampler = vkcv::samplerLinear(core);
 
 	const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = {
-		vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()),
-		vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()),
-		vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle())
+			vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[0].offset),
+			vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[1].offset),
+			vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[2].offset)
 	};
 
 	vkcv::DescriptorWrites setWrites;
@@ -141,11 +141,13 @@ int main(int argc, const char** argv) {
 	vkcv::ImageHandle depthBuffer;
 
 	const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
-
-	const vkcv::Mesh renderMesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), mesh.vertexGroups[0].numIndices);
-
-	vkcv::DescriptorSetUsage    descriptorUsage(0, descriptorSet);
-	vkcv::DrawcallInfo          drawcall(renderMesh, { descriptorUsage },1);
+	
+	vkcv::VertexData vertexData (vertexBufferBindings);
+	vertexData.setIndexBuffer(indexBuffer.getHandle());
+	vertexData.setCount(mesh.vertexGroups[0].numIndices);
+	
+	vkcv::InstanceDrawcall drawcall (vertexData);
+	drawcall.useDescriptorSet(0, descriptorSet);
 
     vkcv::camera::CameraManager cameraManager(window);
     uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp
index 6544c7ad..28a2f2d4 100644
--- a/projects/first_scene/src/main.cpp
+++ b/projects/first_scene/src/main.cpp
@@ -115,18 +115,20 @@ int main(int argc, const char** argv) {
 
 		auto recordMesh = [](const glm::mat4& MVP, const glm::mat4& M,
 							 vkcv::PushConstants &pushConstants,
-							 vkcv::DrawcallInfo& drawcallInfo) {
+							 vkcv::Drawcall& drawcall) {
 			pushConstants.appendDrawcall(MVP);
 		};
 		
-		scene.recordDrawcalls(cmdStream,
-							  cameraManager.getActiveCamera(),
-							  scenePass,
-							  scenePipeline,
-							  sizeof(glm::mat4),
-							  recordMesh,
-							  renderTargets,
-							  windowHandle);
+		scene.recordDrawcalls(
+				cmdStream,
+				cameraManager.getActiveCamera(),
+				scenePass,
+				scenePipeline,
+				sizeof(glm::mat4),
+				recordMesh,
+				renderTargets,
+				windowHandle
+		);
 		
 		core.prepareSwapchainImageForPresent(cmdStream);
 		core.submitCommandStream(cmdStream);
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 7a8fa04b..18c62285 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -65,8 +65,11 @@ int main(int argc, const char** argv) {
 	
 	core.setDebugLabel(trianglePipeline, "Triangle Pipeline");
 
-	const vkcv::Mesh renderMesh({}, triangleIndexBuffer.getVulkanHandle(), 3);
-	vkcv::DrawcallInfo drawcall(renderMesh, {},1);
+	vkcv::VertexData vertexData;
+	vertexData.setIndexBuffer(triangleIndexBuffer.getHandle());
+	vertexData.setCount(3);
+	
+	vkcv::InstanceDrawcall drawcall (vertexData);
 
 	const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
 
diff --git a/projects/head_demo/src/main.cpp b/projects/head_demo/src/main.cpp
index e3773cb7..2a0891f8 100644
--- a/projects/head_demo/src/main.cpp
+++ b/projects/head_demo/src/main.cpp
@@ -186,32 +186,34 @@ int main(int argc, const char** argv) {
 		
 		auto recordMesh = [&](const glm::mat4& MVP, const glm::mat4& M,
 							 vkcv::PushConstants &pushConstants,
-							 vkcv::DrawcallInfo& drawcallInfo) {
+							 vkcv::Drawcall& drawcall) {
 			pushConstants.appendDrawcall(MVP);
-			drawcallInfo.descriptorSets.push_back(
-					vkcv::DescriptorSetUsage(1, clipDescriptorSet)
-			);
+			drawcall.useDescriptorSet(1, clipDescriptorSet);
 		};
 		
-		scene.recordDrawcalls(cmdStream,
-							  cameraManager.getActiveCamera(),
-							  linePass,
-							  linePipeline,
-							  sizeof(glm::mat4),
-							  recordMesh,
-							  renderTargets,
-							  windowHandle);
+		scene.recordDrawcalls(
+				cmdStream,
+				cameraManager.getActiveCamera(),
+				linePass,
+				linePipeline,
+				sizeof(glm::mat4),
+				recordMesh,
+				renderTargets,
+				windowHandle
+		);
 		
 		bloomAndFlares.recordEffect(cmdStream, colorBuffer, colorBuffer);
 		
-		scene.recordDrawcalls(cmdStream,
-							  cameraManager.getActiveCamera(),
-							  scenePass,
-							  scenePipeline,
-							  sizeof(glm::mat4),
-							  recordMesh,
-							  renderTargets,
-							  windowHandle);
+		scene.recordDrawcalls(
+				cmdStream,
+				cameraManager.getActiveCamera(),
+				scenePass,
+				scenePipeline,
+				sizeof(glm::mat4),
+				recordMesh,
+				renderTargets,
+				windowHandle
+		);
 		
 		core.prepareImageForSampling(cmdStream, colorBuffer);
 		core.prepareImageForStorage(cmdStream, swapchainInput);
diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp
index ef5afaf1..c52acec1 100644
--- a/projects/indirect_dispatch/src/App.cpp
+++ b/projects/indirect_dispatch/src/App.cpp
@@ -80,10 +80,10 @@ bool App::initialize() {
 
 void App::run() {
 
-	auto                        frameStartTime = std::chrono::system_clock::now();
-	const auto                  appStartTime   = std::chrono::system_clock::now();
-	const vkcv::ImageHandle     swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
-	const vkcv::DrawcallInfo    skyDrawcall(m_cubeMesh.mesh, {}, 1);
+	auto                         frameStartTime = std::chrono::system_clock::now();
+	const auto                   appStartTime   = std::chrono::system_clock::now();
+	const vkcv::ImageHandle      swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
+	const vkcv::InstanceDrawcall skyDrawcall(m_cubeMesh.mesh);
 
 	vkcv::gui::GUI gui(m_core, m_windowHandle);
 
@@ -214,9 +214,9 @@ void App::run() {
 			m_renderTargets.motionBuffer,
 			m_renderTargets.depthBuffer };
 
-		std::vector<vkcv::DrawcallInfo> prepassSceneDrawcalls;
+		std::vector<vkcv::InstanceDrawcall> prepassSceneDrawcalls;
 		for (const Object& obj : sceneObjects) {
-			prepassSceneDrawcalls.push_back(vkcv::DrawcallInfo(obj.meshResources.mesh, {}));
+			prepassSceneDrawcalls.push_back(vkcv::InstanceDrawcall(obj.meshResources.mesh));
 		}
 
 		m_core.recordDrawcallsToCmdStream(
@@ -253,11 +253,11 @@ void App::run() {
 			meshPushConstants.appendDrawcall(matrices);
 		}
 
-		std::vector<vkcv::DrawcallInfo> forwardSceneDrawcalls;
+		std::vector<vkcv::InstanceDrawcall> forwardSceneDrawcalls;
 		for (const Object& obj : sceneObjects) {
-			forwardSceneDrawcalls.push_back(vkcv::DrawcallInfo(
-				obj.meshResources.mesh, 
-				{ vkcv::DescriptorSetUsage(0, m_meshPass.descriptorSet) }));
+			vkcv::InstanceDrawcall drawcall (obj.meshResources.mesh);
+			drawcall.useDescriptorSet(0, m_meshPass.descriptorSet);
+			forwardSceneDrawcalls.push_back(drawcall);
 		}
 
 		m_core.recordDrawcallsToCmdStream(
@@ -297,7 +297,7 @@ void App::run() {
 				cameraNear,
 				cameraFar,
 				fDeltaTimeSeconds,
-				cameraShutterSpeedInverse,
+				static_cast<float>(cameraShutterSpeedInverse),
 				motionBlurTileOffsetLength,
 				motionBlurFastPathThreshold);
 		}
@@ -329,7 +329,7 @@ void App::run() {
 			cmdStream,
 			m_gammaCorrectionPass.pipeline,
 			fullScreenImageDispatch,
-			{ vkcv::DescriptorSetUsage(0, m_gammaCorrectionPass.descriptorSet) },
+			{ vkcv::useDescriptorSet(0, m_gammaCorrectionPass.descriptorSet) },
 			vkcv::PushConstants(0));
 
 		m_core.prepareSwapchainImageForPresent(cmdStream);
diff --git a/projects/indirect_dispatch/src/AppSetup.cpp b/projects/indirect_dispatch/src/AppSetup.cpp
index e91b9691..fb542509 100644
--- a/projects/indirect_dispatch/src/AppSetup.cpp
+++ b/projects/indirect_dispatch/src/AppSetup.cpp
@@ -52,11 +52,14 @@ bool loadMesh(vkcv::Core& core, const std::filesystem::path& path, MeshResources
 	});
 
 	const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = {
-		vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()),
-		vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()),
-		vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) };
-
-	outMesh->mesh = vkcv::Mesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), scene.vertexGroups[0].numIndices);
+		vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[0].offset),
+		vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[1].offset),
+		vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[2].offset)
+	};
+
+	outMesh->mesh = vkcv::VertexData(vertexBufferBindings);
+	outMesh->mesh.setIndexBuffer(indexBuffer.getHandle());
+	outMesh->mesh.setCount(scene.vertexGroups[0].numIndices);
 
 	return true;
 }
diff --git a/projects/indirect_dispatch/src/AppSetup.hpp b/projects/indirect_dispatch/src/AppSetup.hpp
index b0ade431..41e020c3 100644
--- a/projects/indirect_dispatch/src/AppSetup.hpp
+++ b/projects/indirect_dispatch/src/AppSetup.hpp
@@ -21,7 +21,7 @@ struct ComputePassHandles {
 };
 
 struct MeshResources {
-	vkcv::Mesh          mesh;
+	vkcv::VertexData    mesh;
 	vkcv::BufferHandle  vertexBuffer;
 	vkcv::BufferHandle  indexBuffer;
 };
diff --git a/projects/indirect_dispatch/src/MotionBlur.cpp b/projects/indirect_dispatch/src/MotionBlur.cpp
index d90171de..fe55a582 100644
--- a/projects/indirect_dispatch/src/MotionBlur.cpp
+++ b/projects/indirect_dispatch/src/MotionBlur.cpp
@@ -107,7 +107,7 @@ vkcv::ImageHandle MotionBlur::render(
 		cmdStream,
 		m_tileResetPass.pipeline,
 		1,
-		{ vkcv::DescriptorSetUsage(0, m_tileResetPass.descriptorSet) },
+		{ vkcv::useDescriptorSet(0, m_tileResetPass.descriptorSet) },
 		vkcv::PushConstants(0)
 	);
 
@@ -162,7 +162,7 @@ vkcv::ImageHandle MotionBlur::render(
 		cmdStream,
 		m_tileClassificationPass.pipeline,
 		tileClassificationDispatch,
-		{ vkcv::DescriptorSetUsage(0, m_tileClassificationPass.descriptorSet) },
+		{ vkcv::useDescriptorSet(0, m_tileClassificationPass.descriptorSet) },
 		classificationPushConstants);
 
 	m_core->recordBufferMemoryBarrier(cmdStream, m_fullPathWorkTileBuffer);
@@ -247,7 +247,7 @@ vkcv::ImageHandle MotionBlur::render(
 			m_motionBlurPass.pipeline,
 			m_fullPathWorkTileBuffer,
 			0,
-			{ vkcv::DescriptorSetUsage(0, m_motionBlurPass.descriptorSet) },
+			{ vkcv::useDescriptorSet(0, m_motionBlurPass.descriptorSet) },
 			motionBlurPushConstants);
 
 		m_core->recordComputeIndirectDispatchToCmdStream(
@@ -255,7 +255,7 @@ vkcv::ImageHandle MotionBlur::render(
 			m_colorCopyPass.pipeline,
 			m_copyPathWorkTileBuffer,
 			0,
-			{ vkcv::DescriptorSetUsage(0, m_colorCopyPass.descriptorSet) },
+			{ vkcv::useDescriptorSet(0, m_colorCopyPass.descriptorSet) },
 			vkcv::PushConstants(0));
 
 		m_core->recordComputeIndirectDispatchToCmdStream(
@@ -263,7 +263,7 @@ vkcv::ImageHandle MotionBlur::render(
 			m_motionBlurFastPathPass.pipeline,
 			m_fastPathWorkTileBuffer,
 			0,
-			{ vkcv::DescriptorSetUsage(0, m_motionBlurFastPathPass.descriptorSet) },
+			{ vkcv::useDescriptorSet(0, m_motionBlurFastPathPass.descriptorSet) },
 			fastPathPushConstants);
 	}
 	else if(mode == eMotionBlurMode::Disabled) {
@@ -294,7 +294,7 @@ vkcv::ImageHandle MotionBlur::render(
 			cmdStream,
 			m_tileVisualisationPass.pipeline,
 			tileCount,
-			{ vkcv::DescriptorSetUsage(0, m_tileVisualisationPass.descriptorSet) },
+			{ vkcv::useDescriptorSet(0, m_tileVisualisationPass.descriptorSet) },
 			vkcv::PushConstants(0));
 	}
 	else {
@@ -360,7 +360,7 @@ vkcv::ImageHandle MotionBlur::renderMotionVectorVisualisation(
 		cmdStream,
 		m_motionVectorVisualisationPass.pipeline,
 		dispatchSizes,
-		{ vkcv::DescriptorSetUsage(0, m_motionVectorVisualisationPass.descriptorSet) },
+		{ vkcv::useDescriptorSet(0, m_motionVectorVisualisationPass.descriptorSet) },
 		motionVectorVisualisationPushConstants);
 
 	return m_renderTargets.outputColor;
@@ -398,7 +398,7 @@ void MotionBlur::computeMotionTiles(
 		cmdStream,
 		m_motionVectorMinMaxPass.pipeline,
 		motionTileDispatchCounts,
-		{ vkcv::DescriptorSetUsage(0, m_motionVectorMinMaxPass.descriptorSet) },
+		{ vkcv::useDescriptorSet(0, m_motionVectorMinMaxPass.descriptorSet) },
 		vkcv::PushConstants(0));
 
 	// motion vector min max neighbourhood
@@ -428,6 +428,6 @@ void MotionBlur::computeMotionTiles(
 		cmdStream,
 		m_motionVectorMinMaxNeighbourhoodPass.pipeline,
 		motionTileDispatchCounts,
-		{ vkcv::DescriptorSetUsage(0, m_motionVectorMinMaxNeighbourhoodPass.descriptorSet) },
+		{ vkcv::useDescriptorSet(0, m_motionVectorMinMaxNeighbourhoodPass.descriptorSet) },
 		vkcv::PushConstants(0));
 }
\ No newline at end of file
diff --git a/projects/indirect_draw/src/main.cpp b/projects/indirect_draw/src/main.cpp
index b6e9049b..4e852dbb 100644
--- a/projects/indirect_draw/src/main.cpp
+++ b/projects/indirect_draw/src/main.cpp
@@ -431,10 +431,11 @@ int main(int argc, const char** argv) {
 	modelBuffer.fill(modelMatrix);
 
 	const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = {
-			vkcv::VertexBufferBinding(static_cast<vk::DeviceSize> (0), vkCompiledVertexBuffer.getVulkanHandle() )
+			vkcv::vertexBufferBinding(vkCompiledVertexBuffer.getHandle())
 	};
-
-	const vkcv::Mesh compiledMesh(vertexBufferBindings, vkCompiledIndexBuffer.getVulkanHandle(), 0, vkcv::IndexBitCount::Bit32);
+	
+	vkcv::VertexData vertexData (vertexBufferBindings);
+	vertexData.setIndexBuffer(vkCompiledIndexBuffer.getHandle(), vkcv::IndexBitCount::Bit32);
 
     //assert(compiledMaterial.baseColor.size() == compiledMaterial.metalRough.size());
 
@@ -512,7 +513,7 @@ int main(int argc, const char** argv) {
     ceiledDispatchCount = std::ceil(ceiledDispatchCount);
     const vkcv::DispatchSize dispatchCount = static_cast<uint32_t>(ceiledDispatchCount);
 
-    vkcv::DescriptorSetUsage cullingUsage(0, cullingDescSet, {});
+    vkcv::DescriptorSetUsage cullingUsage (0, cullingDescSet, {});
     vkcv::PushConstants emptyPushConstant(0);
 
     bool updateFrustumPlanes    = true;
@@ -549,15 +550,20 @@ int main(int argc, const char** argv) {
 
         core.recordBufferMemoryBarrier(cmdStream, indirectBuffer.getHandle());
 
-		core.recordIndexedIndirectDrawcallsToCmdStream(
+		vkcv::IndirectDrawcall drawcall (
+				indirectBuffer.getHandle(),
+				vertexData,
+				indexedIndirectCommands.size()
+		);
+		
+		drawcall.useDescriptorSet(0, descriptorSet);
+		
+		core.recordIndirectDrawcallsToCmdStream(
 			cmdStream,
             sponzaPipelineHandle,
             pushConstants,
-			{ vkcv::DescriptorSetUsage(0, descriptorSet) },
-            compiledMesh,
+			{ drawcall },
 			renderTargets,
-			indirectBuffer.getHandle(),
-            indexedIndirectCommands.size(),
 			windowHandle
 		);
 
diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp
index 786674d0..5fab2874 100644
--- a/projects/mesh_shader/src/main.cpp
+++ b/projects/mesh_shader/src/main.cpp
@@ -129,9 +129,10 @@ int main(int argc, const char** argv) {
 	});
 
 	const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = {
-			vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()),
-			vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()),
-			vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) };
+			vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[0].offset),
+			vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[1].offset),
+			vkcv::vertexBufferBinding(vertexBuffer.getHandle(), attributes[2].offset)
+	};
 
 	const auto& bunny = mesh.vertexGroups[0];
 	std::vector<vkcv::meshlet::Vertex> interleavedVertices = vkcv::meshlet::convertToVertices(bunny.vertexBuffer.data, bunny.numVertices, attributes[0], attributes[1]);
@@ -282,7 +283,9 @@ int main(int argc, const char** argv) {
     vkcv::ImageHandle depthBuffer;
 	vkcv::ImageHandle swapchainImageHandle = vkcv::ImageHandle::createSwapchainImageHandle();
 
-    const vkcv::Mesh renderMesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), mesh.vertexGroups[0].numIndices, vkcv::IndexBitCount::Bit32);
+	vkcv::VertexData vertexData (vertexBufferBindings);
+	vertexData.setIndexBuffer(indexBuffer.getHandle(), vkcv::IndexBitCount::Bit32);
+	vertexData.setCount(mesh.vertexGroups[0].numIndices);
 
 	const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
 
@@ -334,26 +337,28 @@ int main(int argc, const char** argv) {
 		pushConstantData.appendDrawcall(pushConstants);
 
 		if (useMeshShader) {
-
-			vkcv::DescriptorSetUsage descriptorUsage(0, meshShaderDescriptorSet);
 			const uint32_t taskCount = (meshShaderModelData.meshlets.size() + 31) / 32;
+			
+			vkcv::TaskDrawcall drawcall (taskCount);
+			drawcall.useDescriptorSet(0, meshShaderDescriptorSet);
 
 			core.recordMeshShaderDrawcalls(
 				cmdStream,
 				meshShaderPipeline,
 				pushConstantData,
-				{ vkcv::MeshShaderDrawcall({descriptorUsage}, taskCount)},
+				{ drawcall },
 				{ renderTargets },
 				windowHandle
 			);
 		} else {
-			vkcv::DescriptorSetUsage descriptorUsage(0, vertexShaderDescriptorSet);
+			vkcv::InstanceDrawcall drawcall (vertexData);
+			drawcall.useDescriptorSet(0, vertexShaderDescriptorSet);
 
 			core.recordDrawcallsToCmdStream(
 				cmdStream,
 				bunnyPipeline,
 				pushConstantData,
-				{ vkcv::DrawcallInfo(renderMesh, { descriptorUsage }) },
+				{ drawcall },
 				{ renderTargets },
 				windowHandle
 			);
diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp
index 147a6109..62a61806 100644
--- a/projects/particle_simulation/src/main.cpp
+++ b/projects/particle_simulation/src/main.cpp
@@ -98,7 +98,8 @@ int main(int argc, const char **argv) {
     const std::vector<vkcv::VertexAttachment> vertexAttachments = particleShaderProgram.getVertexAttachments();
 
     const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = {
-            vkcv::VertexBufferBinding(0, vertexBuffer.getVulkanHandle())};
+            vkcv::vertexBufferBinding(vertexBuffer.getHandle())
+	};
 
     std::vector<vkcv::VertexBinding> bindings;
     for (size_t i = 0; i < vertexAttachments.size(); i++) {
@@ -170,8 +171,10 @@ int main(int argc, const char **argv) {
 
     const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
 
-    const vkcv::Mesh renderMesh({vertexBufferBindings}, particleIndexBuffer.getVulkanHandle(),
-                                particleIndexBuffer.getCount());
+	vkcv::VertexData vertexData (vertexBufferBindings);
+	vertexData.setIndexBuffer(particleIndexBuffer.getHandle());
+	vertexData.setCount(particleIndexBuffer.getCount());
+	
     vkcv::DescriptorSetUsage descriptorUsage(0, descriptorSet);
 
     auto pos = glm::vec2(0.f);
@@ -186,8 +189,9 @@ int main(int argc, const char **argv) {
     });
 
     std::vector<glm::mat4> modelMatrices;
-    std::vector<vkcv::DrawcallInfo> drawcalls;
-    drawcalls.push_back(vkcv::DrawcallInfo(renderMesh, {descriptorUsage}, particleSystem.getParticles().size()));
+	
+	vkcv::InstanceDrawcall drawcall (vertexData, particleSystem.getParticles().size());
+	drawcall.useDescriptorSet(0, descriptorSet);
 	
     glm::vec4 colorData = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f);
     uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
@@ -279,7 +283,7 @@ int main(int argc, const char **argv) {
                 cmdStream,
                 particlePipeline,
 				pushConstantsDraw,
-                {drawcalls},
+                { drawcall },
                 { colorBuffer },
                 windowHandle
 		);
@@ -307,8 +311,9 @@ int main(int argc, const char **argv) {
             cmdStream, 
             tonemappingPipe, 
             tonemappingDispatchCount, 
-            {vkcv::DescriptorSetUsage(0, tonemappingDescriptor) },
-            vkcv::PushConstants(0));
+            { vkcv::useDescriptorSet(0, tonemappingDescriptor) },
+            vkcv::PushConstants(0)
+		);
 
         core.prepareSwapchainImageForPresent(cmdStream);
         core.submitCommandStream(cmdStream);
diff --git a/projects/path_tracer/src/main.cpp b/projects/path_tracer/src/main.cpp
index 808490f7..9a89696e 100644
--- a/projects/path_tracer/src/main.cpp
+++ b/projects/path_tracer/src/main.cpp
@@ -334,7 +334,7 @@ int main(int argc, const char** argv) {
 			core.recordComputeDispatchToCmdStream(cmdStream,
 				imageClearPipeline,
 				fullscreenDispatchCount,
-				{ vkcv::DescriptorSetUsage(0, imageClearDescriptorSet) },
+				{ vkcv::useDescriptorSet(0, imageClearDescriptorSet) },
 				vkcv::PushConstants(0));
 
 			clearMeanImage = false;
@@ -369,7 +369,7 @@ int main(int argc, const char** argv) {
 		core.recordComputeDispatchToCmdStream(cmdStream,
 			tracePipeline,
 			traceDispatchCount,
-			{ vkcv::DescriptorSetUsage(0, traceDescriptorSet) },
+			{ vkcv::useDescriptorSet(0, traceDescriptorSet) },
 			pushConstantsCompute);
 
 		core.prepareImageForStorage(cmdStream, meanImage);
@@ -379,7 +379,7 @@ int main(int argc, const char** argv) {
 		core.recordComputeDispatchToCmdStream(cmdStream,
 			imageCombinePipeline,
 			fullscreenDispatchCount,
-			{ vkcv::DescriptorSetUsage(0, imageCombineDescriptorSet) },
+			{ vkcv::useDescriptorSet(0, imageCombineDescriptorSet) },
 			vkcv::PushConstants(0));
 
 		core.recordImageMemoryBarrier(cmdStream, meanImage);
@@ -401,7 +401,7 @@ int main(int argc, const char** argv) {
 		core.recordComputeDispatchToCmdStream(cmdStream,
 			presentPipeline,
 			fullscreenDispatchCount,
-			{ vkcv::DescriptorSetUsage(0, presentDescriptorSet) },
+			{ vkcv::useDescriptorSet(0, presentDescriptorSet) },
 			vkcv::PushConstants(0));
 
 		core.prepareSwapchainImageForPresent(cmdStream);
diff --git a/projects/rtx_ambient_occlusion/src/main.cpp b/projects/rtx_ambient_occlusion/src/main.cpp
index eb1a9253..d3d29049 100644
--- a/projects/rtx_ambient_occlusion/src/main.cpp
+++ b/projects/rtx_ambient_occlusion/src/main.cpp
@@ -134,7 +134,7 @@ int main(int argc, const char** argv) {
 			rtxRegions.rmissRegion,
 			rtxRegions.rchitRegion,
 			rtxRegions.rcallRegion,
-			{	vkcv::DescriptorSetUsage(0, rtxShaderDescriptorSet)},
+			{ vkcv::useDescriptorSet(0, rtxShaderDescriptorSet) },
 			pushConstantsRTX,
 			windowHandle);
 
diff --git a/projects/saf_r/src/main.cpp b/projects/saf_r/src/main.cpp
index 2ddbd0cf..1f446a8f 100644
--- a/projects/saf_r/src/main.cpp
+++ b/projects/saf_r/src/main.cpp
@@ -181,9 +181,12 @@ int main(int argc, const char** argv) {
 		return EXIT_FAILURE;
 	}
 	
-	const vkcv::Mesh renderMesh({}, safrIndexBuffer.getVulkanHandle(), 3);
-	vkcv::DescriptorSetUsage descriptorUsage(0, descriptorSet);
-	vkcv::DrawcallInfo drawcall(renderMesh, { descriptorUsage }, 1);
+	vkcv::VertexData vertexData;
+	vertexData.setIndexBuffer(safrIndexBuffer.getHandle());
+	vertexData.setCount(3);
+	
+	vkcv::InstanceDrawcall drawcall (vertexData);
+	drawcall.useDescriptorSet(0, descriptorSet);
 
 	//create the camera
 	vkcv::camera::CameraManager cameraManager(window);
@@ -250,7 +253,7 @@ int main(int argc, const char** argv) {
 		core.recordComputeDispatchToCmdStream(cmdStream,
 			computePipeline,
 			computeDispatchCount,
-			{ vkcv::DescriptorSetUsage(0, computeDescriptorSet) },
+			{ vkcv::useDescriptorSet(0, computeDescriptorSet) },
 			pushConstantsCompute
 		);
 
diff --git a/projects/sph/src/main.cpp b/projects/sph/src/main.cpp
index 8d41b3bc..4989b037 100644
--- a/projects/sph/src/main.cpp
+++ b/projects/sph/src/main.cpp
@@ -96,7 +96,8 @@ int main(int argc, const char **argv) {
     const std::vector<vkcv::VertexAttachment> vertexAttachments = particleShaderProgram.getVertexAttachments();
 
     const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = {
-            vkcv::VertexBufferBinding(0, vertexBuffer.getVulkanHandle())};
+            vkcv::vertexBufferBinding(vertexBuffer.getHandle())
+	};
 
     std::vector<vkcv::VertexBinding> bindings;
     for (size_t i = 0; i < vertexAttachments.size(); i++) {
@@ -197,14 +198,14 @@ int main(int argc, const char **argv) {
 
     const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
 
-    const vkcv::Mesh renderMesh({vertexBufferBindings}, particleIndexBuffer.getVulkanHandle(),
-                                particleIndexBuffer.getCount());
-    vkcv::DescriptorSetUsage descriptorUsage(0, descriptorSet);
+	vkcv::VertexData vertexData (vertexBufferBindings);
+	vertexData.setIndexBuffer(particleIndexBuffer.getHandle());
+	vertexData.setCount(particleIndexBuffer.getCount());
 
     auto pos = glm::vec2(0.f);
-
-    std::vector<vkcv::DrawcallInfo> drawcalls;
-    drawcalls.push_back(vkcv::DrawcallInfo(renderMesh, {descriptorUsage}, numberParticles));
+	
+	vkcv::InstanceDrawcall drawcall (vertexData, numberParticles);
+	drawcall.useDescriptorSet(0, descriptorSet);
 	
     glm::vec4 colorData = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f);
     uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
@@ -329,7 +330,7 @@ int main(int argc, const char **argv) {
 				cmdStream,
 				pressurePipeline,
 				computeDispatchCount,
-				{vkcv::DescriptorSetUsage(0, pressureDescriptorSet)},
+				{ vkcv::useDescriptorSet(0, pressureDescriptorSet) },
 				pushConstantsCompute
 		);
 
@@ -341,7 +342,7 @@ int main(int argc, const char **argv) {
 				cmdStream,
 				forcePipeline,
 				computeDispatchCount,
-				{vkcv::DescriptorSetUsage(0, forceDescriptorSet)},
+				{ vkcv::useDescriptorSet(0, forceDescriptorSet) },
 				pushConstantsCompute
 		);
 
@@ -353,7 +354,7 @@ int main(int argc, const char **argv) {
 				cmdStream,
 				updateDataPipeline,
 				computeDispatchCount,
-				{ vkcv::DescriptorSetUsage(0, updateDataDescriptorSet) },
+				{ vkcv::useDescriptorSet(0, updateDataDescriptorSet) },
 				pushConstantsCompute
 		);
 
@@ -365,7 +366,7 @@ int main(int argc, const char **argv) {
 				cmdStream,
 				flipPipeline,
 				computeDispatchCount,
-				{ vkcv::DescriptorSetUsage(0, flipDescriptorSet) },
+				{ vkcv::useDescriptorSet(0, flipDescriptorSet) },
 				pushConstantsCompute
 		);
 
@@ -381,7 +382,7 @@ int main(int argc, const char **argv) {
                 cmdStream,
                 particlePipeline,
 				pushConstantsDraw,
-                {drawcalls},
+                { drawcall },
                 { colorBuffer },
                 windowHandle
 		);
@@ -409,7 +410,7 @@ int main(int argc, const char **argv) {
             cmdStream, 
             tonemappingPipe, 
             tonemappingDispatchCount, 
-            {vkcv::DescriptorSetUsage(0, tonemappingDescriptor) },
+            { vkcv::useDescriptorSet(0, tonemappingDescriptor) },
             vkcv::PushConstants(0)
 		);
 
diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp
index 01b2a3c3..73f98cd3 100644
--- a/projects/voxelization/src/ShadowMapping.cpp
+++ b/projects/voxelization/src/ShadowMapping.cpp
@@ -222,18 +222,18 @@ ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vert
 }
 
 void ShadowMapping::recordShadowMapRendering(
-	const vkcv::CommandStreamHandle&    cmdStream,
-	const glm::vec2&                    lightAngleRadian,
-	const glm::vec3&                    lightColor,
-	float                               lightStrength,
-	float                               maxShadowDistance,
-	const std::vector<vkcv::Mesh>&      meshes,
-	const std::vector<glm::mat4>&       modelMatrices,
-	const vkcv::camera::Camera&         camera,
-	const glm::vec3&                    voxelVolumeOffset,
-	float                               voxelVolumeExtent,
-	const vkcv::WindowHandle&           windowHandle,
-	vkcv::Downsampler&					downsampler) {
+	const vkcv::CommandStreamHandle&     cmdStream,
+	const glm::vec2&                     lightAngleRadian,
+	const glm::vec3&                     lightColor,
+	float                                lightStrength,
+	float                                maxShadowDistance,
+	const std::vector<vkcv::VertexData>& meshes,
+	const std::vector<glm::mat4>&        modelMatrices,
+	const vkcv::camera::Camera&          camera,
+	const glm::vec3&                     voxelVolumeOffset,
+	float                                voxelVolumeExtent,
+	const vkcv::WindowHandle&            windowHandle,
+	vkcv::Downsampler&					 downsampler) {
 
 	LightInfo lightInfo;
 	lightInfo.sunColor = lightColor;
@@ -257,9 +257,9 @@ void ShadowMapping::recordShadowMapRendering(
 		shadowPushConstants.appendDrawcall(lightInfo.lightMatrix * m);
 	}
 	
-	std::vector<vkcv::DrawcallInfo> drawcalls;
+	std::vector<vkcv::InstanceDrawcall> drawcalls;
 	for (const auto& mesh : meshes) {
-		drawcalls.push_back(vkcv::DrawcallInfo(mesh, {}));
+		drawcalls.push_back(vkcv::InstanceDrawcall(mesh));
 	}
 
 	m_corePtr->recordBeginDebugLabel(cmdStream, "Shadow map depth", {1, 1, 1, 1});
@@ -292,7 +292,7 @@ void ShadowMapping::recordShadowMapRendering(
 		cmdStream,
 		m_depthToMomentsPipe,
 		dispatchCount,
-		{ vkcv::DescriptorSetUsage(0, m_depthToMomentsDescriptorSet) },
+		{ vkcv::useDescriptorSet(0, m_depthToMomentsDescriptorSet) },
 		msaaPushConstants
 	);
 	m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle());
@@ -306,7 +306,7 @@ void ShadowMapping::recordShadowMapRendering(
 		cmdStream,
 		m_shadowBlurXPipe,
 		dispatchCount,
-		{ vkcv::DescriptorSetUsage(0, m_shadowBlurXDescriptorSet) },
+		{ vkcv::useDescriptorSet(0, m_shadowBlurXDescriptorSet) },
 		vkcv::PushConstants(0)
 	);
 	m_corePtr->prepareImageForSampling(cmdStream, m_shadowMapIntermediate.getHandle());
@@ -317,7 +317,7 @@ void ShadowMapping::recordShadowMapRendering(
 		cmdStream,
 		m_shadowBlurYPipe,
 		dispatchCount,
-		{ vkcv::DescriptorSetUsage(0, m_shadowBlurYDescriptorSet) },
+		{ vkcv::useDescriptorSet(0, m_shadowBlurYDescriptorSet) },
 		vkcv::PushConstants(0)
 	);
 	m_shadowMap.recordMipChainGeneration(cmdStream, downsampler);
diff --git a/projects/voxelization/src/ShadowMapping.hpp b/projects/voxelization/src/ShadowMapping.hpp
index ed1eaed5..a843a7de 100644
--- a/projects/voxelization/src/ShadowMapping.hpp
+++ b/projects/voxelization/src/ShadowMapping.hpp
@@ -23,18 +23,18 @@ public:
 	ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vertexLayout);
 
 	void recordShadowMapRendering(
-		const vkcv::CommandStreamHandle&    cmdStream,
-		const glm::vec2&                    lightAngleRadian,
-		const glm::vec3&                    lightColor,
-		float                               lightStrength,
-		float                               maxShadowDistance,
-		const std::vector<vkcv::Mesh>&      meshes,
-		const std::vector<glm::mat4>&       modelMatrices,
-		const vkcv::camera::Camera&         camera,
-		const glm::vec3&                    voxelVolumeOffset,
-		float                               voxelVolumeExtent,
-		const vkcv::WindowHandle&           windowHandle,
-		vkcv::Downsampler&					downsampler);
+		const vkcv::CommandStreamHandle&     cmdStream,
+		const glm::vec2&                     lightAngleRadian,
+		const glm::vec3&                     lightColor,
+		float                                lightStrength,
+		float                                maxShadowDistance,
+		const std::vector<vkcv::VertexData>& meshes,
+		const std::vector<glm::mat4>&        modelMatrices,
+		const vkcv::camera::Camera&          camera,
+		const glm::vec3&                     voxelVolumeOffset,
+		float                                voxelVolumeExtent,
+		const vkcv::WindowHandle&            windowHandle,
+		vkcv::Downsampler&					 downsampler);
 
 	vkcv::ImageHandle   getShadowMap();
 	vkcv::SamplerHandle getShadowSampler();
diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp
index 9fd41827..f7401124 100644
--- a/projects/voxelization/src/Voxelization.cpp
+++ b/projects/voxelization/src/Voxelization.cpp
@@ -212,7 +212,7 @@ Voxelization::Voxelization(
 
 void Voxelization::voxelizeMeshes(
 	vkcv::CommandStreamHandle                       cmdStream,
-	const std::vector<vkcv::Mesh>&                  meshes,
+	const std::vector<vkcv::VertexData>&            meshes,
 	const std::vector<glm::mat4>&                   modelMatrices,
 	const std::vector<vkcv::DescriptorSetHandle>&   perMeshDescriptorSets,
 	const vkcv::WindowHandle&                       windowHandle,
@@ -256,14 +256,12 @@ void Voxelization::voxelizeMeshes(
 	m_corePtr->recordEndDebugLabel(cmdStream);
 
 	// voxelization
-	std::vector<vkcv::DrawcallInfo> drawcalls;
+	std::vector<vkcv::InstanceDrawcall> drawcalls;
 	for (size_t i = 0; i < meshes.size(); i++) {
-		drawcalls.push_back(vkcv::DrawcallInfo(
-			meshes[i],
-			{ 
-				vkcv::DescriptorSetUsage(0, m_voxelizationDescriptorSet),
-				vkcv::DescriptorSetUsage(1, perMeshDescriptorSets[i])
-			},1));
+		vkcv::InstanceDrawcall drawcall (meshes[i]);
+		drawcall.useDescriptorSet(0, m_voxelizationDescriptorSet);
+		drawcall.useDescriptorSet(1, perMeshDescriptorSets[i]);
+		drawcalls.push_back(drawcall);
 	}
 
 	m_corePtr->recordBeginDebugLabel(cmdStream, "Voxelization", { 1, 1, 1, 1 });
@@ -338,10 +336,12 @@ void Voxelization::renderVoxelVisualisation(
 	m_corePtr->writeDescriptorSet(m_visualisationDescriptorSet, voxelVisualisationDescriptorWrite);
 
 	uint32_t drawVoxelCount = voxelCount / exp2(mipLevel);
-
-	const auto drawcall = vkcv::DrawcallInfo(
-		vkcv::Mesh({}, nullptr, drawVoxelCount),
-		{ vkcv::DescriptorSetUsage(0, m_visualisationDescriptorSet) },1);
+	
+	vkcv::VertexData voxelData;
+	voxelData.setCount(drawVoxelCount);
+	
+	vkcv::InstanceDrawcall drawcall (voxelData);
+	drawcall.useDescriptorSet(0, m_visualisationDescriptorSet);
 
 	m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel visualisation", { 1, 1, 1, 1 });
 	m_corePtr->prepareImageForStorage(cmdStream, m_voxelImage.getHandle());
diff --git a/projects/voxelization/src/Voxelization.hpp b/projects/voxelization/src/Voxelization.hpp
index 2e71b1fc..f624d035 100644
--- a/projects/voxelization/src/Voxelization.hpp
+++ b/projects/voxelization/src/Voxelization.hpp
@@ -25,7 +25,7 @@ public:
 
 	void voxelizeMeshes(
 		vkcv::CommandStreamHandle                       cmdStream,
-		const std::vector<vkcv::Mesh>&                  meshes,
+		const std::vector<vkcv::VertexData>&            meshes,
 		const std::vector<glm::mat4>&                   modelMatrices,
 		const std::vector<vkcv::DescriptorSetHandle>&   perMeshDescriptorSets,
 		const vkcv::WindowHandle&                       windowHandle,
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index 862ac3c2..740de623 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -175,7 +175,10 @@ int main(int argc, const char** argv) {
 	for (const auto& vertexGroup : scene.vertexGroups) {
 		for (const auto& attribute : vertexGroup.vertexBuffer.attributes) {
 			vAttributes.push_back(attribute);
-			vBufferBindings.push_back(vkcv::VertexBufferBinding(attribute.offset, vertexBuffers[vertexBufferIndex].getVulkanHandle()));
+			vBufferBindings.push_back(vkcv::vertexBufferBinding(
+					vertexBuffers[vertexBufferIndex].getHandle(),
+					attribute.offset
+			));
 		}
 		vertexBufferBindings.push_back(vBufferBindings);
 		vBufferBindings.clear();
@@ -512,22 +515,27 @@ int main(int argc, const char** argv) {
 	}
 
 	// prepare meshes
-	std::vector<vkcv::Mesh> meshes;
+	std::vector<vkcv::VertexData> meshes;
 	for (size_t i = 0; i < scene.vertexGroups.size(); i++) {
-		vkcv::Mesh mesh(vertexBufferBindings[i], indexBuffers[i].getVulkanHandle(), scene.vertexGroups[i].numIndices);
+		vkcv::VertexData mesh (vertexBufferBindings[i]);
+		mesh.setIndexBuffer(indexBuffers[i].getHandle());
+		mesh.setCount(scene.vertexGroups[i].numIndices);
 		meshes.push_back(mesh);
 	}
 
-	std::vector<vkcv::DrawcallInfo> drawcalls;
-	std::vector<vkcv::DrawcallInfo> prepassDrawcalls;
+	std::vector<vkcv::InstanceDrawcall> drawcalls;
+	std::vector<vkcv::InstanceDrawcall> prepassDrawcalls;
 	for (size_t i = 0; i < meshes.size(); i++) {
-
-		drawcalls.push_back(vkcv::DrawcallInfo(meshes[i], { 
-			vkcv::DescriptorSetUsage(0, forwardShadingDescriptorSet),
-			vkcv::DescriptorSetUsage(1, perMeshDescriptorSets[i]) }));
-		prepassDrawcalls.push_back(vkcv::DrawcallInfo(meshes[i], {
-			vkcv::DescriptorSetUsage(0, prepassDescriptorSet),
-			vkcv::DescriptorSetUsage(1, perMeshDescriptorSets[i]) }));
+		vkcv::InstanceDrawcall drawcall (meshes[i]);
+		drawcall.useDescriptorSet(0, forwardShadingDescriptorSet);
+		drawcall.useDescriptorSet(1, perMeshDescriptorSets[i]);
+		
+		vkcv::InstanceDrawcall prepassDrawcall (meshes[i]);
+		prepassDrawcall.useDescriptorSet(0, prepassDescriptorSet);
+		prepassDrawcall.useDescriptorSet(1, perMeshDescriptorSets[i]);
+		
+		drawcalls.push_back(drawcall);
+		prepassDrawcalls.push_back(prepassDrawcall);
 	}
 
 	vkcv::SamplerHandle voxelSampler = vkcv::samplerLinear(core, true);
@@ -810,6 +818,9 @@ int main(int argc, const char** argv) {
 		
 		vkcv::PushConstants skySettingsPushConstants = vkcv::pushConstants<SkySettings>();
 		skySettingsPushConstants.appendDrawcall(skySettings);
+		
+		vkcv::VertexData skyData;
+		skyData.setCount(3);
 
 		// sky
 		core.recordBeginDebugLabel(cmdStream, "Sky", { 1, 1, 1, 1 });
@@ -817,7 +828,7 @@ int main(int argc, const char** argv) {
 			cmdStream,
 			skyPipe,
 			skySettingsPushConstants,
-			{ vkcv::DrawcallInfo(vkcv::Mesh({}, nullptr, 3), {}) },
+			{ vkcv::InstanceDrawcall(skyData) },
 			renderTargets,
 			windowHandle
 		);
@@ -840,7 +851,7 @@ int main(int argc, const char** argv) {
 						cmdStream,
 						resolvePipeline,
 						fullscreenDispatchCount,
-						{ vkcv::DescriptorSetUsage(0, resolveDescriptorSet) },
+						{ vkcv::useDescriptorSet(0, resolveDescriptorSet) },
 						vkcv::PushConstants(0)
 				);
 
@@ -863,7 +874,7 @@ int main(int argc, const char** argv) {
 				cmdStream,
 				tonemappingPipeline,
 				fullscreenDispatchCount,
-				{ vkcv::DescriptorSetUsage(0, tonemappingDescriptorSet) },
+				{ vkcv::useDescriptorSet(0, tonemappingDescriptorSet) },
 				vkcv::PushConstants(0)
 		);
 		
@@ -901,7 +912,7 @@ int main(int argc, const char** argv) {
 				cmdStream,
 				postEffectsPipeline,
 				fullscreenDispatchCount,
-				{ vkcv::DescriptorSetUsage(0, postEffectsDescriptorSet) },
+				{ vkcv::useDescriptorSet(0, postEffectsDescriptorSet) },
 				timePushConstants
 		);
 		core.recordEndDebugLabel(cmdStream);
diff --git a/projects/wobble_bobble/src/main.cpp b/projects/wobble_bobble/src/main.cpp
index 58a07deb..e4f02691 100644
--- a/projects/wobble_bobble/src/main.cpp
+++ b/projects/wobble_bobble/src/main.cpp
@@ -548,16 +548,8 @@ int main(int argc, const char **argv) {
 		glm::vec2(+1.0f, -1.0f)
 	});
 	
-	vkcv::Buffer<uint16_t> triangleIndices = vkcv::buffer<uint16_t>(core, vkcv::BufferType::INDEX, 3);
-	triangleIndices.fill({
-		0, 1, 2
-	});
-	
-	vkcv::Mesh triangleMesh (
-			{ vkcv::VertexBufferBinding(0, trianglePositions.getVulkanHandle()) },
-			triangleIndices.getVulkanHandle(),
-			triangleIndices.getCount()
-	);
+	vkcv::VertexData triangleData ({ vkcv::vertexBufferBinding(trianglePositions.getHandle()) });
+	triangleData.setCount(trianglePositions.getCount());
 	
 	vkcv::Buffer<glm::vec3> linesPositions = vkcv::buffer<glm::vec3>(core, vkcv::BufferType::VERTEX, 8);
 	linesPositions.fill({
@@ -589,38 +581,23 @@ int main(int argc, const char **argv) {
 		3, 7
 	});
 	
-	vkcv::Mesh linesMesh (
-			{ vkcv::VertexBufferBinding(0, linesPositions.getVulkanHandle()) },
-			linesIndices.getVulkanHandle(),
-			linesIndices.getCount()
-	);
-	
-	std::vector<vkcv::DrawcallInfo> drawcallsGrid;
+	vkcv::VertexData linesData ({ vkcv::vertexBufferBinding(linesPositions.getHandle()) });
+	linesData.setIndexBuffer(linesIndices.getHandle());
+	linesData.setCount(linesIndices.getCount());
 	
-	drawcallsGrid.push_back(vkcv::DrawcallInfo(
-			triangleMesh,
-			{ vkcv::DescriptorSetUsage(0, gfxSetGrid) },
+	vkcv::InstanceDrawcall drawcallGrid (
+			triangleData,
 			grid.getWidth() * grid.getHeight() * grid.getDepth()
-	));
-	
-	std::vector<vkcv::DrawcallInfo> drawcallsParticles;
+	);
 	
-	drawcallsParticles.push_back(vkcv::DrawcallInfo(
-			triangleMesh,
-			{ vkcv::DescriptorSetUsage(0, gfxSetParticles) },
-			sim->count
-	));
+	drawcallGrid.useDescriptorSet(0, gfxSetGrid);
 	
-	std::vector<vkcv::DrawcallInfo> drawcallsLines;
+	vkcv::InstanceDrawcall drawcallParticle (triangleData, sim->count);
+	drawcallParticle.useDescriptorSet(0, gfxSetParticles);
 	
-	drawcallsLines.push_back(vkcv::DrawcallInfo(
-			linesMesh,
-			{},
-			1
-	));
+	vkcv::InstanceDrawcall drawcallLines (linesData);
 	
 	bool renderGrid = true;
-	
 	float speed_factor = 1.0f;
 	
 	core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt,
@@ -669,10 +646,10 @@ int main(int argc, const char **argv) {
 					initParticleWeightsPipeline,
 					dispatchSizeParticles,
 					{
-						vkcv::DescriptorSetUsage(
+						vkcv::useDescriptorSet(
 								0, initParticleWeightsSets[0]
 						),
-						vkcv::DescriptorSetUsage(
+						vkcv::useDescriptorSet(
 								1, initParticleWeightsSets[1]
 						)
 					},
@@ -691,13 +668,13 @@ int main(int argc, const char **argv) {
 					transformParticlesToGridPipeline,
 					dispatchSizeGrid,
 					{
-						vkcv::DescriptorSetUsage(
+						vkcv::useDescriptorSet(
 								0, transformParticlesToGridSets[0]
 						),
-						vkcv::DescriptorSetUsage(
+						vkcv::useDescriptorSet(
 								1, transformParticlesToGridSets[1]
 						),
-						vkcv::DescriptorSetUsage(
+						vkcv::useDescriptorSet(
 								2, transformParticlesToGridSets[2]
 						)
 					},
@@ -717,13 +694,13 @@ int main(int argc, const char **argv) {
 					updateParticleVelocitiesPipeline,
 					dispatchSizeParticles,
 					{
-						vkcv::DescriptorSetUsage(
+						vkcv::useDescriptorSet(
 								0, updateParticleVelocitiesSets[0]
 						),
-						vkcv::DescriptorSetUsage(
+						vkcv::useDescriptorSet(
 								1, updateParticleVelocitiesSets[1]
 						),
-						vkcv::DescriptorSetUsage(
+						vkcv::useDescriptorSet(
 								2, updateParticleVelocitiesSets[2]
 						)
 					},
@@ -748,7 +725,7 @@ int main(int argc, const char **argv) {
 					cmdStream,
 					gfxPipelineGrid,
 					cameraPushConstants,
-					drawcallsGrid,
+					{ drawcallGrid },
 					renderTargets,
 					windowHandle
 			);
@@ -762,7 +739,7 @@ int main(int argc, const char **argv) {
 					cmdStream,
 					gfxPipelineParticles,
 					cameraPushConstants,
-					drawcallsParticles,
+					{ drawcallParticle },
 					renderTargets,
 					windowHandle
 			);
@@ -776,7 +753,7 @@ int main(int argc, const char **argv) {
 				cmdStream,
 				gfxPipelineLines,
 				cameraPushConstants,
-				drawcallsLines,
+				{ drawcallLines },
 				renderTargets,
 				windowHandle
 		);
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 3d7d126c..576ddc4d 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -396,24 +396,32 @@ namespace vkcv
 	}
 	
 	static void recordDrawcall(const DescriptorSetManager &descriptorSetManager,
-							   const DrawcallInfo &drawcall,
+							   const BufferManager &bufferManager,
+							   const InstanceDrawcall &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];
-			cmdBuffer.bindVertexBuffers(i, vertexBinding.buffer, vertexBinding.offset);
+		const auto& vertexData = drawcall.getVertexData();
+		
+		for (uint32_t i = 0; i < vertexData.getVertexBufferBindings().size(); i++) {
+			const auto& vertexBinding = vertexData.getVertexBufferBindings()[i];
+			
+			cmdBuffer.bindVertexBuffers(
+					i,
+					bufferManager.getBuffer(vertexBinding.buffer),
+					vertexBinding.offset
+			);
 		}
 		
-		for (const auto& descriptorUsage : drawcall.descriptorSets) {
+		for (const auto& usage : drawcall.getDescriptorSetUsages()) {
 			cmdBuffer.bindDescriptorSets(
 					vk::PipelineBindPoint::eGraphics,
 					pipelineLayout,
-					descriptorUsage.setLocation,
-					descriptorSetManager.getDescriptorSet(descriptorUsage.descriptorSet).vulkanHandle,
-					descriptorUsage.dynamicOffsets
+					usage.location,
+					descriptorSetManager.getDescriptorSet(usage.descriptorSet).vulkanHandle,
+					usage.dynamicOffsets
 			);
 		}
 		
@@ -427,11 +435,16 @@ namespace vkcv
 			);
 		}
 		
-		if (drawcall.mesh.indexBuffer) {
-			cmdBuffer.bindIndexBuffer(drawcall.mesh.indexBuffer, 0, getIndexType(drawcall.mesh.indexBitCount));
-			cmdBuffer.drawIndexed(drawcall.mesh.indexCount, drawcall.instanceCount, 0, 0, {});
+		if (vertexData.getIndexBuffer()) {
+			cmdBuffer.bindIndexBuffer(
+					bufferManager.getBuffer(vertexData.getIndexBuffer()),
+					0,
+					getIndexType(vertexData.getIndexBitCount())
+			);
+			
+			cmdBuffer.drawIndexed(vertexData.getCount(), drawcall.getInstanceCount(), 0, 0, {});
 		} else {
-			cmdBuffer.draw(drawcall.mesh.indexCount, drawcall.instanceCount, 0, 0, {});
+			cmdBuffer.draw(vertexData.getCount(), drawcall.getInstanceCount(), 0, 0, {});
 		}
 	}
 	
@@ -531,7 +544,7 @@ namespace vkcv
 	void Core::recordDrawcallsToCmdStream(const CommandStreamHandle &cmdStreamHandle,
 										  const GraphicsPipelineHandle &pipelineHandle,
 										  const PushConstants &pushConstantData,
-										  const std::vector<DrawcallInfo> &drawcalls,
+										  const std::vector<InstanceDrawcall> &drawcalls,
 										  const std::vector<ImageHandle> &renderTargets,
 										  const WindowHandle &windowHandle) {
 		
@@ -547,6 +560,7 @@ namespace vkcv
 			for (size_t i = 0; i < drawcalls.size(); i++) {
 				recordDrawcall(
 						*m_DescriptorSetManager,
+						*m_BufferManager,
 						drawcalls[i],
 						cmdBuffer,
 						pipelineLayout,
@@ -570,16 +584,76 @@ namespace vkcv
 				recordFunction
 		);
 	}
+	
+	static void recordIndirectDrawcall(const Core& core,
+									   const DescriptorSetManager &descriptorSetManager,
+									   const BufferManager &bufferManager,
+									   vk::CommandBuffer cmdBuffer,
+									   vk::PipelineLayout pipelineLayout,
+									   const PushConstants& pushConstantData,
+									   size_t drawcallIndex,
+									   const IndirectDrawcall& drawcall) {
+		for (const auto& usage : drawcall.getDescriptorSetUsages()) {
+			cmdBuffer.bindDescriptorSets(
+					vk::PipelineBindPoint::eGraphics,
+					pipelineLayout,
+					usage.location,
+					descriptorSetManager.getDescriptorSet(usage.descriptorSet).vulkanHandle,
+					usage.dynamicOffsets
+			);
+		}
+		
+		const auto& vertexData = drawcall.getVertexData();
+		
+		for (uint32_t i = 0; i < vertexData.getVertexBufferBindings().size(); i++) {
+			const auto& vertexBinding = vertexData.getVertexBufferBindings()[i];
+			
+			cmdBuffer.bindVertexBuffers(
+					i,
+					bufferManager.getBuffer(vertexBinding.buffer),
+					vertexBinding.offset
+			);
+		}
+		
+		if (pushConstantData.getSizePerDrawcall() > 0) {
+			cmdBuffer.pushConstants(
+					pipelineLayout,
+					vk::ShaderStageFlagBits::eAll,
+					0,
+					pushConstantData.getSizePerDrawcall(),
+					pushConstantData.getDrawcallData(0)
+			);
+		}
+		
+		if (vertexData.getIndexBuffer()) {
+			cmdBuffer.bindIndexBuffer(
+					bufferManager.getBuffer(vertexData.getIndexBuffer()),
+					0,
+					getIndexType(vertexData.getIndexBitCount())
+			);
+			
+			cmdBuffer.drawIndexedIndirect(
+					bufferManager.getBuffer(drawcall.getIndirectDrawBuffer()),
+					0,
+					drawcall.getDrawCount(),
+					sizeof(vk::DrawIndexedIndirectCommand)
+			);
+		} else {
+			cmdBuffer.drawIndirect(
+					bufferManager.getBuffer(drawcall.getIndirectDrawBuffer()),
+					0,
+					drawcall.getDrawCount(),
+					sizeof(vk::DrawIndirectCommand)
+			);
+		}
+	}
 
-    void Core::recordIndexedIndirectDrawcallsToCmdStream(const CommandStreamHandle cmdStreamHandle,
-														 const GraphicsPipelineHandle &pipelineHandle,
-														 const PushConstants &pushConstantData,
-														 const std::vector<DescriptorSetUsage> &descriptorSetUsages,
-														 const vkcv::Mesh &compiledMesh,
-														 const std::vector<ImageHandle> &renderTargets,
-														 const BufferHandle &indirectBuffer,
-														 const uint32_t drawCount,
-														 const WindowHandle &windowHandle) {
+	void Core::recordIndirectDrawcallsToCmdStream(const vkcv::CommandStreamHandle cmdStreamHandle,
+												  const vkcv::GraphicsPipelineHandle &pipelineHandle,
+												  const vkcv::PushConstants &pushConstantData,
+												  const std::vector<IndirectDrawcall> &drawcalls,
+												  const std::vector<ImageHandle> &renderTargets,
+												  const vkcv::WindowHandle &windowHandle) {
 
         if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
             return;
@@ -590,36 +664,18 @@ namespace vkcv
 		);
 	
 		auto recordFunction = [&](const vk::CommandBuffer& cmdBuffer) {
-			for (const auto& usage : descriptorSetUsages) {
-				cmdBuffer.bindDescriptorSets(
-						vk::PipelineBindPoint::eGraphics,
-						pipelineLayout,
-						usage.setLocation,
-						m_DescriptorSetManager->getDescriptorSet(usage.descriptorSet).vulkanHandle,
-						usage.dynamicOffsets
-				);
-			}
-			
-			if (pushConstantData.getSizePerDrawcall() > 0) {
-				cmdBuffer.pushConstants(
+			for (size_t i = 0; i < drawcalls.size(); i++) {
+				recordIndirectDrawcall(
+						*this,
+						*m_DescriptorSetManager,
+						*m_BufferManager,
+						cmdBuffer,
 						pipelineLayout,
-						vk::ShaderStageFlagBits::eAll,
-						0,
-						pushConstantData.getSizePerDrawcall(),
-						pushConstantData.getDrawcallData(0)
+						pushConstantData,
+						i,
+						drawcalls[i]
 				);
 			}
-			
-			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)
-			);
 		};
 	
 		recordGraphicsPipeline(
@@ -643,7 +699,7 @@ namespace vkcv
 										 vk::PipelineLayout pipelineLayout,
 										 const PushConstants& pushConstantData,
 										 size_t drawcallIndex,
-										 const MeshShaderDrawcall& drawcall) {
+										 const TaskDrawcall& drawcall) {
 		
 		static PFN_vkCmdDrawMeshTasksNV cmdDrawMeshTasks = reinterpret_cast<PFN_vkCmdDrawMeshTasksNV>(
 				core.getContext().getDevice().getProcAddr("vkCmdDrawMeshTasksNV")
@@ -654,11 +710,11 @@ namespace vkcv
 			return;
 		}
 		
-		for (const auto& descriptorUsage : drawcall.descriptorSets) {
+		for (const auto& descriptorUsage : drawcall.getDescriptorSetUsages()) {
 			cmdBuffer.bindDescriptorSets(
 					vk::PipelineBindPoint::eGraphics,
 					pipelineLayout,
-					descriptorUsage.setLocation,
+					descriptorUsage.location,
 					descriptorSetManager.getDescriptorSet(descriptorUsage.descriptorSet).vulkanHandle,
 					descriptorUsage.dynamicOffsets
 			);
@@ -674,13 +730,13 @@ namespace vkcv
 			);
 		}
 		
-		cmdDrawMeshTasks(VkCommandBuffer(cmdBuffer), drawcall.taskCount, 0);
+		cmdDrawMeshTasks(VkCommandBuffer(cmdBuffer), drawcall.getTaskCount(), 0);
 	}
 
 	void Core::recordMeshShaderDrawcalls(const CommandStreamHandle &cmdStreamHandle,
 										 const GraphicsPipelineHandle &pipelineHandle,
 										 const PushConstants &pushConstantData,
-										 const std::vector<MeshShaderDrawcall> &drawcalls,
+										 const std::vector<TaskDrawcall> &drawcalls,
 										 const std::vector<ImageHandle> &renderTargets,
 										 const WindowHandle &windowHandle) {
 		
@@ -704,8 +760,6 @@ namespace vkcv
                     drawcalls[i]
 				);
 			}
-
-			cmdBuffer.endRenderPass();
 		};
 		
 		recordGraphicsPipeline(
@@ -733,7 +787,7 @@ namespace vkcv
 											  vk::StridedDeviceAddressRegionKHR rcallRegion,
 											  const std::vector<DescriptorSetUsage>& descriptorSetUsages,
 											  const PushConstants& pushConstants,
-											  const WindowHandle windowHandle) {
+											  const WindowHandle& windowHandle) {
 
 		auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
 			cmdBuffer.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, rtxPipeline);
@@ -741,7 +795,7 @@ namespace vkcv
 				cmdBuffer.bindDescriptorSets(
 					vk::PipelineBindPoint::eRayTracingKHR,
 					rtxPipelineLayout,
-					usage.setLocation,
+					usage.location,
 					{ m_DescriptorSetManager->getDescriptorSet(usage.descriptorSet).vulkanHandle },
 					usage.dynamicOffsets
 				);
@@ -779,7 +833,7 @@ namespace vkcv
 				cmdBuffer.bindDescriptorSets(
 					vk::PipelineBindPoint::eCompute,
 					pipelineLayout,
-					usage.setLocation,
+					usage.location,
 					{ m_DescriptorSetManager->getDescriptorSet(usage.descriptorSet).vulkanHandle },
 					usage.dynamicOffsets
 				);
@@ -859,7 +913,7 @@ namespace vkcv
 				cmdBuffer.bindDescriptorSets(
 					vk::PipelineBindPoint::eCompute,
 					pipelineLayout,
-					usage.setLocation,
+					usage.location,
 					{ m_DescriptorSetManager->getDescriptorSet(usage.descriptorSet).vulkanHandle },
 					usage.dynamicOffsets
 				);
diff --git a/src/vkcv/DescriptorSetUsage.cpp b/src/vkcv/DescriptorSetUsage.cpp
new file mode 100644
index 00000000..4d1ab2ec
--- /dev/null
+++ b/src/vkcv/DescriptorSetUsage.cpp
@@ -0,0 +1,12 @@
+
+#include "vkcv/DescriptorSetUsage.hpp"
+
+namespace vkcv {
+	
+	DescriptorSetUsage useDescriptorSet(uint32_t location, const DescriptorSetHandle &descriptorSet,
+										const std::vector<uint32_t> &dynamicOffsets) {
+		DescriptorSetUsage usage (location, descriptorSet, dynamicOffsets);
+		return usage;
+	}
+	
+}
diff --git a/src/vkcv/Drawcall.cpp b/src/vkcv/Drawcall.cpp
new file mode 100644
index 00000000..657481eb
--- /dev/null
+++ b/src/vkcv/Drawcall.cpp
@@ -0,0 +1,60 @@
+/**
+ * @authors Tobias Frisch
+ * @file src/vkcv/Drawcall.cpp
+ */
+
+#include "vkcv/Drawcall.hpp"
+
+namespace vkcv {
+	
+	const std::vector<DescriptorSetUsage> &Drawcall::getDescriptorSetUsages() const {
+		return m_usages;
+	}
+	
+	void Drawcall::useDescriptorSet(uint32_t location, const DescriptorSetHandle &descriptorSet,
+									const std::vector<uint32_t>& dynamicOffsets) {
+		m_usages.emplace_back(location, descriptorSet, dynamicOffsets);
+	}
+	
+	InstanceDrawcall::InstanceDrawcall(const VertexData &vertexData,
+									   uint32_t instanceCount)
+	: Drawcall(),
+	m_vertexData(vertexData),
+	m_instanceCount(instanceCount) {}
+	
+	const VertexData &InstanceDrawcall::getVertexData() const {
+		return m_vertexData;
+	}
+	
+	uint32_t InstanceDrawcall::getInstanceCount() const {
+		return m_instanceCount;
+	}
+	
+	IndirectDrawcall::IndirectDrawcall(const BufferHandle &indirectDrawBuffer,
+									   const VertexData &vertexData,
+									   uint32_t drawCount)
+	: Drawcall(),
+	m_indirectDrawBuffer(indirectDrawBuffer),
+	m_vertexData(vertexData),
+	m_drawCount(drawCount) {}
+	
+	BufferHandle IndirectDrawcall::getIndirectDrawBuffer() const {
+		return m_indirectDrawBuffer;
+	}
+	
+	const VertexData &IndirectDrawcall::getVertexData() const {
+		return m_vertexData;
+	}
+	
+	uint32_t IndirectDrawcall::getDrawCount() const {
+		return m_drawCount;
+	}
+	
+	TaskDrawcall::TaskDrawcall(uint32_t taskCount)
+	: Drawcall(), m_taskCount(taskCount) {}
+	
+	uint32_t TaskDrawcall::getTaskCount() const {
+		return m_taskCount;
+	}
+	
+}
diff --git a/src/vkcv/VertexData.cpp b/src/vkcv/VertexData.cpp
new file mode 100644
index 00000000..bea3b700
--- /dev/null
+++ b/src/vkcv/VertexData.cpp
@@ -0,0 +1,42 @@
+
+#include "vkcv/VertexData.hpp"
+
+namespace vkcv {
+	
+	VertexBufferBinding vertexBufferBinding(const BufferHandle &buffer, size_t offset) {
+		VertexBufferBinding binding (buffer, offset);
+		return binding;
+	}
+	
+	VertexData::VertexData(const std::vector<VertexBufferBinding> &bindings)
+	: m_bindings(bindings),
+	m_indices(),
+	m_indexBitCount(IndexBitCount::Bit16),
+	m_count(0) {}
+	
+	const std::vector<VertexBufferBinding> &VertexData::getVertexBufferBindings() const {
+		return m_bindings;
+	}
+	
+	void VertexData::setIndexBuffer(const BufferHandle &indices, IndexBitCount indexBitCount) {
+		m_indices = indices;
+		m_indexBitCount = indexBitCount;
+	}
+	
+	const BufferHandle &VertexData::getIndexBuffer() const {
+		return m_indices;
+	}
+	
+	IndexBitCount VertexData::getIndexBitCount() const {
+		return m_indexBitCount;
+	}
+	
+	void VertexData::setCount(size_t count) {
+		m_count = count;
+	}
+	
+	size_t VertexData::getCount() const {
+		return m_count;
+	}
+	
+}
-- 
GitLab