From 636a493863f8db4c15dcb0cd97a3bdcd65a8e354 Mon Sep 17 00:00:00 2001
From: John Hunter <jjsh1g20@soton.ac.uk>
Date: Tue, 31 Jan 2023 21:35:26 +0000
Subject: [PATCH] attempt to add mesh shading

---
 Cargo.lock         |  27 ++++++-----
 Cargo.toml         |  11 +++++
 src/cube.mesh.glsl |  51 +++++++++++++++++++++
 src/main.rs        | 109 ++++++++++++++++++++++++++++++++++++---------
 src/objects.rs     |  35 +++++++--------
 5 files changed, 183 insertions(+), 50 deletions(-)
 create mode 100644 src/cube.mesh.glsl

diff --git a/Cargo.lock b/Cargo.lock
index 18923c2..cfb15f9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -671,8 +671,7 @@ dependencies = [
 [[package]]
 name = "egui_winit_vulkano"
 version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c16b9a2bcbfc85f5a4e1d91d1126958451c881c69efcc98e5d6b1b0e5fbb7419"
+source = "git+https://github.com/Molive-0/egui_winit_vulkano#7136d8243a6803709b304bad965b22280351ebbf"
 dependencies = [
  "ahash",
  "bytemuck",
@@ -715,6 +714,7 @@ dependencies = [
 name = "erroccfisumreg"
 version = "0.1.0"
 dependencies = [
+ "ash",
  "bytemuck",
  "cgmath",
  "egui",
@@ -2235,9 +2235,7 @@ dependencies = [
 
 [[package]]
 name = "vulkano"
-version = "0.32.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f80b11c6c46ecb2c42155c8bcbc3ff04b783185181d4bbe19d9635a711ec747f"
+version = "0.32.0"
 dependencies = [
  "ahash",
  "ash",
@@ -2247,9 +2245,9 @@ dependencies = [
  "half",
  "heck",
  "indexmap",
- "lazy_static",
  "libloading",
  "objc",
+ "once_cell",
  "parking_lot",
  "proc-macro2",
  "quote",
@@ -2259,13 +2257,12 @@ dependencies = [
  "smallvec",
  "thread_local",
  "vk-parse",
+ "vulkano_macros",
 ]
 
 [[package]]
 name = "vulkano-shaders"
 version = "0.32.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96bbe0784b21e32661fde8a883bb3f659a473693c9f23bab12c26d7884c15ed0"
 dependencies = [
  "ahash",
  "heck",
@@ -2279,8 +2276,6 @@ dependencies = [
 [[package]]
 name = "vulkano-util"
 version = "0.32.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df7d34bf37d622aa10d63a05396d91566d8298ca04ebc632f536946659a62f58"
 dependencies = [
  "ahash",
  "vulkano",
@@ -2291,8 +2286,6 @@ dependencies = [
 [[package]]
 name = "vulkano-win"
 version = "0.32.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac1056e3238fe9025628b3de0f401d8c60b7a6dc89e059534568f55fef4e29f7"
 dependencies = [
  "core-graphics-types",
  "objc",
@@ -2301,6 +2294,16 @@ dependencies = [
  "winit",
 ]
 
+[[package]]
+name = "vulkano_macros"
+version = "0.32.0"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "walkdir"
 version = "2.3.2"
diff --git a/Cargo.toml b/Cargo.toml
index 6e1ab4e..20f20fe 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -30,3 +30,14 @@ rodio = "0.16"
 
 egui = "0.20"
 egui_winit_vulkano = "0.22"
+
+ash = "*"
+
+
+# using latest gits
+[patch.crates-io]
+vulkano = { path = "../vulkano/vulkano" }
+vulkano-shaders = { path = "../vulkano/vulkano-shaders" }
+vulkano-win = { path = "../vulkano/vulkano-win" }
+vulkano-util = { path = "../vulkano/vulkano-util" }
+egui_winit_vulkano = { git = "https://github.com/Molive-0/egui_winit_vulkano" }
diff --git a/src/cube.mesh.glsl b/src/cube.mesh.glsl
new file mode 100644
index 0000000..82b0330
--- /dev/null
+++ b/src/cube.mesh.glsl
@@ -0,0 +1,51 @@
+/* Copyright (c) 2021, Sascha Willems
+*
+* SPDX-License-Identifier: MIT
+*
+*/
+
+#version 450
+#extension GL_EXT_mesh_shader:require
+
+layout(push_constant)uniform PushConstantData{
+    mat4 world;
+    mat4 view;
+    mat4 proj;
+}pc;
+
+layout(local_size_x=1,local_size_y=1,local_size_z=1)in;
+layout(triangles,max_vertices=3,max_primitives=1)out;
+
+layout(location=0)out VertexOutput
+{
+    vec4 color;
+}vertexOutput[];
+
+const vec4[3]positions={
+    vec4(0.,-1.,0.,1.),
+    vec4(-1.,1.,0.,1.),
+    vec4(1.,1.,0.,1.)
+};
+
+const vec4[3]colors={
+    vec4(0.,1.,0.,1.),
+    vec4(0.,0.,1.,1.),
+    vec4(1.,0.,0.,1.)
+};
+
+void main()
+{
+    uint iid=gl_LocalInvocationID.x;
+    
+    vec4 offset=vec4(0.,0.,gl_GlobalInvocationID.x,0.);
+    
+    SetMeshOutputsEXT(3,1);
+    mat4 mvp=pc.proj*pc.view*pc.world;
+    gl_MeshVerticesEXT[0].gl_Position=mvp*(positions[0]+offset);
+    gl_MeshVerticesEXT[1].gl_Position=mvp*(positions[1]+offset);
+    gl_MeshVerticesEXT[2].gl_Position=mvp*(positions[2]+offset);
+    vertexOutput[0].color=colors[0];
+    vertexOutput[1].color=colors[1];
+    vertexOutput[2].color=colors[2];
+    gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex]=uvec3(0,1,2);
+}
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 7287a04..116d682 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -24,27 +24,36 @@ use obj::{LoadConfig, ObjData};
 use rodio::{source::Source, Decoder, OutputStream};
 use std::io::Cursor;
 use std::{sync::Arc, time::Instant};
-use vulkano::buffer::CpuBufferPool;
-use vulkano::command_buffer::allocator::StandardCommandBufferAllocator;
+use vulkano::buffer::allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo};
+use vulkano::buffer::sys::BufferCreateInfo;
+use vulkano::buffer::{Buffer, BufferAllocateInfo};
+use vulkano::command_buffer::allocator::{
+    CommandBufferAllocator, CommandBufferBuilderAlloc, StandardCommandBufferAllocator,
+};
+use vulkano::command_buffer::synced::SyncCommandBufferBuilder;
+use vulkano::command_buffer::sys::{CommandBufferBeginInfo, UnsafeCommandBufferBuilder};
+use vulkano::command_buffer::CommandBufferInheritanceInfo;
 use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
 use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
-use vulkano::device::DeviceOwned;
+use vulkano::device::{DeviceOwned, QueueFlags};
 use vulkano::format::Format;
 use vulkano::image::AttachmentImage;
 use vulkano::memory::allocator::{MemoryUsage, StandardMemoryAllocator};
 use vulkano::pipeline::graphics::depth_stencil::DepthStencilState;
 use vulkano::pipeline::graphics::rasterization::CullMode;
 use vulkano::pipeline::graphics::rasterization::FrontFace::Clockwise;
+use vulkano::pipeline::graphics::vertex_input::Vertex;
 use vulkano::pipeline::PipelineBindPoint;
 use vulkano::shader::ShaderModule;
 use vulkano::swapchain::{PresentMode, SwapchainPresentInfo};
-use vulkano::VulkanLibrary;
+use vulkano::{NonExhaustive, VulkanLibrary, VulkanObject};
 use winit::event::{DeviceEvent, DeviceId, ElementState, MouseButton, VirtualKeyCode};
 
+use ash::vk::CommandBuffer;
 use egui_winit_vulkano::Gui;
 use vulkano::pipeline::StateMode::Fixed;
 use vulkano::{
-    buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
+    buffer::BufferUsage,
     command_buffer::{
         AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
     },
@@ -53,7 +62,7 @@ use vulkano::{
     },
     image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
     impl_vertex,
-    instance::{Instance, InstanceCreateInfo},
+    instance::{Instance, InstanceCreateInfo, IntanceExtensions},
     pipeline::{
         graphics::{
             input_assembly::InputAssemblyState,
@@ -98,7 +107,10 @@ fn main() {
     let instance = Instance::new(
         library,
         InstanceCreateInfo {
-            enabled_extensions: required_extensions,
+            enabled_extensions: IntanceExtensions {
+                khr_get_physical_device_properties2,
+                ..required_extensions,
+            },
             // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK)
             enumerate_portability: true,
             ..Default::default()
@@ -127,6 +139,9 @@ fn main() {
     // `khr_swapchain` extension.
     let device_extensions = DeviceExtensions {
         khr_swapchain: true,
+        ext_mesh_shader: true,
+        khr_spirv_1_4: true,
+        khr_shader_float_controls: true,
         ..DeviceExtensions::empty()
     };
 
@@ -161,7 +176,8 @@ fn main() {
                     // We select a queue family that supports graphics operations. When drawing to
                     // a window surface, as we do in this example, we also need to check that queues
                     // in this queue family are capable of presenting images to the surface.
-                    q.queue_flags.graphics && p.surface_support(i as u32, &surface).unwrap_or(false)
+                    q.queue_flags.intersects(QueueFlags::GRAPHICS)
+                        && p.surface_support(i as u32, &surface).unwrap_or(false)
                 })
                 // The code here searches for the first queue family that is suitable. If none is
                 // found, `None` is returned to `filter_map`, which disqualifies this physical
@@ -273,16 +289,13 @@ fn main() {
                 // use that.
                 image_extent: window.inner_size().into(),
 
-                image_usage: ImageUsage {
-                    color_attachment: true,
-                    ..ImageUsage::empty()
-                },
+                image_usage: ImageUsage::COLOR_ATTACHMENT,
 
                 // The alpha mode indicates how the alpha value of the final image will behave. For
                 // example, you can choose whether the window will be opaque or transparent.
                 composite_alpha: surface_capabilities
                     .supported_composite_alpha
-                    .iter()
+                    .into_iter()
                     .next()
                     .unwrap(),
 
@@ -338,6 +351,8 @@ fn main() {
 
                 #[derive(Clone, Copy, Zeroable, Pod, Debug)]
             },
+            vulkan_version: "1.2",
+            spirv_version: "1.4"
         }
     }
 
@@ -350,12 +365,30 @@ fn main() {
 
                 #[derive(Clone, Copy, Zeroable, Pod, Debug)]
             },
+            vulkan_version: "1.2",
+            spirv_version: "1.4"
         }
     }
 
     let mesh_vs = mesh_vs::load(device.clone()).unwrap();
     let mesh_fs = mesh_fs::load(device.clone()).unwrap();
 
+    mod implicit_ms {
+        vulkano_shaders::shader! {
+            ty: "mesh",
+            path: "src/cube.mesh.glsl",
+            types_meta: {
+                use bytemuck::{Pod, Zeroable};
+
+                #[derive(Clone, Copy, Zeroable, Pod, Debug)]
+            },
+            vulkan_version: "1.2",
+            spirv_version: "1.4"
+        }
+    }
+
+    let implicit_ms = implicit_ms::load(device.clone()).unwrap();
+
     /*let uniform_buffer =
     CpuBufferPool::<vs::ty::PushConstantData>::uniform_buffer(memory_allocator);*/
 
@@ -429,6 +462,7 @@ fn main() {
         &memory_allocator,
         &mesh_vs,
         &mesh_fs,
+        &implicit_ms,
         &images,
         render_pass.clone(),
         &mut viewport,
@@ -476,13 +510,13 @@ fn main() {
 
     let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
 
-    let uniform_buffer = CpuBufferPool::<mesh_fs::ty::Data>::new(
+    let uniform_buffer = SubbufferAllocator::new(
         memory_allocator.clone(),
-        BufferUsage {
-            uniform_buffer: true,
-            ..BufferUsage::empty()
+        SubbufferAllocatorCreateInfo {
+            // We want to use the allocated subbuffers as vertex buffers.
+            buffer_usage: BufferUsage::UNIFORM_BUFFER,
+            ..Default::default()
         },
-        MemoryUsage::Upload,
     );
 
     // Create an egui GUI
@@ -638,6 +672,7 @@ fn main() {
                         &memory_allocator,
                         &mesh_vs,
                         &mesh_fs,
+                        &implicit_ms,
                         &new_images,
                         render_pass.clone(),
                         &mut viewport,
@@ -737,7 +772,9 @@ fn main() {
                         light_count: gstate.lights.len() as u32,
                     };
 
-                    uniform_buffer.from_data(uniform_data).unwrap()
+                    let sub = uniform_buffer.allocate_sized().unwrap();
+                    *sub.write().unwrap() = uniform_data;
+                    sub
                 };
 
                 let layout = mesh_pipeline.layout().set_layouts().get(0).unwrap();
@@ -843,6 +880,36 @@ fn main() {
                         .unwrap();
                 }
 
+                /*unsafe {
+                    let secondary_builder = AutoCommandBufferBuilder::secondary(
+                        &command_buffer_allocator,
+                        queue_family_index,
+                        CommandBufferUsage::OneTimeSubmit,
+                        CommandBufferInheritanceInfo {
+                            render_pass: Some(
+                                Subpass::from(render_pass.clone(), 0).unwrap().into(),
+                            ),
+                            ..Default::default()
+                        },
+                    )
+                    .unwrap();
+
+                    let secondary_buffer = secondary_builder.build().unwrap();
+
+                    (device.fns().ext_mesh_shader.cmd_draw_mesh_tasks_ext)(
+                        secondary_buffer.handle(),
+                        1,
+                        1,
+                        1,
+                    );
+
+                    /*builder
+                    .execute_commands(secondary_buffer)
+                    .expect("Failed to execute chicanery");*/
+                }*/
+
+                builder.draw_mesh([1, 1, 1]).unwrap();
+
                 // We leave the render pass. Note that if we had multiple
                 // subpasses we could have called `next_subpass` to jump to the next subpass.
                 builder
@@ -898,6 +965,7 @@ fn window_size_dependent_setup(
     allocator: &StandardMemoryAllocator,
     mesh_vs: &ShaderModule,
     mesh_fs: &ShaderModule,
+    implicit_ms: &ShaderModule,
     images: &[Arc<SwapchainImage>],
     render_pass: Arc<RenderPass>,
     viewport: &mut Viewport,
@@ -932,7 +1000,7 @@ fn window_size_dependent_setup(
         // in. The pipeline will only be usable from this particular subpass.
         .render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
         // We need to indicate the layout of the vertices.
-        .vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
+        .vertex_input_state(OVertex::per_vertex())
         // The content of the vertex buffer describes a list of triangles.
         .input_assembly_state(InputAssemblyState::new())
         // A Vulkan shader can in theory contain multiple entry points, so we have to specify
@@ -947,6 +1015,7 @@ fn window_size_dependent_setup(
         ]))
         // See `vertex_shader`.
         .fragment_shader(mesh_fs.entry_point("main").unwrap(), ())
+        .mesh_shader(implicit_ms.entry_point("main").unwrap(), ())
         .depth_stencil_state(DepthStencilState::simple_depth_test())
         .rasterization_state(RasterizationState {
             front_face: Fixed(Clockwise),
diff --git a/src/objects.rs b/src/objects.rs
index b5ed89f..441e632 100644
--- a/src/objects.rs
+++ b/src/objects.rs
@@ -4,8 +4,8 @@ use bytemuck::{Pod, Zeroable};
 use cgmath::{Deg, Euler, Matrix3, Point3, SquareMatrix, Vector3};
 use obj::{LoadConfig, ObjData};
 use vulkano::{
-    buffer::{BufferUsage, CpuAccessibleBuffer},
-    impl_vertex,
+    buffer::{Buffer, BufferAllocateInfo, BufferUsage, Subbuffer},
+    pipeline::graphics::vertex_input::Vertex,
 };
 
 use crate::MemoryAllocator;
@@ -16,18 +16,19 @@ pub const PLATONIC_SOLIDS: [(&str, &[u8]); 1] = [("Buny", include_bytes!("bunny.
 // We use #[repr(C)] here to force rustc to not do anything funky with our data, although for this
 // particular example, it doesn't actually change the in-memory representation.
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
-pub struct Vertex {
+#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, Vertex)]
+pub struct OVertex {
+    #[format(R32G32B32_SFLOAT)]
     position: [f32; 3],
+    #[format(R32G32B32_SFLOAT)]
     normal: [f32; 3],
 }
-impl_vertex!(Vertex, position, normal);
 
 #[derive(Debug)]
 pub struct Mesh {
     pub name: String,
-    pub vertices: Arc<CpuAccessibleBuffer<[Vertex]>>,
-    pub indices: Arc<CpuAccessibleBuffer<[u32]>>,
+    pub vertices: Subbuffer<[OVertex]>,
+    pub indices: Subbuffer<[u32]>,
     pub pos: Point3<f32>,
     pub rot: Euler<Deg<f32>>,
     pub scale: f32,
@@ -55,7 +56,7 @@ pub fn load_obj(memory_allocator: &MemoryAllocator, input: &mut dyn Read, name:
                     //println!("{:?}", exist);
                     indices.push(exist);
                 } else {
-                    vertices.push(Vertex {
+                    vertices.push(OVertex {
                         position: object.position[mapping.0 as usize],
                         normal: object.normal[mapping.1 as usize],
                     });
@@ -66,24 +67,22 @@ pub fn load_obj(memory_allocator: &MemoryAllocator, input: &mut dyn Read, name:
         }
     }
 
-    let vertex_buffer = CpuAccessibleBuffer::from_iter(
+    let vertex_buffer = Buffer::from_iter(
         memory_allocator,
-        BufferUsage {
-            vertex_buffer: true,
-            ..BufferUsage::empty()
+        BufferAllocateInfo {
+            buffer_usage: BufferUsage::VERTEX_BUFFER,
+            ..Default::default()
         },
-        false,
         vertices,
     )
     .unwrap();
 
-    let index_buffer = CpuAccessibleBuffer::from_iter(
+    let index_buffer = Buffer::from_iter(
         memory_allocator,
-        BufferUsage {
-            index_buffer: true,
-            ..BufferUsage::empty()
+        BufferAllocateInfo {
+            buffer_usage: BufferUsage::INDEX_BUFFER,
+            ..Default::default()
         },
-        false,
         indices,
     )
     .unwrap();
-- 
GitLab