diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index c21ee3d60169b538da113e2cde802dfbf54a2bb3..061a2bd787b78f1af1e948b8a5b0486dff57e249 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -260,5 +260,6 @@ namespace vkcv
 		void prepareSwapchainImageForPresent(const CommandStreamHandle handle);
 		void prepareImageForSampling(const CommandStreamHandle cmdStream, const ImageHandle image);
 		void prepareImageForStorage(const CommandStreamHandle cmdStream, const ImageHandle image);
+		void recordImageMemoryBarrier(const CommandStreamHandle cmdStream, const ImageHandle image);
     };
 }
diff --git a/include/vkcv/PipelineConfig.hpp b/include/vkcv/PipelineConfig.hpp
index 2d1d1488abec25b0e602b9690f4a5b89e506616c..55f659b8ed32af4371eb6631dc19c3978838c122 100644
--- a/include/vkcv/PipelineConfig.hpp
+++ b/include/vkcv/PipelineConfig.hpp
@@ -13,6 +13,8 @@
 
 namespace vkcv {
 
+    enum class PrimitiveTopology{PointList, LineList, TriangleList };
+
     struct PipelineConfig {
         /**
          *  Constructor for the pipeline. Creates a pipeline using @p vertexCode, @p fragmentCode as well as the
@@ -31,7 +33,8 @@ namespace vkcv {
             const std::vector<VertexAttribute>          &vertexAttributes,
             const std::vector<vk::DescriptorSetLayout>  &descriptorLayouts,
             bool                                        useDynamicViewport,
-            bool                                        useConservativeRasterization = false);
+            bool                                        useConservativeRasterization = false,
+            PrimitiveTopology                           primitiveTopology = PrimitiveTopology::TriangleList);
 
         ShaderProgram                           m_ShaderProgram;
         uint32_t                                m_Height;
@@ -41,6 +44,7 @@ namespace vkcv {
         std::vector<vk::DescriptorSetLayout>    m_DescriptorLayouts;
         bool                                    m_UseDynamicViewport;
         bool                                    m_UseConservativeRasterization;
+        PrimitiveTopology                       m_PrimitiveTopology;
     };
 
 }
\ No newline at end of file
diff --git a/modules/camera/include/vkcv/camera/Camera.hpp b/modules/camera/include/vkcv/camera/Camera.hpp
index ff8fda811eaad7a99dbb940601f9e5904025255e..f21dcc4829000e21484866a1c418dbcd10d9440f 100644
--- a/modules/camera/include/vkcv/camera/Camera.hpp
+++ b/modules/camera/include/vkcv/camera/Camera.hpp
@@ -95,7 +95,7 @@ namespace vkcv {
 
         void moveRight(int action);
 
-
+        void setSpeed(float speed);
     };
 
 }
diff --git a/modules/camera/src/vkcv/camera/Camera.cpp b/modules/camera/src/vkcv/camera/Camera.cpp
index af89ed86881acc8b754a041d32599a78caac57b4..f77d55fc09c6735360478557117a2c9f9bddfed0 100644
--- a/modules/camera/src/vkcv/camera/Camera.cpp
+++ b/modules/camera/src/vkcv/camera/Camera.cpp
@@ -176,4 +176,8 @@ namespace vkcv {
     void Camera::moveRight(int action){
         m_right = static_cast<bool>(action);
     }
+
+    void Camera::setSpeed(float speed) {
+        m_cameraSpeed = speed;
+    }
 }
\ No newline at end of file
diff --git a/projects/cmd_sync_test/resources/shaders/compile.bat b/projects/cmd_sync_test/resources/shaders/compile.bat
index d8f0abf7f6bab49c1d57f31058e9fa8fd60b684b..26239841e85e2e4f32d9fc7ecc555ed1b2c78163 100644
--- a/projects/cmd_sync_test/resources/shaders/compile.bat
+++ b/projects/cmd_sync_test/resources/shaders/compile.bat
@@ -1,8 +1,14 @@
 %VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv
 %VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv
+
 %VULKAN_SDK%\Bin32\glslc.exe shadow.vert -o shadow_vert.spv
 %VULKAN_SDK%\Bin32\glslc.exe shadow.frag -o shadow_frag.spv
+
 %VULKAN_SDK%\Bin32\glslc.exe voxelization.vert -o voxelization_vert.spv
 %VULKAN_SDK%\Bin32\glslc.exe voxelization.geom -o voxelization_geom.spv
 %VULKAN_SDK%\Bin32\glslc.exe voxelization.frag -o voxelization_frag.spv
+
+%VULKAN_SDK%\Bin32\glslc.exe voxelVisualisation.vert -o voxelVisualisation_vert.spv
+%VULKAN_SDK%\Bin32\glslc.exe voxelVisualisation.geom -o voxelVisualisation_geom.spv
+%VULKAN_SDK%\Bin32\glslc.exe voxelVisualisation.frag -o voxelVisualisation_frag.spv
 pause
\ No newline at end of file
diff --git a/projects/cmd_sync_test/resources/shaders/voxelVisualisation.frag b/projects/cmd_sync_test/resources/shaders/voxelVisualisation.frag
new file mode 100644
index 0000000000000000000000000000000000000000..e1a363c799a6ede52f07df436653fad3dc455164
--- /dev/null
+++ b/projects/cmd_sync_test/resources/shaders/voxelVisualisation.frag
@@ -0,0 +1,9 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+
+layout(location=0) in vec3 inColor;
+layout(location=0) out vec3 outColor;
+
+void main()	{
+    outColor = inColor;
+}
\ No newline at end of file
diff --git a/projects/cmd_sync_test/resources/shaders/voxelVisualisation.geom b/projects/cmd_sync_test/resources/shaders/voxelVisualisation.geom
new file mode 100644
index 0000000000000000000000000000000000000000..ff0b8b6fd93efe52749a06b9bb54ab227c0a9a18
--- /dev/null
+++ b/projects/cmd_sync_test/resources/shaders/voxelVisualisation.geom
@@ -0,0 +1,103 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+
+layout(points) in;
+layout (triangle_strip, max_vertices = 24) out;
+
+layout( push_constant ) uniform constants{
+    mat4 viewProjection;
+};
+
+layout(location = 0) in float passCubeHalf[1];
+
+layout(location = 0) out vec3 passColor;
+
+void main()	{
+    float cubeHalf = passCubeHalf[0];
+    // right
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, 1, 1), 1);
+    passColor = vec3(1, 0, 0);
+    EmitVertex();
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, 1, -1), 1);
+    passColor = vec3(1, 0, 0);
+    EmitVertex();
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, -1, 1), 1);
+    passColor = vec3(1, 0, 0);
+    EmitVertex();
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, -1, -1), 1);
+    passColor = vec3(1, 0, 0);
+    EmitVertex();
+    EndPrimitive();
+    // left
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, 1, 1), 1);
+    passColor = vec3(1, 0, 0);
+    EmitVertex();
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, 1, -1), 1);
+    passColor = vec3(1, 0, 0);
+    EmitVertex();
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1, 1), 1);
+    passColor = vec3(1, 0, 0);
+    EmitVertex();
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1, -1), 1);
+    passColor = vec3(1, 0, 0);
+    EmitVertex();
+    EndPrimitive();
+    // back
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1,   1, -1), 1);
+    passColor = vec3(1, 0, 0);
+    EmitVertex();                                                                  
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1,  -1, -1), 1);
+    passColor = vec3(1, 0, 0);
+    EmitVertex();                                                                  
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1,  1, -1), 1);
+    passColor = vec3(1, 0, 0);
+    EmitVertex();                                                                  
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1, -1), 1);
+    passColor = vec3(0, 0, 1);
+    EmitVertex();
+    EndPrimitive();
+    // front
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1,   1, 1), 1);
+    passColor = vec3(0, 0, 1);
+    EmitVertex();                                                                  
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1,  -1, 1), 1);
+    passColor = vec3(0, 0, 1);
+    EmitVertex();                                                                  
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1,  1, 1), 1);
+    passColor = vec3(0, 0, 1);
+    EmitVertex();                                                                  
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1, 1), 1);
+    passColor = vec3(0, 0, 1);
+    EmitVertex();
+    EndPrimitive();
+    // bot
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1,  1,  1), 1);
+    passColor = vec3(0, 1, 0);
+    EmitVertex(); 
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1,  1, -1), 1);
+    passColor = vec3(0, 1, 0);
+    EmitVertex();
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, 1,  1), 1);
+    passColor = vec3(0, 1, 0);
+    EmitVertex();  
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, 1, -1), 1);
+    passColor = vec3(0, 1, 0);
+    passColor = vec3(0, 1, 0);
+    EmitVertex();
+    EndPrimitive();
+    // top
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1,  -1,  1), 1);
+    passColor = vec3(0, 1, 0);
+    EmitVertex();   
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1,  -1, -1), 1);
+    passColor = vec3(0, 1, 0);
+    EmitVertex();  
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1,  1), 1);
+    passColor = vec3(0, 1, 0);
+    EmitVertex();   
+    gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1, -1), 1);
+    passColor = vec3(0, 1, 0);
+    passColor = vec3(0, 1, 0);
+    EmitVertex();
+    EndPrimitive();
+}
\ No newline at end of file
diff --git a/projects/cmd_sync_test/resources/shaders/voxelVisualisation.vert b/projects/cmd_sync_test/resources/shaders/voxelVisualisation.vert
new file mode 100644
index 0000000000000000000000000000000000000000..270b9ac58a386b257a42eddc3d10530638bfa0e8
--- /dev/null
+++ b/projects/cmd_sync_test/resources/shaders/voxelVisualisation.vert
@@ -0,0 +1,30 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+
+layout(location = 0) out float passCubeHalf;
+
+layout( push_constant ) uniform constants{
+    mat4 viewProjection;
+};
+
+layout(set=0, binding=0, r8) uniform image3D  voxelImage;
+layout(set=0, binding=1) uniform voxelizationInfo{
+    float extent;
+} voxelInfo;
+
+
+void main()	{
+    passCubeHalf        = voxelInfo.extent / float(imageSize(voxelImage).x) * 0.5f;
+    int voxelResolution = imageSize(voxelImage).x;
+    int slicePixelCount = voxelResolution * voxelResolution;
+    int z               = gl_VertexIndex / slicePixelCount;
+    int index2D         = gl_VertexIndex % slicePixelCount;
+    int y               = index2D / voxelResolution;
+    int x               = index2D % voxelResolution;
+    vec3 position       = (vec3(x, y, z) / voxelResolution - 0.5) * voxelInfo.extent + passCubeHalf;
+	gl_Position         = vec4(position, 1.0);
+    
+    if(imageLoad(voxelImage, ivec3(x,y,z)).x == 0){
+        gl_Position.x /= 0; // clip
+    }
+}
\ No newline at end of file
diff --git a/projects/cmd_sync_test/resources/shaders/voxelVisualisation_frag.spv b/projects/cmd_sync_test/resources/shaders/voxelVisualisation_frag.spv
new file mode 100644
index 0000000000000000000000000000000000000000..0d182806527c32ddab5e234ecf03929ae26277e6
Binary files /dev/null and b/projects/cmd_sync_test/resources/shaders/voxelVisualisation_frag.spv differ
diff --git a/projects/cmd_sync_test/resources/shaders/voxelVisualisation_geom.spv b/projects/cmd_sync_test/resources/shaders/voxelVisualisation_geom.spv
new file mode 100644
index 0000000000000000000000000000000000000000..6a804b752393f0d84c0287580c50c71bb9413492
Binary files /dev/null and b/projects/cmd_sync_test/resources/shaders/voxelVisualisation_geom.spv differ
diff --git a/projects/cmd_sync_test/resources/shaders/voxelVisualisation_vert.spv b/projects/cmd_sync_test/resources/shaders/voxelVisualisation_vert.spv
new file mode 100644
index 0000000000000000000000000000000000000000..52a320bb31926efffb96e7384f76836ca1690dec
Binary files /dev/null and b/projects/cmd_sync_test/resources/shaders/voxelVisualisation_vert.spv differ
diff --git a/projects/cmd_sync_test/resources/shaders/voxelization.geom b/projects/cmd_sync_test/resources/shaders/voxelization.geom
index 1546a75d4e90ece6d26010f1ddc9d8c594cd5d68..23084853e0c8809eb55f88c44c254b4c5ddd12d8 100644
--- a/projects/cmd_sync_test/resources/shaders/voxelization.geom
+++ b/projects/cmd_sync_test/resources/shaders/voxelization.geom
@@ -24,7 +24,8 @@ void main()	{
         else{
             gl_Position = gl_in[i].gl_Position.xzyw;
         }
-        passPos = passPosIn[i].xzy;
+        gl_Position.z = gl_Position.z * 0.5 + 0.5;  // xyz are kept in NDC range [-1, 1] so swizzling works, but vulkan needs final z in range [0, 1]
+        passPos = passPosIn[i];
         EmitVertex();
     }
     EndPrimitive();
diff --git a/projects/cmd_sync_test/resources/shaders/voxelization_geom.spv b/projects/cmd_sync_test/resources/shaders/voxelization_geom.spv
index abf747e5ff0d15043e493e01d08972e04df6f993..df9871889f968450232a4b8355c9493e50de76ee 100644
Binary files a/projects/cmd_sync_test/resources/shaders/voxelization_geom.spv and b/projects/cmd_sync_test/resources/shaders/voxelization_geom.spv differ
diff --git a/projects/cmd_sync_test/src/main.cpp b/projects/cmd_sync_test/src/main.cpp
index 3fb53692eedb925b8c43483b084bdef8cc102c48..894e4a8abfbd9e4d8b5bf83c2984eaf2dc0ee7b8 100644
--- a/projects/cmd_sync_test/src/main.cpp
+++ b/projects/cmd_sync_test/src/main.cpp
@@ -21,6 +21,7 @@ int main(int argc, const char** argv) {
 	vkcv::CameraManager cameraManager(window, windowWidth, windowHeight);
 	cameraManager.getCamera().setPosition(glm::vec3(0.f, 0.f, 3.f));
 	cameraManager.getCamera().setNearFar(0.1, 30);
+    cameraManager.getCamera().setSpeed(25.f);
 
 	window.initEvents();
 
@@ -83,10 +84,11 @@ int main(int argc, const char** argv) {
 		core.getSwapchainImageFormat()
 	);
 	
+	const vk::Format depthBufferFormat = vk::Format::eD32Sfloat;
 	const vkcv::AttachmentDescription depth_attachment(
-			vkcv::AttachmentOperation::STORE,
-			vkcv::AttachmentOperation::CLEAR,
-			vk::Format::eD32Sfloat
+		vkcv::AttachmentOperation::STORE,
+		vkcv::AttachmentOperation::CLEAR,
+		depthBufferFormat
 	);
 
 	vkcv::PassConfig trianglePassDefinition({ present_color_attachment, depth_attachment });
@@ -237,6 +239,64 @@ int main(int argc, const char** argv) {
 	voxelizationDescriptorWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(1, voxelizationInfoBuffer.getHandle()) };
 	core.writeDescriptorSet(voxelizationDescriptorSet, voxelizationDescriptorWrites);
 
+	const size_t voxelCount = voxelResolution * voxelResolution * voxelResolution;
+
+	vkcv::ShaderProgram voxelVisualisationShader;
+	voxelVisualisationShader.addShader(vkcv::ShaderStage::VERTEX, "resources/shaders/voxelVisualisation_vert.spv");
+	voxelVisualisationShader.addShader(vkcv::ShaderStage::GEOMETRY, "resources/shaders/voxelVisualisation_geom.spv");
+	voxelVisualisationShader.addShader(vkcv::ShaderStage::FRAGMENT, "resources/shaders/voxelVisualisation_frag.spv");
+	voxelVisualisationShader.reflectShader(vkcv::ShaderStage::VERTEX);
+	voxelVisualisationShader.reflectShader(vkcv::ShaderStage::GEOMETRY);
+	voxelVisualisationShader.reflectShader(vkcv::ShaderStage::FRAGMENT);
+
+	const std::vector<vkcv::DescriptorBinding> voxelVisualisationDescriptorBindings = {
+		vkcv::DescriptorBinding(vkcv::DescriptorType::IMAGE_STORAGE,    1, vkcv::ShaderStage::VERTEX),
+		vkcv::DescriptorBinding(vkcv::DescriptorType::UNIFORM_BUFFER,   1, vkcv::ShaderStage::VERTEX) };
+	vkcv::DescriptorSetHandle voxelVisualisationDescriptorSet = core.createDescriptorSet(voxelVisualisationDescriptorBindings);
+
+	const vkcv::AttachmentDescription voxelVisualisationColorAttachments(
+		vkcv::AttachmentOperation::STORE,
+		vkcv::AttachmentOperation::LOAD,
+		core.getSwapchainImageFormat()
+	);
+
+	const vkcv::AttachmentDescription voxelVisualisationDepthAttachments(
+		vkcv::AttachmentOperation::STORE,
+		vkcv::AttachmentOperation::LOAD,
+		depthBufferFormat
+	);
+
+	vkcv::PassConfig voxelVisualisationPassDefinition({ voxelVisualisationColorAttachments, voxelVisualisationDepthAttachments });
+	vkcv::PassHandle voxelVisualisationPass = core.createPass(voxelVisualisationPassDefinition);
+
+	const vkcv::PipelineConfig voxelVisualisationPipeConfig(
+		voxelVisualisationShader, 
+		0, 
+		0, 
+		voxelVisualisationPass,
+		{}, 
+		{ core.getDescriptorSet(voxelVisualisationDescriptorSet).layout },
+		true,
+		false,
+		vkcv::PrimitiveTopology::PointList);	// points are extended to cubes in the geometry shader
+	const vkcv::PipelineHandle voxelVisualisationPipe = core.createGraphicsPipeline(voxelVisualisationPipeConfig);
+
+	vkcv::Buffer<uint16_t> voxelVisualisationIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, voxelCount);
+	std::vector<uint16_t> voxelIndexData;
+	for (int i = 0; i < voxelCount; i++) {
+		voxelIndexData.push_back(i);
+	}
+
+	vkcv::DescriptorWrites voxelVisualisationDescriptorWrite;
+	voxelVisualisationDescriptorWrite.storageImageWrites  = { vkcv::StorageImageDescriptorWrite(0,  voxelImage.getHandle()) };
+	voxelVisualisationDescriptorWrite.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(1, voxelizationInfoBuffer.getHandle()) };
+	core.writeDescriptorSet(voxelVisualisationDescriptorSet, voxelVisualisationDescriptorWrite);
+
+	voxelVisualisationIndexBuffer.fill(voxelIndexData);
+	const vkcv::DrawcallInfo voxelVisualisationDrawcall(
+		vkcv::Mesh({}, voxelVisualisationIndexBuffer.getVulkanHandle(), voxelCount),
+		{ vkcv::DescriptorSetUsage(0, core.getDescriptorSet(voxelVisualisationDescriptorSet).vulkanHandle) });
+
 	const std::vector<glm::vec3> instancePositions = {
 		glm::vec3(0.f, -2.f, 0.f),
 		glm::vec3(3.f,  0.f, 0.f),
@@ -264,6 +324,13 @@ int main(int argc, const char** argv) {
 	std::vector<glm::mat4> mvpLight;
 	std::vector<std::array<glm::mat4, 2>> voxelizationMatrices;
 
+	bool renderVoxelVis = false;
+	window.e_key.add([&renderVoxelVis](int key ,int scancode, int action, int mods) {
+		if (key == GLFW_KEY_V && action == GLFW_PRESS) {
+			renderVoxelVis = !renderVoxelVis;
+		}
+	});
+
 	auto start = std::chrono::system_clock::now();
 	const auto appStartTime = start;
 	while (window.isWindowOpen()) {
@@ -275,7 +342,7 @@ int main(int argc, const char** argv) {
 		}
 		
 		if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) {
-			depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle();
+			depthBuffer = core.createImage(depthBufferFormat, swapchainWidth, swapchainHeight).getHandle();
 			
 			windowWidth = swapchainWidth;
 			windowHeight = swapchainHeight;
@@ -311,7 +378,7 @@ int main(int argc, const char** argv) {
 		const glm::mat4 viewProjectionCamera = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView();
 
 		const float voxelizationHalfExtent = 0.5f * voxelizationExtent;
-		const glm::mat4 voxelizationProjection = vulkanCorrectionMatrix * glm::ortho(
+		const glm::mat4 voxelizationProjection = glm::ortho(
 			-voxelizationHalfExtent,
 			 voxelizationHalfExtent,
 			-voxelizationHalfExtent,
@@ -362,6 +429,20 @@ int main(int argc, const char** argv) {
 			pushConstantData,
 			drawcalls,
 			renderTargets);
+
+		if (renderVoxelVis) {
+			const vkcv::PushConstantData voxelVisualisationPushConstantData((void*)&viewProjectionCamera, sizeof(glm::mat4));
+
+			core.recordImageMemoryBarrier(cmdStream, voxelImage.getHandle());
+			core.recordDrawcallsToCmdStream(
+				cmdStream,
+				voxelVisualisationPass,
+				voxelVisualisationPipe,
+				voxelVisualisationPushConstantData,
+				{ voxelVisualisationDrawcall },
+				renderTargets);
+		}
+
 		core.prepareSwapchainImageForPresent(cmdStream);
 		core.submitCommandStream(cmdStream);
 
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index b7fc5aa9459436c8d90d968d455d3778f818a5ca..0d3bf032f5bc9e4997dabd90ae210166edd57160 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -470,4 +470,10 @@ namespace vkcv
 			m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eGeneral, cmdBuffer);
 		}, nullptr);
 	}
+
+	void Core::recordImageMemoryBarrier(const CommandStreamHandle cmdStream, const ImageHandle image) {
+		recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) {
+			m_ImageManager->recordImageMemoryBarrier(image, cmdBuffer);
+		}, nullptr);
+	}
 }
diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp
index 8084937538a96255b15e7390b8baddf9683f0ca4..cb0ebc73f9565b32bb006ebbf62f64c5573820d8 100644
--- a/src/vkcv/ImageManager.cpp
+++ b/src/vkcv/ImageManager.cpp
@@ -295,6 +295,22 @@ namespace vkcv {
 		recordImageBarrier(cmdBuffer, transitionBarrier);
 		image.m_layout = newLayout;
 	}
+
+	void ImageManager::recordImageMemoryBarrier(
+		const ImageHandle& handle,
+		vk::CommandBuffer cmdBuffer) {
+
+		const uint64_t id = handle.getId();
+
+		if (id >= m_images.size()) {
+			std::cerr << "Error: ImageManager::recordImageMemoryBarrier invalid handle" << std::endl;
+			return;
+		}
+
+		auto& image = m_images[id];
+		const auto transitionBarrier = createImageLayoutTransitionBarrier(image, image.m_layout);
+		recordImageBarrier(cmdBuffer, transitionBarrier);
+	}
 	
 	void ImageManager::fillImage(const ImageHandle& handle, void* data, size_t size)
 	{
diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp
index 316ad2312c0bd26f6ecd06a664042b8b51d946d5..6b3bea33f902db94567cdefa3d3c90ea78054876 100644
--- a/src/vkcv/ImageManager.hpp
+++ b/src/vkcv/ImageManager.hpp
@@ -86,6 +86,10 @@ namespace vkcv {
 			vk::ImageLayout newLayout, 
 			vk::CommandBuffer cmdBuffer);
 
+		void recordImageMemoryBarrier(
+			const ImageHandle& handle,
+			vk::CommandBuffer cmdBuffer);
+
 		void fillImage(const ImageHandle& handle, void* data, size_t size);
 		
 		[[nodiscard]]
diff --git a/src/vkcv/PipelineConfig.cpp b/src/vkcv/PipelineConfig.cpp
index 306e468520ec8e932f5bb8e81f0895a334c65dc4..46911736240bc515929f2d1183790fd2ce6b38fe 100644
--- a/src/vkcv/PipelineConfig.cpp
+++ b/src/vkcv/PipelineConfig.cpp
@@ -16,7 +16,8 @@ namespace vkcv {
 		const std::vector<VertexAttribute>          &vertexAttributes,
 		const std::vector<vk::DescriptorSetLayout>  &descriptorLayouts,
 		bool                                        useDynamicViewport,
-		bool                                        useConservativeRasterization)
+		bool                                        useConservativeRasterization,
+        PrimitiveTopology                           primitiveTopology)
 		:
 		m_ShaderProgram(shaderProgram),
 		m_Height(height),
@@ -25,6 +26,7 @@ namespace vkcv {
 		m_VertexAttributes(vertexAttributes),
 		m_DescriptorLayouts(descriptorLayouts),
 		m_UseDynamicViewport(useDynamicViewport),
-		m_UseConservativeRasterization(useConservativeRasterization)
+		m_UseConservativeRasterization(useConservativeRasterization),
+        m_PrimitiveTopology(primitiveTopology)
 		{}
 }
diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp
index 5c7e830efb5b4d4eaa9e06bc39a269777c293214..1971222aa424de084e30f5c574db77992b932ced 100644
--- a/src/vkcv/PipelineManager.cpp
+++ b/src/vkcv/PipelineManager.cpp
@@ -32,6 +32,15 @@ namespace vkcv
 		}
 	}
 
+    vk::PrimitiveTopology primitiveTopologyToVulkanPrimitiveTopology(const PrimitiveTopology topology) {
+        switch (topology) {
+        case(PrimitiveTopology::PointList):     return vk::PrimitiveTopology::ePointList;
+        case(PrimitiveTopology::LineList):      return vk::PrimitiveTopology::eLineList;
+        case(PrimitiveTopology::TriangleList):  return vk::PrimitiveTopology::eTriangleList;
+        default: std::cout << "Error: Unknown primitive topology type" << std::endl; return vk::PrimitiveTopology::eTriangleList;
+        }
+    }
+
     PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, PassManager& passManager)
     {
 		const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle);
@@ -114,9 +123,9 @@ namespace vkcv
 
         // input assembly state
         vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo(
-                {},
-                vk::PrimitiveTopology::eTriangleList,
-                false
+            {},
+            primitiveTopologyToVulkanPrimitiveTopology(config.m_PrimitiveTopology),
+            false
         );
 
         // viewport state