From 7f32c3a64f6228d15a84d5f23d020011d683ce00 Mon Sep 17 00:00:00 2001 From: buckn Date: Sun, 4 Feb 2024 13:13:54 -0500 Subject: [PATCH] preparing to create app init function for computed particles, lots of errors --- Session.vim | 131 +++++ build.rs | 4 + diffs | 602 +++++++++++++++++++ rnd.rs | 943 ++++++++++++++++++++++++++++++ src/entities.rs | 29 +- src/render.rs | 877 +++++++++++++++------------- src/rnd.rs | 979 +++++++++++++++++++++++++++++++ src/shaders.rs | 1 + src/shaders/tri.comp | 39 +- src/utility.rs | 1 - src/utility/share.rs | 1156 ++++++++++++++++++++++++------------- src/utility/structures.rs | 258 ++++++--- src/utility/window.rs | 88 --- 13 files changed, 4131 insertions(+), 977 deletions(-) create mode 100644 Session.vim create mode 100644 diffs create mode 100644 rnd.rs create mode 100644 src/rnd.rs diff --git a/Session.vim b/Session.vim new file mode 100644 index 0000000..128cb2d --- /dev/null +++ b/Session.vim @@ -0,0 +1,131 @@ +let SessionLoad = 1 +let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1 +let v:this_session=expand(":p") +silent only +silent tabonly +cd ~/bin/rs/tri +if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == '' + let s:wipebuf = bufnr('%') +endif +let s:shortmess_save = &shortmess +if &shortmess =~ 'A' + set shortmess=aoOA +else + set shortmess=aoO +endif +badd +1 ~/bin/rs/tri +badd +1 src/render.rs +badd +0 src/utility/share.rs +argglobal +%argdel +$argadd ~/bin/rs/tri +edit src/render.rs +let s:save_splitbelow = &splitbelow +let s:save_splitright = &splitright +set splitbelow splitright +wincmd _ | wincmd | +vsplit +wincmd _ | wincmd | +vsplit +2wincmd h +wincmd w +wincmd w +let &splitbelow = s:save_splitbelow +let &splitright = s:save_splitright +wincmd t +let s:save_winminheight = &winminheight +let s:save_winminwidth = &winminwidth +set winminheight=0 +set winheight=1 +set winminwidth=0 +set winwidth=1 +exe 'vert 1resize ' . ((&columns * 71 + 107) / 214) +exe 'vert 2resize ' . ((&columns * 71 + 107) / 214) +exe 'vert 3resize ' . ((&columns * 70 + 107) / 214) +argglobal +setlocal fdm=manual +setlocal fde=0 +setlocal fmr={{{,}}} +setlocal fdi=# +setlocal fdl=0 +setlocal fml=1 +setlocal fdn=20 +setlocal fen +silent! normal! zE +let &fdl = &fdl +let s:l = 61 - ((45 * winheight(0) + 40) / 81) +if s:l < 1 | let s:l = 1 | endif +keepjumps exe s:l +normal! zt +keepjumps 61 +normal! 0 +lcd ~/bin/rs/tri +wincmd w +argglobal +if bufexists(fnamemodify("~/bin/rs/tri/src/utility/share.rs", ":p")) | buffer ~/bin/rs/tri/src/utility/share.rs | else | edit ~/bin/rs/tri/src/utility/share.rs | endif +if &buftype ==# 'terminal' + silent file ~/bin/rs/tri/src/utility/share.rs +endif +setlocal fdm=manual +setlocal fde=0 +setlocal fmr={{{,}}} +setlocal fdi=# +setlocal fdl=0 +setlocal fml=1 +setlocal fdn=20 +setlocal fen +silent! normal! zE +let &fdl = &fdl +let s:l = 190 - ((53 * winheight(0) + 40) / 81) +if s:l < 1 | let s:l = 1 | endif +keepjumps exe s:l +normal! zt +keepjumps 190 +normal! 013| +lcd ~/bin/rs/tri +wincmd w +argglobal +if bufexists(fnamemodify("~/bin/rs/tri/src/utility/share.rs", ":p")) | buffer ~/bin/rs/tri/src/utility/share.rs | else | edit ~/bin/rs/tri/src/utility/share.rs | endif +if &buftype ==# 'terminal' + silent file ~/bin/rs/tri/src/utility/share.rs +endif +setlocal fdm=manual +setlocal fde=0 +setlocal fmr={{{,}}} +setlocal fdi=# +setlocal fdl=0 +setlocal fml=1 +setlocal fdn=20 +setlocal fen +silent! normal! zE +let &fdl = &fdl +let s:l = 1651 - ((36 * winheight(0) + 40) / 81) +if s:l < 1 | let s:l = 1 | endif +keepjumps exe s:l +normal! zt +keepjumps 1651 +normal! 016| +lcd ~/bin/rs/tri +wincmd w +3wincmd w +exe 'vert 1resize ' . ((&columns * 71 + 107) / 214) +exe 'vert 2resize ' . ((&columns * 71 + 107) / 214) +exe 'vert 3resize ' . ((&columns * 70 + 107) / 214) +tabnext 1 +if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0 && getbufvar(s:wipebuf, '&buftype') isnot# 'terminal' + silent exe 'bwipe ' . s:wipebuf +endif +unlet! s:wipebuf +set winheight=1 winwidth=20 +let &shortmess = s:shortmess_save +let &winminheight = s:save_winminheight +let &winminwidth = s:save_winminwidth +let s:sx = expand(":p:r")."x.vim" +if filereadable(s:sx) + exe "source " . fnameescape(s:sx) +endif +let &g:so = s:so_save | let &g:siso = s:siso_save +set hlsearch +doautoall SessionLoadPost +unlet SessionLoad +" vim: set ft=vim : diff --git a/build.rs b/build.rs index dc24b92..a8ae123 100644 --- a/build.rs +++ b/build.rs @@ -25,6 +25,10 @@ fn main() -> std::io::Result<()> { shader_path_string ); let shader_file: &OsStr = OsStr::new::(shader_path_string.as_str()); + println!( + "cargo:warning=compiling destination: {:?}", + shader_file + ); Command::new("glslc") .arg("-c") .arg(shader_path) diff --git a/diffs b/diffs new file mode 100644 index 0000000..40da610 --- /dev/null +++ b/diffs @@ -0,0 +1,602 @@ +diff --git a/src/render.rs b/src/render.rs +index c8f2dc6..b094570 100644 +--- a/src/render.rs ++++ b/src/render.rs +@@ -14,6 +14,22 @@ use std::ptr; + // Constants + const WINDOW_TITLE: &'static str = "Template"; + ++const IS_PAINT_FPS_COUNTER: bool = true; ++ ++pub fn init_window( ++ event_loop: &EventLoop<()>, ++ title: &str, ++ width: u32, ++ height: u32, ++) -> winit::window::Window { ++ winit::window::WindowBuilder::new() ++ .with_title(title) ++ .with_inner_size(winit::dpi::LogicalSize::new(width, height)) ++ .build(event_loop) ++ .expect("Failed to create window.") ++} ++ ++ + pub struct VulkanApp { + window: winit::window::Window, + +@@ -31,7 +47,10 @@ pub struct VulkanApp { + queue_family: QueueFamilyIndices, + graphics_queue: vk::Queue, + present_queue: vk::Queue, ++ //new from C++ ++ compute_queue: vk::Queue, + ++ //not in C++ + swapchain_loader: ash::extensions::khr::Swapchain, + swapchain: vk::SwapchainKHR, + swapchain_images: Vec, +@@ -41,14 +60,31 @@ pub struct VulkanApp { + swapchain_framebuffers: Vec, + + render_pass: vk::RenderPass, +- pipeline_layout: vk::PipelineLayout, ++ ++ graphics_pipeline_layout: vk::PipelineLayout, + graphics_pipeline: vk::Pipeline, ++ ++ //new from C++ ++ compute_descriptor_set_layout: vk::DescriptorSetLayout, ++ compute_pipeline_layout: vk::PipelineLayout, ++ compute_pipeline: vk::Pipeline, ++ ++ //vertex buffer for the triangle verticies ++ //i think this is the same as shaderStorageBuffers in C++ version ++ shader_storage_buffers: Vec, ++ shader_storage_buffers_memory: Vec, ++ ++ uniform_buffers: Vec, ++ uniform_buffers_memory: Vec, ++ uniform_buffers_mapped: Vec<*mut c_void>, ++ + +- vertex_buffer: vk::Buffer, +- vertex_buffer_memory: vk::DeviceMemory, ++ descriptor_pool: vk::DescriptorPool, ++ compute_descriptor_sets: Vec, + + command_pool: vk::CommandPool, + command_buffers: Vec, ++ compute_command_buffers: Vec, + + image_available_semaphores: Vec, + render_finished_semaphores: Vec, +@@ -59,9 +95,33 @@ pub struct VulkanApp { + } + + impl VulkanApp { ++ //C++ code:: ++ /* ++ ### cleanup(); ++ createInstance(); DONE ++ setupDebugMessenger(); DONE ++ createSurface(); SurfaceStuff::new DONE ++ pickPhysicalDevice(); DONE ++ createLogicalDevice(); ++ createSwapChain(); ++ createImageViews(); ++ createRenderPass(); ++ createComputeDescriptorSetLayout(); ++ createGraphicsPipeline(); ++ createComputePipeline(); ++ createFramebuffers(); DONE ++ createCommandPool(); DONE ++ createShaderStorageBuffers(); DONE ++ createUniformBuffers(); DONE ++ createDescriptorPool(); DONE ++ createComputeDescriptorSets(); DONE ++ createCommandBuffers(); DONE ++ createComputeCommandBuffers(); DONE ++ createSyncObjects(); DONE ++ */ + pub fn new(event_loop: &winit::event_loop::EventLoop<()>) -> VulkanApp { + let window = +- utility::window::init_window(event_loop, WINDOW_TITLE, WINDOW_WIDTH, WINDOW_HEIGHT); ++ init_window(event_loop, WINDOW_TITLE, WINDOW_WIDTH, WINDOW_HEIGHT); + + // init vulkan stuff + let entry = unsafe { Entry::load().unwrap() }; +@@ -72,7 +132,7 @@ impl VulkanApp { + &VALIDATION.required_validation_layers.to_vec(), + ); + let surface_stuff = +- share::create_surface(&entry, &instance, &window, WINDOW_WIDTH, WINDOW_HEIGHT); ++ SurfaceStuff::new(&entry, &instance, &window, WINDOW_WIDTH, WINDOW_HEIGHT); + let (debug_utils_loader, debug_merssager) = + setup_debug_utils(VALIDATION.is_enable, &entry, &instance); + let physical_device = +@@ -88,7 +148,9 @@ impl VulkanApp { + unsafe { device.get_device_queue(queue_family.graphics_family.unwrap(), 0) }; + let present_queue = + unsafe { device.get_device_queue(queue_family.present_family.unwrap(), 0) }; +- let swapchain_stuff = share::create_swapchain( ++ let compute_queue = ++ unsafe { device.get_device_queue(queue_family.compute_family.unwrap(), 0) }; ++ let swapchain_stuff = SwapChainStuff::new( + &instance, + &device, + physical_device, +@@ -102,11 +164,19 @@ impl VulkanApp { + &swapchain_stuff.swapchain_images, + ); + let render_pass = share::create_render_pass(&device, swapchain_stuff.swapchain_format); +- let (graphics_pipeline, pipeline_layout) = VulkanApp::create_graphics_pipeline( ++ let (graphics_pipeline, graphics_pipeline_layout) = VulkanApp::create_graphics_pipeline( ++ &device, ++ render_pass, ++ swapchain_stuff.swapchain_extent, ++ ); ++ let (compute_pipelines, compute_pipeline_layout) = VulkanApp::create_compute_pipelines( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); ++ ++ let compute_pipeline = compute_pipelines[0]; ++ + let swapchain_framebuffers = share::create_framebuffers( + &device, + render_pass, +@@ -125,7 +195,7 @@ impl VulkanApp { + swapchain_stuff.swapchain_extent, + vertex_buffer, + ); +- let sync_ojbects = share::create_sync_objects(&device, MAX_FRAMES_IN_FLIGHT); ++ let sync_ojbects = SyncObjects::new(&device, MAX_FRAMES_IN_FLIGHT); + + // cleanup(); the 'drop' function will take care of it. + VulkanApp { +@@ -146,6 +216,7 @@ impl VulkanApp { + queue_family, + graphics_queue, + present_queue, ++ compute_queue, + + swapchain_loader: swapchain_stuff.swapchain_loader, + swapchain: swapchain_stuff.swapchain, +@@ -155,10 +226,15 @@ impl VulkanApp { + swapchain_imageviews, + swapchain_framebuffers, + +- pipeline_layout, ++ graphics_pipeline_layout, + render_pass, + graphics_pipeline, + ++ ++ compute_descriptor_sets, ++ compute_pipeline_layout, ++ compute_pipeline, ++ + vertex_buffer, + vertex_buffer_memory, + +@@ -174,6 +250,56 @@ impl VulkanApp { + } + } + ++ pub fn main_loop(self) { ++ let mut tick_counter = super::fps_limiter::FPSLimiter::new(); ++ ++ self.event_loop ++ .run(move |event, _, control_flow| match event { ++ Event::WindowEvent { event, .. } => match event { ++ WindowEvent::CloseRequested => { ++ vulkan_app.wait_device_idle(); ++ *control_flow = ControlFlow::Exit ++ } ++ WindowEvent::KeyboardInput { input, .. } => match input { ++ KeyboardInput { ++ virtual_keycode, ++ state, ++ .. ++ } => match (virtual_keycode, state) { ++ (Some(VirtualKeyCode::Escape), ElementState::Pressed) => { ++ vulkan_app.wait_device_idle(); ++ *control_flow = ControlFlow::Exit ++ } ++ _ => {} ++ }, ++ }, ++ WindowEvent::Resized(_new_size) => { ++ vulkan_app.wait_device_idle(); ++ vulkan_app.resize_framebuffer(); ++ } ++ _ => {} ++ }, ++ Event::MainEventsCleared => { ++ vulkan_app.window_ref().request_redraw(); ++ } ++ Event::RedrawRequested(_window_id) => { ++ let delta_time = tick_counter.delta_time(); ++ vulkan_app.draw_frame(delta_time); ++ ++ if IS_PAINT_FPS_COUNTER { ++ print!("FPS: {}\r", tick_counter.fps()); ++ } ++ ++ tick_counter.tick_frame(); ++ } ++ Event::LoopDestroyed => { ++ vulkan_app.wait_device_idle(); ++ } ++ _ => (), ++ }) ++ ++ } ++ + fn create_vertex_buffer( + instance: &ash::Instance, + device: &ash::Device, +@@ -263,10 +389,111 @@ impl VulkanApp { + } + + panic!("Failed to find suitable memory type!") ++ share::pick_physical_device(&instance, &surface_stuff, &DEVICE_EXTENSIONS); + } ++ /* ++ * IDEK WHERE THIS CAME FROM I FUCKED UP THIS FILE, SHITS WHACK ++ * let (device, queue_family) = share::create_logical_device( ++ &instance, ++ physical_device, ++ &VALIDATION, ++ &DEVICE_EXTENSIONS, ++ &surface_stuff, ++ ); ++ let graphics_queue = ++ unsafe { device.get_device_queue(queue_family.graphics_family.unwrap(), 0) }; ++ let present_queue = ++ unsafe { device.get_device_queue(queue_family.present_family.unwrap(), 0) }; ++ let compute_queue = ++ unsafe { device.get_device_queue(queue_family.compute_family.unwrap(), 0) }; ++ let swapchain_stuff = SwapChainStuff::new( ++ &instance, ++ &device, ++ physical_device, ++ &window, ++ &surface_stuff, ++ &queue_family, ++ ); ++ let swapchain_imageviews = share::create_image_views( ++ &device, ++ swapchain_stuff.swapchain_format, ++ &swapchain_stuff.swapchain_images, ++ ); ++ let render_pass = share::create_render_pass(&device, swapchain_stuff.swapchain_format); ++ let (graphics_pipeline, graphics_pipeline_layout) = VulkanApp::create_graphics_pipeline( ++ &device, ++ render_pass, ++ swapchain_stuff.swapchain_extent, ++ ); ++ let (compute_pipelines, compute_pipeline_layout) = VulkanApp::create_compute_pipelines( ++ &device, ++ render_pass, ++ swapchain_stuff.swapchain_extent, ++ ); + +- fn create_command_buffers( +- device: &ash::Device, ++ let compute_pipeline = compute_pipelines[0]; ++ ++ let swapchain_framebuffers = share::create_framebuffers( ++ &device, ++ render_pass, ++ &swapchain_imageviews, ++ swapchain_stuff.swapchain_extent, ++ ); ++ let command_pool = share::create_command_pool(&device, &queue_family); ++ let (vertex_buffer, vertex_buffer_memory) = ++ VulkanApp::create_vertex_buffer(&instance, &device, physical_device); ++ let command_buffers = VulkanApp::create_command_buffers( ++ &device, ++ command_pool, ++ graphics_pipeline, ++ &swapchain_framebuffers, ++ render_pass, ++ swapchain_stuff.swapchain_extent, ++ vertex_buffer, ++ ); ++ let sync_ojbects = SyncObjects::new(&device, MAX_FRAMES_IN_FLIGHT); ++ ++ // cleanup(); the 'drop' function will take care of it. ++ VulkanApp { ++ // winit stuff ++ window, ++ ++ // vulkan stuff ++ _entry: entry, ++ instance, ++ surface: surface_stuff.surface, ++ surface_loader: surface_stuff.surface_loader, ++ debug_utils_loader, ++ debug_merssager, ++ ++ physical_device, ++ device, ++ ++ queue_family, ++ graphics_queue, ++ present_queue, ++ compute_queue, ++ ++ swapchain_loader: swapchain_stuff.swapchain_loader, ++ swapchain: swapchain_stuff.swapchain, ++ swapchain_format: swapchain_stuff.swapchain_format, ++ swapchain_images: swapchain_stuff.swapchain_images, ++ swapchain_extent: swapchain_stuff.swapchain_extent, ++ swapchain_imageviews, ++ swapchain_framebuffers, ++ ++ graphics_pipeline_layout, ++ render_pass, ++ graphics_pipeline, ++ ++ ++ compute_descriptor_set, ++ compute_pipeline_layout, ++ compute_pipeline,*/ ++ ++ ++/* FUCKED UP GRAPHICS PIPELINE CREATION FUNCTION WITH INTEGRATED COMPUTE PIPELINE CCREATION, THIS ++ * IS SUPER FUCKED + command_pool: vk::CommandPool, + graphics_pipeline: vk::Pipeline, + framebuffers: &Vec, +@@ -346,31 +573,42 @@ impl VulkanApp { + .end_command_buffer(command_buffer) + .expect("Failed to record Command Buffer at Ending!"); + } +- } +- +- command_buffers +- } +-} +- +-// Fix content ------------------------------------------------------------------------------- +-impl VulkanApp { +- fn create_graphics_pipeline( +- device: &ash::Device, +- render_pass: vk::RenderPass, +- swapchain_extent: vk::Extent2D, +- ) -> (vk::Pipeline, vk::PipelineLayout) { +- let mut shader_modules: Vec = vec![]; +- let main_function = CString::new("main").unwrap(); +- for (shader, stage_i) in shaders() { +- shader_modules.push(vk::PipelineShaderStageCreateInfo { +- s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, +- p_next: ptr::null(), +- flags: vk::PipelineShaderStageCreateFlags::empty(), +- module: share::create_shader_module(device, shader), +- p_name: main_function.as_ptr(), +- stage: stage_i, +- p_specialization_info: ptr::null(), +- }) ++ shader_modules.push(vk::PipelineShaderStageCreateInfo { ++ s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, ++ p_next: ptr::null(), ++ flags: vk::PipelineShaderStageCreateFlags::empty(), ++ module: share::create_shader_module(device, shader), ++ p_name: main_function.as_ptr(), ++ stage: stage_flag, ++ p_specialization_info: ptr::null(), ++ }); ++ } else if stage_flag == vk::ShaderStageFlags::FRAGMENT { ++ shader_modules.push( ++ vk::PipelineShaderStageCreateInfo { ++ s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, ++ p_next: ptr::null(), ++ flags: vk::PipelineShaderStageCreateFlags::empty(), ++ module: share::create_shader_module(device, shader), ++ p_name: main_function.as_ptr(), ++ stage: stage_flag, ++ p_specialization_info: ptr::null(), ++ ++ } ++ ) ++ } else if stage_flag == vk::ShaderStageFlags::VERTEX { ++ shader_modules.push( ++ vk::PipelineShaderStageCreateInfo { ++ s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, ++ p_next: ptr::null(), ++ flags: vk::PipelineShaderStageCreateFlags::empty(), ++ module: share::create_shader_module(device, shader), ++ p_name: main_function.as_ptr(), ++ stage: stage_flag, ++ p_specialization_info: ptr::null(), ++ ++ } ++ ) ++ } + } + + let binding_description = Vertex::get_binding_description(); +@@ -417,6 +655,12 @@ impl VulkanApp { + p_viewports: viewports.as_ptr(), + }; + ++ let rasterization_statue_create_info = vk::PipelineRasterizationStateCreateInfo { ++ s_type: vk::StructureType::PIPELINE_RASTERIZATION_STATE_CREATE_INFO, ++ p_next: ptr::null(), ++ p_viewports: viewports.as_ptr(), ++ }; ++ + let rasterization_statue_create_info = vk::PipelineRasterizationStateCreateInfo { + s_type: vk::StructureType::PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + p_next: ptr::null(), +@@ -492,21 +736,7 @@ impl VulkanApp { + blend_constants: [0.0, 0.0, 0.0, 0.0], + }; + +- let pipeline_layout_create_info = vk::PipelineLayoutCreateInfo { +- s_type: vk::StructureType::PIPELINE_LAYOUT_CREATE_INFO, +- p_next: ptr::null(), +- flags: vk::PipelineLayoutCreateFlags::empty(), +- set_layout_count: 0, +- p_set_layouts: ptr::null(), +- push_constant_range_count: 0, +- p_push_constant_ranges: ptr::null(), +- }; +- +- let pipeline_layout = unsafe { +- device +- .create_pipeline_layout(&pipeline_layout_create_info, None) +- .expect("Failed to create pipeline layout!") +- }; ++ println!("shader module count: {}", shader_modules.len()); + + let graphic_pipeline_create_infos = [vk::GraphicsPipelineCreateInfo { + s_type: vk::StructureType::GRAPHICS_PIPELINE_CREATE_INFO, +@@ -520,34 +750,26 @@ impl VulkanApp { + p_viewport_state: &viewport_state_create_info, + p_rasterization_state: &rasterization_statue_create_info, + p_multisample_state: &multisample_state_create_info, +- p_depth_stencil_state: &depth_state_create_info, +- p_color_blend_state: &color_blend_state, +- p_dynamic_state: ptr::null(), +- layout: pipeline_layout, +- render_pass, +- subpass: 0, +- base_pipeline_handle: vk::Pipeline::null(), +- base_pipeline_index: -1, +- }]; ++ s_type: vk::StructureType::COMPUTE_PIPELINE_CREATE_INFO, ++ p_next: ptr::null(), ++ layout: pipeline_layout, ++ flags: vk::PipelineCreateFlags::empty(), ++ ..Default::default() ++ } ++ ); + +- let graphics_pipelines = unsafe { ++ } ++ let compute_pipelines = unsafe { + device +- .create_graphics_pipelines( ++ .create_compute_pipelines( + vk::PipelineCache::null(), +- &graphic_pipeline_create_infos, ++ &compute_infos, + None, + ) +- .expect("Failed to create Graphics Pipeline!.") +- }; +- +- unsafe { +- for shader in shader_modules { +- device.destroy_shader_module(shader.module, None) +- } +- } ++ }.unwrap(); + +- (graphics_pipelines[0], pipeline_layout) +- } ++ (compute_pipelines, pipeline_layout) ++ }*/ + + fn draw_frame(&mut self) { + let wait_fences = [self.in_flight_fences[self.current_frame]]; +@@ -657,7 +879,7 @@ impl VulkanApp { + }; + self.cleanup_swapchain(); + +- let swapchain_stuff = share::create_swapchain( ++ let swapchain_stuff = SwapChainStuff::new( + &self.instance, + &self.device, + self.physical_device, +@@ -680,7 +902,7 @@ impl VulkanApp { + swapchain_stuff.swapchain_extent, + ); + self.graphics_pipeline = graphics_pipeline; +- self.pipeline_layout = pipeline_layout; ++ self.graphics_pipeline_layout = pipeline_layout; + + self.swapchain_framebuffers = share::create_framebuffers( + &self.device, +@@ -708,7 +930,7 @@ impl VulkanApp { + } + self.device.destroy_pipeline(self.graphics_pipeline, None); + self.device +- .destroy_pipeline_layout(self.pipeline_layout, None); ++ .destroy_pipeline_layout(self.graphics_pipeline_layout, None); + self.device.destroy_render_pass(self.render_pass, None); + for &image_view in self.swapchain_imageviews.iter() { + self.device.destroy_image_view(image_view, None); +@@ -719,7 +941,10 @@ impl VulkanApp { + } + } + ++ ++ + impl Drop for VulkanApp { ++ //cleanup in C++ + fn drop(&mut self) { + unsafe { + for i in 0..MAX_FRAMES_IN_FLIGHT { +@@ -732,6 +957,9 @@ impl Drop for VulkanApp { + + self.cleanup_swapchain(); + ++ self.device ++ .destory ++ + self.device.destroy_buffer(self.vertex_buffer, None); + self.device.free_memory(self.vertex_buffer_memory, None); + +@@ -749,46 +977,3 @@ impl Drop for VulkanApp { + } + } + +-impl VulkanApp { +- pub fn main_loop(mut self, event_loop: EventLoop<()>) { +- let mut tick_counter = utility::fps_limiter::FPSLimiter::new(); +- +- event_loop.run(move |event, _, control_flow| match event { +- Event::WindowEvent { event, .. } => match event { +- WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, +- WindowEvent::KeyboardInput { input, .. } => match input { +- KeyboardInput { +- virtual_keycode, +- state, +- .. +- } => match (virtual_keycode, state) { +- (Some(VirtualKeyCode::Escape), ElementState::Pressed) => { +- *control_flow = ControlFlow::Exit +- } +- _ => {} +- }, +- }, +- _ => {} +- }, +- Event::MainEventsCleared => { +- self.window.request_redraw(); +- } +- Event::RedrawRequested(_window_id) => { +- self.draw_frame(); +- +- tick_counter.tick_frame(); +- if true { +- print!("FPS: {}\r", tick_counter.fps()); +- } +- } +- Event::LoopDestroyed => { +- unsafe { +- self.device +- .device_wait_idle() +- .expect("Failed to wait device idle!") +- }; +- } +- _ => (), +- }) +- } +-} diff --git a/rnd.rs b/rnd.rs new file mode 100644 index 0000000..f1c290f --- /dev/null +++ b/rnd.rs @@ -0,0 +1,943 @@ +use crate::{ + entities::*, shaders::*, utility, utility::constants::*, utility::debug::*, utility::share, + utility::structures::*, +}; + +use ash::{vk, Entry}; + +use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; +use winit::event_loop::{ControlFlow, EventLoop}; + +use std::ffi::CString; +use std::ptr; + +// Constants +const WINDOW_TITLE: &'static str = "Template"; + +pub struct VulkanApp { + window: winit::window::Window, + + // vulkan stuff + _entry: ash::Entry, + instance: ash::Instance, + surface_loader: ash::extensions::khr::Surface, + surface: vk::SurfaceKHR, + debug_utils_loader: ash::extensions::ext::DebugUtils, + debug_merssager: vk::DebugUtilsMessengerEXT, + + physical_device: vk::PhysicalDevice, + device: ash::Device, + + queue_family: QueueFamilyIndices, + graphics_queue: vk::Queue, + present_queue: vk::Queue, + //new from C++ + compute_queue: vk::Queue, + + //not in C++ + swapchain_loader: ash::extensions::khr::Swapchain, + swapchain: vk::SwapchainKHR, + swapchain_images: Vec, + swapchain_format: vk::Format, + swapchain_extent: vk::Extent2D, + swapchain_imageviews: Vec, + swapchain_framebuffers: Vec, + + render_pass: vk::RenderPass, + + graphics_pipeline_layout: vk::PipelineLayout, + graphics_pipeline: vk::Pipeline, + + //new from C++ + compute_descriptor_set_layout: vk::DescriptorSetLayout, + compute_pipeline_layout: vk::PipelineLayout, + compute_pipeline: vk::Pipeline, + + //vertex buffer for the triangle verticies + //i think this is the same as shaderStorageBuffers in C++ version + shader_storage_buffers: Vec, + shader_storage_buffers_memory: Vec, + + uniform_buffers: Vec, + uniform_buffers_memory: Vec, + uniform_buffers_mapped: Vec<*mut c_void>, + + + descriptor_pool: vk::DescriptorPool, + compute_descriptor_sets: Vec, + + command_pool: vk::CommandPool, + command_buffers: Vec, + compute_command_buffers: Vec, + + image_available_semaphores: Vec, + render_finished_semaphores: Vec, + in_flight_fences: Vec, + current_frame: usize, + + is_framebuffer_resized: bool, +} + +impl VulkanApp { + //C++ code:: + /* + createInstance(); + setupDebugMessenger(); + createSurface(); + pickPhysicalDevice(); + createLogicalDevice(); + createSwapChain(); + createImageViews(); + createRenderPass(); + createComputeDescriptorSetLayout(); + createGraphicsPipeline(); + createComputePipeline(); + createFramebuffers(); + createCommandPool(); + createShaderStorageBuffers(); + createUniformBuffers(); DONE + createDescriptorPool(); DONE + createComputeDescriptorSets(); DONE + createCommandBuffers(); DONE + createComputeCommandBuffers(); DONE + createSyncObjects(); DONE + */ + pub fn new(event_loop: &winit::event_loop::EventLoop<()>) -> VulkanApp { + let window = + utility::window::init_window(event_loop, WINDOW_TITLE, WINDOW_WIDTH, WINDOW_HEIGHT); + + // init vulkan stuff + let entry = unsafe { Entry::load().unwrap() }; + let instance = share::create_instance( + &entry, + WINDOW_TITLE, + VALIDATION.is_enable, + &VALIDATION.required_validation_layers.to_vec(), + ); + let surface_stuff = + SurfaceStuff::new(&entry, &instance, &window, WINDOW_WIDTH, WINDOW_HEIGHT); + let (debug_utils_loader, debug_merssager) = + setup_debug_utils(VALIDATION.is_enable, &entry, &instance); + let physical_device = + share::pick_physical_device(&instance, &surface_stuff, &DEVICE_EXTENSIONS); + let (device, queue_family) = share::create_logical_device( + &instance, + physical_device, + &VALIDATION, + &DEVICE_EXTENSIONS, + &surface_stuff, + ); + let graphics_queue = + unsafe { device.get_device_queue(queue_family.graphics_family.unwrap(), 0) }; + let present_queue = + unsafe { device.get_device_queue(queue_family.present_family.unwrap(), 0) }; + let compute_queue = + unsafe { device.get_device_queue(queue_family.compute_family.unwrap(), 0) }; + let swapchain_stuff = SwapChainStuff::new( + &instance, + &device, + physical_device, + &window, + &surface_stuff, + &queue_family, + ); + let swapchain_imageviews = share::create_image_views( + &device, + swapchain_stuff.swapchain_format, + &swapchain_stuff.swapchain_images, + ); + let render_pass = share::create_render_pass(&device, swapchain_stuff.swapchain_format); + let (graphics_pipeline, graphics_pipeline_layout) = VulkanApp::create_graphics_pipeline( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); + let (compute_pipelines, compute_pipeline_layout) = VulkanApp::create_compute_pipelines( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); + + let compute_pipeline = compute_pipelines[0]; + + let swapchain_framebuffers = share::create_framebuffers( + &device, + render_pass, + &swapchain_imageviews, + swapchain_stuff.swapchain_extent, + ); + let command_pool = share::create_command_pool(&device, &queue_family); + let (vertex_buffer, vertex_buffer_memory) = + VulkanApp::create_vertex_buffer(&instance, &device, physical_device); + let command_buffers = VulkanApp::create_command_buffers( + &device, + command_pool, + graphics_pipeline, + &swapchain_framebuffers, + render_pass, + swapchain_stuff.swapchain_extent, + vertex_buffer, + ); + let sync_ojbects = SyncObjects::new(&device, MAX_FRAMES_IN_FLIGHT); + + // cleanup(); the 'drop' function will take care of it. + VulkanApp { + // winit stuff + window, + + // vulkan stuff + _entry: entry, + instance, + surface: surface_stuff.surface, + surface_loader: surface_stuff.surface_loader, + debug_utils_loader, + debug_merssager, + + physical_device, + device, + + queue_family, + graphics_queue, + present_queue, + compute_queue, + + swapchain_loader: swapchain_stuff.swapchain_loader, + swapchain: swapchain_stuff.swapchain, + swapchain_format: swapchain_stuff.swapchain_format, + swapchain_images: swapchain_stuff.swapchain_images, + swapchain_extent: swapchain_stuff.swapchain_extent, + swapchain_imageviews, + swapchain_framebuffers, + + graphics_pipeline_layout, + render_pass, + graphics_pipeline, + + + compute_descriptor_sets, + compute_pipeline_layout, + compute_pipeline, + + vertex_buffer, + vertex_buffer_memory, + + command_pool, + command_buffers, + + image_available_semaphores: sync_ojbects.image_available_semaphores, + render_finished_semaphores: sync_ojbects.render_finished_semaphores, + in_flight_fences: sync_ojbects.inflight_fences, + current_frame: 0, + + is_framebuffer_resized: false, + } + } + + fn create_vertex_buffer( + instance: &ash::Instance, + device: &ash::Device, + physical_device: vk::PhysicalDevice, + ) -> (vk::Buffer, vk::DeviceMemory) { + let vertex_buffer_create_info = vk::BufferCreateInfo { + s_type: vk::StructureType::BUFFER_CREATE_INFO, + p_next: ptr::null(), + flags: vk::BufferCreateFlags::empty(), + size: std::mem::size_of_val(&TRI_VERT_DATA) as u64, + usage: vk::BufferUsageFlags::VERTEX_BUFFER + | vk::BufferUsageFlags::STORAGE_BUFFER + | vk::BufferUsageFlags::TRANSFER_DST, + sharing_mode: vk::SharingMode::EXCLUSIVE, + queue_family_index_count: 0, + p_queue_family_indices: ptr::null(), + }; + + let vertex_buffer = unsafe { + device + .create_buffer(&vertex_buffer_create_info, None) + .expect("Failed to create Vertex Buffer") + }; + + let mem_requirements = unsafe { device.get_buffer_memory_requirements(vertex_buffer) }; + let mem_properties = + unsafe { instance.get_physical_device_memory_properties(physical_device) }; + let required_memory_flags: vk::MemoryPropertyFlags = + vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT; + let memory_type = VulkanApp::find_memory_type( + mem_requirements.memory_type_bits, + required_memory_flags, + mem_properties, + ); + + let allocate_info = vk::MemoryAllocateInfo { + s_type: vk::StructureType::MEMORY_ALLOCATE_INFO, + p_next: ptr::null(), + allocation_size: mem_requirements.size, + memory_type_index: memory_type, + }; + + let vertex_buffer_memory = unsafe { + device + .allocate_memory(&allocate_info, None) + .expect("Failed to allocate vertex buffer memory!") + }; + + unsafe { + device + .bind_buffer_memory(vertex_buffer, vertex_buffer_memory, 0) + .expect("Failed to bind Buffer"); + + let data_ptr = device + .map_memory( + vertex_buffer_memory, + 0, + vertex_buffer_create_info.size, + vk::MemoryMapFlags::empty(), + ) + .expect("Failed to Map Memory") as *mut Vertex; + + data_ptr.copy_from_nonoverlapping(TRI_VERT_DATA.as_ptr(), TRI_VERT_DATA.len()); + + device.unmap_memory(vertex_buffer_memory); + } + + (vertex_buffer, vertex_buffer_memory) + } + + fn find_memory_type( + type_filter: u32, + required_properties: vk::MemoryPropertyFlags, + mem_properties: vk::PhysicalDeviceMemoryProperties, + ) -> u32 { + for (i, memory_type) in mem_properties.memory_types.iter().enumerate() { + //if (type_filter & (1 << i)) > 0 && (memory_type.property_flags & required_properties) == required_properties { + // return i as u32 + // } + + // same implementation + if (type_filter & (1 << i)) > 0 + && memory_type.property_flags.contains(required_properties) + { + return i as u32; + } + } + + panic!("Failed to find suitable memory type!") + share::pick_physical_device(&instance, &surface_stuff, &DEVICE_EXTENSIONS); + let (device, queue_family) = share::create_logical_device( + &instance, + physical_device, + &VALIDATION, + &DEVICE_EXTENSIONS, + &surface_stuff, + ); + let graphics_queue = + unsafe { device.get_device_queue(queue_family.graphics_family.unwrap(), 0) }; + let present_queue = + unsafe { device.get_device_queue(queue_family.present_family.unwrap(), 0) }; + let compute_queue = + unsafe { device.get_device_queue(queue_family.compute_family.unwrap(), 0) }; + let swapchain_stuff = SwapChainStuff::new( + &instance, + &device, + physical_device, + &window, + &surface_stuff, + &queue_family, + ); + let swapchain_imageviews = share::create_image_views( + &device, + swapchain_stuff.swapchain_format, + &swapchain_stuff.swapchain_images, + ); + let render_pass = share::create_render_pass(&device, swapchain_stuff.swapchain_format); + let (graphics_pipeline, graphics_pipeline_layout) = VulkanApp::create_graphics_pipeline( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); + let (compute_pipelines, compute_pipeline_layout) = VulkanApp::create_compute_pipelines( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); + + let compute_pipeline = compute_pipelines[0]; + + let swapchain_framebuffers = share::create_framebuffers( + &device, + render_pass, + &swapchain_imageviews, + swapchain_stuff.swapchain_extent, + ); + let command_pool = share::create_command_pool(&device, &queue_family); + let (vertex_buffer, vertex_buffer_memory) = + VulkanApp::create_vertex_buffer(&instance, &device, physical_device); + let command_buffers = VulkanApp::create_command_buffers( + &device, + command_pool, + graphics_pipeline, + &swapchain_framebuffers, + render_pass, + swapchain_stuff.swapchain_extent, + vertex_buffer, + ); + let sync_ojbects = SyncObjects::new(&device, MAX_FRAMES_IN_FLIGHT); + + // cleanup(); the 'drop' function will take care of it. + VulkanApp { + // winit stuff + window, + + // vulkan stuff + _entry: entry, + instance, + surface: surface_stuff.surface, + surface_loader: surface_stuff.surface_loader, + debug_utils_loader, + debug_merssager, + + physical_device, + device, + + queue_family, + graphics_queue, + present_queue, + compute_queue, + + swapchain_loader: swapchain_stuff.swapchain_loader, + swapchain: swapchain_stuff.swapchain, + swapchain_format: swapchain_stuff.swapchain_format, + swapchain_images: swapchain_stuff.swapchain_images, + swapchain_extent: swapchain_stuff.swapchain_extent, + swapchain_imageviews, + swapchain_framebuffers, + + graphics_pipeline_layout, + render_pass, + graphics_pipeline, + + + compute_descriptor_set, + compute_pipeline_layout, + compute_pipeline, + + command_pool: vk::CommandPool, + graphics_pipeline: vk::Pipeline, + framebuffers: &Vec, + render_pass: vk::RenderPass, + surface_extent: vk::Extent2D, + vertex_buffer: vk::Buffer, + ) -> Vec { + let command_buffer_allocate_info = vk::CommandBufferAllocateInfo { + s_type: vk::StructureType::COMMAND_BUFFER_ALLOCATE_INFO, + p_next: ptr::null(), + command_buffer_count: framebuffers.len() as u32, + command_pool, + level: vk::CommandBufferLevel::PRIMARY, + }; + + let command_buffers = unsafe { + device + .allocate_command_buffers(&command_buffer_allocate_info) + .expect("Failed to allocate Command Buffers!") + }; + + for (i, &command_buffer) in command_buffers.iter().enumerate() { + let command_buffer_begin_info = vk::CommandBufferBeginInfo { + s_type: vk::StructureType::COMMAND_BUFFER_BEGIN_INFO, + p_next: ptr::null(), + flags: vk::CommandBufferUsageFlags::SIMULTANEOUS_USE, + p_inheritance_info: ptr::null(), + }; + + unsafe { + device + .begin_command_buffer(command_buffer, &command_buffer_begin_info) + .expect("Failed to begin recording Command Buffer at beginning!"); + } + + let clear_values = [vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.0, 0.0, 0.0, 1.0], + }, + }]; + + let render_pass_begin_info = vk::RenderPassBeginInfo { + s_type: vk::StructureType::RENDER_PASS_BEGIN_INFO, + p_next: ptr::null(), + framebuffer: framebuffers[i], + render_pass, + clear_value_count: clear_values.len() as u32, + p_clear_values: clear_values.as_ptr(), + render_area: vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: surface_extent, + }, + }; + + unsafe { + device.cmd_begin_render_pass( + command_buffer, + &render_pass_begin_info, + vk::SubpassContents::INLINE, + ); + device.cmd_bind_pipeline( + command_buffer, + vk::PipelineBindPoint::GRAPHICS, + graphics_pipeline, + ); + + let vertex_buffers = [vertex_buffer]; + let offsets = [0_u64]; + + device.cmd_bind_vertex_buffers(command_buffer, 0, &vertex_buffers, &offsets); + + device.cmd_draw(command_buffer, TRI_VERT_DATA.len() as u32, 1, 0, 0); + + device.cmd_end_render_pass(command_buffer); + + device + .end_command_buffer(command_buffer) + .expect("Failed to record Command Buffer at Ending!"); + } + shader_modules.push(vk::PipelineShaderStageCreateInfo { + s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineShaderStageCreateFlags::empty(), + module: share::create_shader_module(device, shader), + p_name: main_function.as_ptr(), + stage: stage_flag, + p_specialization_info: ptr::null(), + }); + } else if stage_flag == vk::ShaderStageFlags::FRAGMENT { + shader_modules.push( + vk::PipelineShaderStageCreateInfo { + s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineShaderStageCreateFlags::empty(), + module: share::create_shader_module(device, shader), + p_name: main_function.as_ptr(), + stage: stage_flag, + p_specialization_info: ptr::null(), + + } + ) + } else if stage_flag == vk::ShaderStageFlags::VERTEX { + shader_modules.push( + vk::PipelineShaderStageCreateInfo { + s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineShaderStageCreateFlags::empty(), + module: share::create_shader_module(device, shader), + p_name: main_function.as_ptr(), + stage: stage_flag, + p_specialization_info: ptr::null(), + + } + ) + } + } + + let binding_description = Vertex::get_binding_description(); + let attribute_description = Vertex::get_attribute_descriptions(); + + let vertex_input_state_create_info = vk::PipelineVertexInputStateCreateInfo { + s_type: vk::StructureType::PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineVertexInputStateCreateFlags::empty(), + vertex_attribute_description_count: attribute_description.len() as u32, + p_vertex_attribute_descriptions: attribute_description.as_ptr(), + vertex_binding_description_count: binding_description.len() as u32, + p_vertex_binding_descriptions: binding_description.as_ptr(), + }; + let vertex_input_assembly_state_info = vk::PipelineInputAssemblyStateCreateInfo { + s_type: vk::StructureType::PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + flags: vk::PipelineInputAssemblyStateCreateFlags::empty(), + p_next: ptr::null(), + topology: vk::PrimitiveTopology::TRIANGLE_LIST, + primitive_restart_enable: vk::FALSE, + }; + + let viewports = [vk::Viewport { + x: 0.0, + y: 0.0, + width: swapchain_extent.width as f32, + height: swapchain_extent.height as f32, + min_depth: 0.0, + max_depth: 1.0, + }]; + + let scissors = [vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: swapchain_extent, + }]; + + let viewport_state_create_info = vk::PipelineViewportStateCreateInfo { + s_type: vk::StructureType::PIPELINE_VIEWPORT_STATE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineViewportStateCreateFlags::empty(), + scissor_count: scissors.len() as u32, + p_scissors: scissors.as_ptr(), + viewport_count: viewports.len() as u32, + p_viewports: viewports.as_ptr(), + }; + + let rasterization_statue_create_info = vk::PipelineRasterizationStateCreateInfo { + s_type: vk::StructureType::PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + p_next: ptr::null(), + p_viewports: viewports.as_ptr(), + }; + + let rasterization_statue_create_info = vk::PipelineRasterizationStateCreateInfo { + s_type: vk::StructureType::PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineRasterizationStateCreateFlags::empty(), + cull_mode: vk::CullModeFlags::BACK, + front_face: vk::FrontFace::CLOCKWISE, + line_width: 1.0, + polygon_mode: vk::PolygonMode::FILL, + rasterizer_discard_enable: vk::FALSE, + depth_clamp_enable: vk::FALSE, + depth_bias_clamp: 0.0, + depth_bias_constant_factor: 0.0, + depth_bias_enable: vk::FALSE, + depth_bias_slope_factor: 0.0, + }; + + let multisample_state_create_info = vk::PipelineMultisampleStateCreateInfo { + s_type: vk::StructureType::PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + flags: vk::PipelineMultisampleStateCreateFlags::empty(), + p_next: ptr::null(), + rasterization_samples: vk::SampleCountFlags::TYPE_1, + sample_shading_enable: vk::FALSE, + min_sample_shading: 0.0, + p_sample_mask: ptr::null(), + alpha_to_one_enable: vk::FALSE, + alpha_to_coverage_enable: vk::FALSE, + }; + + let stencil_state = vk::StencilOpState { + fail_op: vk::StencilOp::KEEP, + pass_op: vk::StencilOp::KEEP, + depth_fail_op: vk::StencilOp::KEEP, + compare_op: vk::CompareOp::ALWAYS, + compare_mask: 0, + write_mask: 0, + reference: 0, + }; + + let depth_state_create_info = vk::PipelineDepthStencilStateCreateInfo { + s_type: vk::StructureType::PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineDepthStencilStateCreateFlags::empty(), + depth_test_enable: vk::FALSE, + depth_write_enable: vk::FALSE, + depth_compare_op: vk::CompareOp::LESS_OR_EQUAL, + depth_bounds_test_enable: vk::FALSE, + stencil_test_enable: vk::FALSE, + front: stencil_state, + back: stencil_state, + max_depth_bounds: 1.0, + min_depth_bounds: 0.0, + }; + + let color_blend_attachment_states = [vk::PipelineColorBlendAttachmentState { + blend_enable: vk::FALSE, + color_write_mask: vk::ColorComponentFlags::RGBA, + src_color_blend_factor: vk::BlendFactor::ONE, + dst_color_blend_factor: vk::BlendFactor::ZERO, + color_blend_op: vk::BlendOp::ADD, + src_alpha_blend_factor: vk::BlendFactor::ONE, + dst_alpha_blend_factor: vk::BlendFactor::ZERO, + alpha_blend_op: vk::BlendOp::ADD, + }]; + + let color_blend_state = vk::PipelineColorBlendStateCreateInfo { + s_type: vk::StructureType::PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineColorBlendStateCreateFlags::empty(), + logic_op_enable: vk::FALSE, + logic_op: vk::LogicOp::COPY, + attachment_count: color_blend_attachment_states.len() as u32, + p_attachments: color_blend_attachment_states.as_ptr(), + blend_constants: [0.0, 0.0, 0.0, 0.0], + }; + + println!("shader module count: {}", shader_modules.len()); + + let graphic_pipeline_create_infos = [vk::GraphicsPipelineCreateInfo { + s_type: vk::StructureType::GRAPHICS_PIPELINE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineCreateFlags::empty(), + stage_count: shader_modules.len() as u32, + p_stages: shader_modules.as_ptr(), + p_vertex_input_state: &vertex_input_state_create_info, + p_input_assembly_state: &vertex_input_assembly_state_info, + p_tessellation_state: ptr::null(), + p_viewport_state: &viewport_state_create_info, + p_rasterization_state: &rasterization_statue_create_info, + p_multisample_state: &multisample_state_create_info, + s_type: vk::StructureType::COMPUTE_PIPELINE_CREATE_INFO, + p_next: ptr::null(), + layout: pipeline_layout, + flags: vk::PipelineCreateFlags::empty(), + ..Default::default() + } + ); + + } + let compute_pipelines = unsafe { + device + .create_compute_pipelines( + vk::PipelineCache::null(), + &compute_infos, + None, + ) + }.unwrap(); + + (compute_pipelines, pipeline_layout) + } + + fn draw_frame(&mut self) { + let wait_fences = [self.in_flight_fences[self.current_frame]]; + + unsafe { + self.device + .wait_for_fences(&wait_fences, true, std::u64::MAX) + .expect("Failed to wait for Fence!"); + } + + let (image_index, _is_sub_optimal) = unsafe { + let result = self.swapchain_loader.acquire_next_image( + self.swapchain, + std::u64::MAX, + self.image_available_semaphores[self.current_frame], + vk::Fence::null(), + ); + match result { + Ok(image_index) => image_index, + Err(vk_result) => match vk_result { + vk::Result::ERROR_OUT_OF_DATE_KHR => { + self.recreate_swapchain(); + return; + } + _ => panic!("Failed to acquire Swap Chain Image!"), + }, + } + }; + + let wait_semaphores = [self.image_available_semaphores[self.current_frame]]; + let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; + let signal_semaphores = [self.render_finished_semaphores[self.current_frame]]; + + let submit_infos = [vk::SubmitInfo { + s_type: vk::StructureType::SUBMIT_INFO, + p_next: ptr::null(), + wait_semaphore_count: wait_semaphores.len() as u32, + p_wait_semaphores: wait_semaphores.as_ptr(), + p_wait_dst_stage_mask: wait_stages.as_ptr(), + command_buffer_count: 1, + p_command_buffers: &self.command_buffers[image_index as usize], + signal_semaphore_count: signal_semaphores.len() as u32, + p_signal_semaphores: signal_semaphores.as_ptr(), + }]; + + unsafe { + self.device + .reset_fences(&wait_fences) + .expect("Failed to reset Fence!"); + + self.device + .queue_submit( + self.graphics_queue, + &submit_infos, + self.in_flight_fences[self.current_frame], + ) + .expect("Failed to execute queue submit."); + } + + let swapchains = [self.swapchain]; + + let present_info = vk::PresentInfoKHR { + s_type: vk::StructureType::PRESENT_INFO_KHR, + p_next: ptr::null(), + wait_semaphore_count: 1, + p_wait_semaphores: signal_semaphores.as_ptr(), + swapchain_count: 1, + p_swapchains: swapchains.as_ptr(), + p_image_indices: &image_index, + p_results: ptr::null_mut(), + }; + + let result = unsafe { + self.swapchain_loader + .queue_present(self.present_queue, &present_info) + }; + + let is_resized = match result { + Ok(_) => self.is_framebuffer_resized, + Err(vk_result) => match vk_result { + vk::Result::ERROR_OUT_OF_DATE_KHR | vk::Result::SUBOPTIMAL_KHR => true, + _ => panic!("Failed to execute queue present."), + }, + }; + if is_resized { + self.is_framebuffer_resized = false; + self.recreate_swapchain(); + } + + self.current_frame = (self.current_frame + 1) % MAX_FRAMES_IN_FLIGHT; + } + + fn recreate_swapchain(&mut self) { + // parameters ------------- + let surface_suff = SurfaceStuff { + surface_loader: self.surface_loader.clone(), + surface: self.surface, + screen_width: WINDOW_WIDTH, + screen_height: WINDOW_HEIGHT, + }; + // ------------------------ + + unsafe { + self.device + .device_wait_idle() + .expect("Failed to wait device idle!") + }; + self.cleanup_swapchain(); + + let swapchain_stuff = SwapChainStuff::new( + &self.instance, + &self.device, + self.physical_device, + &self.window, + &surface_suff, + &self.queue_family, + ); + self.swapchain_loader = swapchain_stuff.swapchain_loader; + self.swapchain = swapchain_stuff.swapchain; + self.swapchain_images = swapchain_stuff.swapchain_images; + self.swapchain_format = swapchain_stuff.swapchain_format; + self.swapchain_extent = swapchain_stuff.swapchain_extent; + + self.swapchain_imageviews = + share::create_image_views(&self.device, self.swapchain_format, &self.swapchain_images); + self.render_pass = share::create_render_pass(&self.device, self.swapchain_format); + let (graphics_pipeline, pipeline_layout) = VulkanApp::create_graphics_pipeline( + &self.device, + self.render_pass, + swapchain_stuff.swapchain_extent, + ); + self.graphics_pipeline = graphics_pipeline; + self.graphics_pipeline_layout = pipeline_layout; + + self.swapchain_framebuffers = share::create_framebuffers( + &self.device, + self.render_pass, + &self.swapchain_imageviews, + self.swapchain_extent, + ); + self.command_buffers = VulkanApp::create_command_buffers( + &self.device, + self.command_pool, + self.graphics_pipeline, + &self.swapchain_framebuffers, + self.render_pass, + self.swapchain_extent, + self.vertex_buffer, + ); + } + + fn cleanup_swapchain(&self) { + unsafe { + self.device + .free_command_buffers(self.command_pool, &self.command_buffers); + for &framebuffer in self.swapchain_framebuffers.iter() { + self.device.destroy_framebuffer(framebuffer, None); + } + self.device.destroy_pipeline(self.graphics_pipeline, None); + self.device + .destroy_pipeline_layout(self.graphics_pipeline_layout, None); + self.device.destroy_render_pass(self.render_pass, None); + for &image_view in self.swapchain_imageviews.iter() { + self.device.destroy_image_view(image_view, None); + } + self.swapchain_loader + .destroy_swapchain(self.swapchain, None); + } + } +} + +impl Drop for VulkanApp { + fn drop(&mut self) { + unsafe { + for i in 0..MAX_FRAMES_IN_FLIGHT { + self.device + .destroy_semaphore(self.image_available_semaphores[i], None); + self.device + .destroy_semaphore(self.render_finished_semaphores[i], None); + self.device.destroy_fence(self.in_flight_fences[i], None); + } + + share::pick_physical_device(&instance, &surface_stuff, &DEVICE_EXTENSIONS); + let (device, queue_family) = share::create_logical_device( + &instance, + physical_device, + &VALIDATION, + &DEVICE_EXTENSIONS, + &surface_stuff, + ); + let graphics_queue = + unsafe { device.get_device_queue(queue_family.graphics_family.unwrap(), 0) }; + let present_queue = + unsafe { device.get_device_queue(queue_family.present_family.unwrap(), 0) }; + let compute_queue = + unsafe { device.get_device_queue(queue_family.compute_family.unwrap(), 0) }; + let swapchain_stuff = SwapChainStuff::new( + &instance, + &device, + physical_device, + &window, + &surface_stuff, + &queue_family, + ); + let swapchain_imageviews = share::create_image_views( + &device, + swapchain_stuff.swapchain_format, + &swapchain_stuff.swapchain_images, + ); + let render_pass = share::create_render_pass(&device, swapchain_stuff.swapchain_format); + let (graphics_pipeline, graphics_pipeline_layout) = VulkanApp::create_graphics_pipeline( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); + let (compute_pipelines, compute_pipeline_layout) = VulkanApp::create_compute_pipelines( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); + + let compute_pipeline = compute_pipelines[0]; + + let swapchain_framebuffers = share::create_framebuffers( + &device, + render_pass, + &swapchain_imageviews, + swapchain_stuff.swapchain_extent, + ); + let command_pool = share::create_command_pool(&device, &queue_family); + let (vertex_buffer, vertex_buffer_memory) = + VulkanApp::create_vertex_buffer(&instance, &device, physical_device); + let command_buffers = VulkanApp::create_command_buffers( + &device, + command_pool, + graphics_pipeline, + &swapchain_framebuffers, + render_pass, + swapchain_stuff.swapchain_extent, + vertex_buffer, + ); + let sync_ojbects = SyncObjects::new(&device, MAX_FRAMES_IN_FLIGHT); + + // cleanup(); the 'drop' function will take care of it. diff --git a/src/entities.rs b/src/entities.rs index 2e7f3d0..7c4dd78 100644 --- a/src/entities.rs +++ b/src/entities.rs @@ -9,7 +9,7 @@ use rand::{ use crate::utility::constants::*; use std::f32::consts::PI; -const PARTICLE_COUNT: i32 = 1000; +pub const PARTICLE_COUNT: i32 = 1000; #[repr(C)] #[derive(Clone, Debug, Copy)] @@ -44,8 +44,35 @@ impl Particle { } res } + + pub fn get_binding_description() -> [vk::VertexInputBindingDescription; 1] { + [vk::VertexInputBindingDescription { + binding: 0, + stride: std::mem::size_of::() as u32, + input_rate: vk::VertexInputRate::VERTEX, + }] + } + + pub fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] { + [ + vk::VertexInputAttributeDescription { + binding: 0, + location: 0, + format: vk::Format::R32G32_SFLOAT, + offset: offset_of!(Particle, pos) as u32, + }, + vk::VertexInputAttributeDescription { + binding: 0, + location: 1, + format: vk::Format::R32G32B32_SFLOAT, + offset: offset_of!(Particle, color) as u32, + }, + ] + } + } + #[repr(C)] #[derive(Clone, Debug, Copy)] pub struct Vertex { diff --git a/src/render.rs b/src/render.rs index c8f2dc6..c3d9c99 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,10 +1,3 @@ -use crate::{ - entities::*, shaders::*, utility, utility::constants::*, utility::debug::*, utility::share, - utility::structures::*, -}; - -use ash::{vk, Entry}; - use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; @@ -14,7 +7,67 @@ use std::ptr; // Constants const WINDOW_TITLE: &'static str = "Template"; -pub struct VulkanApp { +const IS_PAINT_FPS_COUNTER: bool = true; + +/* Non share.rs functions to check + * + * debug fns covered by setup_debug_utils + + * Particle related functions get_binding, get_attribute + + * create_swapchain relocated to structures.rs + + * + * check_validation_layer_support + * + * + * + * + */ + +/* LIST USED share.rs functions here + * + * create_swapchain + * create_shader_module + + * pick_physical_device + + * create_instance + + * create_logical_device + + * create_image_views + + * create_render_pass + + * create_framebuffers + + * create_command_pool + * choose_swap_surface_format + + * choose_swap_present_mode + + * choose_swap_extent + + * query_swapchain_support + + * is_physical_device_suitable + + * check_device_extension_support + + * find_queue_family + + * required_extension_names + + * create_command_buffers + * record_command_buffer + + */ + +/* + * TODO fix create_command_buffers so it matches C++ code + * TODO create initVulkan equivalent + * TODO cleanup_swapchain and cleanup functions + * TODO create_command_buffer, record_command_buffer + * */ + + +pub fn init_window( + event_loop: &EventLoop<()>, + title: &str, + width: u32, + height: u32, +) -> winit::window::Window { + winit::window::WindowBuilder::new() + .with_title(title) + .with_inner_size(winit::dpi::LogicalSize::new(width, height)) + .build(event_loop) + .expect("Failed to create window.") +} + + +pub struct App { window: winit::window::Window, // vulkan stuff @@ -31,37 +84,63 @@ pub struct VulkanApp { queue_family: QueueFamilyIndices, graphics_queue: vk::Queue, present_queue: vk::Queue, - - swapchain_loader: ash::extensions::khr::Swapchain, - swapchain: vk::SwapchainKHR, - swapchain_images: Vec, - swapchain_format: vk::Format, - swapchain_extent: vk::Extent2D, - swapchain_imageviews: Vec, - swapchain_framebuffers: Vec, + //new from C++ + compute_queue: vk::Queue, + + swapchain_stuff: SwapChainStuff, + //not in C++ + //swapchain_loader: ash::extensions::khr::Swapchain, + //swapchain: vk::SwapchainKHR, + //swapchain_images: Vec, + //swapchain_format: vk::Format, + //swapchain_extent: vk::Extent2D, + //swapchain_imageviews: Vec, + //swapchain_framebuffers: Vec, render_pass: vk::RenderPass, - pipeline_layout: vk::PipelineLayout, + + graphics_pipeline_layout: vk::PipelineLayout, graphics_pipeline: vk::Pipeline, + + //new from C++ + compute_descriptor_set_layout: vk::DescriptorSetLayout, + compute_pipeline_layout: vk::PipelineLayout, + compute_pipeline: vk::Pipeline, - vertex_buffer: vk::Buffer, - vertex_buffer_memory: vk::DeviceMemory, + //vertex buffer for the triangle verticies + //i think this is the same as shaderStorageBuffers in C++ version + shader_storage_buffers: Vec, + shader_storage_buffers_memory: Vec, + + uniform_buffers: Vec, + uniform_buffers_memory: Vec, + uniform_buffers_mapped: Vec<*mut c_void>, + + + descriptor_pool: vk::DescriptorPool, + compute_descriptor_sets: Vec, command_pool: vk::CommandPool, command_buffers: Vec, + compute_command_buffers: Vec, - image_available_semaphores: Vec, - render_finished_semaphores: Vec, - in_flight_fences: Vec, + sync_objects: SyncObjects, + //image_available_semaphores: Vec, + //render_finished_semaphores: Vec, + //in_flight_fences: Vec, + //compute_in_flight_fences: Vec, current_frame: usize, + last_frame_time: float, + is_framebuffer_resized: bool, } -impl VulkanApp { - pub fn new(event_loop: &winit::event_loop::EventLoop<()>) -> VulkanApp { +impl App { + ///initVulkan in C++ + pub fn new(event_loop: &winit::event_loop::EventLoop<()>) -> App { let window = - utility::window::init_window(event_loop, WINDOW_TITLE, WINDOW_WIDTH, WINDOW_HEIGHT); + init_window(event_loop, WINDOW_TITLE, WINDOW_WIDTH, WINDOW_HEIGHT); // init vulkan stuff let entry = unsafe { Entry::load().unwrap() }; @@ -72,7 +151,7 @@ impl VulkanApp { &VALIDATION.required_validation_layers.to_vec(), ); let surface_stuff = - share::create_surface(&entry, &instance, &window, WINDOW_WIDTH, WINDOW_HEIGHT); + SurfaceStuff::new(&entry, &instance, &window, WINDOW_WIDTH, WINDOW_HEIGHT); let (debug_utils_loader, debug_merssager) = setup_debug_utils(VALIDATION.is_enable, &entry, &instance); let physical_device = @@ -88,7 +167,9 @@ impl VulkanApp { unsafe { device.get_device_queue(queue_family.graphics_family.unwrap(), 0) }; let present_queue = unsafe { device.get_device_queue(queue_family.present_family.unwrap(), 0) }; - let swapchain_stuff = share::create_swapchain( + let compute_queue = + unsafe { device.get_device_queue(queue_family.compute_family.unwrap(), 0) }; + let swapchain_stuff = SwapChainStuff::new( &instance, &device, physical_device, @@ -102,11 +183,19 @@ impl VulkanApp { &swapchain_stuff.swapchain_images, ); let render_pass = share::create_render_pass(&device, swapchain_stuff.swapchain_format); - let (graphics_pipeline, pipeline_layout) = VulkanApp::create_graphics_pipeline( + let (graphics_pipeline, graphics_pipeline_layout) = App::create_graphics_pipeline( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); + let (compute_pipelines, compute_pipeline_layout) = App::create_compute_pipelines( &device, render_pass, swapchain_stuff.swapchain_extent, ); + + let compute_pipeline = compute_pipelines[0]; + let swapchain_framebuffers = share::create_framebuffers( &device, render_pass, @@ -115,8 +204,8 @@ impl VulkanApp { ); let command_pool = share::create_command_pool(&device, &queue_family); let (vertex_buffer, vertex_buffer_memory) = - VulkanApp::create_vertex_buffer(&instance, &device, physical_device); - let command_buffers = VulkanApp::create_command_buffers( + App::create_vertex_buffer(&instance, &device, physical_device); + let command_buffers = App::create_command_buffers( &device, command_pool, graphics_pipeline, @@ -125,10 +214,10 @@ impl VulkanApp { swapchain_stuff.swapchain_extent, vertex_buffer, ); - let sync_ojbects = share::create_sync_objects(&device, MAX_FRAMES_IN_FLIGHT); + let sync_ojbects = SyncObjects::new(&device, MAX_FRAMES_IN_FLIGHT); // cleanup(); the 'drop' function will take care of it. - VulkanApp { + App { // winit stuff window, @@ -146,6 +235,7 @@ impl VulkanApp { queue_family, graphics_queue, present_queue, + compute_queue, swapchain_loader: swapchain_stuff.swapchain_loader, swapchain: swapchain_stuff.swapchain, @@ -155,10 +245,15 @@ impl VulkanApp { swapchain_imageviews, swapchain_framebuffers, - pipeline_layout, + graphics_pipeline_layout, render_pass, graphics_pipeline, + + compute_descriptor_sets, + compute_pipeline_layout, + compute_pipeline, + vertex_buffer, vertex_buffer_memory, @@ -174,6 +269,55 @@ impl VulkanApp { } } + pub fn main_loop(self) { + let mut tick_counter = super::fps_limiter::FPSLimiter::new(); + + self.event_loop + .run(move |event, _, control_flow| match event { + Event::WindowEvent { event, .. } => match event { + WindowEvent::CloseRequested => { + vulkan_app.wait_device_idle(); + *control_flow = ControlFlow::Exit + } + WindowEvent::KeyboardInput { input, .. } => match input { + KeyboardInput { + virtual_keycode, + state, + .. + } => match (virtual_keycode, state) { + (Some(VirtualKeyCode::Escape), ElementState::Pressed) => { + vulkan_app.wait_device_idle(); + *control_flow = ControlFlow::Exit + } + _ => {} + }, + }, + WindowEvent::Resized(_new_size) => { + vulkan_app.wait_device_idle(); + vulkan_app.resize_framebuffer(); + } + _ => {} + }, + Event::MainEventsCleared => { + vulkan_app.window_ref().request_redraw(); + } + Event::RedrawRequested(_window_id) => { + let delta_time = tick_counter.delta_time(); + vulkan_app.draw_frame(delta_time); + + if IS_PAINT_FPS_COUNTER { + print!("FPS: {}\r", tick_counter.fps()); + } + + tick_counter.tick_frame(); + } + Event::LoopDestroyed => { + vulkan_app.wait_device_idle(); + } + _ => (), + }) + } + fn create_vertex_buffer( instance: &ash::Instance, device: &ash::Device, @@ -243,118 +387,24 @@ impl VulkanApp { (vertex_buffer, vertex_buffer_memory) } - + fn find_memory_type( type_filter: u32, required_properties: vk::MemoryPropertyFlags, mem_properties: vk::PhysicalDeviceMemoryProperties, ) -> u32 { for (i, memory_type) in mem_properties.memory_types.iter().enumerate() { - //if (type_filter & (1 << i)) > 0 && (memory_type.property_flags & required_properties) == required_properties { - // return i as u32 - // } - - // same implementation - if (type_filter & (1 << i)) > 0 - && memory_type.property_flags.contains(required_properties) - { - return i as u32; + if (type_filter & (1 << i)) > 0 && (memory_type.property_flags & required_properties) == required_properties { + return i as u32 } } panic!("Failed to find suitable memory type!") + share::pick_physical_device(&instance, &surface_stuff, &DEVICE_EXTENSIONS); } - fn create_command_buffers( - device: &ash::Device, - command_pool: vk::CommandPool, - graphics_pipeline: vk::Pipeline, - framebuffers: &Vec, - render_pass: vk::RenderPass, - surface_extent: vk::Extent2D, - vertex_buffer: vk::Buffer, - ) -> Vec { - let command_buffer_allocate_info = vk::CommandBufferAllocateInfo { - s_type: vk::StructureType::COMMAND_BUFFER_ALLOCATE_INFO, - p_next: ptr::null(), - command_buffer_count: framebuffers.len() as u32, - command_pool, - level: vk::CommandBufferLevel::PRIMARY, - }; - - let command_buffers = unsafe { - device - .allocate_command_buffers(&command_buffer_allocate_info) - .expect("Failed to allocate Command Buffers!") - }; - - for (i, &command_buffer) in command_buffers.iter().enumerate() { - let command_buffer_begin_info = vk::CommandBufferBeginInfo { - s_type: vk::StructureType::COMMAND_BUFFER_BEGIN_INFO, - p_next: ptr::null(), - flags: vk::CommandBufferUsageFlags::SIMULTANEOUS_USE, - p_inheritance_info: ptr::null(), - }; - - unsafe { - device - .begin_command_buffer(command_buffer, &command_buffer_begin_info) - .expect("Failed to begin recording Command Buffer at beginning!"); - } - - let clear_values = [vk::ClearValue { - color: vk::ClearColorValue { - float32: [0.0, 0.0, 0.0, 1.0], - }, - }]; - - let render_pass_begin_info = vk::RenderPassBeginInfo { - s_type: vk::StructureType::RENDER_PASS_BEGIN_INFO, - p_next: ptr::null(), - framebuffer: framebuffers[i], - render_pass, - clear_value_count: clear_values.len() as u32, - p_clear_values: clear_values.as_ptr(), - render_area: vk::Rect2D { - offset: vk::Offset2D { x: 0, y: 0 }, - extent: surface_extent, - }, - }; - - unsafe { - device.cmd_begin_render_pass( - command_buffer, - &render_pass_begin_info, - vk::SubpassContents::INLINE, - ); - device.cmd_bind_pipeline( - command_buffer, - vk::PipelineBindPoint::GRAPHICS, - graphics_pipeline, - ); - - let vertex_buffers = [vertex_buffer]; - let offsets = [0_u64]; - - device.cmd_bind_vertex_buffers(command_buffer, 0, &vertex_buffers, &offsets); - - device.cmd_draw(command_buffer, TRI_VERT_DATA.len() as u32, 1, 0, 0); - - device.cmd_end_render_pass(command_buffer); - - device - .end_command_buffer(command_buffer) - .expect("Failed to record Command Buffer at Ending!"); - } - } - - command_buffers - } -} - -// Fix content ------------------------------------------------------------------------------- -impl VulkanApp { fn create_graphics_pipeline( + self, device: &ash::Device, render_pass: vk::RenderPass, swapchain_extent: vk::Extent2D, @@ -362,52 +412,66 @@ impl VulkanApp { let mut shader_modules: Vec = vec![]; let main_function = CString::new("main").unwrap(); for (shader, stage_i) in shaders() { - shader_modules.push(vk::PipelineShaderStageCreateInfo { - s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, - p_next: ptr::null(), - flags: vk::PipelineShaderStageCreateFlags::empty(), - module: share::create_shader_module(device, shader), - p_name: main_function.as_ptr(), - stage: stage_i, - p_specialization_info: ptr::null(), - }) + //check if graphics shader + if stage_i.contains(ShaderStageFlags::ALL_GRAPHICS) { + shader_modules.push( + vk::PipelineShaderStageCreateInfo { + s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineShaderStageCreateFlags::empty(), + module: share::create_shader_module(device, shader), + p_name: main_function.as_ptr(), + stage: stage_i, + p_specialization_info: ptr::null(), + } + ); + } } + + //grab shader modules from index informed by shaders.rs generated file + let frag_shader = shader_modules[0]; + let vert_shader = shader_modules[1]; - let binding_description = Vertex::get_binding_description(); - let attribute_description = Vertex::get_attribute_descriptions(); + //612-621 + let binding_description = Particle::get_binding_description(); + let attribute_description = Particle::get_attribute_description(); - let vertex_input_state_create_info = vk::PipelineVertexInputStateCreateInfo { + let vertex_input_info = vk::PipelineVertexInputStateCreateInfo { s_type: vk::StructureType::PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, p_next: ptr::null(), flags: vk::PipelineVertexInputStateCreateFlags::empty(), vertex_attribute_description_count: attribute_description.len() as u32, p_vertex_attribute_descriptions: attribute_description.as_ptr(), vertex_binding_description_count: binding_description.len() as u32, - p_vertex_binding_descriptions: binding_description.as_ptr(), - }; - let vertex_input_assembly_state_info = vk::PipelineInputAssemblyStateCreateInfo { + p_ver + } + + + //623-626 + let input_assembly = vk::PipelineInputAssemblyStateCreateInfo { s_type: vk::StructureType::PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, flags: vk::PipelineInputAssemblyStateCreateFlags::empty(), p_next: ptr::null(), - topology: vk::PrimitiveTopology::TRIANGLE_LIST, + topology: vk::PrimitiveTopology::POINT_LIST, primitive_restart_enable: vk::FALSE, }; + //628-631, more verbose and explicit than C++ let viewports = [vk::Viewport { x: 0.0, y: 0.0, - width: swapchain_extent.width as f32, - height: swapchain_extent.height as f32, + width: self.swapchain_stuff.swapchain_extent.width as f32, + height: self.swapchain_stuff.swapchain_extent.height as f32, min_depth: 0.0, max_depth: 1.0, }]; let scissors = [vk::Rect2D { offset: vk::Offset2D { x: 0, y: 0 }, - extent: swapchain_extent, + extent: self.swapchain_stuff.swapchain_extent, }]; - let viewport_state_create_info = vk::PipelineViewportStateCreateInfo { + let viewport_state = vk::PipelineViewportStateCreateInfo { s_type: vk::StructureType::PIPELINE_VIEWPORT_STATE_CREATE_INFO, p_next: ptr::null(), flags: vk::PipelineViewportStateCreateFlags::empty(), @@ -417,7 +481,8 @@ impl VulkanApp { p_viewports: viewports.as_ptr(), }; - let rasterization_statue_create_info = vk::PipelineRasterizationStateCreateInfo { + //633-641 + let rasterizer = vk::PipelineRasterizationStateCreateInfo { s_type: vk::StructureType::PIPELINE_RASTERIZATION_STATE_CREATE_INFO, p_next: ptr::null(), flags: vk::PipelineRasterizationStateCreateFlags::empty(), @@ -428,12 +493,14 @@ impl VulkanApp { rasterizer_discard_enable: vk::FALSE, depth_clamp_enable: vk::FALSE, depth_bias_clamp: 0.0, + device.destroy_shader_module(); depth_bias_constant_factor: 0.0, depth_bias_enable: vk::FALSE, depth_bias_slope_factor: 0.0, }; - let multisample_state_create_info = vk::PipelineMultisampleStateCreateInfo { + //643-646 + let multisampling = vk::PipelineMultisampleStateCreateInfo { s_type: vk::StructureType::PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, flags: vk::PipelineMultisampleStateCreateFlags::empty(), p_next: ptr::null(), @@ -445,43 +512,20 @@ impl VulkanApp { alpha_to_coverage_enable: vk::FALSE, }; - let stencil_state = vk::StencilOpState { - fail_op: vk::StencilOp::KEEP, - pass_op: vk::StencilOp::KEEP, - depth_fail_op: vk::StencilOp::KEEP, - compare_op: vk::CompareOp::ALWAYS, - compare_mask: 0, - write_mask: 0, - reference: 0, - }; - - let depth_state_create_info = vk::PipelineDepthStencilStateCreateInfo { - s_type: vk::StructureType::PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, - p_next: ptr::null(), - flags: vk::PipelineDepthStencilStateCreateFlags::empty(), - depth_test_enable: vk::FALSE, - depth_write_enable: vk::FALSE, - depth_compare_op: vk::CompareOp::LESS_OR_EQUAL, - depth_bounds_test_enable: vk::FALSE, - stencil_test_enable: vk::FALSE, - front: stencil_state, - back: stencil_state, - max_depth_bounds: 1.0, - min_depth_bounds: 0.0, - }; - - let color_blend_attachment_states = [vk::PipelineColorBlendAttachmentState { - blend_enable: vk::FALSE, + //648-656 + let color_blend_attachment = vk::PipelineColorBlendAttachmentState { + blend_enable: vk::TRUE, color_write_mask: vk::ColorComponentFlags::RGBA, - src_color_blend_factor: vk::BlendFactor::ONE, - dst_color_blend_factor: vk::BlendFactor::ZERO, + src_color_blend_factor: vk::BlendFactor::SRC_ALPHA, + dst_color_blend_factor: vk::BlendFactor::ONE_MINUS_SRC_ALPHA, color_blend_op: vk::BlendOp::ADD, - src_alpha_blend_factor: vk::BlendFactor::ONE, + src_alpha_blend_factor: vk::BlendFactor::ONE_MINUS_SRC_ALPHA, dst_alpha_blend_factor: vk::BlendFactor::ZERO, alpha_blend_op: vk::BlendOp::ADD, - }]; + }; - let color_blend_state = vk::PipelineColorBlendStateCreateInfo { + //658-667 + let color_blending = vk::PipelineColorBlendStateCreateInfo { s_type: vk::StructureType::PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, p_next: ptr::null(), flags: vk::PipelineColorBlendStateCreateFlags::empty(), @@ -492,77 +536,242 @@ impl VulkanApp { blend_constants: [0.0, 0.0, 0.0, 0.0], }; - let pipeline_layout_create_info = vk::PipelineLayoutCreateInfo { + //669-676 + let dynamic_states = vk::DynamicState { + vk::DynamicState::VIEWPORT, + vk::DynamicState::SCISSOR, + }; + + let dynamic_state = vk::PipelineDynamicStateCreateInfo { + s_type: vk::StructureType::PIPELINE_DYNAMIC_STATE_CREATE_INFO, + dynamic_state_count: dynamic_states.len() as u32, + p_dynamic_states: dynamic_states.as_ptr(), + ..default::Default() + }; + + //678-685 + let pipeline_layout_info = vk::PipelineLayoutCreateInfo { s_type: vk::StructureType::PIPELINE_LAYOUT_CREATE_INFO, - p_next: ptr::null(), - flags: vk::PipelineLayoutCreateFlags::empty(), set_layout_count: 0, - p_set_layouts: ptr::null(), - push_constant_range_count: 0, - p_push_constant_ranges: ptr::null(), + p_sets_layout: ptr::null(), }; - let pipeline_layout = unsafe { + unsafe { device - .create_pipeline_layout(&pipeline_layout_create_info, None) - .expect("Failed to create pipeline layout!") - }; + .create_pipeline_layout(&pipeline_layout_info, ptr::null(), self.graphics_pipeline_layout) + .expect("failed to create graphics pipeline layout"); + } - let graphic_pipeline_create_infos = [vk::GraphicsPipelineCreateInfo { - s_type: vk::StructureType::GRAPHICS_PIPELINE_CREATE_INFO, - p_next: ptr::null(), - flags: vk::PipelineCreateFlags::empty(), - stage_count: shader_modules.len() as u32, - p_stages: shader_modules.as_ptr(), - p_vertex_input_state: &vertex_input_state_create_info, - p_input_assembly_state: &vertex_input_assembly_state_info, - p_tessellation_state: ptr::null(), - p_viewport_state: &viewport_state_create_info, - p_rasterization_state: &rasterization_statue_create_info, - p_multisample_state: &multisample_state_create_info, - p_depth_stencil_state: &depth_state_create_info, - p_color_blend_state: &color_blend_state, - p_dynamic_state: ptr::null(), - layout: pipeline_layout, - render_pass, + let pipeline_info = vk::GraphicsPipelineCreateInfo { + s_type: vk::StructureType::GRAPHICS_PIPELINE_CREATE_INFO + stage_count: 2, + p_stages: shader_modules, + p_vertex_input_state: &vertex_input_info, + p_input_assembly_state: &input_assembly, + p_viewport_state: &viewport_state, + p_rasterization_state: &rasterizer, + p_multisample_state: &multisampling, + p_color_blend_state: &color_blending, + p_dynamic_state: &dynamic_state, + layout: self.graphics_pipeline_layout, + render_pass: self.render_pass, subpass: 0, base_pipeline_handle: vk::Pipeline::null(), - base_pipeline_index: -1, - }]; + ..default::Default() + }; - let graphics_pipelines = unsafe { + //703-708 + unsafe { device - .create_graphics_pipelines( + .create_graphics_pipeline(vk::PipelineCache::null, pipeline_info, None) + .expect("failed to create graphics pipeline"); + + for shader in shader_modules { + device.destroy_shader_module(shader); + } + } + } + + fn create_compute_pipeline( + self + device: &ash::Device + ) { + //712-720 + let mut shader_modules: Vec = vec![]; + let main_function = CString::new("main").unwrap(); + for (shader, stage_i) in shaders() { + //check if graphics shader + if stage_i.contains(ShaderStageFlags::COMPUTE) { + share::create_shader_module(device, ) + shader_modules.push( + vk::PipelineShaderStageCreateInfo { + s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineShaderStageCreateFlags::empty(), + module: share::create_shader_module(device, shader), + p_name: main_function.as_ptr(), + stage: stage_i, + p_specialization_info: ptr::null(), + } + ); + } + } + + //grab shader modules from index informed by shaders.rs generated file + let comp_shader = shader_modules[0]; + + let pipeline_layout_info = vk::PipelineLayoutCreateInfo { + s_type: vk::StructureType::LAYOUT_CREATE_INFO, + set_layout_count: 1, + p_set_layouts: &self.compute_descriptor_set_layout, + }; + + self.compute_pipeline_layout = unsafe { + device + .create_pipeline_layout(&pipeline_layout_info, None) + .expect("couldnt create compute pipeline layout") + }; + + pipeline_info = vk::ComputePipelineCreateInfo { + s_type: vk::StructureType::COMPUTE_PIPELINE_CREATE_INFO, + layout: self.compute_pipeline_layout, + stage: compute_shader, + }; + + self.compute__pipeline = unsafe { + device + .create_compute_pipelines( vk::PipelineCache::null(), - &graphic_pipeline_create_infos, + &pipeline_info, None, ) - .expect("Failed to create Graphics Pipeline!.") }; unsafe { - for shader in shader_modules { - device.destroy_shader_module(shader.module, None) - } + device.destroy_shader_module( + comp_shader.module, + None, + ); + } + } + + fn update_uniform_buffer(&mut self, current_image: u32) { + ubo = UniformBufferObject { + delta_time: self.last_frame_time, + } + unsafe { + ptr::copy_nonoverlapping( + ubo, + self.uniform_buffers_mapped, + size_of::() + ); } + } + + + fn record_compute_command_buffer( + self, + device: &ash::Device, + command_buffer: vk::CommandBuffer + ) { + let begin_info = vk::CommandBufferBeginInfo::default(); + + unsafe { + device + .begin_command_buffer(command_buffer, &begin_info) + .expect("failed to begin recording compute command buffer"); + + device + .cmd_bind_pipeline( + command_buffer, + vk::PipelineBindPoint::COMPUTE, + self.compute_pipeline, + ); + + device + .cmd_bind_descriptor_sets( + command_buffer, + vk::PipelineBindPoint::COMPUTE, + self.compute_pipeline_layout, + 0, + &self.compute_descriptor_sets[self.current_frame], + &[], + ); - (graphics_pipelines[0], pipeline_layout) + device + .cmd_dispatch( + command_buffer, + PARTICLE_COUNT / 256, + 1, + 1, + ); + device + .end_command_buffer(command_buffer) + .expect("failed ending compute command buffer"); + } } - fn draw_frame(&mut self) { - let wait_fences = [self.in_flight_fences[self.current_frame]]; + fn draw_frame(&mut self, device: &ash::Device) { + //compute submission + let submit_infos; + + unsafe { + device + .wait_for_fences( + &self.sync_objects.compute_in_flight_fences[self.current_frame], + true, + u32::MAX, + ); + } + + update_uniform_buffer(&mut self, current_frame); + + unsafe { + device + .reset_fences(&self.sync_objects.compute_in_flight_fences[self.current_frame]); + + device + .reset_command_buffer(self.compute_command_buffers[self.current_frame], vk::CommandBufferResetFlags::empty()); + } + + record_compute_command_buffer(self.compute_command_buffers[self.current_frame]); + + submit_infos = [vk::SubmitInfo { + s_type: vk::StructureType::SUBMIT_INFO, + p_next: ptr::null(), + command_buffer_count: 1, + p_command_buffers: &self.compute_command_buffers[self.current_frame], + signal_semaphore_count: 1, + p_signal_semaphores: &self.sync_objects.compute_finished_semaphores[self.current_frame], + ..default::Default() + }]; + + + unsafe { + device + .queue_submit( + self.compute_queue, + &submit_infos, + self.sync_objects.compute_in_flight_fences[self.current_frame] + ); + } + //graphics submission + unsafe { - self.device - .wait_for_fences(&wait_fences, true, std::u64::MAX) - .expect("Failed to wait for Fence!"); + device + .wait_for_fences( + &self.sync_objects.in_flight_fences[self.current_frame], + true, + u32::MAX, + ); } let (image_index, _is_sub_optimal) = unsafe { - let result = self.swapchain_loader.acquire_next_image( - self.swapchain, + let result = self.swapchain_stuff.swapchain_loader.acquire_next_image( + self.swapchain_stuff.swapchain, std::u64::MAX, - self.image_available_semaphores[self.current_frame], + self.sync_objects.image_available_semaphores[self.current_frame], vk::Fence::null(), ); match result { @@ -577,51 +786,65 @@ impl VulkanApp { } }; - let wait_semaphores = [self.image_available_semaphores[self.current_frame]]; - let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; - let signal_semaphores = [self.render_finished_semaphores[self.current_frame]]; + unsafe { + device + .reset_fences(self.sync_objects.in_flight_fences[self.current_frame]); + device + .reset_command_buffer( + self.command_buffers[self.current_frame], + CommandBufferResetFlags::empty, + ); + } + + share::record_command_buffer(self.command_buffers[current_frame]); + + + let wait_semaphores = [ + self.sync_objects.compute_finished_semaphores[self.current_frame], + self.sync_objects.image_available_semaphores[self.current_frame], + ]; + let wait_stages = [ + vk::PipelineStageFlags::VERTEX_INPUT, + vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT, + ]; - let submit_infos = [vk::SubmitInfo { + submit_infos = [vk::SubmitInfo { s_type: vk::StructureType::SUBMIT_INFO, + wait_semaphore_count: 2, + p_wait_semaphores: wait_semaphores, + p_wait_dst_stage_mask: wait_stages, p_next: ptr::null(), - wait_semaphore_count: wait_semaphores.len() as u32, - p_wait_semaphores: wait_semaphores.as_ptr(), - p_wait_dst_stage_mask: wait_stages.as_ptr(), command_buffer_count: 1, - p_command_buffers: &self.command_buffers[image_index as usize], - signal_semaphore_count: signal_semaphores.len() as u32, - p_signal_semaphores: signal_semaphores.as_ptr(), + p_command_buffers: &self.command_buffers[self.current_frame], + signal_semaphore_count: 1, + p_signal_semaphores: &self.sync_objects.render_finished_semaphores[current_frame], + ..default::Default() }]; unsafe { - self.device - .reset_fences(&wait_fences) - .expect("Failed to reset Fence!"); - - self.device + device .queue_submit( self.graphics_queue, &submit_infos, - self.in_flight_fences[self.current_frame], + self.sync_objects.in_flight_fences[self.current_frame], ) - .expect("Failed to execute queue submit."); + .expect("failed to submit draw command buffer"); } - let swapchains = [self.swapchain]; + let swapchains = [self.swapchain_stuff.swapchain]; let present_info = vk::PresentInfoKHR { s_type: vk::StructureType::PRESENT_INFO_KHR, p_next: ptr::null(), wait_semaphore_count: 1, - p_wait_semaphores: signal_semaphores.as_ptr(), + p_wait_semaphores: &self.sync_objects.render_finished_semaphores, swapchain_count: 1, p_swapchains: swapchains.as_ptr(), p_image_indices: &image_index, p_results: ptr::null_mut(), }; - let result = unsafe { - self.swapchain_loader + self.swapchain_stuff.swapchain_loader .queue_present(self.present_queue, &present_info) }; @@ -640,155 +863,5 @@ impl VulkanApp { self.current_frame = (self.current_frame + 1) % MAX_FRAMES_IN_FLIGHT; } - fn recreate_swapchain(&mut self) { - // parameters ------------- - let surface_suff = SurfaceStuff { - surface_loader: self.surface_loader.clone(), - surface: self.surface, - screen_width: WINDOW_WIDTH, - screen_height: WINDOW_HEIGHT, - }; - // ------------------------ - - unsafe { - self.device - .device_wait_idle() - .expect("Failed to wait device idle!") - }; - self.cleanup_swapchain(); - - let swapchain_stuff = share::create_swapchain( - &self.instance, - &self.device, - self.physical_device, - &self.window, - &surface_suff, - &self.queue_family, - ); - self.swapchain_loader = swapchain_stuff.swapchain_loader; - self.swapchain = swapchain_stuff.swapchain; - self.swapchain_images = swapchain_stuff.swapchain_images; - self.swapchain_format = swapchain_stuff.swapchain_format; - self.swapchain_extent = swapchain_stuff.swapchain_extent; - - self.swapchain_imageviews = - share::create_image_views(&self.device, self.swapchain_format, &self.swapchain_images); - self.render_pass = share::create_render_pass(&self.device, self.swapchain_format); - let (graphics_pipeline, pipeline_layout) = VulkanApp::create_graphics_pipeline( - &self.device, - self.render_pass, - swapchain_stuff.swapchain_extent, - ); - self.graphics_pipeline = graphics_pipeline; - self.pipeline_layout = pipeline_layout; - - self.swapchain_framebuffers = share::create_framebuffers( - &self.device, - self.render_pass, - &self.swapchain_imageviews, - self.swapchain_extent, - ); - self.command_buffers = VulkanApp::create_command_buffers( - &self.device, - self.command_pool, - self.graphics_pipeline, - &self.swapchain_framebuffers, - self.render_pass, - self.swapchain_extent, - self.vertex_buffer, - ); - } - - fn cleanup_swapchain(&self) { - unsafe { - self.device - .free_command_buffers(self.command_pool, &self.command_buffers); - for &framebuffer in self.swapchain_framebuffers.iter() { - self.device.destroy_framebuffer(framebuffer, None); - } - self.device.destroy_pipeline(self.graphics_pipeline, None); - self.device - .destroy_pipeline_layout(self.pipeline_layout, None); - self.device.destroy_render_pass(self.render_pass, None); - for &image_view in self.swapchain_imageviews.iter() { - self.device.destroy_image_view(image_view, None); - } - self.swapchain_loader - .destroy_swapchain(self.swapchain, None); - } - } -} - -impl Drop for VulkanApp { - fn drop(&mut self) { - unsafe { - for i in 0..MAX_FRAMES_IN_FLIGHT { - self.device - .destroy_semaphore(self.image_available_semaphores[i], None); - self.device - .destroy_semaphore(self.render_finished_semaphores[i], None); - self.device.destroy_fence(self.in_flight_fences[i], None); - } - - self.cleanup_swapchain(); - - self.device.destroy_buffer(self.vertex_buffer, None); - self.device.free_memory(self.vertex_buffer_memory, None); - self.device.destroy_command_pool(self.command_pool, None); - - self.device.destroy_device(None); - self.surface_loader.destroy_surface(self.surface, None); - - if VALIDATION.is_enable { - self.debug_utils_loader - .destroy_debug_utils_messenger(self.debug_merssager, None); - } - self.instance.destroy_instance(None); - } - } -} - -impl VulkanApp { - pub fn main_loop(mut self, event_loop: EventLoop<()>) { - let mut tick_counter = utility::fps_limiter::FPSLimiter::new(); - - event_loop.run(move |event, _, control_flow| match event { - Event::WindowEvent { event, .. } => match event { - WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, - WindowEvent::KeyboardInput { input, .. } => match input { - KeyboardInput { - virtual_keycode, - state, - .. - } => match (virtual_keycode, state) { - (Some(VirtualKeyCode::Escape), ElementState::Pressed) => { - *control_flow = ControlFlow::Exit - } - _ => {} - }, - }, - _ => {} - }, - Event::MainEventsCleared => { - self.window.request_redraw(); - } - Event::RedrawRequested(_window_id) => { - self.draw_frame(); - - tick_counter.tick_frame(); - if true { - print!("FPS: {}\r", tick_counter.fps()); - } - } - Event::LoopDestroyed => { - unsafe { - self.device - .device_wait_idle() - .expect("Failed to wait device idle!") - }; - } - _ => (), - }) - } } diff --git a/src/rnd.rs b/src/rnd.rs new file mode 100644 index 0000000..b094570 --- /dev/null +++ b/src/rnd.rs @@ -0,0 +1,979 @@ +use crate::{ + entities::*, shaders::*, utility, utility::constants::*, utility::debug::*, utility::share, + utility::structures::*, +}; + +use ash::{vk, Entry}; + +use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; +use winit::event_loop::{ControlFlow, EventLoop}; + +use std::ffi::CString; +use std::ptr; + +// Constants +const WINDOW_TITLE: &'static str = "Template"; + +const IS_PAINT_FPS_COUNTER: bool = true; + +pub fn init_window( + event_loop: &EventLoop<()>, + title: &str, + width: u32, + height: u32, +) -> winit::window::Window { + winit::window::WindowBuilder::new() + .with_title(title) + .with_inner_size(winit::dpi::LogicalSize::new(width, height)) + .build(event_loop) + .expect("Failed to create window.") +} + + +pub struct VulkanApp { + window: winit::window::Window, + + // vulkan stuff + _entry: ash::Entry, + instance: ash::Instance, + surface_loader: ash::extensions::khr::Surface, + surface: vk::SurfaceKHR, + debug_utils_loader: ash::extensions::ext::DebugUtils, + debug_merssager: vk::DebugUtilsMessengerEXT, + + physical_device: vk::PhysicalDevice, + device: ash::Device, + + queue_family: QueueFamilyIndices, + graphics_queue: vk::Queue, + present_queue: vk::Queue, + //new from C++ + compute_queue: vk::Queue, + + //not in C++ + swapchain_loader: ash::extensions::khr::Swapchain, + swapchain: vk::SwapchainKHR, + swapchain_images: Vec, + swapchain_format: vk::Format, + swapchain_extent: vk::Extent2D, + swapchain_imageviews: Vec, + swapchain_framebuffers: Vec, + + render_pass: vk::RenderPass, + + graphics_pipeline_layout: vk::PipelineLayout, + graphics_pipeline: vk::Pipeline, + + //new from C++ + compute_descriptor_set_layout: vk::DescriptorSetLayout, + compute_pipeline_layout: vk::PipelineLayout, + compute_pipeline: vk::Pipeline, + + //vertex buffer for the triangle verticies + //i think this is the same as shaderStorageBuffers in C++ version + shader_storage_buffers: Vec, + shader_storage_buffers_memory: Vec, + + uniform_buffers: Vec, + uniform_buffers_memory: Vec, + uniform_buffers_mapped: Vec<*mut c_void>, + + + descriptor_pool: vk::DescriptorPool, + compute_descriptor_sets: Vec, + + command_pool: vk::CommandPool, + command_buffers: Vec, + compute_command_buffers: Vec, + + image_available_semaphores: Vec, + render_finished_semaphores: Vec, + in_flight_fences: Vec, + current_frame: usize, + + is_framebuffer_resized: bool, +} + +impl VulkanApp { + //C++ code:: + /* + ### cleanup(); + createInstance(); DONE + setupDebugMessenger(); DONE + createSurface(); SurfaceStuff::new DONE + pickPhysicalDevice(); DONE + createLogicalDevice(); + createSwapChain(); + createImageViews(); + createRenderPass(); + createComputeDescriptorSetLayout(); + createGraphicsPipeline(); + createComputePipeline(); + createFramebuffers(); DONE + createCommandPool(); DONE + createShaderStorageBuffers(); DONE + createUniformBuffers(); DONE + createDescriptorPool(); DONE + createComputeDescriptorSets(); DONE + createCommandBuffers(); DONE + createComputeCommandBuffers(); DONE + createSyncObjects(); DONE + */ + pub fn new(event_loop: &winit::event_loop::EventLoop<()>) -> VulkanApp { + let window = + init_window(event_loop, WINDOW_TITLE, WINDOW_WIDTH, WINDOW_HEIGHT); + + // init vulkan stuff + let entry = unsafe { Entry::load().unwrap() }; + let instance = share::create_instance( + &entry, + WINDOW_TITLE, + VALIDATION.is_enable, + &VALIDATION.required_validation_layers.to_vec(), + ); + let surface_stuff = + SurfaceStuff::new(&entry, &instance, &window, WINDOW_WIDTH, WINDOW_HEIGHT); + let (debug_utils_loader, debug_merssager) = + setup_debug_utils(VALIDATION.is_enable, &entry, &instance); + let physical_device = + share::pick_physical_device(&instance, &surface_stuff, &DEVICE_EXTENSIONS); + let (device, queue_family) = share::create_logical_device( + &instance, + physical_device, + &VALIDATION, + &DEVICE_EXTENSIONS, + &surface_stuff, + ); + let graphics_queue = + unsafe { device.get_device_queue(queue_family.graphics_family.unwrap(), 0) }; + let present_queue = + unsafe { device.get_device_queue(queue_family.present_family.unwrap(), 0) }; + let compute_queue = + unsafe { device.get_device_queue(queue_family.compute_family.unwrap(), 0) }; + let swapchain_stuff = SwapChainStuff::new( + &instance, + &device, + physical_device, + &window, + &surface_stuff, + &queue_family, + ); + let swapchain_imageviews = share::create_image_views( + &device, + swapchain_stuff.swapchain_format, + &swapchain_stuff.swapchain_images, + ); + let render_pass = share::create_render_pass(&device, swapchain_stuff.swapchain_format); + let (graphics_pipeline, graphics_pipeline_layout) = VulkanApp::create_graphics_pipeline( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); + let (compute_pipelines, compute_pipeline_layout) = VulkanApp::create_compute_pipelines( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); + + let compute_pipeline = compute_pipelines[0]; + + let swapchain_framebuffers = share::create_framebuffers( + &device, + render_pass, + &swapchain_imageviews, + swapchain_stuff.swapchain_extent, + ); + let command_pool = share::create_command_pool(&device, &queue_family); + let (vertex_buffer, vertex_buffer_memory) = + VulkanApp::create_vertex_buffer(&instance, &device, physical_device); + let command_buffers = VulkanApp::create_command_buffers( + &device, + command_pool, + graphics_pipeline, + &swapchain_framebuffers, + render_pass, + swapchain_stuff.swapchain_extent, + vertex_buffer, + ); + let sync_ojbects = SyncObjects::new(&device, MAX_FRAMES_IN_FLIGHT); + + // cleanup(); the 'drop' function will take care of it. + VulkanApp { + // winit stuff + window, + + // vulkan stuff + _entry: entry, + instance, + surface: surface_stuff.surface, + surface_loader: surface_stuff.surface_loader, + debug_utils_loader, + debug_merssager, + + physical_device, + device, + + queue_family, + graphics_queue, + present_queue, + compute_queue, + + swapchain_loader: swapchain_stuff.swapchain_loader, + swapchain: swapchain_stuff.swapchain, + swapchain_format: swapchain_stuff.swapchain_format, + swapchain_images: swapchain_stuff.swapchain_images, + swapchain_extent: swapchain_stuff.swapchain_extent, + swapchain_imageviews, + swapchain_framebuffers, + + graphics_pipeline_layout, + render_pass, + graphics_pipeline, + + + compute_descriptor_sets, + compute_pipeline_layout, + compute_pipeline, + + vertex_buffer, + vertex_buffer_memory, + + command_pool, + command_buffers, + + image_available_semaphores: sync_ojbects.image_available_semaphores, + render_finished_semaphores: sync_ojbects.render_finished_semaphores, + in_flight_fences: sync_ojbects.inflight_fences, + current_frame: 0, + + is_framebuffer_resized: false, + } + } + + pub fn main_loop(self) { + let mut tick_counter = super::fps_limiter::FPSLimiter::new(); + + self.event_loop + .run(move |event, _, control_flow| match event { + Event::WindowEvent { event, .. } => match event { + WindowEvent::CloseRequested => { + vulkan_app.wait_device_idle(); + *control_flow = ControlFlow::Exit + } + WindowEvent::KeyboardInput { input, .. } => match input { + KeyboardInput { + virtual_keycode, + state, + .. + } => match (virtual_keycode, state) { + (Some(VirtualKeyCode::Escape), ElementState::Pressed) => { + vulkan_app.wait_device_idle(); + *control_flow = ControlFlow::Exit + } + _ => {} + }, + }, + WindowEvent::Resized(_new_size) => { + vulkan_app.wait_device_idle(); + vulkan_app.resize_framebuffer(); + } + _ => {} + }, + Event::MainEventsCleared => { + vulkan_app.window_ref().request_redraw(); + } + Event::RedrawRequested(_window_id) => { + let delta_time = tick_counter.delta_time(); + vulkan_app.draw_frame(delta_time); + + if IS_PAINT_FPS_COUNTER { + print!("FPS: {}\r", tick_counter.fps()); + } + + tick_counter.tick_frame(); + } + Event::LoopDestroyed => { + vulkan_app.wait_device_idle(); + } + _ => (), + }) + + } + + fn create_vertex_buffer( + instance: &ash::Instance, + device: &ash::Device, + physical_device: vk::PhysicalDevice, + ) -> (vk::Buffer, vk::DeviceMemory) { + let vertex_buffer_create_info = vk::BufferCreateInfo { + s_type: vk::StructureType::BUFFER_CREATE_INFO, + p_next: ptr::null(), + flags: vk::BufferCreateFlags::empty(), + size: std::mem::size_of_val(&TRI_VERT_DATA) as u64, + usage: vk::BufferUsageFlags::VERTEX_BUFFER + | vk::BufferUsageFlags::STORAGE_BUFFER + | vk::BufferUsageFlags::TRANSFER_DST, + sharing_mode: vk::SharingMode::EXCLUSIVE, + queue_family_index_count: 0, + p_queue_family_indices: ptr::null(), + }; + + let vertex_buffer = unsafe { + device + .create_buffer(&vertex_buffer_create_info, None) + .expect("Failed to create Vertex Buffer") + }; + + let mem_requirements = unsafe { device.get_buffer_memory_requirements(vertex_buffer) }; + let mem_properties = + unsafe { instance.get_physical_device_memory_properties(physical_device) }; + let required_memory_flags: vk::MemoryPropertyFlags = + vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT; + let memory_type = VulkanApp::find_memory_type( + mem_requirements.memory_type_bits, + required_memory_flags, + mem_properties, + ); + + let allocate_info = vk::MemoryAllocateInfo { + s_type: vk::StructureType::MEMORY_ALLOCATE_INFO, + p_next: ptr::null(), + allocation_size: mem_requirements.size, + memory_type_index: memory_type, + }; + + let vertex_buffer_memory = unsafe { + device + .allocate_memory(&allocate_info, None) + .expect("Failed to allocate vertex buffer memory!") + }; + + unsafe { + device + .bind_buffer_memory(vertex_buffer, vertex_buffer_memory, 0) + .expect("Failed to bind Buffer"); + + let data_ptr = device + .map_memory( + vertex_buffer_memory, + 0, + vertex_buffer_create_info.size, + vk::MemoryMapFlags::empty(), + ) + .expect("Failed to Map Memory") as *mut Vertex; + + data_ptr.copy_from_nonoverlapping(TRI_VERT_DATA.as_ptr(), TRI_VERT_DATA.len()); + + device.unmap_memory(vertex_buffer_memory); + } + + (vertex_buffer, vertex_buffer_memory) + } + + fn find_memory_type( + type_filter: u32, + required_properties: vk::MemoryPropertyFlags, + mem_properties: vk::PhysicalDeviceMemoryProperties, + ) -> u32 { + for (i, memory_type) in mem_properties.memory_types.iter().enumerate() { + //if (type_filter & (1 << i)) > 0 && (memory_type.property_flags & required_properties) == required_properties { + // return i as u32 + // } + + // same implementation + if (type_filter & (1 << i)) > 0 + && memory_type.property_flags.contains(required_properties) + { + return i as u32; + } + } + + panic!("Failed to find suitable memory type!") + share::pick_physical_device(&instance, &surface_stuff, &DEVICE_EXTENSIONS); + } + /* + * IDEK WHERE THIS CAME FROM I FUCKED UP THIS FILE, SHITS WHACK + * let (device, queue_family) = share::create_logical_device( + &instance, + physical_device, + &VALIDATION, + &DEVICE_EXTENSIONS, + &surface_stuff, + ); + let graphics_queue = + unsafe { device.get_device_queue(queue_family.graphics_family.unwrap(), 0) }; + let present_queue = + unsafe { device.get_device_queue(queue_family.present_family.unwrap(), 0) }; + let compute_queue = + unsafe { device.get_device_queue(queue_family.compute_family.unwrap(), 0) }; + let swapchain_stuff = SwapChainStuff::new( + &instance, + &device, + physical_device, + &window, + &surface_stuff, + &queue_family, + ); + let swapchain_imageviews = share::create_image_views( + &device, + swapchain_stuff.swapchain_format, + &swapchain_stuff.swapchain_images, + ); + let render_pass = share::create_render_pass(&device, swapchain_stuff.swapchain_format); + let (graphics_pipeline, graphics_pipeline_layout) = VulkanApp::create_graphics_pipeline( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); + let (compute_pipelines, compute_pipeline_layout) = VulkanApp::create_compute_pipelines( + &device, + render_pass, + swapchain_stuff.swapchain_extent, + ); + + let compute_pipeline = compute_pipelines[0]; + + let swapchain_framebuffers = share::create_framebuffers( + &device, + render_pass, + &swapchain_imageviews, + swapchain_stuff.swapchain_extent, + ); + let command_pool = share::create_command_pool(&device, &queue_family); + let (vertex_buffer, vertex_buffer_memory) = + VulkanApp::create_vertex_buffer(&instance, &device, physical_device); + let command_buffers = VulkanApp::create_command_buffers( + &device, + command_pool, + graphics_pipeline, + &swapchain_framebuffers, + render_pass, + swapchain_stuff.swapchain_extent, + vertex_buffer, + ); + let sync_ojbects = SyncObjects::new(&device, MAX_FRAMES_IN_FLIGHT); + + // cleanup(); the 'drop' function will take care of it. + VulkanApp { + // winit stuff + window, + + // vulkan stuff + _entry: entry, + instance, + surface: surface_stuff.surface, + surface_loader: surface_stuff.surface_loader, + debug_utils_loader, + debug_merssager, + + physical_device, + device, + + queue_family, + graphics_queue, + present_queue, + compute_queue, + + swapchain_loader: swapchain_stuff.swapchain_loader, + swapchain: swapchain_stuff.swapchain, + swapchain_format: swapchain_stuff.swapchain_format, + swapchain_images: swapchain_stuff.swapchain_images, + swapchain_extent: swapchain_stuff.swapchain_extent, + swapchain_imageviews, + swapchain_framebuffers, + + graphics_pipeline_layout, + render_pass, + graphics_pipeline, + + + compute_descriptor_set, + compute_pipeline_layout, + compute_pipeline,*/ + + +/* FUCKED UP GRAPHICS PIPELINE CREATION FUNCTION WITH INTEGRATED COMPUTE PIPELINE CCREATION, THIS + * IS SUPER FUCKED + command_pool: vk::CommandPool, + graphics_pipeline: vk::Pipeline, + framebuffers: &Vec, + render_pass: vk::RenderPass, + surface_extent: vk::Extent2D, + vertex_buffer: vk::Buffer, + ) -> Vec { + let command_buffer_allocate_info = vk::CommandBufferAllocateInfo { + s_type: vk::StructureType::COMMAND_BUFFER_ALLOCATE_INFO, + p_next: ptr::null(), + command_buffer_count: framebuffers.len() as u32, + command_pool, + level: vk::CommandBufferLevel::PRIMARY, + }; + + let command_buffers = unsafe { + device + .allocate_command_buffers(&command_buffer_allocate_info) + .expect("Failed to allocate Command Buffers!") + }; + + for (i, &command_buffer) in command_buffers.iter().enumerate() { + let command_buffer_begin_info = vk::CommandBufferBeginInfo { + s_type: vk::StructureType::COMMAND_BUFFER_BEGIN_INFO, + p_next: ptr::null(), + flags: vk::CommandBufferUsageFlags::SIMULTANEOUS_USE, + p_inheritance_info: ptr::null(), + }; + + unsafe { + device + .begin_command_buffer(command_buffer, &command_buffer_begin_info) + .expect("Failed to begin recording Command Buffer at beginning!"); + } + + let clear_values = [vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.0, 0.0, 0.0, 1.0], + }, + }]; + + let render_pass_begin_info = vk::RenderPassBeginInfo { + s_type: vk::StructureType::RENDER_PASS_BEGIN_INFO, + p_next: ptr::null(), + framebuffer: framebuffers[i], + render_pass, + clear_value_count: clear_values.len() as u32, + p_clear_values: clear_values.as_ptr(), + render_area: vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: surface_extent, + }, + }; + + unsafe { + device.cmd_begin_render_pass( + command_buffer, + &render_pass_begin_info, + vk::SubpassContents::INLINE, + ); + device.cmd_bind_pipeline( + command_buffer, + vk::PipelineBindPoint::GRAPHICS, + graphics_pipeline, + ); + + let vertex_buffers = [vertex_buffer]; + let offsets = [0_u64]; + + device.cmd_bind_vertex_buffers(command_buffer, 0, &vertex_buffers, &offsets); + + device.cmd_draw(command_buffer, TRI_VERT_DATA.len() as u32, 1, 0, 0); + + device.cmd_end_render_pass(command_buffer); + + device + .end_command_buffer(command_buffer) + .expect("Failed to record Command Buffer at Ending!"); + } + shader_modules.push(vk::PipelineShaderStageCreateInfo { + s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineShaderStageCreateFlags::empty(), + module: share::create_shader_module(device, shader), + p_name: main_function.as_ptr(), + stage: stage_flag, + p_specialization_info: ptr::null(), + }); + } else if stage_flag == vk::ShaderStageFlags::FRAGMENT { + shader_modules.push( + vk::PipelineShaderStageCreateInfo { + s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineShaderStageCreateFlags::empty(), + module: share::create_shader_module(device, shader), + p_name: main_function.as_ptr(), + stage: stage_flag, + p_specialization_info: ptr::null(), + + } + ) + } else if stage_flag == vk::ShaderStageFlags::VERTEX { + shader_modules.push( + vk::PipelineShaderStageCreateInfo { + s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineShaderStageCreateFlags::empty(), + module: share::create_shader_module(device, shader), + p_name: main_function.as_ptr(), + stage: stage_flag, + p_specialization_info: ptr::null(), + + } + ) + } + } + + let binding_description = Vertex::get_binding_description(); + let attribute_description = Vertex::get_attribute_descriptions(); + + let vertex_input_state_create_info = vk::PipelineVertexInputStateCreateInfo { + s_type: vk::StructureType::PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineVertexInputStateCreateFlags::empty(), + vertex_attribute_description_count: attribute_description.len() as u32, + p_vertex_attribute_descriptions: attribute_description.as_ptr(), + vertex_binding_description_count: binding_description.len() as u32, + p_vertex_binding_descriptions: binding_description.as_ptr(), + }; + let vertex_input_assembly_state_info = vk::PipelineInputAssemblyStateCreateInfo { + s_type: vk::StructureType::PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + flags: vk::PipelineInputAssemblyStateCreateFlags::empty(), + p_next: ptr::null(), + topology: vk::PrimitiveTopology::TRIANGLE_LIST, + primitive_restart_enable: vk::FALSE, + }; + + let viewports = [vk::Viewport { + x: 0.0, + y: 0.0, + width: swapchain_extent.width as f32, + height: swapchain_extent.height as f32, + min_depth: 0.0, + max_depth: 1.0, + }]; + + let scissors = [vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: swapchain_extent, + }]; + + let viewport_state_create_info = vk::PipelineViewportStateCreateInfo { + s_type: vk::StructureType::PIPELINE_VIEWPORT_STATE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineViewportStateCreateFlags::empty(), + scissor_count: scissors.len() as u32, + p_scissors: scissors.as_ptr(), + viewport_count: viewports.len() as u32, + p_viewports: viewports.as_ptr(), + }; + + let rasterization_statue_create_info = vk::PipelineRasterizationStateCreateInfo { + s_type: vk::StructureType::PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + p_next: ptr::null(), + p_viewports: viewports.as_ptr(), + }; + + let rasterization_statue_create_info = vk::PipelineRasterizationStateCreateInfo { + s_type: vk::StructureType::PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineRasterizationStateCreateFlags::empty(), + cull_mode: vk::CullModeFlags::BACK, + front_face: vk::FrontFace::CLOCKWISE, + line_width: 1.0, + polygon_mode: vk::PolygonMode::FILL, + rasterizer_discard_enable: vk::FALSE, + depth_clamp_enable: vk::FALSE, + depth_bias_clamp: 0.0, + depth_bias_constant_factor: 0.0, + depth_bias_enable: vk::FALSE, + depth_bias_slope_factor: 0.0, + }; + + let multisample_state_create_info = vk::PipelineMultisampleStateCreateInfo { + s_type: vk::StructureType::PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + flags: vk::PipelineMultisampleStateCreateFlags::empty(), + p_next: ptr::null(), + rasterization_samples: vk::SampleCountFlags::TYPE_1, + sample_shading_enable: vk::FALSE, + min_sample_shading: 0.0, + p_sample_mask: ptr::null(), + alpha_to_one_enable: vk::FALSE, + alpha_to_coverage_enable: vk::FALSE, + }; + + let stencil_state = vk::StencilOpState { + fail_op: vk::StencilOp::KEEP, + pass_op: vk::StencilOp::KEEP, + depth_fail_op: vk::StencilOp::KEEP, + compare_op: vk::CompareOp::ALWAYS, + compare_mask: 0, + write_mask: 0, + reference: 0, + }; + + let depth_state_create_info = vk::PipelineDepthStencilStateCreateInfo { + s_type: vk::StructureType::PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineDepthStencilStateCreateFlags::empty(), + depth_test_enable: vk::FALSE, + depth_write_enable: vk::FALSE, + depth_compare_op: vk::CompareOp::LESS_OR_EQUAL, + depth_bounds_test_enable: vk::FALSE, + stencil_test_enable: vk::FALSE, + front: stencil_state, + back: stencil_state, + max_depth_bounds: 1.0, + min_depth_bounds: 0.0, + }; + + let color_blend_attachment_states = [vk::PipelineColorBlendAttachmentState { + blend_enable: vk::FALSE, + color_write_mask: vk::ColorComponentFlags::RGBA, + src_color_blend_factor: vk::BlendFactor::ONE, + dst_color_blend_factor: vk::BlendFactor::ZERO, + color_blend_op: vk::BlendOp::ADD, + src_alpha_blend_factor: vk::BlendFactor::ONE, + dst_alpha_blend_factor: vk::BlendFactor::ZERO, + alpha_blend_op: vk::BlendOp::ADD, + }]; + + let color_blend_state = vk::PipelineColorBlendStateCreateInfo { + s_type: vk::StructureType::PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineColorBlendStateCreateFlags::empty(), + logic_op_enable: vk::FALSE, + logic_op: vk::LogicOp::COPY, + attachment_count: color_blend_attachment_states.len() as u32, + p_attachments: color_blend_attachment_states.as_ptr(), + blend_constants: [0.0, 0.0, 0.0, 0.0], + }; + + println!("shader module count: {}", shader_modules.len()); + + let graphic_pipeline_create_infos = [vk::GraphicsPipelineCreateInfo { + s_type: vk::StructureType::GRAPHICS_PIPELINE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::PipelineCreateFlags::empty(), + stage_count: shader_modules.len() as u32, + p_stages: shader_modules.as_ptr(), + p_vertex_input_state: &vertex_input_state_create_info, + p_input_assembly_state: &vertex_input_assembly_state_info, + p_tessellation_state: ptr::null(), + p_viewport_state: &viewport_state_create_info, + p_rasterization_state: &rasterization_statue_create_info, + p_multisample_state: &multisample_state_create_info, + s_type: vk::StructureType::COMPUTE_PIPELINE_CREATE_INFO, + p_next: ptr::null(), + layout: pipeline_layout, + flags: vk::PipelineCreateFlags::empty(), + ..Default::default() + } + ); + + } + let compute_pipelines = unsafe { + device + .create_compute_pipelines( + vk::PipelineCache::null(), + &compute_infos, + None, + ) + }.unwrap(); + + (compute_pipelines, pipeline_layout) + }*/ + + fn draw_frame(&mut self) { + let wait_fences = [self.in_flight_fences[self.current_frame]]; + + unsafe { + self.device + .wait_for_fences(&wait_fences, true, std::u64::MAX) + .expect("Failed to wait for Fence!"); + } + + let (image_index, _is_sub_optimal) = unsafe { + let result = self.swapchain_loader.acquire_next_image( + self.swapchain, + std::u64::MAX, + self.image_available_semaphores[self.current_frame], + vk::Fence::null(), + ); + match result { + Ok(image_index) => image_index, + Err(vk_result) => match vk_result { + vk::Result::ERROR_OUT_OF_DATE_KHR => { + self.recreate_swapchain(); + return; + } + _ => panic!("Failed to acquire Swap Chain Image!"), + }, + } + }; + + let wait_semaphores = [self.image_available_semaphores[self.current_frame]]; + let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; + let signal_semaphores = [self.render_finished_semaphores[self.current_frame]]; + + let submit_infos = [vk::SubmitInfo { + s_type: vk::StructureType::SUBMIT_INFO, + p_next: ptr::null(), + wait_semaphore_count: wait_semaphores.len() as u32, + p_wait_semaphores: wait_semaphores.as_ptr(), + p_wait_dst_stage_mask: wait_stages.as_ptr(), + command_buffer_count: 1, + p_command_buffers: &self.command_buffers[image_index as usize], + signal_semaphore_count: signal_semaphores.len() as u32, + p_signal_semaphores: signal_semaphores.as_ptr(), + }]; + + unsafe { + self.device + .reset_fences(&wait_fences) + .expect("Failed to reset Fence!"); + + self.device + .queue_submit( + self.graphics_queue, + &submit_infos, + self.in_flight_fences[self.current_frame], + ) + .expect("Failed to execute queue submit."); + } + + let swapchains = [self.swapchain]; + + let present_info = vk::PresentInfoKHR { + s_type: vk::StructureType::PRESENT_INFO_KHR, + p_next: ptr::null(), + wait_semaphore_count: 1, + p_wait_semaphores: signal_semaphores.as_ptr(), + swapchain_count: 1, + p_swapchains: swapchains.as_ptr(), + p_image_indices: &image_index, + p_results: ptr::null_mut(), + }; + + let result = unsafe { + self.swapchain_loader + .queue_present(self.present_queue, &present_info) + }; + + let is_resized = match result { + Ok(_) => self.is_framebuffer_resized, + Err(vk_result) => match vk_result { + vk::Result::ERROR_OUT_OF_DATE_KHR | vk::Result::SUBOPTIMAL_KHR => true, + _ => panic!("Failed to execute queue present."), + }, + }; + if is_resized { + self.is_framebuffer_resized = false; + self.recreate_swapchain(); + } + + self.current_frame = (self.current_frame + 1) % MAX_FRAMES_IN_FLIGHT; + } + + fn recreate_swapchain(&mut self) { + // parameters ------------- + let surface_suff = SurfaceStuff { + surface_loader: self.surface_loader.clone(), + surface: self.surface, + screen_width: WINDOW_WIDTH, + screen_height: WINDOW_HEIGHT, + }; + // ------------------------ + + unsafe { + self.device + .device_wait_idle() + .expect("Failed to wait device idle!") + }; + self.cleanup_swapchain(); + + let swapchain_stuff = SwapChainStuff::new( + &self.instance, + &self.device, + self.physical_device, + &self.window, + &surface_suff, + &self.queue_family, + ); + self.swapchain_loader = swapchain_stuff.swapchain_loader; + self.swapchain = swapchain_stuff.swapchain; + self.swapchain_images = swapchain_stuff.swapchain_images; + self.swapchain_format = swapchain_stuff.swapchain_format; + self.swapchain_extent = swapchain_stuff.swapchain_extent; + + self.swapchain_imageviews = + share::create_image_views(&self.device, self.swapchain_format, &self.swapchain_images); + self.render_pass = share::create_render_pass(&self.device, self.swapchain_format); + let (graphics_pipeline, pipeline_layout) = VulkanApp::create_graphics_pipeline( + &self.device, + self.render_pass, + swapchain_stuff.swapchain_extent, + ); + self.graphics_pipeline = graphics_pipeline; + self.graphics_pipeline_layout = pipeline_layout; + + self.swapchain_framebuffers = share::create_framebuffers( + &self.device, + self.render_pass, + &self.swapchain_imageviews, + self.swapchain_extent, + ); + self.command_buffers = VulkanApp::create_command_buffers( + &self.device, + self.command_pool, + self.graphics_pipeline, + &self.swapchain_framebuffers, + self.render_pass, + self.swapchain_extent, + self.vertex_buffer, + ); + } + + fn cleanup_swapchain(&self) { + unsafe { + self.device + .free_command_buffers(self.command_pool, &self.command_buffers); + for &framebuffer in self.swapchain_framebuffers.iter() { + self.device.destroy_framebuffer(framebuffer, None); + } + self.device.destroy_pipeline(self.graphics_pipeline, None); + self.device + .destroy_pipeline_layout(self.graphics_pipeline_layout, None); + self.device.destroy_render_pass(self.render_pass, None); + for &image_view in self.swapchain_imageviews.iter() { + self.device.destroy_image_view(image_view, None); + } + self.swapchain_loader + .destroy_swapchain(self.swapchain, None); + } + } +} + + + +impl Drop for VulkanApp { + //cleanup in C++ + fn drop(&mut self) { + unsafe { + for i in 0..MAX_FRAMES_IN_FLIGHT { + self.device + .destroy_semaphore(self.image_available_semaphores[i], None); + self.device + .destroy_semaphore(self.render_finished_semaphores[i], None); + self.device.destroy_fence(self.in_flight_fences[i], None); + } + + self.cleanup_swapchain(); + + self.device + .destory + + self.device.destroy_buffer(self.vertex_buffer, None); + self.device.free_memory(self.vertex_buffer_memory, None); + + self.device.destroy_command_pool(self.command_pool, None); + + self.device.destroy_device(None); + self.surface_loader.destroy_surface(self.surface, None); + + if VALIDATION.is_enable { + self.debug_utils_loader + .destroy_debug_utils_messenger(self.debug_merssager, None); + } + self.instance.destroy_instance(None); + } + } +} + diff --git a/src/shaders.rs b/src/shaders.rs index 073e820..44ca414 100644 --- a/src/shaders.rs +++ b/src/shaders.rs @@ -4,4 +4,5 @@ pub fn shaders() -> Vec<(Vec, ShaderStageFlags)> { vec![ (include_bytes!("../target/shaders/tri.frag.spv").to_vec(), ShaderStageFlags::FRAGMENT), (include_bytes!("../target/shaders/tri.vert.spv").to_vec(), ShaderStageFlags::VERTEX), +(include_bytes!("../target/shaders/tri.comp.spv").to_vec(), ShaderStageFlags::COMPUTE), ]} \ No newline at end of file diff --git a/src/shaders/tri.comp b/src/shaders/tri.comp index 18af350..44a1790 100644 --- a/src/shaders/tri.comp +++ b/src/shaders/tri.comp @@ -1,21 +1,40 @@ #version 450 -#extension GL_ARB_separate_shader_objects: enable - struct Particle { vec2 position; vec2 velocity; - vec4 color; -} + vec4 color; +}; -layout (std140, binding = 1) readonly buffer ParticleSSBOIn { - Particle particlesIn[ ]; +layout (binding = 0) uniform ParameterUBO { + float deltaTime; +} ubo; + +layout(std140, binding = 1) readonly buffer ParticleSSBOIn { + Particle particlesIn[ ]; }; -layout (std140, binding = 2) buffer ParticleSSBOOut { - Particle particlesOut[ ]; +layout(std140, binding = 2) buffer ParticleSSBOOut { + Particle particlesOut[ ]; }; -void main() { - particlesOut[index].position = particlesIn[index].position + particlesIn[index].velocity.xy * ubo.deltaTime; +layout (local_size_x = 256, local_size_y = 1, local_size_z = 1) in; + +void main() +{ + uint index = gl_GlobalInvocationID.x; + + Particle particleIn = particlesIn[index]; + + particlesOut[index].position = particleIn.position + particleIn.velocity.xy * ubo.deltaTime; + particlesOut[index].velocity = particleIn.velocity; + + // Flip movement at window border + if ((particlesOut[index].position.x <= -1.0) || (particlesOut[index].position.x >= 1.0)) { + particlesOut[index].velocity.x = -particlesOut[index].velocity.x; + } + if ((particlesOut[index].position.y <= -1.0) || (particlesOut[index].position.y >= 1.0)) { + particlesOut[index].velocity.y = -particlesOut[index].velocity.y; + } + } diff --git a/src/utility.rs b/src/utility.rs index 7aa301a..bac03bb 100644 --- a/src/utility.rs +++ b/src/utility.rs @@ -5,4 +5,3 @@ pub mod platforms; pub mod share; pub mod structures; pub mod tools; -pub mod window; diff --git a/src/utility/share.rs b/src/utility/share.rs index 4492798..4c4a403 100644 --- a/src/utility/share.rs +++ b/src/utility/share.rs @@ -5,12 +5,84 @@ use image::GenericImageView; use crate::utility::constants::*; use crate::utility::structures::*; use crate::utility::{debug, platforms}; +use crate::entities::PARTICLE_COUNT; + use std::cmp::max; use std::ffi::CString; use std::os::raw::{c_char, c_void}; use std::path::Path; use std::{ptr, mem::size_of}; +pub fn create_instance( + entry: &ash::Entry, + window_title: &str, + is_enable_debug: bool, + required_validation_layers: &Vec<&str>, +) -> ash::Instance { + if is_enable_debug + && debug::check_validation_layer_support(entry, required_validation_layers) == false + { + panic!("Validation layers requested, but not available!"); + } + + let app_name = CString::new(window_title).unwrap(); + let engine_name = CString::new("Vulkan Engine").unwrap(); + let app_info = vk::ApplicationInfo { + p_application_name: app_name.as_ptr(), + s_type: vk::StructureType::APPLICATION_INFO, + p_next: ptr::null(), + application_version: APPLICATION_VERSION, + p_engine_name: engine_name.as_ptr(), + engine_version: ENGINE_VERSION, + api_version: API_VERSION, + }; + + // This create info used to debug issues in vk::createInstance and vk::destroyInstance. + let debug_utils_create_info = debug::populate_debug_messenger_create_info(); + + // VK_EXT debug report has been requested here. + let extension_names = platforms::required_extension_names(); + + let requred_validation_layer_raw_names: Vec = required_validation_layers + .iter() + .map(|layer_name| CString::new(*layer_name).unwrap()) + .collect(); + let layer_names: Vec<*const i8> = requred_validation_layer_raw_names + .iter() + .map(|layer_name| layer_name.as_ptr()) + .collect(); + + let create_info = vk::InstanceCreateInfo { + s_type: vk::StructureType::INSTANCE_CREATE_INFO, + p_next: if VALIDATION.is_enable { + &debug_utils_create_info as *const vk::DebugUtilsMessengerCreateInfoEXT + as *const c_void + } else { + ptr::null() + }, + flags: vk::InstanceCreateFlags::empty(), + p_application_info: &app_info, + pp_enabled_layer_names: if is_enable_debug { + layer_names.as_ptr() + } else { + ptr::null() + }, + enabled_layer_count: if is_enable_debug { + layer_names.len() + } else { + 0 + } as u32, + pp_enabled_extension_names: extension_names.as_ptr(), + enabled_extension_count: extension_names.len() as u32, + }; + + unsafe { + entry + .create_instance(&create_info, None) + .expect("Failed to create instance!") + } +} + pub fn create_render_pass(device: &ash::Device, surface_format: vk::Format) -> vk::RenderPass { let color_attachment = vk::AttachmentDescription { format: surface_format, @@ -116,7 +188,7 @@ pub fn create_command_pool( s_type: vk::StructureType::COMMAND_POOL_CREATE_INFO, p_next: ptr::null(), flags: vk::CommandPoolCreateFlags::empty(), - queue_family_index: queue_families.graphics_family.unwrap(), + queue_family_index: queue_families.graphics_and_compute_family.unwrap(), }; unsafe { @@ -126,18 +198,97 @@ pub fn create_command_pool( } } +/* +let (staging_buffer, staging_buffer_memory) = create_buffer( + device, + buffer_size, + vk::BufferUsageFlags::TRANSFER_SRC, + vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT, + &device_memory_properties, + ); + +*/ + +pub fn create_shader_storage_buffers( + device: &ash::Device, + shader_storage_buffers: Vec, + shader_storage_buffers_memory: Vec +) { + let particles = Particle::gen(); + + let buffer_size = std::mem::size_of::() * PARTICLE_COUNT; + + + let (staging_buffer, staging_buffer_memory) = create_buffer( + device, + buffer_size, + BufferUsageFlags::TRANSFER_SRC, + MemoryPropertyFlags::HOST_VISIBLE | + MemoryPropertyFlags::HOST_COHERENT, + staging_buffer, + staging_buffer_memory, + ); + + unsafe { + let data = device + .map_memory( + staging_buffer_memory, + 0, + buffer_size, + 0, + ) + .expect("failed to map shader storage buffer memory"); + ptr::copy_nonoverlapping( + data, + particles.as_mut_ptr(), + buffer_size + ); + device + .unmap_memory(staging_buffer_memory); + + for i in 0..MAX_FRAMES_IN_FLIGHT { + (shader_storage_buffers[i], shader_storage_buffers_memory[i]) = create_buffer( + device, + buffer_size, + BufferUsageFlags::STORAGE_BUFFER | + BufferUsageFlags::VERTEX_BUFFER | + BufferUsageFlags::TRANSFER_DST, + MemoryPropertyFlags::DEVICE_LOCAL, + shader_storage_buffers, + shader_storage_buffers_memory, + ); + + let (buffer_copy, buffer_copy_memory) = + copy_buffer( + staging_buffer, + shader_storage_buffers[i], + buffer_size + ); + + } + + device + .destory_buffer(staging_buffer, ptr::null()) + + device + .free_memory(staging_buffer_memory, ptr::null); + } +} + +///createCommandBuffers in C++ pub fn create_command_buffers( device: &ash::Device, command_pool: vk::CommandPool, - graphics_pipeline: vk::Pipeline, - framebuffers: &Vec, - render_pass: vk::RenderPass, - surface_extent: vk::Extent2D, + command_buffers: &Vec, + //graphics_pipeline: vk::Pipeline, + //framebuffers: &Vec, + //render_pass: vk::RenderPass, + //surface_extent: vk::Extent2D, ) -> Vec { let command_buffer_allocate_info = vk::CommandBufferAllocateInfo { s_type: vk::StructureType::COMMAND_BUFFER_ALLOCATE_INFO, p_next: ptr::null(), - command_buffer_count: framebuffers.len() as u32, + command_buffer_count: command_buffers.len() as u32, command_pool, level: vk::CommandBufferLevel::PRIMARY, }; @@ -148,123 +299,193 @@ pub fn create_command_buffers( .expect("Failed to allocate Command Buffers!") }; - for (i, &command_buffer) in command_buffers.iter().enumerate() { - let command_buffer_begin_info = vk::CommandBufferBeginInfo { - s_type: vk::StructureType::COMMAND_BUFFER_BEGIN_INFO, - p_next: ptr::null(), - p_inheritance_info: ptr::null(), - flags: vk::CommandBufferUsageFlags::SIMULTANEOUS_USE, - }; + command_buffers +} - unsafe { - device - .begin_command_buffer(command_buffer, &command_buffer_begin_info) - .expect("Failed to begin recording Command Buffer at beginning!"); - } +pub fn record_command_buffer( + device: &ash::Device, + command_buffer: vk::CommandBuffer, + image_index: u32, + render_pass: vk::RenderPass, + swapchain_extent: vk::Extent2D, + shader_storage_buffers: Vec, + //shader_storage_buffers_memory: Vec, + current_frame: usize, + graphics_pipeline: vk::GraphicsPipeline, - let clear_values = [vk::ClearValue { + +) { + let command_buffer_begin_info = vk::CommandBufferBeginInfo { + s_type: vk::StructureType::COMMAND_BUFFER_BEGIN_INFO, + p_next: ptr::null(), + p_inheritance_info: ptr::null(), + flags: vk::CommandBufferUsageFlags::SIMULTANEOUS_USE, + } + + unsafe { + device + .begin_command_buffer(command_buffer, &command_buffer_begin_info) + .expect("failed to start recording command buffer") + } + let clear_values = [vk::ClearValue { color: vk::ClearColorValue { float32: [0.0, 0.0, 0.0, 1.0], }, - }]; + }]; - let render_pass_begin_info = vk::RenderPassBeginInfo { - s_type: vk::StructureType::RENDER_PASS_BEGIN_INFO, - p_next: ptr::null(), - render_pass, - framebuffer: framebuffers[i], - render_area: vk::Rect2D { - offset: vk::Offset2D { x: 0, y: 0 }, - extent: surface_extent, - }, - clear_value_count: clear_values.len() as u32, - p_clear_values: clear_values.as_ptr(), - }; + let render_pass_begin_info = vk::RenderPassBeginInfo { + s_type: vk::StructureType::RENDER_PASS_BEGIN_INFO, + p_next: ptr::null(), + render_pass, + framebuffer: framebuffers[i], + render_area: vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: surface_extent, + }, + clear_value_count: clear_values.len() as u32, + p_clear_values: clear_values.as_ptr(), + }; - unsafe { - device.cmd_begin_render_pass( - command_buffer, - &render_pass_begin_info, - vk::SubpassContents::INLINE, - ); - device.cmd_bind_pipeline( - command_buffer, - vk::PipelineBindPoint::GRAPHICS, - graphics_pipeline, - ); - device.cmd_draw(command_buffer, 3, 1, 0, 0); + let viewport = vec![vk::Viewport { + x: 0.0, + y: 0.0, + width: swapchain_extent.width as f32, + height: swapchain_extent.height as f32, + min_depth: 0.0, + max_depth: 1.0, + }]; - device.cmd_end_render_pass(command_buffer); + let scissor = vec![vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: swapchain_extent, + }]; - device - .end_command_buffer(command_buffer) - .expect("Failed to record Command Buffer at Ending!"); - } + let offsets: Vec = vec![0] + + unsafe { + device.cmd_begin_render_pass( + command_buffer, + &render_pass_begin_info, + vk::SubpassContents::INLINE, + .create_framebuffer(&framebuffer_create_info, None) + .expect("Failed to create Framebuffer!") + ); + + + framebuffers.push(framebuffer); } - command_buffers + framebuffers } -pub fn create_sync_objects(device: &ash::Device, max_frame_in_flight: usize) -> SyncObjects { - let mut sync_objects = SyncObjects { - image_available_semaphores: vec![], - render_finished_semaphores: vec![], - inflight_fences: vec![], - }; - - let semaphore_create_info = vk::SemaphoreCreateInfo { - s_type: vk::StructureType::SEMAPHORE_CREATE_INFO, +pub fn create_command_pool( + device: &ash::Device, + queue_families: &QueueFamilyIndices, +) -> vk::CommandPool { + let command_pool_create_info = vk::CommandPoolCreateInfo { + s_type: vk::StructureType::COMMAND_POOL_CREATE_INFO, p_next: ptr::null(), - flags: vk::SemaphoreCreateFlags::empty(), + flags: vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER, + queue_family_index: queue_families.graphics_family.unwrap(), }; - let fence_create_info = vk::FenceCreateInfo { - s_type: vk::StructureType::FENCE_CREATE_INFO, + unsafe { + device + .create_command_pool(&command_pool_create_info, None) + .expect("Failed to create Command Pool!") + } +} + +///createCommandBuffers in C++ +pub fn create_command_buffers( + device: &ash::Device, + command_pool: vk::CommandPool, + command_buffers: &Vec, + //graphics_pipeline: vk::Pipeline, + //framebuffers: &Vec, + //render_pass: vk::RenderPass, + //surface_extent: vk::Extent2D, +) -> Vec { + let command_buffer_allocate_info = vk::CommandBufferAllocateInfo { + s_type: vk::StructureType::COMMAND_BUFFER_ALLOCATE_INFO, p_next: ptr::null(), - flags: vk::FenceCreateFlags::SIGNALED, + command_buffer_count: command_buffers.len() as u32, + command_pool, + level: vk::CommandBufferLevel::PRIMARY, }; - for _ in 0..max_frame_in_flight { - unsafe { - let image_available_semaphore = device - .create_semaphore(&semaphore_create_info, None) - .expect("Failed to create Semaphore Object!"); - let render_finished_semaphore = device - .create_semaphore(&semaphore_create_info, None) - .expect("Failed to create Semaphore Object!"); - let inflight_fence = device - .create_fence(&fence_create_info, None) - .expect("Failed to create Fence Object!"); - - sync_objects - .image_available_semaphores - .push(image_available_semaphore); - sync_objects - .render_finished_semaphores - .push(render_finished_semaphore); - sync_objects.inflight_fences.push(inflight_fence); - } - } + let command_buffers = unsafe { + device + .allocate_command_buffers(&command_buffer_allocate_info) + .expect("Failed to allocate Command Buffers!") + }; - sync_objects + command_buffers } -pub fn create_vertex_buffer( +/*pub fn record_command_buffer( device: &ash::Device, - device_memory_properties: &vk::PhysicalDeviceMemoryProperties, - command_pool: vk::CommandPool, - submit_queue: vk::Queue, - data: &[T], -) -> (vk::Buffer, vk::DeviceMemory) { - let buffer_size = ::std::mem::size_of_val(data) as vk::DeviceSize; + command_buffer: vk::CommandBuffer, + image_index: u32, + render_pass: vk::RenderPass, + swapchain_extent: vk::Extent2D, + shader_storage_buffers: Vec, + //shader_storage_buffers_memory: Vec, + current_frame: usize, + graphics_pipeline: vk::GraphicsPipeline, - let (staging_buffer, staging_buffer_memory) = create_buffer( - device, - buffer_size, - vk::BufferUsageFlags::TRANSFER_SRC, - vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT, - &device_memory_properties, - ); + +) { + let command_buffer_begin_info = vk::CommandBufferBeginInfo { + s_type: vk::StructureType::COMMAND_BUFFER_BEGIN_INFO, + p_next: ptr::null(), + p_inheritance_info: ptr::null(), + flags: vk::CommandBufferUsageFlags::SIMULTANEOUS_USE, + } + + unsafe { + device + .begin_command_buffer(command_buffer, &command_buffer_begin_info) + .expect("failed to start recording command buffer") + } + let clear_values = [vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.0, 0.0, 0.0, 1.0], + }, + }]; + + let render_pass_begin_info = vk::RenderPassBeginInfo { + s_type: vk::StructureType::RENDER_PASS_BEGIN_INFO, + p_next: ptr::null(), + render_pass, + framebuffer: framebuffers[i], + render_area: vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: surface_extent, + }, + clear_value_count: clear_values.len() as u32, + p_clear_values: clear_values.as_ptr(), + }; + + let viewport = vec![vk::Viewport { + x: 0.0, + y: 0.0, + width: swapchain_extent.width as f32, + height: swapchain_extent.height as f32, + min_depth: 0.0, + max_depth: 1.0, + }]; + + let scissor = vec![vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: swapchain_extent, + }]; + + let offsets: Vec = vec![0] + + unsafe { + device.cmd_begin_render_pass(); + } unsafe { let data_ptr = device @@ -304,16 +525,22 @@ pub fn create_vertex_buffer( } (vertex_buffer, vertex_buffer_memory) -} +}*/ pub fn create_descriptor_pool( device: &ash::Device, swapchain_images_size: usize, ) -> vk::DescriptorPool { - let pool_sizes = [vk::DescriptorPoolSize { - ty: vk::DescriptorType::UNIFORM_BUFFER, - descriptor_count: swapchain_images_size as u32, - }]; + let pool_sizes = [ + vk::DescriptorPoolSize { + ty: vk::DescriptorType::UNIFORM_BUFFER, + descriptor_count: swapchain_images_size as u32, + }, + vk::DescriptorPoolSize { + ty: vk::DescriptorType::STORAGE_BUFFER, + descriptor_count: swapchain_images_size as u32 * 2, + } + ]; let descriptor_pool_create_info = vk::DescriptorPoolCreateInfo { s_type: vk::StructureType::DESCRIPTOR_POOL_CREATE_INFO, @@ -331,7 +558,90 @@ pub fn create_descriptor_pool( } } -pub fn create_descriptor_sets( +pub fn create_compute_descriptor_sets( + device: &ash::Device, + compute_descriptor_set_layout: vk::DescriptorSetLayout, + descriptor_pool: vk::DescriptorPool, + compute_descriptor_sets: Vec, + uniform_buffers: Vec, + shader_storage_buffers: Vec +) { + let layouts = vec![compute_descriptor_set_layout; MAX_FRAMES_IN_FLIGHT]; + + let alloc_info - vk::DescriptorSetAllocateInfo { + s_type: DESCRIPTOR_SET_ALLOCATE_INFO, + p_next: ptr::null() DONE, + descriptor_pool: descriptor_pool, + descriptor_set_count: MAX_FRAMES_IN_FLIGHT as u32, + p_set_layouts: layouts.as_ptr(), + }; + + unsafe { + device + .allocate_descriptor_sets() + .expect("failed to allocate descriptor sets") + } + + for i in 0..MAX_FRAMES_IN_FLIGHT { + uniform_buffer_info = vk::DescriptorBufferInfo { + buffer: uniform_buffers, + offset: 0, + range: size_of:: as u64, + }; + + storage_buffer_info_last_frame = vk::DescriptorBufferInfo { + buffer: shader_storage_buffers[(i - 1) % MAX_FRAMES_IN_FLIGHT], + offset: 0, + range: size_of:: as u64 * PARTICLE_COUNT, + }; + + storage_buffer_info_current_frame = vk::DescriptorBufferInfo { + buffer: shader_storage_buffers[i], + offset: 0, + range: size_of:: as u64 * PARTICLE_COUNT, + }; + + descriptor_writes = [ + vk::WriteDescriptorSet { + s_type: WRITE_DESCRIPTOR_SET, + dst_set: compute_descriptor_sets[i], + dst_binding: 0, + dst_array_element: 0, + descriptor_type: DescriptorType::UNIFORM_BUFFER, + descriptor_count: 1, + p_buffer_info: uniform_buffer_info, + ..Default::default() + } + vk::WriteDescriptorSet { + s_type: WRITE_DESCRIPTOR_SET, + dst_set: compute_descriptor_sets[i], + dst_binding: 1, + dst_array_element: 0, + descriptor_type: DescriptorType::STORAGE_BUFFER, + descriptor_count: 1, + p_buffer_info: storage_buffer_info_last_frame, + ..Default::default() + } + vk::WriteDescriptorSet { + s_type: WRITE_DESCRIPTOR_SET, + dst_set: compute_descriptor_sets[i], + dst_binding: 2, + dst_array_element: 0, + descriptor_type: DescriptorType::STORAGE_BUFFER, + descriptor_count: 1, + p_buffer_info: storage_buffer_info_current_frame, + ..Default::default() + } + ] + + unsafe { + device + .update_descriptor_sets(descriptor_writes, vec![]) + } + } +} + +/*pub fn create_descriptor_sets( device: &ash::Device, descriptor_pool: vk::DescriptorPool, descriptor_set_layout: vk::DescriptorSetLayout, @@ -348,36 +658,6 @@ pub fn create_descriptor_sets( s_type: vk::StructureType::DESCRIPTOR_SET_ALLOCATE_INFO, p_next: ptr::null(), descriptor_pool, - descriptor_set_count: swapchain_images_size as u32, - p_set_layouts: layouts.as_ptr(), - }; - - let descriptor_sets = unsafe { - device - .allocate_descriptor_sets(&descriptor_set_allocate_info) - .expect("Failed to allocate descriptor sets!") - }; - - for (i, &descritptor_set) in descriptor_sets.iter().enumerate() { - let uniform_descriptor_info = vec![]; - let compute_descriptor_info = vec![]; - - let uniform_buffers_inner = uniform_buffers.unwrap(); - let compute_buffers_inner = compute_buffers.unwrap(); - - for (i, buffer) in uniform_buffers_inner.iter().enumerate() { - uniform_descriptor_info.push( - vk::DescriptorBufferInfo { - buffer: uniform_buffers.unwrap()[i as usize], - offset: i as u64, - range: size_of:: as u64, - } - ); - } - for (i, buffer) in compute_buffers_inner.iter().enumerate() { - compute_descriptor_info.push( - vk::DescriptorBufferInfo { - buffer: compute_buffers.unwrap()[i as usize], offset: i as u64, range: size_of:: as u64, } @@ -428,7 +708,7 @@ pub fn create_descriptor_sets( } descriptor_sets -} +}*/ pub fn create_descriptor_set_layout(device: &ash::Device) -> vk::DescriptorSetLayout { let ubo_layout_bindings = [ @@ -874,7 +1154,7 @@ pub fn create_depth_resources( (depth_image, depth_image_view, depth_image_memory) } -pub fn generate_mipmaps( +/*pub fn generate_mipmaps( device: &ash::Device, command_pool: vk::CommandPool, submit_queue: vk::Queue, @@ -928,113 +1208,113 @@ pub fn generate_mipmaps( let blits = [vk::ImageBlit { src_subresource: vk::ImageSubresourceLayers { - aspect_mask: vk::ImageAspectFlags::COLOR, - mip_level: i - 1, - base_array_layer: 0, - layer_count: 1, - }, - src_offsets: [ - vk::Offset3D { x: 0, y: 0, z: 0 }, - vk::Offset3D { - x: mip_width, - y: mip_height, - z: 1, - }, - ], - dst_subresource: vk::ImageSubresourceLayers { - aspect_mask: vk::ImageAspectFlags::COLOR, - mip_level: i, - base_array_layer: 0, - layer_count: 1, - }, - dst_offsets: [ - vk::Offset3D { x: 0, y: 0, z: 0 }, - vk::Offset3D { - x: max(mip_width / 2, 1), - y: max(mip_height / 2, 1), - z: 1, - }, - ], + .create_framebuffer(&framebuffer_create_info, None) + .expect("Failed to create Framebuffer!") }]; - unsafe { - device.cmd_blit_image( - command_buffer, - image, - vk::ImageLayout::TRANSFER_SRC_OPTIMAL, - image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - &blits, - vk::Filter::LINEAR, - ); - } + framebuffers.push(framebuffer); + } + + framebuffers +}*/ + +pub fn create_command_pool( + device: &ash::Device, + queue_families: &QueueFamilyIndices, +) -> vk::CommandPool { + let command_pool_create_info = vk::CommandPoolCreateInfo { + s_type: vk::StructureType::COMMAND_POOL_CREATE_INFO, + p_next: ptr::null(), + flags: vk::CommandPoolCreateFlags::empty(), + queue_family_index: queue_families.graphics_family.unwrap(), + }; + + unsafe { + device + .create_command_pool(&command_pool_create_info, None) + .expect("Failed to create Command Pool!") + } +} + +///createCommandBuffers in C++ +pub fn create_command_buffers( + device: &ash::Device, + command_pool: vk::CommandPool, + command_buffers: &Vec, + //graphics_pipeline: vk::Pipeline, + //framebuffers: &Vec, + //render_pass: vk::RenderPass, + //surface_extent: vk::Extent2D, +) -> Vec { + let command_buffer_allocate_info = vk::CommandBufferAllocateInfo { + s_type: vk::StructureType::COMMAND_BUFFER_ALLOCATE_INFO, + p_next: ptr::null(), + command_buffer_count: command_buffers.len() as u32, + command_pool, + level: vk::CommandBufferLevel::PRIMARY, + }; - image_barrier.old_layout = vk::ImageLayout::TRANSFER_SRC_OPTIMAL; - image_barrier.new_layout = vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL; - image_barrier.src_access_mask = vk::AccessFlags::TRANSFER_READ; - image_barrier.dst_access_mask = vk::AccessFlags::SHADER_READ; + let command_buffers = unsafe { + device + .allocate_command_buffers(&command_buffer_allocate_info) + .expect("Failed to allocate Command Buffers!") + }; - unsafe { - device.cmd_pipeline_barrier( - command_buffer, - vk::PipelineStageFlags::TRANSFER, - vk::PipelineStageFlags::FRAGMENT_SHADER, - vk::DependencyFlags::empty(), - &[], - &[], - &[image_barrier.clone()], - ); - } + command_buffers +} - mip_width = max(mip_width / 2, 1); - mip_height = max(mip_height / 2, 1); - } +/*pub fn record_command_buffer( + device: &ash::Device, + command_buffer: vk::CommandBuffer, + image_index: u32, + render_pass: vk::RenderPass, + swapchain_extent: vk::Extent2D, + shader_storage_buffers: Vec, + //shader_storage_buffers_memory: Vec, + current_frame: usize, + graphics_pipeline: vk::GraphicsPipeline, - image_barrier.subresource_range.base_mip_level = mip_levels - 1; - image_barrier.old_layout = vk::ImageLayout::TRANSFER_DST_OPTIMAL; - image_barrier.new_layout = vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL; - image_barrier.src_access_mask = vk::AccessFlags::TRANSFER_WRITE; - image_barrier.dst_access_mask = vk::AccessFlags::SHADER_READ; - unsafe { - device.cmd_pipeline_barrier( - command_buffer, - vk::PipelineStageFlags::TRANSFER, - vk::PipelineStageFlags::FRAGMENT_SHADER, - vk::DependencyFlags::empty(), - &[], - &[], - &[image_barrier.clone()], - ); +) { + let command_buffer_begin_info = vk::CommandBufferBeginInfo { + s_type: vk::StructureType::COMMAND_BUFFER_BEGIN_INFO, + p_next: ptr::null(), + p_inheritance_info: ptr::null(), + flags: vk::CommandBufferUsageFlags::SIMULTANEOUS_USE, } - end_single_time_command(device, command_pool, submit_queue, command_buffer); -} - -pub fn create_instance( - entry: &ash::Entry, - window_title: &str, - is_enable_debug: bool, - required_validation_layers: &Vec<&str>, -) -> ash::Instance { - if is_enable_debug - && debug::check_validation_layer_support(entry, required_validation_layers) == false - { - panic!("Validation layers requested, but not available!"); + unsafe { + device + .begin_command_buffer(command_buffer, &command_buffer_begin_info) + .expect("failed to start recording command buffer") } + let clear_values = [vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.0, 0.0, 0.0, 1.0], + }, + }]; - let app_name = CString::new(window_title).unwrap(); - let engine_name = CString::new("Vulkan Engine").unwrap(); - let app_info = vk::ApplicationInfo { - p_application_name: app_name.as_ptr(), - s_type: vk::StructureType::APPLICATION_INFO, + let render_pass_begin_info = vk::RenderPassBeginInfo { + s_type: vk::StructureType::RENDER_PASS_BEGIN_INFO, p_next: ptr::null(), - application_version: APPLICATION_VERSION, - p_engine_name: engine_name.as_ptr(), - engine_version: ENGINE_VERSION, - api_version: API_VERSION, + render_pass, + framebuffer: framebuffers[i], + render_area: vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: surface_extent, + }, + clear_value_count: clear_values.len() as u32, + p_clear_values: clear_values.as_ptr(), }; + let viewport = vec![vk::Viewport { + x: 0.0, + y: 0.0, + width: swapchain_extent.width as f32, + height: swapchain_extent.height as f32, + min_depth: 0.0, + max_depth: 1.0, + // This create info used to debug issues in vk::createInstance and vk::destroyInstance. let debug_utils_create_info = debug::populate_debug_messenger_create_info(); @@ -1080,27 +1360,10 @@ pub fn create_instance( }; instance -} +}*/ + -pub fn create_surface( - entry: &ash::Entry, - instance: &ash::Instance, - window: &winit::window::Window, - screen_width: u32, - screen_height: u32, -) -> SurfaceStuff { - let surface = unsafe { - platforms::create_surface(entry, instance, window).expect("Failed to create surface.") - }; - let surface_loader = ash::extensions::khr::Surface::new(entry, instance); - SurfaceStuff { - surface_loader, - surface, - screen_width, - screen_height, - } -} pub fn pick_physical_device( instance: &ash::Instance, @@ -1121,12 +1384,6 @@ pub fn pick_physical_device( required_device_extensions, ); - // if is_suitable { - // let device_properties = instance.get_physical_device_properties(**physical_device); - // let device_name = super::tools::vk_to_string(&device_properties.device_name); - // println!("Using GPU: {}", device_name); - // } - is_suitable }); @@ -1169,7 +1426,7 @@ pub fn create_logical_device( validation: &super::debug::ValidationInfo, device_extensions: &DeviceExtension, surface_stuff: &SurfaceStuff, -) -> (ash::Device, QueueFamilyIndices) { +) -> (ash::Device, QueueFamilyIndices, vk::Queue, vk::Queue, vk::Queue) { let indices = find_queue_family(instance, physical_device, surface_stuff); use std::collections::HashSet; @@ -1179,16 +1436,16 @@ pub fn create_logical_device( let queue_priorities = [1.0_f32]; let mut queue_create_infos = vec![]; + for &queue_family in unique_queue_families.iter() { - let queue_create_info = vk::DeviceQueueCreateInfo { + queue_create_infos.push(vk::DeviceQueueCreateInfo { s_type: vk::StructureType::DEVICE_QUEUE_CREATE_INFO, p_next: ptr::null(), flags: vk::DeviceQueueCreateFlags::empty(), queue_family_index: queue_family, p_queue_priorities: queue_priorities.as_ptr(), queue_count: queue_priorities.len() as u32, - }; - queue_create_infos.push(queue_create_info); + }); } let physical_device_features = vk::PhysicalDeviceFeatures { @@ -1226,9 +1483,17 @@ pub fn create_logical_device( .expect("Failed to create logical Device!") }; - (device, indices) + let graphics_queue = + unsafe { device.get_device_queue(queue_family.graphics_family.unwrap(), 0) }; + let present_queue = + unsafe { device.get_device_queue(queue_family.present_family.unwrap(), 0) }; + let compute_queue = + unsafe { device.get_device_queue(queue_family.compute_family.unwrap(), 0) }; + + (device, indices, graphics_queue, compute_queue, present_queue) } +//Updated from C++ to support compute pub fn find_queue_family( instance: &ash::Instance, physical_device: vk::PhysicalDevice, @@ -1239,12 +1504,14 @@ pub fn find_queue_family( let mut queue_family_indices = QueueFamilyIndices::new(); - let mut index = 0; - for queue_family in queue_families.iter() { + for (i, queue_family) in queue_families.iter().enumerate() { if queue_family.queue_count > 0 - && queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS) + && ( + queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS) && + queue_family.queue_flags.contains(vk::QueueFlags::COMPUTE) + ) { - queue_family_indices.graphics_family = Some(index); + queue_family_indices.graphics_and_compute_family = Some(i); } let is_present_support = unsafe { @@ -1252,20 +1519,18 @@ pub fn find_queue_family( .surface_loader .get_physical_device_surface_support( physical_device, - index as u32, + i as u32, surface_stuff.surface, ) .unwrap() }; if queue_family.queue_count > 0 && is_present_support { - queue_family_indices.present_family = Some(index); + queue_family_indices.present_family = Some(i); } if queue_family_indices.is_complete() { break; } - - index += 1; } queue_family_indices @@ -1329,84 +1594,6 @@ pub fn query_swapchain_support( } } -pub fn create_swapchain( - instance: &ash::Instance, - device: &ash::Device, - physical_device: vk::PhysicalDevice, - window: &winit::window::Window, - surface_stuff: &SurfaceStuff, - queue_family: &QueueFamilyIndices, -) -> SwapChainStuff { - let swapchain_support = query_swapchain_support(physical_device, surface_stuff); - - let surface_format = choose_swapchain_format(&swapchain_support.formats); - let present_mode = choose_swapchain_present_mode(&swapchain_support.present_modes); - let extent = choose_swapchain_extent(&swapchain_support.capabilities, window); - - let image_count = swapchain_support.capabilities.min_image_count + 1; - let image_count = if swapchain_support.capabilities.max_image_count > 0 { - image_count.min(swapchain_support.capabilities.max_image_count) - } else { - image_count - }; - - let (image_sharing_mode, queue_family_index_count, queue_family_indices) = - if queue_family.graphics_family != queue_family.present_family { - ( - vk::SharingMode::CONCURRENT, - 2, - vec![ - queue_family.graphics_family.unwrap(), - queue_family.present_family.unwrap(), - ], - ) - } else { - (vk::SharingMode::EXCLUSIVE, 0, vec![]) - }; - - let swapchain_create_info = vk::SwapchainCreateInfoKHR { - s_type: vk::StructureType::SWAPCHAIN_CREATE_INFO_KHR, - p_next: ptr::null(), - flags: vk::SwapchainCreateFlagsKHR::empty(), - surface: surface_stuff.surface, - min_image_count: image_count, - image_color_space: surface_format.color_space, - image_format: surface_format.format, - image_extent: extent, - image_usage: vk::ImageUsageFlags::COLOR_ATTACHMENT, - image_sharing_mode, - p_queue_family_indices: queue_family_indices.as_ptr(), - queue_family_index_count, - pre_transform: swapchain_support.capabilities.current_transform, - composite_alpha: vk::CompositeAlphaFlagsKHR::OPAQUE, - present_mode, - clipped: vk::TRUE, - old_swapchain: vk::SwapchainKHR::null(), - image_array_layers: 1, - }; - - let swapchain_loader = ash::extensions::khr::Swapchain::new(instance, device); - let swapchain = unsafe { - swapchain_loader - .create_swapchain(&swapchain_create_info, None) - .expect("Failed to create Swapchain!") - }; - - let swapchain_images = unsafe { - swapchain_loader - .get_swapchain_images(swapchain) - .expect("Failed to get Swapchain Images.") - }; - - SwapChainStuff { - swapchain_loader, - swapchain, - swapchain_format: surface_format.format, - swapchain_extent: extent, - swapchain_images, - } -} - pub fn choose_swapchain_format( available_formats: &Vec, ) -> vk::SurfaceFormatKHR { @@ -1539,20 +1726,74 @@ pub fn copy_buffer( src_buffer: vk::Buffer, dst_buffer: vk::Buffer, size: vk::DeviceSize, + graphics_queue: vk::Queue, ) { - let command_buffer = begin_single_time_command(device, command_pool); + let command_buffer_allocate_info = vk::CommandBufferAllocateInfo { + s_type: vk::StructureType::COMMAND_BUFFER_ALLOCATE_INFO, + p_next: ptr::null(), + command_buffer_count: 1, + command_pool, + level: vk::CommandBufferLevel::PRIMARY, + }; - let copy_regions = [vk::BufferCopy { - src_offset: 0, - dst_offset: 0, - size, - }]; + unsafe { + let command_buffers = device + .allocate_command_buffers( + command_buffer_allocate_info + ); + } + + let begin_info = vk::CommandBufferBeginInfo { + s_type: StructureType::COMMAND_BUFFER_BEGIN_INFO, + flags: CommandBufferUsageFlags::ONE_TIME_SUBMIT, + ..default::Default() + }; unsafe { - device.cmd_copy_buffer(command_buffer, src_buffer, dst_buffer, ©_regions); + device + .begin_command_buffer(command_buffers[0], &begin_info); } - end_single_time_command(device, command_pool, submit_queue, command_buffer); + let copy_region = vk::BufferCopy { + size: size, + ..default::Default() + }; + + unsafe { + device + .cmd_copy_buffer( + command_buffers[0], + src_buffer, + dst_buffer, + copy_region, + ); + + vk::end_command_buffer(command_buffers[0]); + } + + let submit_info = vk::SubmitInfo { + s_type: StructureType::SUBMIT_INFO, + command_buffer_count: 1, + p_command_buffers: command_buffers[0], + ..default::Default() + }; + + unsafe { + device + .queue_submit( + graphics_queue, + submit_info, + Fence::null(), + ); + + device + .queue_wait_idle( + graphics_queue + ); + + device + .free_command_buffers(command_pool, command_buffers); + } } pub fn begin_single_time_command( @@ -1687,7 +1928,7 @@ pub fn copy_buffer_to_image( end_single_time_command(device, command_pool, submit_queue, command_buffer); } -pub fn find_depth_format( +/*pub fn find_depth_format( instance: &ash::Instance, physical_device: vk::PhysicalDevice, ) -> vk::Format { @@ -1696,12 +1937,16 @@ pub fn find_depth_format( physical_device, &[ vk::Format::D32_SFLOAT, - vk::Format::D32_SFLOAT_S8_UINT, - vk::Format::D24_UNORM_S8_UINT, + vk::Format::D32_SFLOAT_S8_UINT ], - vk::ImageTiling::OPTIMAL, - vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT, - ) + .create_framebuffer(&framebuffer_create_info, None) + .expect("Failed to create Framebuffer!") + ); + + framebuffers.push(framebuffer); + } + + framebuffers } pub fn find_supported_format( @@ -1726,56 +1971,169 @@ pub fn find_supported_format( } panic!("Failed to find supported format!") +}*/ + +pub fn create_command_pool( + device: &ash::Device, + queue_families: &QueueFamilyIndices, +) -> vk::CommandPool { + let command_pool_create_info = vk::CommandPoolCreateInfo { + s_type: vk::StructureType::COMMAND_POOL_CREATE_INFO, + p_next: ptr::null(), + flags: vk::CommandPoolCreateFlags::empty(), + queue_family_index: queue_families.graphics_family.unwrap(), + }; + + unsafe { + device + .create_command_pool(&command_pool_create_info, None) + .expect("Failed to create Command Pool!") + } } -pub fn load_model(model_path: &Path) -> (Vec, Vec) { - let model_obj = tobj::load_obj(model_path).expect("Failed to load model object!"); +///createCommandBuffers in C++ +pub fn create_command_buffers( + device: &ash::Device, + command_pool: vk::CommandPool, + command_buffers: &Vec, + //graphics_pipeline: vk::Pipeline, + //framebuffers: &Vec, + //render_pass: vk::RenderPass, + //surface_extent: vk::Extent2D, +) -> Vec { + let command_buffer_allocate_info = vk::CommandBufferAllocateInfo { + s_type: vk::StructureType::COMMAND_BUFFER_ALLOCATE_INFO, + p_next: ptr::null(), + command_buffer_count: command_buffers.len() as u32, + command_pool, + level: vk::CommandBufferLevel::PRIMARY, + }; + + let command_buffers = unsafe { + device + .allocate_command_buffers(&command_buffer_allocate_info) + .expect("Failed to allocate Command Buffers!") + }; - let mut vertices = vec![]; - let mut indices = vec![]; + command_buffers +} - let (models, _) = model_obj; - for m in models.iter() { - let mesh = &m.mesh; +pub fn record_command_buffer( + device: &ash::Device, + command_buffer: vk::CommandBuffer, + image_index: u32, + render_pass: vk::RenderPass, + swapchain_extent: vk::Extent2D, + shader_storage_buffers: Vec, + //shader_storage_buffers_memory: Vec, + current_frame: usize, + graphics_pipeline: vk::GraphicsPipeline, - if mesh.texcoords.len() == 0 { - panic!("Missing texture coordinate for the model.") - } - let total_vertices_count = mesh.positions.len() / 3; - for i in 0..total_vertices_count { - let vertex = VertexV3 { - pos: [ - mesh.positions[i * 3], - mesh.positions[i * 3 + 1], - mesh.positions[i * 3 + 2], - 1.0, - ], - color: [1.0, 1.0, 1.0, 1.0], - tex_coord: [mesh.texcoords[i * 2], mesh.texcoords[i * 2 + 1]], - }; - vertices.push(vertex); - } +) { + let command_buffer_begin_info = vk::CommandBufferBeginInfo { + s_type: vk::StructureType::COMMAND_BUFFER_BEGIN_INFO, + p_next: ptr::null(), + p_inheritance_info: ptr::null(), + flags: vk::CommandBufferUsageFlags::SIMULTANEOUS_USE, + } - indices = mesh.indices.clone(); + unsafe { + device + .begin_command_buffer(command_buffer, &command_buffer_begin_info) + .expect("failed to start recording command buffer") } + let clear_color = [vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.0, 0.0, 0.0, 1.0], + }, + }]; - (vertices, indices) -} + let render_pass_begin_info = vk::RenderPassBeginInfo { + s_type: vk::StructureType::RENDER_PASS_BEGIN_INFO, + p_next: ptr::null(), + render_pass, + framebuffer: framebuffers[i], + render_area: vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: surface_extent, + }, + clear_value_count: clear_color.len() as u32, + p_clear_values: clear_color.as_ptr(), + }; -pub fn check_mipmap_support( - instance: &ash::Instance, - physcial_device: vk::PhysicalDevice, - image_format: vk::Format, -) { - let format_properties = - unsafe { instance.get_physical_device_format_properties(physcial_device, image_format) }; + unsafe { + device + .cmd_begin_render_pass( + command_buffer, + &render_pass_begin_info, + vk::SubPassContents::INLINE, + ); + + device + .cmd_bind_pipeline( + command_buffer, + vk::PipelineBindPoint::GRAPHICS, + graphics_pipeline, + ); + } + + let viewport = vec![vk::Viewport { + x: 0.0, + y: 0.0, + width: swapchain_extent.width as f32, + height: swapchain_extent.height as f32, + min_depth: 0.0, + max_depth: 1.0, + }]; + + unsafe { + device + .cmd_set_viewport( + command_buffer, + 0, + viewport, + ); + } + + let scissor = vec![vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: swapchain_extent, + }]; + + unsafe { + device + .cmd_set_scissor( + command_buffer, + 0, + &scissor + ); + } - let is_sample_image_filter_linear_support = format_properties - .optimal_tiling_features - .contains(vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR); + let offsets = 0 as vk::DeviceSize; - if is_sample_image_filter_linear_support == false { - panic!("Texture Image format does not support linear blitting!") + unsafe { + device + .cmd_bind_vertex_buffers( + command_buffer, + 0, + shader_storage_buffers[current_frame], + offsets, + ); + device + .cmd_draw( + command_buffer, + PARTICLE_COUNT, + 1, + 0, + 0, + ); + device + .cmd_end_render_pass( + command_buffer + ); + device + .end_command_buffer(command_buffer) + .expect("failed to end command buffer"); } } diff --git a/src/utility/structures.rs b/src/utility/structures.rs index 898eca9..5058d9b 100644 --- a/src/utility/structures.rs +++ b/src/utility/structures.rs @@ -1,8 +1,13 @@ +use std::ptr; + use ash::vk; use cgmath::Matrix4; use memoffset::offset_of; +use super::platforms; +use super::share::*; + pub struct DeviceExtension { pub names: [&'static str; 1], // pub raw_names: [*const i8; 1], @@ -15,121 +20,222 @@ pub struct SurfaceStuff { pub screen_width: u32, pub screen_height: u32, } + +impl SurfaceStuff { + pub fn new( + entry: &ash::Entry, + instance: &ash::Instance, + window: &winit::window::Window, + screen_width: u32, + screen_height: u32, + ) -> SurfaceStuff { + let surface = unsafe { + platforms::create_surface(entry, instance, window).expect("Failed to create surface.") + }; + let surface_loader = ash::extensions::khr::Surface::new(entry, instance); + + SurfaceStuff { + surface_loader, + surface, + screen_width, + screen_height, + } + } + +} + pub struct SwapChainStuff { pub swapchain_loader: ash::extensions::khr::Swapchain, pub swapchain: vk::SwapchainKHR, pub swapchain_images: Vec, pub swapchain_format: vk::Format, pub swapchain_extent: vk::Extent2D, + pub swapchain_imageviews: Vec, + pub swapchain_framebuffers: Vec,* +} + +impl SwapChainStuff { + pub fn new( + instance: &ash::Instance, + device: &ash::Device, + physical_device: vk::PhysicalDevice, + window: &winit::window::Window, + surface_stuff: &SurfaceStuff, + queue_family: &QueueFamilyIndices, + ) -> Self { + let swapchain_support = query_swapchain_support(physical_device, surface_stuff); + + let surface_format = choose_swapchain_format(&swapchain_support.formats); + let present_mode = choose_swapchain_present_mode(&swapchain_support.present_modes); + let extent = choose_swapchain_extent(&swapchain_support.capabilities, window); + + let image_count = swapchain_support.capabilities.min_image_count + 1; + let image_count = if swapchain_support.capabilities.max_image_count > 0 { + image_count.min(swapchain_support.capabilities.max_image_count) + } else { + image_count + }; + + let (image_sharing_mode, queue_family_index_count, queue_family_indices) = + if queue_family.graphics_family != queue_family.present_family { + ( + vk::SharingMode::CONCURRENT, + 2, + vec![ + queue_family.graphics_and_compute_family.unwrap(), + queue_family.present_family.unwrap(), + ], + ) + } else { + (vk::SharingMode::EXCLUSIVE, 0, vec![]) + }; + + let swapchain_create_info = vk::SwapchainCreateInfoKHR { + s_type: vk::StructureType::SWAPCHAIN_CREATE_INFO_KHR, + p_next: ptr::null(), + flags: vk::SwapchainCreateFlagsKHR::empty(), + surface: surface_stuff.surface, + min_image_count: image_count, + image_color_space: surface_format.color_space, + image_format: surface_format.format, + image_extent: extent, + image_usage: vk::ImageUsageFlags::COLOR_ATTACHMENT, + image_sharing_mode, + p_queue_family_indices: queue_family_indices.as_ptr(), + queue_family_index_count, + pre_transform: swapchain_support.capabilities.current_transform, + composite_alpha: vk::CompositeAlphaFlagsKHR::OPAQUE, + present_mode, + clipped: vk::TRUE, + old_swapchain: vk::SwapchainKHR::null(), + image_array_layers: 1, + }; + + let swapchain_loader = ash::extensions::khr::Swapchain::new(instance, device); + let swapchain = unsafe { + swapchain_loader + .create_swapchain(&swapchain_create_info, None) + .expect("Failed to create Swapchain!") + }; + + let swapchain_images = unsafe { + swapchain_loader + .get_swapchain_images(swapchain) + .expect("Failed to get Swapchain Images.") + }; + + SwapChainStuff { + swapchain_loader, + swapchain, + swapchain_format: surface_format.format, + swapchain_extent: extent, + swapchain_images, + } + + } } -pub struct SwapChainSupportDetail { +pub struct SwapChainSupportDetails { pub capabilities: vk::SurfaceCapabilitiesKHR, pub formats: Vec, pub present_modes: Vec, } pub struct QueueFamilyIndices { - pub graphics_family: Option, + pub graphics_and_compute_family: Option, pub present_family: Option, } impl QueueFamilyIndices { pub fn new() -> QueueFamilyIndices { QueueFamilyIndices { - graphics_family: None, + graphics_and_compute_family: None, present_family: None, } } pub fn is_complete(&self) -> bool { - self.graphics_family.is_some() && self.present_family.is_some() + self.graphics_and_compute_family.is_some() && self.present_family.is_some() } } pub struct SyncObjects { pub image_available_semaphores: Vec, pub render_finished_semaphores: Vec, + pub compute_finished_semaphores: Vec, pub inflight_fences: Vec, + pub compute_inflight_fences: Vec } -#[repr(C)] -#[derive(Clone, Debug, Copy)] -pub struct UniformBufferObject { - pub model: Matrix4, - pub view: Matrix4, - pub proj: Matrix4, -} +impl SyncObjects { + //createSyncObjects in C++ + pub fn new(device: &ash::Device, max_frame_in_flight: usize) -> Self { + let mut sync_objects = SyncObjects { + image_available_semaphores: vec![], + render_finished_semaphores: vec![], + compute_finished_semaphores: vec![], + inflight_fences: vec![], + compute_inflight_fences: vec![], + }; -#[repr(C)] -#[derive(Clone, Debug, Copy)] -pub struct VertexV1 { - pub pos: [f32; 2], - pub color: [f32; 3], -} -impl VertexV1 { - pub fn get_binding_description() -> [vk::VertexInputBindingDescription; 1] { - [vk::VertexInputBindingDescription { - binding: 0, - stride: ::std::mem::size_of::() as u32, - input_rate: vk::VertexInputRate::VERTEX, - }] - } + let semaphore_create_info = vk::SemaphoreCreateInfo { + s_type: vk::StructureType::SEMAPHORE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::SemaphoreCreateFlags::empty(), + }; + + let fence_create_info = vk::FenceCreateInfo { + s_type: vk::StructureType::FENCE_CREATE_INFO, + p_next: ptr::null(), + flags: vk::FenceCreateFlags::SIGNALED, + }; + + for _ in 0..max_frame_in_flight { + unsafe { + let image_available_semaphore = device + .create_semaphore(&semaphore_create_info, None) + .expect("Failed to create Semaphore Object!"); + let render_finished_semaphore = device + .create_semaphore(&semaphore_create_info, None) + .expect("Failed to create Semaphore Object!"); + + let inflight_fence = device + .create_fence(&fence_create_info, None) + .expect("Failed to create Fence Object!"); + + let compute_finished_semaphore = device + .create_semaphore(&semaphore_create_info, None) + .expect("Failed to create Semaphore Object!"); + let compute_inflight_fence = device + .create_fence(&fence_create_info, None) + .expect("Failed to create Fence Object!"); + + sync_objects + .image_available_semaphores + .push(image_available_semaphore); + sync_objects + .render_finished_semaphores + .push(render_finished_semaphore); + sync_objects.inflight_fences.push(inflight_fence); + + sync_objects + .image_available_semaphores + .push(image_available_semaphore); + sync_objects + .image_available_semaphores + .push(image_available_semaphore); + + } + } + + sync_objects - pub fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] { - [ - vk::VertexInputAttributeDescription { - binding: 0, - location: 0, - format: vk::Format::R32G32_SFLOAT, - offset: offset_of!(VertexV1, pos) as u32, - }, - vk::VertexInputAttributeDescription { - binding: 0, - location: 1, - format: vk::Format::R32G32B32_SFLOAT, - offset: offset_of!(VertexV1, color) as u32, - }, - ] } } #[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct VertexV3 { - pub pos: [f32; 4], - pub color: [f32; 4], - pub tex_coord: [f32; 2], +#[derive(Clone, Debug, Copy)] +pub struct UniformBufferObject { + pub delta_time = 1.0, } -impl VertexV3 { - pub fn get_binding_descriptions() -> [vk::VertexInputBindingDescription; 1] { - [vk::VertexInputBindingDescription { - binding: 0, - stride: ::std::mem::size_of::() as u32, - input_rate: vk::VertexInputRate::VERTEX, - }] - } - pub fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 3] { - [ - vk::VertexInputAttributeDescription { - binding: 0, - location: 0, - format: vk::Format::R32G32B32A32_SFLOAT, - offset: offset_of!(Self, pos) as u32, - }, - vk::VertexInputAttributeDescription { - binding: 0, - location: 1, - format: vk::Format::R32G32B32A32_SFLOAT, - offset: offset_of!(Self, color) as u32, - }, - vk::VertexInputAttributeDescription { - binding: 0, - location: 2, - format: vk::Format::R32G32_SFLOAT, - offset: offset_of!(Self, tex_coord) as u32, - }, - ] - } -} diff --git a/src/utility/window.rs b/src/utility/window.rs index 735b5f5..e69de29 100644 --- a/src/utility/window.rs +++ b/src/utility/window.rs @@ -1,88 +0,0 @@ -use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; -use winit::event_loop::{ControlFlow, EventLoop}; - -const IS_PAINT_FPS_COUNTER: bool = true; - -pub fn init_window( - event_loop: &EventLoop<()>, - title: &str, - width: u32, - height: u32, -) -> winit::window::Window { - winit::window::WindowBuilder::new() - .with_title(title) - .with_inner_size(winit::dpi::LogicalSize::new(width, height)) - .build(event_loop) - .expect("Failed to create window.") -} - -pub trait VulkanApp { - fn draw_frame(&mut self, delta_time: f32); - fn recreate_swapchain(&mut self); - fn cleanup_swapchain(&self); - fn wait_device_idle(&self); - fn resize_framebuffer(&mut self); - fn window_ref(&self) -> &winit::window::Window; -} - -pub struct ProgramProc { - pub event_loop: EventLoop<()>, -} - -impl ProgramProc { - pub fn new() -> ProgramProc { - // init window stuff - let event_loop = EventLoop::new(); - - ProgramProc { event_loop } - } - - pub fn main_loop(self, mut vulkan_app: A) { - let mut tick_counter = super::fps_limiter::FPSLimiter::new(); - - self.event_loop - .run(move |event, _, control_flow| match event { - Event::WindowEvent { event, .. } => match event { - WindowEvent::CloseRequested => { - vulkan_app.wait_device_idle(); - *control_flow = ControlFlow::Exit - } - WindowEvent::KeyboardInput { input, .. } => match input { - KeyboardInput { - virtual_keycode, - state, - .. - } => match (virtual_keycode, state) { - (Some(VirtualKeyCode::Escape), ElementState::Pressed) => { - vulkan_app.wait_device_idle(); - *control_flow = ControlFlow::Exit - } - _ => {} - }, - }, - WindowEvent::Resized(_new_size) => { - vulkan_app.wait_device_idle(); - vulkan_app.resize_framebuffer(); - } - _ => {} - }, - Event::MainEventsCleared => { - vulkan_app.window_ref().request_redraw(); - } - Event::RedrawRequested(_window_id) => { - let delta_time = tick_counter.delta_time(); - vulkan_app.draw_frame(delta_time); - - if IS_PAINT_FPS_COUNTER { - print!("FPS: {}\r", tick_counter.fps()); - } - - tick_counter.tick_frame(); - } - Event::LoopDestroyed => { - vulkan_app.wait_device_idle(); - } - _ => (), - }) - } -}