diff --git a/src/app.rs b/src/app.rs index 9ae9728..e890656 100644 --- a/src/app.rs +++ b/src/app.rs @@ -6,7 +6,6 @@ use structs::*; use ::anyhow::{anyhow, Result}; use ::nalgebra_glm as glm; -use ::std::collections::HashSet; use ::std::mem::size_of; use ::std::ptr::copy_nonoverlapping as memcpy; use ::std::time::Instant; @@ -206,112 +205,3 @@ impl App { Ok(()) } } - -//================================================ -// Functions -//================================================ - -pub(crate) unsafe fn check_physical_device_extensions( - instance: &Instance, - physical_device: vk::PhysicalDevice, -) -> Result<()> { - let extensions = instance - .enumerate_device_extension_properties(physical_device, None)? - .iter() - .map(|e| e.extension_name) - .collect::>(); - - if DEVICE_EXTENSIONS.iter().all(|e| extensions.contains(e)) { - Ok(()) - } else { - Err(anyhow!(SuitabilityError( - "Missing required device extensions." - ))) - } -} - -pub(crate) fn get_swapchain_surface_format( - formats: &[vk::SurfaceFormatKHR], -) -> vk::SurfaceFormatKHR { - formats - .iter() - .cloned() - .find(|f| { - f.format == vk::Format::B8G8R8A8_SRGB - && f.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR - }) - .unwrap_or_else(|| formats[0]) -} - -pub(crate) fn get_swapchain_present_mode( - present_modes: &[vk::PresentModeKHR], -) -> vk::PresentModeKHR { - present_modes - .iter() - .cloned() - .find(|m| *m == vk::PresentModeKHR::MAILBOX) - .unwrap_or(vk::PresentModeKHR::FIFO) -} - -pub(crate) fn get_swapchain_extent( - window: &Window, - capabilities: vk::SurfaceCapabilitiesKHR, -) -> vk::Extent2D { - if capabilities.current_extent.width != u32::MAX { - capabilities.current_extent - } else { - let size = window.inner_size(); - let clamp = |min: u32, max: u32, v: u32| min.max(max.min(v)); - vk::Extent2D::builder() - .width(clamp( - capabilities.min_image_extent.width, - capabilities.max_image_extent.width, - size.width, - )) - .height(clamp( - capabilities.min_image_extent.height, - capabilities.max_image_extent.height, - size.height, - )) - .build() - } -} - -pub(crate) unsafe fn create_shader_module( - device: &Device, - bytecode: &[u8], -) -> Result { - let bytecode = Vec::::from(bytecode); - let (prefix, code, suffix) = bytecode.align_to::(); - if !prefix.is_empty() || !suffix.is_empty() { - return Err(anyhow!("Shader bytecode is not properly aligned.")); - } - - let info = vk::ShaderModuleCreateInfo::builder() - .code_size(bytecode.len()) - .code(code); - - Ok(device.create_shader_module(&info, None)?) -} - -pub(crate) unsafe fn create_image_view( - device: &Device, - image: vk::Image, - format: vk::Format, - aspects: vk::ImageAspectFlags, -) -> Result { - let subresource_range = vk::ImageSubresourceRange::builder() - .aspect_mask(aspects) - .base_mip_level(0) - .level_count(1) - .base_array_layer(0) - .layer_count(1); - - let info = vk::ImageViewCreateInfo::builder() - .image(image) - .view_type(vk::ImageViewType::_2D) - .format(format) - .subresource_range(subresource_range); - - Ok(device.create_image_view(&info, None)?) -} diff --git a/src/app/data.rs b/src/app/data.rs index 4787193..cfa60ab 100644 --- a/src/app/data.rs +++ b/src/app/data.rs @@ -95,11 +95,10 @@ pub(crate) struct AppData { pub(super) images_in_flight: Vec, } +//================================================ +// Create / Destroy Data +//================================================ impl AppData { - //================================================ - // Create / Destroy Data - //================================================ - pub(super) unsafe fn create( &mut self, window: &Window, @@ -134,6 +133,43 @@ impl AppData { Ok((instance, device)) } + /// Destroys our Vulkan app, in reverse order of creation + /// + /// # Safety + /// Here be Dragons + pub(super) unsafe fn destroy(&mut self, instance: &Instance, device: &Device) { + self.destroy_swapchain(device); + device.destroy_sampler(self.texture_sampler, None); + device.destroy_image_view(self.texture_image_view, None); + device.destroy_image(self.texture_image, None); + device.free_memory(self.texture_image_memory, None); + device.destroy_descriptor_set_layout(self.descriptor_set_layout, None); + + device.destroy_buffer(self.index_buffer, None); + device.free_memory(self.index_buffer_memory, None); + device.destroy_buffer(self.vertex_buffer, None); + device.free_memory(self.vertex_buffer_memory, None); + + self.in_flight_fences + .iter() + .for_each(|f| device.destroy_fence(*f, None)); + self.render_finished_semaphores + .iter() + .for_each(|s| device.destroy_semaphore(*s, None)); + self.image_available_semaphores + .iter() + .for_each(|s| device.destroy_semaphore(*s, None)); + device.destroy_command_pool(self.command_pool, None); + device.destroy_device(None); + instance.destroy_surface_khr(self.surface, None); + + if VALIDATION_ENABLED { + instance.destroy_debug_utils_messenger_ext(self.messenger, None); + } + + instance.destroy_instance(None); + } + unsafe fn create_instance(&mut self, window: &Window, entry: &Entry) -> Result { // Application Info let application_info = vk::ApplicationInfo::builder() @@ -241,48 +277,12 @@ impl AppData { .for_each(|v| device.destroy_image_view(*v, None)); device.destroy_swapchain_khr(self.swapchain, None); } +} - /// Destroys our Vulkan app, in reverse order of creation - /// - /// # Safety - /// Here be Dragons - pub unsafe fn destroy(&mut self, instance: &Instance, device: &Device) { - self.destroy_swapchain(device); - device.destroy_sampler(self.texture_sampler, None); - device.destroy_image_view(self.texture_image_view, None); - device.destroy_image(self.texture_image, None); - device.free_memory(self.texture_image_memory, None); - device.destroy_descriptor_set_layout(self.descriptor_set_layout, None); - - device.destroy_buffer(self.index_buffer, None); - device.free_memory(self.index_buffer_memory, None); - device.destroy_buffer(self.vertex_buffer, None); - device.free_memory(self.vertex_buffer_memory, None); - - self.in_flight_fences - .iter() - .for_each(|f| device.destroy_fence(*f, None)); - self.render_finished_semaphores - .iter() - .for_each(|s| device.destroy_semaphore(*s, None)); - self.image_available_semaphores - .iter() - .for_each(|s| device.destroy_semaphore(*s, None)); - device.destroy_command_pool(self.command_pool, None); - device.destroy_device(None); - instance.destroy_surface_khr(self.surface, None); - - if VALIDATION_ENABLED { - instance.destroy_debug_utils_messenger_ext(self.messenger, None); - } - - instance.destroy_instance(None); - } - - //================================================ - // Physical Device - //================================================ - +//================================================ +// Physical Device +//================================================ +impl AppData { unsafe fn pick_physical_device(&mut self, instance: &Instance) -> Result<()> { for physical_device in instance.enumerate_physical_devices()? { let properties = instance.get_physical_device_properties(physical_device); @@ -322,11 +322,31 @@ impl AppData { Ok(()) } +} - //================================================ - // Logical Device - //================================================ +pub(crate) unsafe fn check_physical_device_extensions( + instance: &Instance, + physical_device: vk::PhysicalDevice, +) -> Result<()> { + let extensions = instance + .enumerate_device_extension_properties(physical_device, None)? + .iter() + .map(|e| e.extension_name) + .collect::>(); + if DEVICE_EXTENSIONS.iter().all(|e| extensions.contains(e)) { + Ok(()) + } else { + Err(anyhow!(SuitabilityError( + "Missing required device extensions." + ))) + } +} + +//================================================ +// Logical Device +//================================================ +impl AppData { unsafe fn create_logical_device(&mut self, instance: &Instance) -> Result { // Queue Create Infos let indices = QueueFamilyIndices::get(instance, self, self.physical_device)?; @@ -385,11 +405,12 @@ impl AppData { Ok(device) } +} - //================================================ - // Swapchain - //================================================ - +//================================================ +// Swapchain +//================================================ +impl AppData { unsafe fn create_swapchain( &mut self, window: &Window, @@ -488,11 +509,59 @@ impl AppData { Ok(()) } +} - //================================================ - // Pipeline - //================================================ +pub(crate) fn get_swapchain_surface_format( + formats: &[vk::SurfaceFormatKHR], +) -> vk::SurfaceFormatKHR { + formats + .iter() + .cloned() + .find(|f| { + f.format == vk::Format::B8G8R8A8_SRGB + && f.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR + }) + .unwrap_or_else(|| formats[0]) +} +pub(crate) fn get_swapchain_present_mode( + present_modes: &[vk::PresentModeKHR], +) -> vk::PresentModeKHR { + present_modes + .iter() + .cloned() + .find(|m| *m == vk::PresentModeKHR::MAILBOX) + .unwrap_or(vk::PresentModeKHR::FIFO) +} + +pub(crate) fn get_swapchain_extent( + window: &Window, + capabilities: vk::SurfaceCapabilitiesKHR, +) -> vk::Extent2D { + if capabilities.current_extent.width != u32::MAX { + capabilities.current_extent + } else { + let size = window.inner_size(); + let clamp = |min: u32, max: u32, v: u32| min.max(max.min(v)); + vk::Extent2D::builder() + .width(clamp( + capabilities.min_image_extent.width, + capabilities.max_image_extent.width, + size.width, + )) + .height(clamp( + capabilities.min_image_extent.height, + capabilities.max_image_extent.height, + size.height, + )) + .build() + } +} + +//================================================ +// Pipeline +//================================================ +impl AppData { unsafe fn create_render_pass(&mut self, instance: &Instance, device: &Device) -> Result<()> { let color_attachment = vk::AttachmentDescription::builder() .format(self.swapchain_format) @@ -687,11 +756,29 @@ impl AppData { Ok(()) } +} - //================================================ - // Framebuffers - //================================================ +pub(crate) unsafe fn create_shader_module( + device: &Device, + bytecode: &[u8], +) -> Result { + let bytecode = Vec::::from(bytecode); + let (prefix, code, suffix) = bytecode.align_to::(); + if !prefix.is_empty() || !suffix.is_empty() { + return Err(anyhow!("Shader bytecode is not properly aligned.")); + } + let info = vk::ShaderModuleCreateInfo::builder() + .code_size(bytecode.len()) + .code(code); + + Ok(device.create_shader_module(&info, None)?) +} + +//================================================ +// Framebuffers +//================================================ +impl AppData { unsafe fn create_framebuffers(&mut self, device: &Device) -> Result<()> { self.framebuffers = self .swapchain_image_views @@ -711,11 +798,12 @@ impl AppData { Ok(()) } +} - //================================================ - // Command Pool - //================================================ - +//================================================ +// Command Pool +//================================================ +impl AppData { unsafe fn create_command_pool(&mut self, instance: &Instance, device: &Device) -> Result<()> { let indices = QueueFamilyIndices::get(instance, self, self.physical_device)?; @@ -727,11 +815,12 @@ impl AppData { Ok(()) } +} - //================================================ - // Depth Objects - //================================================ - +//================================================ +// Depth Objects +//================================================ +impl AppData { unsafe fn create_depth_objects(&mut self, instance: &Instance, device: &Device) -> Result<()> { let format = self.get_depth_format(instance)?; @@ -798,11 +887,12 @@ impl AppData { }) .ok_or_else(|| anyhow!("Failed to find supported depth image format.")) } +} - //================================================ - // Texture - //================================================ - +//================================================ +// Texture +//================================================ +impl AppData { fn create_texture_image(&mut self, instance: &Instance, device: &Device) -> Result<()> { // Load the image let image = File::open("resources/viking_room.png")?; @@ -908,11 +998,12 @@ impl AppData { Ok(()) } +} - //================================================ - // Model - //================================================ - +//================================================ +// Model +//================================================ +impl AppData { unsafe fn load_model(&mut self) -> Result<()> { let mut reader = BufReader::new(File::open("resources/viking_room.obj")?); @@ -958,11 +1049,12 @@ impl AppData { Ok(()) } +} - //================================================ - // Buffers - //================================================ - +//================================================ +// Buffers +//================================================ +impl AppData { unsafe fn create_vertex_buffer(&mut self, instance: &Instance, device: &Device) -> Result<()> { // Create staging buffer let size = (size_of::() * self.vertices.len()) as u64; @@ -1058,11 +1150,11 @@ impl AppData { Ok(()) } - - //================================================ - // Descriptors - //================================================ - +} +//================================================ +// Descriptors +//================================================ +impl AppData { unsafe fn create_descriptor_pool(&mut self, device: &Device) -> Result<()> { let ubo_size = vk::DescriptorPoolSize::builder() .type_(vk::DescriptorType::UNIFORM_BUFFER) @@ -1125,11 +1217,12 @@ impl AppData { Ok(()) } +} - //================================================ - // Command Buffers - //================================================ - +//================================================ +// Command Buffers +//================================================ +impl AppData { unsafe fn create_command_buffers(&mut self, device: &Device) -> Result<()> { // Create the buffers let allocate_info = vk::CommandBufferAllocateInfo::builder() @@ -1202,11 +1295,12 @@ impl AppData { Ok(()) } +} - //================================================ - // Sync Objects - //================================================ - +//================================================ +// Sync Objects +//================================================ +impl AppData { unsafe fn create_sync_objects(&mut self, device: &Device) -> Result<()> { let semaphore_info = vk::SemaphoreCreateInfo::builder(); let fence_info = vk::FenceCreateInfo::builder().flags(vk::FenceCreateFlags::SIGNALED); @@ -1229,11 +1323,12 @@ impl AppData { Ok(()) } +} - //================================================ - // Shared (Buffers) - //================================================ - +//================================================ +// Shared (Buffers) +//================================================ +impl AppData { unsafe fn create_buffer( &self, instance: &Instance, @@ -1278,11 +1373,12 @@ impl AppData { Ok(()) } +} - //================================================ - // Shared (Images) - //================================================ - +//================================================ +// Shared (Images) +//================================================ +impl AppData { unsafe fn create_image( &self, instance: &Instance, @@ -1427,11 +1523,34 @@ impl AppData { Ok(()) } +} - //================================================ - // Shared (Other) - //================================================ +pub(crate) unsafe fn create_image_view( + device: &Device, + image: vk::Image, + format: vk::Format, + aspects: vk::ImageAspectFlags, +) -> Result { + let subresource_range = vk::ImageSubresourceRange::builder() + .aspect_mask(aspects) + .base_mip_level(0) + .level_count(1) + .base_array_layer(0) + .layer_count(1); + let info = vk::ImageViewCreateInfo::builder() + .image(image) + .view_type(vk::ImageViewType::_2D) + .format(format) + .subresource_range(subresource_range); + + Ok(device.create_image_view(&info, None)?) +} + +//================================================ +// Shared (Other) +//================================================ +impl AppData { unsafe fn get_memory_type_index( &self, instance: &Instance,