From 6b26187cd86ef8b0bc2611b0071c9b8dd6a2e6fe Mon Sep 17 00:00:00 2001 From: buckn Date: Sun, 24 Dec 2023 08:52:30 -0500 Subject: [PATCH] improved file structure --- build.rs | 3 +- rec | 801 ++++++++++++++++++++++++++++++++++++ src/entities.rs | 63 +++ src/main.rs | 852 +-------------------------------------- src/render.rs | 801 ++++++++++++++++++++++++++++++++++++ src/utility/constants.rs | 4 +- 6 files changed, 1673 insertions(+), 851 deletions(-) create mode 100644 rec create mode 100644 src/entities.rs create mode 100644 src/render.rs diff --git a/build.rs b/build.rs index 0615ee3..7cf98a3 100644 --- a/build.rs +++ b/build.rs @@ -17,10 +17,11 @@ fn main() -> std::io::Result<()> { for entry in shaders.read_dir().expect("reading shader directory failed") { if let Ok(entry) = entry { let shader_path = entry.path(); - println!("compiling shader: {:?}", shader_path); + println!("cargo:warning=compiling shader: {:?}", shader_path); let shader_path_string: String = "./target/shaders/".to_string() + shader_path.file_name().unwrap().to_str().unwrap() + ".spv"; + println!("cargo:warning=compiling destination: {:?}", shader_path_string); let shader_file: &OsStr = OsStr::new::(shader_path_string.as_str()); Command::new("glslc") .arg("-c") diff --git a/rec b/rec new file mode 100644 index 0000000..3e52a3f --- /dev/null +++ b/rec @@ -0,0 +1,801 @@ +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!") + }; + } + _ => (), + }) + } +} + diff --git a/src/entities.rs b/src/entities.rs new file mode 100644 index 0000000..bb27118 --- /dev/null +++ b/src/entities.rs @@ -0,0 +1,63 @@ +use memoffset::offset_of; +use ash::vk; + +#[repr(C)] +#[derive(Clone, Debug, Copy)] +pub struct Particle { + pos: [f32; 2], + vel: [f32; 4], + color: [f32; 4], +} + +impl Particle { + +} + +#[repr(C)] +#[derive(Clone, Debug, Copy)] +pub struct Vertex { + pos: [f32; 2], + color: [f32; 3], +} + +impl Vertex { + 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!(Vertex, pos) as u32, + }, + vk::VertexInputAttributeDescription { + binding: 0, + location: 1, + format: vk::Format::R32G32B32_SFLOAT, + offset: offset_of!(Vertex, color) as u32, + }, + ] + } +} + +pub const TRI_VERT_DATA: [Vertex; 3] = [ + Vertex { + pos: [0.0, -0.5], + color: [1.0, 1.0, 1.0], + }, + Vertex { + pos: [0.5, 0.5], + color: [0.0, 1.0, 0.0], + }, + Vertex { + pos: [-0.5, 0.5], + color: [0.0, 0.0, 1.0], + }, +]; diff --git a/src/main.rs b/src/main.rs index 108e9ab..bb804f7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,854 +1,10 @@ pub mod shaders; pub mod utility; +pub mod render; +pub mod entities; -use crate::{ - shaders::*, 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"; - -#[repr(C)] -#[derive(Clone, Debug, Copy)] -struct Vertex { - pos: [f32; 2], - color: [f32; 3], -} -impl Vertex { - fn get_binding_description() -> [vk::VertexInputBindingDescription; 1] { - [vk::VertexInputBindingDescription { - binding: 0, - stride: std::mem::size_of::() as u32, - input_rate: vk::VertexInputRate::VERTEX, - }] - } - - fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] { - [ - vk::VertexInputAttributeDescription { - binding: 0, - location: 0, - format: vk::Format::R32G32_SFLOAT, - offset: offset_of!(Vertex, pos) as u32, - }, - vk::VertexInputAttributeDescription { - binding: 0, - location: 1, - format: vk::Format::R32G32B32_SFLOAT, - offset: offset_of!(Vertex, color) as u32, - }, - ] - } -} - -const VERTICES_DATA: [Vertex; 3] = [ - Vertex { - pos: [0.0, -0.5], - color: [1.0, 1.0, 1.0], - }, - Vertex { - pos: [0.5, 0.5], - color: [0.0, 1.0, 0.0], - }, - Vertex { - pos: [-0.5, 0.5], - color: [0.0, 0.0, 1.0], - }, -]; - -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(&VERTICES_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(VERTICES_DATA.as_ptr(), VERTICES_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, VERTICES_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!") - }; - } - _ => (), - }) - } -} +use winit::event_loop::EventLoop; +use render::VulkanApp; fn main() { let event_loop = EventLoop::new(); diff --git a/src/render.rs b/src/render.rs new file mode 100644 index 0000000..3e52a3f --- /dev/null +++ b/src/render.rs @@ -0,0 +1,801 @@ +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!") + }; + } + _ => (), + }) + } +} + diff --git a/src/utility/constants.rs b/src/utility/constants.rs index 99f2f7e..2d588e0 100644 --- a/src/utility/constants.rs +++ b/src/utility/constants.rs @@ -17,8 +17,8 @@ pub const VALIDATION: ValidationInfo = ValidationInfo { pub const DEVICE_EXTENSIONS: DeviceExtension = DeviceExtension { names: ["VK_KHR_swapchain"], }; -pub const MAX_FRAMES_IN_FLIGHT: usize = 2; -pub const IS_PAINT_FPS_COUNTER: bool = false; +pub const MAX_FRAMES_IN_FLIGHT: usize = 4; +pub const IS_PAINT_FPS_COUNTER: bool = true; impl DeviceExtension { pub fn get_extensions_raw_names(&self) -> [*const c_char; 1] {