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