use crate::{ shaders::*, entities::*, utility, utility::constants::*, utility::debug::*, utility::share, utility::structures::*, }; use ash::{vk, Entry}; use memoffset::offset_of; use vk::*; 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, 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: vk::Pipeline, vertex_buffer: vk::Buffer, vertex_buffer_memory: vk::DeviceMemory, command_pool: vk::CommandPool, command_buffers: Vec, image_available_semaphores: Vec, render_finished_semaphores: Vec, in_flight_fences: Vec, current_frame: usize, is_framebuffer_resized: bool, } impl VulkanApp { 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 = share::create_surface(&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 swapchain_stuff = share::create_swapchain( &instance, &device, physical_device, &window, &surface_stuff, &queue_family, ); let swapchain_imageviews = share::v1::create_image_views( &device, swapchain_stuff.swapchain_format, &swapchain_stuff.swapchain_images, ); let render_pass = share::v1::create_render_pass(&device, swapchain_stuff.swapchain_format); let (graphics_pipeline, pipeline_layout) = VulkanApp::create_graphics_pipeline( &device, render_pass, swapchain_stuff.swapchain_extent, ); let swapchain_framebuffers = share::v1::create_framebuffers( &device, render_pass, &swapchain_imageviews, swapchain_stuff.swapchain_extent, ); let command_pool = share::v1::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 = share::v1::create_sync_objects(&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, 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, pipeline_layout, render_pass, graphics_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!") } 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( 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(), } ) } 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(), 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], }; 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!") }; 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, subpass: 0, base_pipeline_handle: vk::Pipeline::null(), base_pipeline_index: -1, }]; let graphics_pipelines = unsafe { device .create_graphics_pipelines( vk::PipelineCache::null(), &graphic_pipeline_create_infos, None, ) .expect("Failed to create Graphics Pipeline!.") }; unsafe { for shader in shader_modules { device.destroy_shader_module(shader.module, None) } } (graphics_pipelines[0], 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 = 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::v1::create_image_views( &self.device, self.swapchain_format, &self.swapchain_images, ); self.render_pass = share::v1::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::v1::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!") }; } _ => (), }) } }