use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use ash::vk; use ash::util::Align; use image; use image::GenericImageView; use crate::utility; use crate::utility::constants::*; use crate::utility::debug::*; use crate::utility::structures::*; use crate::utility::fps_limiter::*; use crate::utility::{debug, platforms}; use crate::utility::tools::*; use crate::entities::*; use crate::VulkanApp; use crate::shaders::shaders; use std::ffi::CString; use std::ptr; use std::mem; use mem::size_of; use std::default; use std::os::raw::{ c_void, c_char }; // Constants const WINDOW_TITLE: &'static str = "Template"; const IS_PAINT_FPS_COUNTER: bool = true; 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_enabled { &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, }; let instance: ash::Instance = unsafe { entry .create_instance(&create_info, None) .expect("Failed to create instance!") }; instance } 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 fn choose_swapchain_format( available_formats: &Vec, ) -> vk::SurfaceFormatKHR { for available_format in available_formats { if available_format.format == vk::Format::B8G8R8A8_SRGB && available_format.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR { return available_format.clone(); } } return available_formats.first().unwrap().clone(); } pub fn choose_swapchain_present_mode( available_present_modes: &Vec, ) -> vk::PresentModeKHR { for &available_present_mode in available_present_modes.iter() { if available_present_mode == vk::PresentModeKHR::MAILBOX { return available_present_mode; } } vk::PresentModeKHR::FIFO } pub fn create_shader_module(device: &ash::Device, code: Vec) -> vk::ShaderModule { let shader_module_create_info = vk::ShaderModuleCreateInfo { s_type: vk::StructureType::SHADER_MODULE_CREATE_INFO, p_next: ptr::null(), flags: vk::ShaderModuleCreateFlags::empty(), code_size: code.len(), p_code: code.as_ptr() as *const u32, }; unsafe { device .create_shader_module(&shader_module_create_info, None) .expect("Failed to create Shader Module!") } } pub 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.contains(required_properties) { return i as u32; } } panic!("Failed to find suitable memory type!") } pub struct App<'a> { pub window: winit::window::Window, // vulkan stuff pub entry: ash::Entry, pub instance: ash::Instance, pub surface_stuff: SurfaceStuff, //surface_loader: ash::extensions::khr::Surface, //surface: vk::SurfaceKHR, pub debug_utils_loader: ash::extensions::ext::DebugUtils, pub debug_messenger: vk::DebugUtilsMessengerEXT, pub physical_device: vk::PhysicalDevice, pub device: ash::Device, pub queue_family: QueueFamilyIndices, pub graphics_queue: vk::Queue, pub present_queue: vk::Queue, //new from C++ pub compute_queue: vk::Queue, pub 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, pub render_pass: vk::RenderPass, pub graphics_pipeline_layout: vk::PipelineLayout, pub graphics_pipeline: vk::Pipeline, //new from C++ pub compute_descriptor_set_layout: vk::DescriptorSetLayout, pub compute_pipeline_layout: vk::PipelineLayout, pub compute_pipeline: vk::Pipeline, //vertex buffer for the triangle verticies //i think this is the same as shaderStorageBuffers in C++ version pub shader_storage_buffers: Vec, pub shader_storage_buffers_memory: Vec, pub uniform_buffers: Vec, pub uniform_buffers_memory: Vec, pub uniform_buffers_mapped: Vec<*mut c_void>, pub descriptor_pool: vk::DescriptorPool, pub compute_descriptor_sets: Vec, pub command_pool: vk::CommandPool, pub command_buffers: Vec, pub compute_command_buffers: Vec, pub sync_objects: SyncObjects, //image_available_semaphores: Vec, //render_finished_semaphores: Vec, //inflight_fences: Vec, //.compute_inflight_fences: Vec, pub current_frame: usize, pub last_frame_time: f32, pub is_framebuffer_resized: bool, pub last_time: f64, pub physical_device_memory_properties: vk::PhysicalDeviceMemoryProperties, pub query_pool: vk::QueryPool, pub query_memory: vk::DeviceMemory, pub query_mapped: &'a mut [u64], } impl<'a> App<'a> { pub fn new(event_loop: &winit::event_loop::EventLoop<()>) -> Self { let window = init_window(&event_loop, WINDOW_TITLE, WINDOW_WIDTH, WINDOW_HEIGHT); let entry = unsafe { ash::Entry::load().unwrap() }; let instance = create_instance( &entry, WINDOW_TITLE, VALIDATION.is_enabled, &VALIDATION.required_validation_layers.to_vec(), ); let (debug_utils_loader, debug_messenger) = setup_debug_utils(VALIDATION.is_enabled, &entry, &instance); let surface_stuff = SurfaceStuff::new( &entry, &instance, &window, WINDOW_WIDTH, WINDOW_HEIGHT ); let physical_device = Self::pick_physical_device(&instance, &surface_stuff, &DEVICE_EXTENSIONS); let physical_device_memory_properties = unsafe { instance.get_physical_device_memory_properties(physical_device) }; let (device, queue_family, graphics_queue, compute_queue, present_queue) = Self::create_logical_device( &instance, physical_device, &VALIDATION, &DEVICE_EXTENSIONS, &surface_stuff, ); /*let graphics_queue = unsafe { device.get_device_queue(queue_family.graphics_and_compute_family.unwrap(), 0) }; let present_queue = unsafe { device.get_device_queue(queue_family.present_family.unwrap(), 0) };*/ let mut swapchain_stuff = SwapChainStuff::new( &instance, &device, physical_device, &window, &surface_stuff, &queue_family, ); swapchain_stuff.swapchain_imageviews = Self::create_image_views(&device, &swapchain_stuff.swapchain_format, &swapchain_stuff.swapchain_images); let render_pass = Self::create_render_pass(&device, &swapchain_stuff.swapchain_format); let compute_descriptor_set_layout = Self::create_compute_descriptor_set_layout(&device); let (graphics_pipeline, graphics_pipeline_layout) = Self::create_graphics_pipeline(&device, render_pass, &swapchain_stuff); let (compute_pipeline, compute_pipeline_layout) = Self::create_compute_pipeline(&device, compute_descriptor_set_layout); let swapchain_framebuffers = Self::create_framebuffers(&device, render_pass, &swapchain_stuff.swapchain_imageviews, &swapchain_stuff.swapchain_extent); swapchain_stuff.swapchain_framebuffers = swapchain_framebuffers; let command_pool = Self::create_command_pool(&device, &queue_family); let (shader_storage_buffers, shader_storage_buffers_memory) = Self::create_shader_storage_buffers(&device, physical_device_memory_properties, command_pool, graphics_queue); let (uniform_buffers, uniform_buffers_memory, uniform_buffers_mapped) = Self::create_uniform_buffers(&device, physical_device_memory_properties); let descriptor_pool = Self::create_descriptor_pool(&device, MAX_FRAMES_IN_FLIGHT); let compute_descriptor_sets = Self::create_compute_descriptor_sets(&device, compute_descriptor_set_layout, descriptor_pool, &uniform_buffers, &shader_storage_buffers); let command_buffers = Self::create_command_buffers(&device, command_pool); let compute_command_buffers = Self::create_compute_command_buffers(&device, command_pool); let sync_objects = SyncObjects::new(&device, MAX_FRAMES_IN_FLIGHT); //setup logging of compute shader invocations // Define the buffer to hold query results let mut query_results_data: [u64; 1] = [0]; // Assuming we're querying one result // Create a buffer to hold the query results let buffer_info = vk::BufferCreateInfo { s_type: vk::StructureType::BUFFER_CREATE_INFO, size: 8, usage: vk::BufferUsageFlags::TRANSFER_DST, sharing_mode: vk::SharingMode::EXCLUSIVE, ..Default::default() }; let query_result_buffer = unsafe { device .create_buffer(&buffer_info, None) .expect("Failed to create query result buffer") }; // Allocate memory for the buffer let mem_requirements = unsafe { device.get_buffer_memory_requirements(query_result_buffer) }; let memory_type_index = find_memory_type( mem_requirements.memory_type_bits, vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT, &physical_device_memory_properties, ); let allocate_info = vk::MemoryAllocateInfo { s_type: vk::StructureType::MEMORY_ALLOCATE_INFO, allocation_size: mem_requirements.size, memory_type_index, ..Default::default() }; let query_memory = unsafe { device .allocate_memory(&allocate_info, None) .expect("Failed to allocate query result memory") }; unsafe { // Bind the buffer with allocated memory device .bind_buffer_memory(query_result_buffer, query_memory, 0) .expect("Failed to bind buffer memory") }; // Now we can use this buffer to store query results let query_mapped = unsafe { let raw_ptr = device .map_memory( query_memory, 0, std::mem::size_of_val(&query_results_data) as u64, vk::MemoryMapFlags::empty(), ) .expect("Failed to map memory"); std::slice::from_raw_parts_mut(raw_ptr as *mut u64, 1) }; // Create a query pool let query_pool_info = vk::QueryPoolCreateInfo { s_type: vk::StructureType::QUERY_POOL_CREATE_INFO, query_type: vk::QueryType::PIPELINE_STATISTICS, query_count: 1, // We're only querying one statistic pipeline_statistics: vk::QueryPipelineStatisticFlags::COMPUTE_SHADER_INVOCATIONS, ..Default::default() }; let query_pool = unsafe { device .create_query_pool(&query_pool_info, None) .expect("Failed to create query pool") }; for i in 0..MAX_FRAMES_IN_FLIGHT { unsafe { device .cmd_reset_query_pool( compute_command_buffers[i], query_pool, 0, 1, ); } } Self { window, entry, instance, surface_stuff, debug_utils_loader, debug_messenger, physical_device, device, queue_family, graphics_queue, present_queue, compute_queue, swapchain_stuff, render_pass, graphics_pipeline_layout, graphics_pipeline, compute_descriptor_set_layout, compute_pipeline_layout, compute_pipeline, shader_storage_buffers, shader_storage_buffers_memory, uniform_buffers, uniform_buffers_memory, uniform_buffers_mapped, descriptor_pool, compute_descriptor_sets, command_pool, command_buffers, compute_command_buffers, sync_objects, current_frame: 0, last_frame_time: 0.0, is_framebuffer_resized: false, last_time: 0.0, physical_device_memory_properties, query_pool, query_memory, query_mapped, } } 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 } } panic!("Failed to find suitable memory type!"); } fn create_graphics_pipeline( device: &ash::Device, render_pass: vk::RenderPass, swapchain_stuff: &SwapChainStuff, ) -> (vk::Pipeline, vk::PipelineLayout) { 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 == vk::ShaderStageFlags::VERTEX || stage_i == vk::ShaderStageFlags::FRAGMENT { println!("shader stage: {:?}", stage_i); shader_modules.push( vk::PipelineShaderStageCreateInfo { s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, p_next: ptr::null(), flags: vk::PipelineShaderStageCreateFlags::empty(), module: 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]; //612-621 let binding_description = Particle::get_binding_description(); let attribute_description = Particle::get_attribute_descriptions(); 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(), }; //623-626 let input_assembly = vk::PipelineInputAssemblyStateCreateInfo { s_type: vk::StructureType::PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, topology: vk::PrimitiveTopology::POINT_LIST, primitive_restart_enable: vk::FALSE, ..Default::default() }; //628-631, more verbose and explicit than C++ let viewports = [vk::Viewport { x: 0.0, y: 0.0, width: swapchain_stuff.swapchain_extent.width as f32, height: 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_stuff.swapchain_extent, }]; let viewport_state = 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(), }; //633-641 let rasterizer = 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, }; //643-646 let multisampling = 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, }; //648-656 let color_blend_attachment = vk::PipelineColorBlendAttachmentState { blend_enable: vk::TRUE, color_write_mask: vk::ColorComponentFlags::RGBA, 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_MINUS_SRC_ALPHA, dst_alpha_blend_factor: vk::BlendFactor::ZERO, alpha_blend_op: vk::BlendOp::ADD, }; //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(), logic_op_enable: vk::FALSE, logic_op: vk::LogicOp::COPY, attachment_count: 1, p_attachments: &color_blend_attachment as *const vk::PipelineColorBlendAttachmentState, blend_constants: [0.0, 0.0, 0.0, 0.0], }; //669-676 let dynamic_states = vec![ 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, set_layout_count: 0, p_set_layouts: ptr::null(), ..Default::default() }; let pipeline_layout = unsafe { device .create_pipeline_layout(&pipeline_layout_info, None) .expect("failed to create graphics pipeline layout") }; let pipeline_info = vk::GraphicsPipelineCreateInfo { s_type: vk::StructureType::GRAPHICS_PIPELINE_CREATE_INFO, stage_count: 2, p_stages: shader_modules.as_ptr(), 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: pipeline_layout, render_pass: render_pass, subpass: 0, base_pipeline_handle: vk::Pipeline::null(), ..Default::default() }; let pipelines = unsafe { device .create_graphics_pipelines(vk::PipelineCache::null(), &[pipeline_info], None) .expect("failed to create graphics pipeline") }; //703-708 unsafe { for shader in shader_modules { device.destroy_shader_module(shader.module, None); } } (pipelines[0], pipeline_layout) } fn create_compute_pipeline( device: &ash::Device, compute_descriptor_set_layout: vk::DescriptorSetLayout, ) -> (vk::Pipeline, vk::PipelineLayout) { //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 == vk::ShaderStageFlags::COMPUTE { shader_modules.push( vk::PipelineShaderStageCreateInfo { s_type: vk::StructureType::PIPELINE_SHADER_STAGE_CREATE_INFO, p_next: ptr::null(), flags: vk::PipelineShaderStageCreateFlags::empty(), module: 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::PIPELINE_LAYOUT_CREATE_INFO, set_layout_count: 1, p_set_layouts: &compute_descriptor_set_layout, ..Default::default() }; let compute_pipeline_layout = unsafe { device .create_pipeline_layout(&pipeline_layout_info, None) .expect("couldnt create compute pipeline layout") }; let pipeline_info = vk::ComputePipelineCreateInfo { s_type: vk::StructureType::COMPUTE_PIPELINE_CREATE_INFO, layout: compute_pipeline_layout, stage: comp_shader, ..Default::default() }; let compute_pipeline = unsafe { device .create_compute_pipelines( vk::PipelineCache::null(), &[pipeline_info], None, ) .expect("failed to create compute pipeline")[0] }; unsafe { device.destroy_shader_module( comp_shader.module, None, ); } (compute_pipeline, compute_pipeline_layout) } fn update_uniform_buffer(&mut self, current_image: usize) { let mut ubo = UniformBufferObject { delta_time: self.last_frame_time, }; unsafe { ptr::copy_nonoverlapping( &mut ubo as *mut UniformBufferObject, self.uniform_buffers_mapped[current_image] as *mut UniformBufferObject, size_of::() ); } } fn record_compute_command_buffer( &mut self, command_buffer: vk::CommandBuffer ) { let begin_info = vk::CommandBufferBeginInfo::default(); unsafe { self.device .begin_command_buffer(command_buffer, &begin_info) .expect("failed to begin recording compute command buffer"); println!("resetting query pool"); self.device .cmd_reset_query_pool( self.compute_command_buffers[self.current_frame], self.query_pool, 0, 1, ); self.device.cmd_begin_query(self.compute_command_buffers[self.current_frame], self.query_pool, 0, vk::QueryControlFlags::empty()); self.device .cmd_bind_pipeline( command_buffer, vk::PipelineBindPoint::COMPUTE, self.compute_pipeline, ); self.device .cmd_bind_descriptor_sets( command_buffer, vk::PipelineBindPoint::COMPUTE, self.compute_pipeline_layout, 0, &[self.compute_descriptor_sets[self.current_frame]], &[], ); self.device .cmd_dispatch( command_buffer, (PARTICLE_COUNT / 256) as u32, 1, 1, ); //log compute shader invocations self.device.cmd_end_query(self.compute_command_buffers[self.current_frame], self.query_pool, 0); let query_results = unsafe { self.device.get_query_pool_results::( self.query_pool, 0, // Starting query index 1, // Number of queries to retrieve (1 in this case) self.query_mapped, // Results will be stored here //0, // Query results stride (optional) vk::QueryResultFlags::TYPE_64, // Flags specifying the type of query results ) .expect("Failed to retrieve query pool results" )}; println!("Compute shader invocations: {:?}", self.query_mapped[0]); self.device .end_command_buffer(command_buffer) .expect("failed ending compute command buffer"); } } pub fn create_shader_storage_buffers( device: &ash::Device, physical_device_memory_properties: vk::PhysicalDeviceMemoryProperties, command_pool: vk::CommandPool, graphics_queue: vk::Queue, ) -> (Vec, Vec) { let mut particles = Particle::gen(); let mut particles_slice_data = particles.as_mut_slice(); //let mut slice = Align::new(); let mut buffer_size: u64 = std::mem::size_of::() as u64 * particles_slice_data.len() as u64; println!("particles count: {}, particle size: {}, buffer size: {}", PARTICLE_COUNT as u64, std::mem::size_of::() as u64, buffer_size as usize); let (staging_buffer, staging_buffer_memory) = Self::create_buffer( device, buffer_size, vk::BufferUsageFlags::TRANSFER_SRC, vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT, physical_device_memory_properties, ); let mut shader_storage_buffers = vec![]; let mut shader_storage_buffers_memory = vec![]; unsafe { println!("isize max is {}", isize::MAX); println!("mapping device memory"); let mut data = device .map_memory( staging_buffer_memory, 0, buffer_size, vk::MemoryMapFlags::empty(), ) .expect("failed to map shader storage buffer memory"); let mem_requirements = unsafe { device.get_buffer_memory_requirements(staging_buffer) }; println!("mem req: {}", mem_requirements.size); let mut slice = Align::new( data, mem::align_of::() as u64, mem_requirements.size, ); slice.copy_from_slice(&particles_slice_data); println!("DATA INSIDE PARTICLES BUFFER: {}", ParticlesList::from_raw_ptr(data as *const Particle, particles.len())); //println!("copying to device memory"); device .unmap_memory(staging_buffer_memory); for i in 0..MAX_FRAMES_IN_FLIGHT { let (current_shader_storage_buffer, current_shader_storage_buffer_memory) = Self::create_buffer( device, buffer_size, vk::BufferUsageFlags::STORAGE_BUFFER | vk::BufferUsageFlags::VERTEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST, vk::MemoryPropertyFlags::DEVICE_LOCAL | vk::MemoryPropertyFlags::HOST_VISIBLE, physical_device_memory_properties, ); shader_storage_buffers.push(current_shader_storage_buffer); shader_storage_buffers_memory.push(current_shader_storage_buffer_memory); Self::copy_buffer( device, staging_buffer, shader_storage_buffers[i], buffer_size, command_pool, graphics_queue, ); } device .destroy_buffer(staging_buffer, None); device .free_memory(staging_buffer_memory, None); } (shader_storage_buffers, shader_storage_buffers_memory) } pub fn copy_buffer( device: &ash::Device, src_buffer: vk::Buffer, dst_buffer: vk::Buffer, size: vk::DeviceSize, command_pool: vk::CommandPool, graphics_queue: vk::Queue, ) { 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: command_pool, level: vk::CommandBufferLevel::PRIMARY, }; let alloced_command_buffer = unsafe { device .allocate_command_buffers( &command_buffer_allocate_info ) .expect("could not allocate command buffer when copying command buffer") [0] }; let begin_info = vk::CommandBufferBeginInfo { s_type: vk::StructureType::COMMAND_BUFFER_BEGIN_INFO, flags: vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT, ..Default::default() }; unsafe { device .begin_command_buffer(alloced_command_buffer, &begin_info); } let copy_region = vk::BufferCopy { size: size, ..Default::default() }; unsafe { device .cmd_copy_buffer( alloced_command_buffer, src_buffer, dst_buffer, &[copy_region], ); device.end_command_buffer(alloced_command_buffer); } println!("src_buffer: {:?}", src_buffer); println!("dst_buffer: {:?}", dst_buffer); let submit_info = vk::SubmitInfo { s_type: vk::StructureType::SUBMIT_INFO, command_buffer_count: 1, p_command_buffers: &alloced_command_buffer as *const vk::CommandBuffer, ..Default::default() }; unsafe { device .queue_submit( graphics_queue, &[submit_info], vk::Fence::null(), ); device .queue_wait_idle( graphics_queue ); device .free_command_buffers(command_pool, &[alloced_command_buffer]); } } pub fn create_buffer( device: &ash::Device, size: vk::DeviceSize, usage: vk::BufferUsageFlags, required_memory_properties: vk::MemoryPropertyFlags, physical_device_memory_properties: vk::PhysicalDeviceMemoryProperties, ) -> (vk::Buffer, vk::DeviceMemory) { let buffer_create_info = vk::BufferCreateInfo { s_type: vk::StructureType::BUFFER_CREATE_INFO, p_next: ptr::null(), flags: vk::BufferCreateFlags::empty(), size, usage, sharing_mode: vk::SharingMode::EXCLUSIVE, queue_family_index_count: 0, p_queue_family_indices: ptr::null(), }; println!("actual buffer size: {}", size); let buffer = unsafe { device .create_buffer(&buffer_create_info, None) .expect("Failed to create Vertex Buffer") }; let mem_requirements = unsafe { device.get_buffer_memory_requirements(buffer) }; println!("memory allocation size: {}", mem_requirements.size); let allocate_info = vk::MemoryAllocateInfo { s_type: vk::StructureType::MEMORY_ALLOCATE_INFO, p_next: ptr::null(), allocation_size: mem_requirements.size, memory_type_index: find_memory_type( mem_requirements.memory_type_bits, required_memory_properties, &physical_device_memory_properties, ), }; let buffer_memory = unsafe { device .allocate_memory(&allocate_info, None) .expect("Failed to allocate vertex buffer memory!") }; unsafe { device .bind_buffer_memory(buffer, buffer_memory, 0) .expect("Failed to bind Buffer"); } (buffer, buffer_memory) } pub fn create_uniform_buffers( device: &ash::Device, physical_device_memory_properties: vk::PhysicalDeviceMemoryProperties, ) -> (Vec, Vec, Vec<*mut c_void>) { let buffer_size = ::std::mem::size_of::(); let mut uniform_buffers = vec![]; let mut uniform_buffers_memory = vec![]; let mut uniform_buffers_mapped = vec![]; for i in 0..MAX_FRAMES_IN_FLIGHT { let (uniform_buffer, uniform_buffer_memory) = Self::create_buffer( device, buffer_size as u64, vk::BufferUsageFlags::UNIFORM_BUFFER, vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT, physical_device_memory_properties ); uniform_buffers.push(uniform_buffer); uniform_buffers_memory.push(uniform_buffer_memory); uniform_buffers_mapped.push( unsafe { device .map_memory( uniform_buffers_memory[i], 0, buffer_size as u64, vk::MemoryMapFlags::empty(), ) .unwrap() } ); } (uniform_buffers, uniform_buffers_memory, uniform_buffers_mapped) } pub fn create_logical_device( instance: &ash::Instance, physical_device: vk::PhysicalDevice, validation: &debug::ValidationInfo, device_extensions: &DeviceExtension, surface_stuff: &SurfaceStuff, ) -> (ash::Device, QueueFamilyIndices, vk::Queue, vk::Queue, vk::Queue) { let indices = App::find_queue_family(&instance, physical_device, &surface_stuff); use std::collections::HashSet; let mut unique_queue_families = HashSet::new(); unique_queue_families.insert(indices.graphics_and_compute_family.unwrap()); unique_queue_families.insert(indices.present_family.unwrap()); let queue_priorities = [1.0_f32]; let mut queue_create_infos = vec![]; for &queue_family in unique_queue_families.iter() { 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, }); } let physical_device_features = vk::PhysicalDeviceFeatures { sampler_anisotropy: vk::TRUE, // enable anisotropy device feature from Chapter-24. pipeline_statistics_query: vk::TRUE, ..Default::default() }; let requred_validation_layer_raw_names: Vec = validation .required_validation_layers .iter() .map(|layer_name| CString::new(*layer_name).unwrap()) .collect(); let _enable_layer_names: Vec<*const c_char> = requred_validation_layer_raw_names .iter() .map(|layer_name| layer_name.as_ptr()) .collect(); let enable_extension_names = device_extensions.get_extensions_raw_names(); let device_create_info = vk::DeviceCreateInfo { s_type: vk::StructureType::DEVICE_CREATE_INFO, p_next: ptr::null(), flags: vk::DeviceCreateFlags::empty(), queue_create_info_count: queue_create_infos.len() as u32, p_queue_create_infos: queue_create_infos.as_ptr(), enabled_extension_count: enable_extension_names.len() as u32, pp_enabled_extension_names: enable_extension_names.as_ptr(), p_enabled_features: &physical_device_features, ..Default::default() }; let device: ash::Device = unsafe { instance .create_device(physical_device, &device_create_info, None) .expect("Failed to create logical Device!") }; let graphics_queue = unsafe { device.get_device_queue(indices.graphics_and_compute_family.unwrap(), 0) }; let present_queue = unsafe { device.get_device_queue(indices.present_family.unwrap(), 0) }; let compute_queue = unsafe { device.get_device_queue(indices.graphics_and_compute_family.unwrap(), 0) }; (device, indices, graphics_queue, compute_queue, present_queue) } pub fn record_command_buffer( &self, //device: &ash::Device, command_buffer: vk::CommandBuffer, image_index: usize, //render_pass: vk::RenderPass, //swapchain_extent: vk::Extent2D, //shader_storage_buffers: Vec, //shader_storage_buffers_memory: Vec, //current_frame: usize, //graphics_pipeline: vk::Pipeline, ) { 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 { self.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, 1.0, 1.0], }, }]; let render_pass_begin_info = vk::RenderPassBeginInfo { s_type: vk::StructureType::RENDER_PASS_BEGIN_INFO, render_pass: self.render_pass, p_next: ptr::null(), framebuffer: self.swapchain_stuff.swapchain_framebuffers[image_index], render_area: vk::Rect2D { offset: vk::Offset2D { x: 0, y: 0 }, extent: self.swapchain_stuff.swapchain_extent, }, clear_value_count: clear_color.len() as u32, p_clear_values: clear_color.as_ptr(), }; unsafe { self.device .cmd_begin_render_pass( command_buffer, &render_pass_begin_info, vk::SubpassContents::INLINE, ); self.device .cmd_bind_pipeline( command_buffer, vk::PipelineBindPoint::GRAPHICS, self.graphics_pipeline, ); } let viewport = vec![vk::Viewport { x: 0.0, y: 0.0, 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, }]; unsafe { self.device .cmd_set_viewport( command_buffer, 0, &viewport, ); } let scissor = vec![vk::Rect2D { offset: vk::Offset2D { x: 0, y: 0 }, extent: self.swapchain_stuff.swapchain_extent, }]; unsafe { self.device .cmd_set_scissor( command_buffer, 0, &scissor ); } let offsets = &[0 as vk::DeviceSize]; unsafe { self.device .cmd_bind_vertex_buffers( command_buffer, 0, &[self.shader_storage_buffers[self.current_frame]], offsets, ); println!("binding to shader storage buffer index: {}", self.current_frame); self.device .cmd_draw( command_buffer, PARTICLE_COUNT as u32, 1, 0, 0, ); self.device .cmd_end_render_pass( command_buffer ); self.device .end_command_buffer(command_buffer) .expect("failed to end command buffer"); } } pub fn create_framebuffers( device: &ash::Device, render_pass: vk::RenderPass, image_views: &Vec, swapchain_extent: &vk::Extent2D, ) -> Vec { let mut framebuffers = vec![]; for &image_view in image_views.iter() { let attachments = [image_view]; let framebuffer_create_info = vk::FramebufferCreateInfo { s_type: vk::StructureType::FRAMEBUFFER_CREATE_INFO, p_next: ptr::null(), flags: vk::FramebufferCreateFlags::empty(), render_pass: render_pass, attachment_count: attachments.len() as u32, p_attachments: attachments.as_ptr(), width: swapchain_extent.width, height: swapchain_extent.height, layers: 1, }; let framebuffer = unsafe { device .create_framebuffer(&framebuffer_create_info, None) .expect("Failed to create Framebuffer!") }; framebuffers.push(framebuffer); } framebuffers } pub fn create_image_views( device: &ash::Device, surface_format: &vk::Format, images: &Vec, ) -> Vec { let swapchain_imageviews: Vec = images .iter() .map(|&image| { App::create_image_view( device, image, surface_format, vk::ImageAspectFlags::COLOR, 1, ) }) .collect(); swapchain_imageviews } pub fn create_image_view( device: &ash::Device, image: vk::Image, format: &vk::Format, aspect_flags: vk::ImageAspectFlags, mip_levels: u32, ) -> vk::ImageView { let imageview_create_info = vk::ImageViewCreateInfo { s_type: vk::StructureType::IMAGE_VIEW_CREATE_INFO, p_next: ptr::null(), flags: vk::ImageViewCreateFlags::empty(), view_type: vk::ImageViewType::TYPE_2D, format: format.clone(), components: vk::ComponentMapping { r: vk::ComponentSwizzle::IDENTITY, g: vk::ComponentSwizzle::IDENTITY, b: vk::ComponentSwizzle::IDENTITY, a: vk::ComponentSwizzle::IDENTITY, }, subresource_range: vk::ImageSubresourceRange { aspect_mask: aspect_flags, base_mip_level: 0, level_count: mip_levels, base_array_layer: 0, layer_count: 1, }, image, }; unsafe { device .create_image_view(&imageview_create_info, None) .expect("Failed to create Image View!") } } pub fn choose_swapchain_extent( &self, capabilities: &vk::SurfaceCapabilitiesKHR, ) -> vk::Extent2D { if capabilities.current_extent.width != u32::max_value() { capabilities.current_extent } else { use num::clamp; let window_size = self.window.inner_size(); println!( "\t\tInner Window Size: ({}, {})", window_size.width, window_size.height ); vk::Extent2D { width: clamp( window_size.width as u32, capabilities.min_image_extent.width, capabilities.max_image_extent.width, ), height: clamp( window_size.height as u32, capabilities.min_image_extent.height, capabilities.max_image_extent.height, ), } } } pub fn query_swapchain_support( physical_device: vk::PhysicalDevice, surface_stuff: &SurfaceStuff, ) -> SwapChainSupportDetails { unsafe { let capabilities = surface_stuff .surface_loader .get_physical_device_surface_capabilities(physical_device, surface_stuff.surface) .expect("Failed to query for surface capabilities."); let formats = surface_stuff .surface_loader .get_physical_device_surface_formats(physical_device, surface_stuff.surface) .expect("Failed to query for surface formats."); let present_modes = surface_stuff .surface_loader .get_physical_device_surface_present_modes(physical_device, surface_stuff.surface) .expect("Failed to query for surface present mode."); SwapChainSupportDetails { capabilities, formats, present_modes, } } } pub fn find_queue_family( instance: &ash::Instance, physical_device: vk::PhysicalDevice, surface_stuff: &SurfaceStuff, ) -> QueueFamilyIndices { let queue_families = unsafe { instance.get_physical_device_queue_family_properties(physical_device) }; let mut queue_family_indices = QueueFamilyIndices::new(); 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::COMPUTE) ) { queue_family_indices.graphics_and_compute_family = Some(i as u32); } let is_present_support = unsafe { surface_stuff .surface_loader .get_physical_device_surface_support( physical_device, i as u32, surface_stuff.surface, ) .unwrap() }; if queue_family.queue_count > 0 && is_present_support { queue_family_indices.present_family = Some(i as u32); } if queue_family_indices.is_complete() { break; } } queue_family_indices } pub fn pick_physical_device( instance: &ash::Instance, surface_stuff: &SurfaceStuff, required_device_extensions: &DeviceExtension, ) -> vk::PhysicalDevice { let physical_devices = unsafe { instance .enumerate_physical_devices() .expect("Failed to enumerate Physical Devices!") }; let result = physical_devices.iter().find(|physical_device| { let is_suitable = Self::is_physical_device_suitable( &instance, **physical_device, &surface_stuff, required_device_extensions, ); is_suitable }); match result { Some(p_physical_device) => *p_physical_device, None => panic!("Failed to find a suitable GPU!"), } } pub fn is_physical_device_suitable( instance: &ash::Instance, physical_device: vk::PhysicalDevice, surface_stuff: &SurfaceStuff, required_device_extensions: &DeviceExtension, ) -> bool { let device_features = unsafe { instance.get_physical_device_features(physical_device) }; let indices = Self::find_queue_family(&instance, physical_device, &surface_stuff); let is_queue_family_supported = indices.is_complete(); let is_device_extension_supported = Self::check_device_extension_support(&instance, physical_device, required_device_extensions); let is_swapchain_supported = if is_device_extension_supported { let swapchain_support = Self::query_swapchain_support(physical_device, &surface_stuff); !swapchain_support.formats.is_empty() && !swapchain_support.present_modes.is_empty() } else { false }; let is_support_sampler_anisotropy = device_features.sampler_anisotropy == 1; return is_queue_family_supported && is_device_extension_supported && is_swapchain_supported && is_support_sampler_anisotropy; } pub fn check_device_extension_support( instance: &ash::Instance, physical_device: vk::PhysicalDevice, device_extensions: &DeviceExtension, ) -> bool { let available_extensions = unsafe { instance .enumerate_device_extension_properties(physical_device) .expect("Failed to get device extension properties.") }; let mut available_extension_names = vec![]; for extension in available_extensions.iter() { let extension_name = vk_to_string(&extension.extension_name); available_extension_names.push(extension_name); } use std::collections::HashSet; let mut required_extensions = HashSet::new(); for extension in device_extensions.names.iter() { required_extensions.insert(extension.to_string()); } for extension_name in available_extension_names.iter() { required_extensions.remove(extension_name); } return required_extensions.is_empty(); } pub fn create_render_pass(device: &ash::Device, surface_format: &vk::Format) -> vk::RenderPass { let color_attachment = vk::AttachmentDescription { format: surface_format.clone(), flags: vk::AttachmentDescriptionFlags::empty(), samples: vk::SampleCountFlags::TYPE_1, load_op: vk::AttachmentLoadOp::CLEAR, store_op: vk::AttachmentStoreOp::STORE, stencil_load_op: vk::AttachmentLoadOp::DONT_CARE, stencil_store_op: vk::AttachmentStoreOp::DONT_CARE, initial_layout: vk::ImageLayout::UNDEFINED, final_layout: vk::ImageLayout::PRESENT_SRC_KHR, }; let color_attachment_ref = vk::AttachmentReference { attachment: 0, layout: vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL, }; let subpasses = [vk::SubpassDescription { color_attachment_count: 1, p_color_attachments: &color_attachment_ref, p_depth_stencil_attachment: ptr::null(), flags: vk::SubpassDescriptionFlags::empty(), pipeline_bind_point: vk::PipelineBindPoint::GRAPHICS, input_attachment_count: 0, p_input_attachments: ptr::null(), p_resolve_attachments: ptr::null(), preserve_attachment_count: 0, p_preserve_attachments: ptr::null(), }]; let render_pass_attachments = [color_attachment]; let subpass_dependencies = [vk::SubpassDependency { src_subpass: vk::SUBPASS_EXTERNAL, dst_subpass: 0, src_stage_mask: vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT, dst_stage_mask: vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT, src_access_mask: vk::AccessFlags::empty(), dst_access_mask: vk::AccessFlags::COLOR_ATTACHMENT_WRITE, dependency_flags: vk::DependencyFlags::empty(), }]; let renderpass_create_info = vk::RenderPassCreateInfo { s_type: vk::StructureType::RENDER_PASS_CREATE_INFO, flags: vk::RenderPassCreateFlags::empty(), p_next: ptr::null(), attachment_count: render_pass_attachments.len() as u32, p_attachments: render_pass_attachments.as_ptr(), subpass_count: subpasses.len() as u32, p_subpasses: subpasses.as_ptr(), dependency_count: subpass_dependencies.len() as u32, p_dependencies: subpass_dependencies.as_ptr(), }; unsafe { device .create_render_pass(&renderpass_create_info, None) .expect("Failed to create render pass!") } } pub fn create_compute_descriptor_set_layout(device: &ash::Device) -> vk::DescriptorSetLayout { let ubo_layout_bindings = [ vk::DescriptorSetLayoutBinding { binding: 0, descriptor_type: vk::DescriptorType::UNIFORM_BUFFER, descriptor_count: 1, stage_flags: vk::ShaderStageFlags::COMPUTE, p_immutable_samplers: ptr::null(), }, vk::DescriptorSetLayoutBinding { binding: 1, descriptor_type: vk::DescriptorType::STORAGE_BUFFER, descriptor_count: 1, stage_flags: vk::ShaderStageFlags::COMPUTE, p_immutable_samplers: ptr::null(), }, vk::DescriptorSetLayoutBinding { binding: 2, descriptor_type: vk::DescriptorType::STORAGE_BUFFER, descriptor_count: 1, stage_flags: vk::ShaderStageFlags::COMPUTE, p_immutable_samplers: ptr::null(), }, ]; let ubo_layout_create_info = vk::DescriptorSetLayoutCreateInfo { s_type: vk::StructureType::DESCRIPTOR_SET_LAYOUT_CREATE_INFO, p_next: ptr::null(), flags: vk::DescriptorSetLayoutCreateFlags::empty(), binding_count: ubo_layout_bindings.len() as u32, p_bindings: ubo_layout_bindings.as_ptr(), }; unsafe { device .create_descriptor_set_layout(&ubo_layout_create_info, None) .expect("Failed to create Descriptor Set Layout!") } } pub fn create_compute_descriptor_sets( device: &ash::Device, compute_descriptor_set_layout: vk::DescriptorSetLayout, descriptor_pool: vk::DescriptorPool, uniform_buffers: &Vec, shader_storage_buffers: &Vec, ) -> Vec { let layouts = vec![compute_descriptor_set_layout; MAX_FRAMES_IN_FLIGHT]; let alloc_info = vk::DescriptorSetAllocateInfo { s_type: vk::StructureType::DESCRIPTOR_SET_ALLOCATE_INFO, p_next: ptr::null(), descriptor_pool: descriptor_pool, descriptor_set_count: MAX_FRAMES_IN_FLIGHT as u32, p_set_layouts: layouts.as_ptr(), }; let descriptor_sets = unsafe { device .allocate_descriptor_sets(&alloc_info) .expect("failed to allocate descriptor sets") }; for i in 0..MAX_FRAMES_IN_FLIGHT { let uniform_buffer_info = vk::DescriptorBufferInfo { buffer: uniform_buffers[i], offset: 0, range: size_of::() as u64, }; println!("STORAGE BUFFERS INDEXES: {}, {}", (i as i32 - 1) as usize % MAX_FRAMES_IN_FLIGHT, i); let storage_buffer_info_last_frame = vk::DescriptorBufferInfo { buffer: shader_storage_buffers[(i as i32 - 1) as usize % MAX_FRAMES_IN_FLIGHT], offset: 0, range: size_of::() as u64 * PARTICLE_COUNT, }; let storage_buffer_info_current_frame = vk::DescriptorBufferInfo { buffer: shader_storage_buffers[i], offset: 0, range: size_of::() as u64 * PARTICLE_COUNT, }; //eprintln!("PARTICLE STRUCT SIZE: {:?}", ::std::mem::size_of::() as u8); let descriptor_writes = [ vk::WriteDescriptorSet { s_type: vk::StructureType::WRITE_DESCRIPTOR_SET, dst_set: descriptor_sets[i], dst_binding: 0, dst_array_element: 0, descriptor_type: vk::DescriptorType::UNIFORM_BUFFER, descriptor_count: 1, p_buffer_info: &uniform_buffer_info as *const vk::DescriptorBufferInfo, ..Default::default() }, vk::WriteDescriptorSet { s_type: vk::StructureType::WRITE_DESCRIPTOR_SET, dst_set: descriptor_sets[i], dst_binding: 1, dst_array_element: 0, descriptor_type: vk::DescriptorType::STORAGE_BUFFER, descriptor_count: 1, p_buffer_info: &storage_buffer_info_last_frame as *const vk::DescriptorBufferInfo, ..Default::default() }, vk::WriteDescriptorSet { s_type: vk::StructureType::WRITE_DESCRIPTOR_SET, dst_set: descriptor_sets[i], dst_binding: 2, dst_array_element: 0, descriptor_type: vk::DescriptorType::STORAGE_BUFFER, descriptor_count: 1, p_buffer_info: &storage_buffer_info_current_frame as *const vk::DescriptorBufferInfo, ..Default::default() }, ]; unsafe { device .update_descriptor_sets(&descriptor_writes, &[]); } } descriptor_sets } 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::RESET_COMMAND_BUFFER, queue_family_index: queue_families.graphics_and_compute_family.unwrap(), }; unsafe { device .create_command_pool(&command_pool_create_info, None) .expect("Failed to create Command Pool!") } } 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, }, 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, p_next: ptr::null(), flags: vk::DescriptorPoolCreateFlags::empty(), max_sets: swapchain_images_size as u32, pool_size_count: pool_sizes.len() as u32, p_pool_sizes: pool_sizes.as_ptr(), }; unsafe { device .create_descriptor_pool(&descriptor_pool_create_info, None) .expect("Failed to create Descriptor Pool!") } } pub fn create_command_buffers( device: &ash::Device, command_pool: vk::CommandPool, ) -> Vec { let command_buffer_allocate_info = vk::CommandBufferAllocateInfo { s_type: vk::StructureType::COMMAND_BUFFER_ALLOCATE_INFO, p_next: ptr::null(), command_buffer_count: MAX_FRAMES_IN_FLIGHT 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!") }; command_buffers } pub fn create_compute_command_buffers( device: &ash::Device, command_pool: vk::CommandPool, ) -> Vec { let command_buffer_allocate_info = vk::CommandBufferAllocateInfo { s_type: vk::StructureType::COMMAND_BUFFER_ALLOCATE_INFO, p_next: ptr::null(), command_buffer_count: MAX_FRAMES_IN_FLIGHT 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!") }; command_buffers } fn wait_device_idle(&self) { unsafe { self.device .device_wait_idle() .expect("Failed to wait device idle!") }; } } impl VulkanApp for App<'_> { fn wait_device_idle(&self) { unsafe { self.device .device_wait_idle() .expect("Failed to wait device idle!") }; } fn resize_framebuffer(&mut self) { self.is_framebuffer_resized = true; } fn window_ref(&self) -> &winit::window::Window { &self.window } fn cleanup_swapchain(&self) { self.swapchain_stuff.cleanup_swapchain(&self.device) } fn recreate_swapchain(&mut self) { SwapChainStuff::recreate_swapchain(self); } fn draw_frame(&mut self) { let mut buffer_size: u64 = std::mem::size_of::() as u64 * PARTICLE_COUNT as u64; //compute submission let mut submit_infos; unsafe { self.device .wait_for_fences( &[self.sync_objects.compute_inflight_fences[self.current_frame]], true, u64::MAX, ); } self.update_uniform_buffer(self.current_frame); unsafe { self.device .reset_fences(&[self.sync_objects.compute_inflight_fences[self.current_frame]]); self.device .reset_command_buffer(self.compute_command_buffers[self.current_frame], vk::CommandBufferResetFlags::empty()); } //RESET query pool for compute shader statistics /*unsafe { self.device .cmd_reset_query_pool( self.compute_command_buffers[self.current_frame], self.query_pool, 0, 1, ); }*/ self.record_compute_command_buffer(self.compute_command_buffers[self.current_frame]); self.update_uniform_buffer(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 { self.device .queue_submit( self.compute_queue, &submit_infos, self.sync_objects.compute_inflight_fences[self.current_frame] ); } /*log compute shader invocations unsafe { self.device.cmd_end_query(self.compute_command_buffers[self.current_frame], query_pool, 0); } let query_results = unsafe { self.device.get_query_pool_results::( query_pool, 0, // Starting query index 1, // Number of queries to retrieve (1 in this case) data, // Results will be stored here //0, // Query results stride (optional) vk::QueryResultFlags::TYPE_64, // Flags specifying the type of query results ) .expect("Failed to retrieve query pool results" )}; println!("Compute shader invocations: {:?}", data[0]);*/ //graphics submission unsafe { self.device .wait_for_fences( &[self.sync_objects.inflight_fences[self.current_frame]], true, u64::MAX, ); } let (image_index, _is_sub_optimal) = unsafe { let result = self.swapchain_stuff.swapchain_loader.acquire_next_image( self.swapchain_stuff.swapchain, std::u64::MAX, self.sync_objects.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 => { SwapChainStuff::recreate_swapchain(self); return; } _ => panic!("Failed to acquire Swap Chain Image!"), }, } }; unsafe { self.device .reset_fences(&[self.sync_objects.inflight_fences[self.current_frame]]); self.device .reset_command_buffer( self.command_buffers[self.current_frame], vk::CommandBufferResetFlags::empty(), ); } self.record_command_buffer(self.command_buffers[self.current_frame], image_index as usize); 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, ]; submit_infos = [vk::SubmitInfo { s_type: vk::StructureType::SUBMIT_INFO, wait_semaphore_count: 2, p_wait_semaphores: wait_semaphores.as_ptr(), p_wait_dst_stage_mask: wait_stages.as_ptr(), p_next: ptr::null(), command_buffer_count: 1, p_command_buffers: &self.command_buffers[self.current_frame], signal_semaphore_count: 1, p_signal_semaphores: &self.sync_objects.render_finished_semaphores[self.current_frame], ..Default::default() }]; unsafe { self.device .queue_submit( self.graphics_queue, &submit_infos, self.sync_objects.inflight_fences[self.current_frame], ) .expect("failed to submit draw command buffer"); } 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: &self.sync_objects.render_finished_semaphores[self.current_frame], swapchain_count: 1, p_swapchains: swapchains.as_ptr(), p_image_indices: &image_index, p_results: ptr::null_mut(), }; let result = unsafe { self.swapchain_stuff.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; SwapChainStuff::recreate_swapchain(self); } //println!("resized {}", self.is_framebuffer_resized); /*log compute shader invocations unsafe { self.device.cmd_end_query(self.compute_command_buffers[self.current_frame], self.query_pool, 0); } let query_results = unsafe { self.device.get_query_pool_results::( self.query_pool, 0, // Starting query index 1, // Number of queries to retrieve (1 in this case) self.query_mapped, // Results will be stored here //0, // Query results stride (optional) vk::QueryResultFlags::TYPE_64, // Flags specifying the type of query results ) .expect("Failed to retrieve query pool results" )}; println!("Compute shader invocations: {:?}", self.query_mapped[0]);*/ self.current_frame = (self.current_frame + 1) % MAX_FRAMES_IN_FLIGHT; } }