From 3dbc718446e1a5efe623996b8bcc9cadb633a82c Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Wed, 12 Apr 2023 11:23:21 -0400 Subject: [PATCH] Modularize AppData struct --- src/app.rs | 84 ++---- src/app/data.rs | 670 +++++++++++++++++++++++++++++++++++++++++++ src/app/functions.rs | 639 +---------------------------------------- 3 files changed, 700 insertions(+), 693 deletions(-) create mode 100644 src/app/data.rs diff --git a/src/app.rs b/src/app.rs index 88901f9..b3c0d3e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,9 +1,7 @@ +mod data; mod functions; -use functions::{ - create_command_buffers, create_command_pool, create_framebuffers, create_instance, - create_logical_device, create_pipeline, create_render_pass, create_swapchain, - create_swapchain_image_views, create_sync_objects, create_vertex_buffer, pick_physical_device, -}; + +use data::AppData; use crate::VALIDATION_ENABLED; use ::anyhow::{anyhow, Result}; @@ -54,21 +52,21 @@ impl App { let entry = Entry::new(loader).map_err(|b| anyhow!("{}", b))?; let mut data = AppData::default(); - let instance = create_instance(window, &entry, &mut data)?; + let instance = data.create_instance(window, &entry)?; data.surface = vk_window::create_surface(&instance, window)?; - pick_physical_device(&instance, &mut data)?; - let device = create_logical_device(&instance, &mut data)?; + data.pick_physical_device(&instance)?; + let device = data.create_logical_device(&instance)?; - create_swapchain(window, &instance, &device, &mut data)?; - create_swapchain_image_views(&device, &mut data)?; - create_render_pass(&instance, &device, &mut data)?; - create_pipeline(&device, &mut data)?; - create_framebuffers(&device, &mut data)?; - create_command_pool(&instance, &device, &mut data)?; - create_vertex_buffer(&instance, &device, &mut data)?; - create_command_buffers(&device, &mut data)?; - create_sync_objects(&device, &mut data)?; + data.create_swapchain(window, &instance, &device)?; + data.create_swapchain_image_views(&device)?; + data.create_render_pass(&instance, &device)?; + data.create_pipeline(&device)?; + data.create_framebuffers(&device)?; + data.create_command_pool(&instance, &device)?; + data.create_vertex_buffer(&instance, &device)?; + data.create_command_buffers(&device)?; + data.create_sync_objects(&device)?; Ok(Self { _entry: entry, @@ -214,12 +212,13 @@ impl App { self.device.device_wait_idle()?; self.destroy_swapchain(); - create_swapchain(window, &self.instance, &self.device, &mut self.data)?; - create_swapchain_image_views(&self.device, &mut self.data)?; - create_render_pass(&self.instance, &self.device, &mut self.data)?; - create_pipeline(&self.device, &mut self.data)?; - create_framebuffers(&self.device, &mut self.data)?; - create_command_buffers(&self.device, &mut self.data)?; + self.data + .create_swapchain(window, &self.instance, &self.device)?; + self.data.create_swapchain_image_views(&self.device)?; + self.data.create_render_pass(&self.instance, &self.device)?; + self.data.create_pipeline(&self.device)?; + self.data.create_framebuffers(&self.device)?; + self.data.create_command_buffers(&self.device)?; self.data .images_in_flight @@ -230,45 +229,6 @@ impl App { } } -/// The Vulkan handles and associated properties used by our Vulkan app. -#[derive(Clone, Debug, Default)] -pub struct AppData { - // Debug - messenger: vk::DebugUtilsMessengerEXT, - // Surface - surface: vk::SurfaceKHR, - // Physical Device / Logical Device - physical_device: vk::PhysicalDevice, - graphics_queue: vk::Queue, - present_queue: vk::Queue, - // Swapchain - swapchain_format: vk::Format, - swapchain_extent: vk::Extent2D, - swapchain: vk::SwapchainKHR, - swapchain_images: Vec, - swapchain_image_views: Vec, - // Pipeline - render_pass: vk::RenderPass, - pipeline_layout: vk::PipelineLayout, - pipeline: vk::Pipeline, - // Framebuffers - framebuffers: Vec, - // Command Pool - command_pool: vk::CommandPool, - // Buffers - vertex_buffer: vk::Buffer, - vertex_buffer_memory: vk::DeviceMemory, - // Command Buffers - command_buffers: Vec, - // Sync Objects - image_available_semaphores: Vec, - render_finished_semaphores: Vec, - in_flight_fences: Vec, - images_in_flight: Vec, -} - -impl AppData {} - #[derive(Debug, Error)] #[error("Missing {0}.")] pub struct SuitabilityError(pub &'static str); diff --git a/src/app/data.rs b/src/app/data.rs new file mode 100644 index 0000000..e2d138c --- /dev/null +++ b/src/app/data.rs @@ -0,0 +1,670 @@ +use super::functions::*; +use super::*; +use crate::VALIDATION_ENABLED; + +use ::anyhow::{anyhow, Result}; +use ::log::*; +use ::std::collections::HashSet; +use ::std::ffi::CStr; +use ::std::os::raw::c_void; +use ::std::ptr::copy_nonoverlapping as memcpy; +use ::vulkanalia::prelude::v1_0::*; +use ::vulkanalia::vk::ExtDebugUtilsExtension; +use ::vulkanalia::window as vk_window; +use ::winit::window::Window; + +extern "system" fn debug_callback( + severity: vk::DebugUtilsMessageSeverityFlagsEXT, + type_: vk::DebugUtilsMessageTypeFlagsEXT, + data: *const vk::DebugUtilsMessengerCallbackDataEXT, + _: *mut c_void, +) -> vk::Bool32 { + let data = unsafe { *data }; + let message = unsafe { CStr::from_ptr(data.message) }.to_string_lossy(); + + if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::ERROR { + error!("({:?}) {}", type_, message); + } else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING { + warn!("({:?}) {}", type_, message); + } else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::INFO { + debug!("({:?}) {}", type_, message); + } else { + trace!("({:?}) {}", type_, message); + } + + vk::FALSE +} + +/// The Vulkan handles and associated properties used by our Vulkan app. +#[derive(Clone, Debug, Default)] +pub struct AppData { + // Debug + pub(crate) messenger: vk::DebugUtilsMessengerEXT, + // Surface + pub(crate) surface: vk::SurfaceKHR, + // Physical Device / Logical Device + pub(crate) physical_device: vk::PhysicalDevice, + pub(crate) graphics_queue: vk::Queue, + pub(crate) present_queue: vk::Queue, + // Swapchain + pub(crate) swapchain_format: vk::Format, + pub(crate) swapchain_extent: vk::Extent2D, + pub(crate) swapchain: vk::SwapchainKHR, + pub(crate) swapchain_images: Vec, + pub(crate) swapchain_image_views: Vec, + // Pipeline + pub(crate) render_pass: vk::RenderPass, + pub(crate) pipeline_layout: vk::PipelineLayout, + pub(crate) pipeline: vk::Pipeline, + // Framebuffers + pub(crate) framebuffers: Vec, + // Command Pool + pub(crate) command_pool: vk::CommandPool, + // Buffers + pub(crate) vertex_buffer: vk::Buffer, + pub(crate) vertex_buffer_memory: vk::DeviceMemory, + // Command Buffers + pub(crate) command_buffers: Vec, + // Sync Objects + pub(crate) image_available_semaphores: Vec, + pub(crate) render_finished_semaphores: Vec, + pub(crate) in_flight_fences: Vec, + pub(crate) images_in_flight: Vec, +} + +impl AppData { + pub unsafe fn create_instance(&mut self, window: &Window, entry: &Entry) -> Result { + // Application Info + let application_info = vk::ApplicationInfo::builder() + .application_name(b"Vulkan Tutorial\0") + .application_version(vk::make_version(1, 0, 0)) + .engine_name(b"No Engine\0") + .engine_version(vk::make_version(1, 0, 0)) + .api_version(vk::make_version(1, 0, 0)); + + // Layers + let available_layers = entry + .enumerate_instance_layer_properties()? + .iter() + .map(|l| l.layer_name) + .collect::>(); + + if VALIDATION_ENABLED && !available_layers.contains(&VALIDATION_LAYER) { + return Err(anyhow!("Validation layer requested but not supported.")); + } + + let layers = if VALIDATION_ENABLED { + vec![VALIDATION_LAYER.as_ptr()] + } else { + Vec::new() + }; + + // Extensions + let mut extensions = vk_window::get_required_instance_extensions(window) + .iter() + .map(|e| e.as_ptr()) + .collect::>(); + if VALIDATION_ENABLED { + extensions.push(vk::EXT_DEBUG_UTILS_EXTENSION.name.as_ptr()); + } + + // Compatibility extension for macOS + let flags = if (cfg!(target_os = "macos") && entry.version()? >= PORTABILITY_MACOS_VERSION) + || entry + .enumerate_instance_extension_properties(None)? + .iter() + .any(|e| e.extension_name == vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name) + { + info!("Enabling extensions for macOS compatibility."); + extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr()); + extensions.push( + vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION + .name + .as_ptr(), + ); + vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR + } else { + vk::InstanceCreateFlags::empty() + }; + + // Create + let mut info = vk::InstanceCreateInfo::builder() + .application_info(&application_info) + .enabled_layer_names(&layers) + .enabled_extension_names(&extensions) + .flags(flags); + + let mut debug_info = vk::DebugUtilsMessengerCreateInfoEXT::builder() + .message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all()) + .message_type(vk::DebugUtilsMessageTypeFlagsEXT::all()) + .user_callback(Some(debug_callback)); + + if VALIDATION_ENABLED { + info = info.push_next(&mut debug_info); + } + + let instance = entry.create_instance(&info, None)?; + + // Messenger + if VALIDATION_ENABLED { + self.messenger = instance.create_debug_utils_messenger_ext(&debug_info, None)?; + } + + Ok(instance) + } + + //================================================ + // Physical Device + //================================================ + + pub(super) 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); + + if let Err(error) = self.check_physical_device(instance, physical_device) { + warn!( + "Skipping physical device (`{}`): {}", + properties.device_name, error + ); + } else { + info!("Selected physical device (`{}`).", properties.device_name); + self.physical_device = physical_device; + return Ok(()); + } + } + + Err(anyhow!("Failed to find suitable physical device.")) + } + + unsafe fn check_physical_device( + &self, + instance: &Instance, + physical_device: vk::PhysicalDevice, + ) -> Result<()> { + QueueFamilyIndices::get(instance, self, physical_device)?; + check_physical_device_extensions(instance, physical_device)?; + + let support = SwapchainSupport::get(instance, self, physical_device)?; + if support.formats.is_empty() || support.present_modes.is_empty() { + return Err(anyhow!(SuitabilityError("Insufficient swapchain support."))); + } + + Ok(()) + } + + //================================================ + // Logical Device + //================================================ + + pub(super) unsafe fn create_logical_device(&mut self, instance: &Instance) -> Result { + // Queue Create Infos + let indices = QueueFamilyIndices::get(instance, self, self.physical_device)?; + + let mut unique_indices = HashSet::new(); + unique_indices.insert(indices.graphics); + unique_indices.insert(indices.present); + + let queue_priorities = &[1.0]; + let queue_infos = unique_indices + .iter() + .map(|i| { + vk::DeviceQueueCreateInfo::builder() + .queue_family_index(*i) + .queue_priorities(queue_priorities) + }) + .collect::>(); + + // Layers + let layers = if VALIDATION_ENABLED { + vec![VALIDATION_LAYER.as_ptr()] + } else { + vec![] + }; + + // Extensions + let mut extensions = DEVICE_EXTENSIONS + .iter() + .map(|n| n.as_ptr()) + .collect::>(); + + // mac OS Metal -> Vulkan rendering fix + if instance + .enumerate_device_extension_properties(self.physical_device, None)? + .iter() + .any(|e| e.extension_name == vk::KHR_PORTABILITY_SUBSET_EXTENSION.name) + { + extensions.push(vk::KHR_PORTABILITY_SUBSET_EXTENSION.name.as_ptr()); + } + + // Features + let features = vk::PhysicalDeviceFeatures::builder(); + + // Create + let info = vk::DeviceCreateInfo::builder() + .queue_create_infos(&queue_infos) + .enabled_layer_names(&layers) + .enabled_extension_names(&extensions) + .enabled_features(&features); + + let device = instance.create_device(self.physical_device, &info, None)?; + + // Queues + self.graphics_queue = device.get_device_queue(indices.graphics, 0); + self.present_queue = device.get_device_queue(indices.present, 0); + + Ok(device) + } + + //================================================ + // Swapchain + //================================================ + + pub(super) unsafe fn create_swapchain( + &mut self, + window: &Window, + instance: &Instance, + device: &Device, + ) -> Result<()> { + let indices = QueueFamilyIndices::get(instance, self, self.physical_device)?; + let support = SwapchainSupport::get(instance, self, self.physical_device)?; + + let surface_format = get_swapchain_surface_format(&support.formats); + let present_mode = get_swapchain_present_mode(&support.present_modes); + let extent = get_swapchain_extent(window, support.capabilities); + + let mut image_count = support.capabilities.min_image_count + 1; + if support.capabilities.max_image_count != 0 + && image_count > support.capabilities.max_image_count + { + image_count = support.capabilities.max_image_count; + } + + let mut queue_family_indices = vec![]; + let image_sharing_mode = if indices.graphics != indices.present { + queue_family_indices.push(indices.graphics); + queue_family_indices.push(indices.present); + vk::SharingMode::CONCURRENT + } else { + vk::SharingMode::EXCLUSIVE + }; + + let info = vk::SwapchainCreateInfoKHR::builder() + .surface(self.surface) + .min_image_count(image_count) + .image_format(surface_format.format) + .image_color_space(surface_format.color_space) + .image_extent(extent) + .image_array_layers(1) + .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) + .image_sharing_mode(image_sharing_mode) + .queue_family_indices(&queue_family_indices) + .pre_transform(support.capabilities.current_transform) + .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) + .present_mode(present_mode) + .clipped(true) + .old_swapchain(vk::SwapchainKHR::null()); + + self.swapchain = device.create_swapchain_khr(&info, None)?; + self.swapchain_images = device.get_swapchain_images_khr(self.swapchain)?; + self.swapchain_format = surface_format.format; + self.swapchain_extent = extent; + + Ok(()) + } + + pub(super) unsafe fn create_swapchain_image_views(&mut self, device: &Device) -> Result<()> { + self.swapchain_image_views = self + .swapchain_images + .iter() + .map(|i| { + let components = vk::ComponentMapping::builder() + .r(vk::ComponentSwizzle::IDENTITY) + .g(vk::ComponentSwizzle::IDENTITY) + .b(vk::ComponentSwizzle::IDENTITY) + .a(vk::ComponentSwizzle::IDENTITY); + + let subresource_range = vk::ImageSubresourceRange::builder() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .base_mip_level(0) + .level_count(1) + .base_array_layer(0) + .layer_count(1); + + let info = vk::ImageViewCreateInfo::builder() + .image(*i) + .view_type(vk::ImageViewType::_2D) + .format(self.swapchain_format) + .components(components) + .subresource_range(subresource_range); + + device.create_image_view(&info, None) + }) + .collect::, _>>()?; + + Ok(()) + } + + //================================================ + // Pipeline + //================================================ + + pub(super) unsafe fn create_render_pass( + &mut self, + _instance: &Instance, + device: &Device, + ) -> Result<()> { + let color_attachment = vk::AttachmentDescription::builder() + .format(self.swapchain_format) + .samples(vk::SampleCountFlags::_1) + .load_op(vk::AttachmentLoadOp::CLEAR) + .store_op(vk::AttachmentStoreOp::STORE) + .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE) + .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE) + .initial_layout(vk::ImageLayout::UNDEFINED) + .final_layout(vk::ImageLayout::PRESENT_SRC_KHR); + + // Subpasses + let color_attachment_ref = vk::AttachmentReference::builder() + .attachment(0) + .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); + let color_attachments = &[color_attachment_ref]; + let subpass = vk::SubpassDescription::builder() + .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) + .color_attachments(color_attachments); + let dependency = vk::SubpassDependency::builder() + .src_subpass(vk::SUBPASS_EXTERNAL) + .dst_subpass(0) + .src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) + .src_access_mask(vk::AccessFlags::empty()) + .dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) + .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE); + + let attachments = &[color_attachment]; + let subpasses = &[subpass]; + let dependencies = &[dependency]; + let info = vk::RenderPassCreateInfo::builder() + .attachments(attachments) + .subpasses(subpasses) + .dependencies(dependencies); + + self.render_pass = device.create_render_pass(&info, None)?; + + Ok(()) + } + + pub(super) unsafe fn create_pipeline(&mut self, device: &Device) -> Result<()> { + let vert = include_bytes!("../../shaders/vert.spv"); + let frag = include_bytes!("../../shaders/frag.spv"); + + let vert_shader_module = create_shader_module(device, &vert[..])?; + let frag_shader_module = create_shader_module(device, &frag[..])?; + + let vert_stage = vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::VERTEX) + .module(vert_shader_module) + .name(b"main\0"); + + let frag_stage = vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::FRAGMENT) + .module(frag_shader_module) + .name(b"main\0"); + + let binding_descriptions = &[Vertex::binding_description()]; + let attribute_descriptions = Vertex::attribute_descriptions(); + let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::builder() + .vertex_binding_descriptions(binding_descriptions) + .vertex_attribute_descriptions(&attribute_descriptions); + + let input_assembly_state = vk::PipelineInputAssemblyStateCreateInfo::builder() + .topology(vk::PrimitiveTopology::TRIANGLE_LIST) + .primitive_restart_enable(false); + + let viewport = vk::Viewport::builder() + .x(0.0) + .y(0.0) + .width(self.swapchain_extent.width as f32) + .height(self.swapchain_extent.height as f32) + .min_depth(0.0) + .max_depth(1.0); + + let scissor = vk::Rect2D::builder() + .offset(vk::Offset2D { x: 0, y: 0 }) + .extent(self.swapchain_extent); + + let viewports = &[viewport]; + let scissors = &[scissor]; + let viewport_state = vk::PipelineViewportStateCreateInfo::builder() + .viewports(viewports) + .scissors(scissors); + + let rasterization_state = vk::PipelineRasterizationStateCreateInfo::builder() + .depth_clamp_enable(false) + .rasterizer_discard_enable(false) + .polygon_mode(vk::PolygonMode::FILL) + .line_width(1.0) + .cull_mode(vk::CullModeFlags::BACK) + .front_face(vk::FrontFace::CLOCKWISE) + .depth_bias_enable(false); + + let multisample_state = vk::PipelineMultisampleStateCreateInfo::builder() + .sample_shading_enable(false) + .rasterization_samples(vk::SampleCountFlags::_1); + + let attachment = vk::PipelineColorBlendAttachmentState::builder() + .color_write_mask(vk::ColorComponentFlags::all()) + .blend_enable(false) + .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 attachments = &[attachment]; + let color_blend_state = vk::PipelineColorBlendStateCreateInfo::builder() + .logic_op_enable(false) + .logic_op(vk::LogicOp::COPY) + .attachments(attachments) + .blend_constants([0.0, 0.0, 0.0, 0.0]); + + let layout_info = vk::PipelineLayoutCreateInfo::builder(); + self.pipeline_layout = device.create_pipeline_layout(&layout_info, None)?; + + let stages = &[vert_stage, frag_stage]; + let info = vk::GraphicsPipelineCreateInfo::builder() + .stages(stages) + .vertex_input_state(&vertex_input_state) + .input_assembly_state(&input_assembly_state) + .viewport_state(&viewport_state) + .rasterization_state(&rasterization_state) + .multisample_state(&multisample_state) + .color_blend_state(&color_blend_state) + .layout(self.pipeline_layout) + .render_pass(self.render_pass) + .subpass(0); + + self.pipeline = device + .create_graphics_pipelines(vk::PipelineCache::null(), &[info], None)? + .0; + + // Cleanup + device.destroy_shader_module(vert_shader_module, None); + device.destroy_shader_module(frag_shader_module, None); + + Ok(()) + } + + pub(super) unsafe fn create_framebuffers(&mut self, device: &Device) -> Result<()> { + self.framebuffers = self + .swapchain_image_views + .iter() + .map(|i| { + let attachments = &[*i]; + let create_info = vk::FramebufferCreateInfo::builder() + .render_pass(self.render_pass) + .attachments(attachments) + .width(self.swapchain_extent.width) + .height(self.swapchain_extent.height) + .layers(1); + + device.create_framebuffer(&create_info, None) + }) + .collect::, _>>()?; + + Ok(()) + } + + //================================================ + // Command Pool + //================================================ + + pub(super) unsafe fn create_command_pool( + &mut self, + instance: &Instance, + device: &Device, + ) -> Result<()> { + let indices = QueueFamilyIndices::get(instance, self, self.physical_device)?; + + let info = vk::CommandPoolCreateInfo::builder() + .flags(vk::CommandPoolCreateFlags::empty()) + .queue_family_index(indices.graphics); + + self.command_pool = device.create_command_pool(&info, None)?; + + Ok(()) + } + + //================================================ + // Command Buffers + //================================================ + + pub(super) unsafe fn create_command_buffers(&mut self, device: &Device) -> Result<()> { + // Create the buffers + let allocate_info = vk::CommandBufferAllocateInfo::builder() + .command_pool(self.command_pool) + .level(vk::CommandBufferLevel::PRIMARY) + .command_buffer_count(self.framebuffers.len() as u32); + + self.command_buffers = device.allocate_command_buffers(&allocate_info)?; + + // Add commands + for (i, command_buffer) in self.command_buffers.iter().enumerate() { + let inheritance = vk::CommandBufferInheritanceInfo::builder(); + + let info = vk::CommandBufferBeginInfo::builder() + .flags(vk::CommandBufferUsageFlags::empty()) + .inheritance_info(&inheritance); + + device.begin_command_buffer(*command_buffer, &info)?; + + let render_area = vk::Rect2D::builder() + .offset(vk::Offset2D::default()) + .extent(self.swapchain_extent); + + let color_clear_value = vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.0, 0.0, 0.0, 1.0], + }, + }; + + let clear_values = &[color_clear_value]; + let info = vk::RenderPassBeginInfo::builder() + .render_pass(self.render_pass) + .framebuffer(self.framebuffers[i]) + .render_area(render_area) + .clear_values(clear_values); + + device.cmd_begin_render_pass(*command_buffer, &info, vk::SubpassContents::INLINE); + device.cmd_bind_pipeline( + *command_buffer, + vk::PipelineBindPoint::GRAPHICS, + self.pipeline, + ); + device.cmd_bind_vertex_buffers(*command_buffer, 0, &[self.vertex_buffer], &[0]); + device.cmd_draw(*command_buffer, 3, 1, 0, 0); + device.cmd_end_render_pass(*command_buffer); + + device.end_command_buffer(*command_buffer)?; + } + + Ok(()) + } + + pub(super) 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); + + for _ in 0..MAX_FRAMES_IN_FLIGHT { + self.image_available_semaphores + .push(device.create_semaphore(&semaphore_info, None)?); + self.render_finished_semaphores + .push(device.create_semaphore(&semaphore_info, None)?); + + self.in_flight_fences + .push(device.create_fence(&fence_info, None)?); + } + + self.images_in_flight = self + .swapchain_images + .iter() + .map(|_| vk::Fence::null()) + .collect(); + + Ok(()) + } + + pub(super) unsafe fn create_vertex_buffer( + &mut self, + instance: &Instance, + device: &Device, + ) -> Result<()> { + let buffer_info = vk::BufferCreateInfo::builder() + .size((size_of::() * VERTICES.len()) as u64) + .usage(vk::BufferUsageFlags::VERTEX_BUFFER) + .sharing_mode(vk::SharingMode::EXCLUSIVE); + + self.vertex_buffer = device.create_buffer(&buffer_info, None)?; + + let requirements = device.get_buffer_memory_requirements(self.vertex_buffer); + let memory_info = vk::MemoryAllocateInfo::builder() + .allocation_size(requirements.size) + .memory_type_index(self.get_memory_type_index( + instance, + vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, + requirements, + )?); + + self.vertex_buffer_memory = device.allocate_memory(&memory_info, None)?; + + device.bind_buffer_memory(self.vertex_buffer, self.vertex_buffer_memory, 0)?; + + let memory = device.map_memory( + self.vertex_buffer_memory, + 0, + buffer_info.size, + vk::MemoryMapFlags::empty(), + )?; + + memcpy(VERTICES.as_ptr(), memory.cast(), VERTICES.len()); + device.unmap_memory(self.vertex_buffer_memory); + + Ok(()) + } + + unsafe fn get_memory_type_index( + &self, + instance: &Instance, + properties: vk::MemoryPropertyFlags, + requirements: vk::MemoryRequirements, + ) -> Result { + let memory = instance.get_physical_device_memory_properties(self.physical_device); + + (0..memory.memory_type_count) + .find(|i| { + let suitable = (requirements.memory_type_bits & (1 << i)) != 0; + let memory_type = memory.memory_types[*i as usize]; + suitable && memory_type.property_flags.contains(properties) + }) + .ok_or_else(|| anyhow!("Failed to find suitable memory type.")) + } +} diff --git a/src/app/functions.rs b/src/app/functions.rs index ce21a77..7ff80af 100644 --- a/src/app/functions.rs +++ b/src/app/functions.rs @@ -1,162 +1,11 @@ use super::*; -use crate::VALIDATION_ENABLED; use ::anyhow::{anyhow, Result}; -use ::log::*; use ::std::collections::HashSet; -use ::std::ffi::CStr; -use ::std::os::raw::c_void; -use ::std::ptr::copy_nonoverlapping as memcpy; use ::vulkanalia::prelude::v1_0::*; -use ::vulkanalia::window as vk_window; use ::winit::window::Window; -extern "system" fn debug_callback( - severity: vk::DebugUtilsMessageSeverityFlagsEXT, - type_: vk::DebugUtilsMessageTypeFlagsEXT, - data: *const vk::DebugUtilsMessengerCallbackDataEXT, - _: *mut c_void, -) -> vk::Bool32 { - let data = unsafe { *data }; - let message = unsafe { CStr::from_ptr(data.message) }.to_string_lossy(); - - if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::ERROR { - error!("({:?}) {}", type_, message); - } else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING { - warn!("({:?}) {}", type_, message); - } else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::INFO { - debug!("({:?}) {}", type_, message); - } else { - trace!("({:?}) {}", type_, message); - } - - vk::FALSE -} - -//================================================ -// Physical Device -//================================================ - -pub(super) unsafe fn create_instance( - window: &Window, - entry: &Entry, - data: &mut AppData, -) -> Result { - // Application Info - let application_info = vk::ApplicationInfo::builder() - .application_name(b"Vulkan Tutorial\0") - .application_version(vk::make_version(1, 0, 0)) - .engine_name(b"No Engine\0") - .engine_version(vk::make_version(1, 0, 0)) - .api_version(vk::make_version(1, 0, 0)); - - // Layers - let available_layers = entry - .enumerate_instance_layer_properties()? - .iter() - .map(|l| l.layer_name) - .collect::>(); - - if VALIDATION_ENABLED && !available_layers.contains(&VALIDATION_LAYER) { - return Err(anyhow!("Validation layer requested but not supported.")); - } - - let layers = if VALIDATION_ENABLED { - vec![VALIDATION_LAYER.as_ptr()] - } else { - Vec::new() - }; - - // Extensions - let mut extensions = vk_window::get_required_instance_extensions(window) - .iter() - .map(|e| e.as_ptr()) - .collect::>(); - if VALIDATION_ENABLED { - extensions.push(vk::EXT_DEBUG_UTILS_EXTENSION.name.as_ptr()); - } - - // Compatibility extension for macOS - let flags = if (cfg!(target_os = "macos") && entry.version()? >= PORTABILITY_MACOS_VERSION) - || entry - .enumerate_instance_extension_properties(None)? - .iter() - .any(|e| e.extension_name == vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name) - { - info!("Enabling extensions for macOS compatibility."); - extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr()); - extensions.push( - vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION - .name - .as_ptr(), - ); - vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR - } else { - vk::InstanceCreateFlags::empty() - }; - - // Create - let mut info = vk::InstanceCreateInfo::builder() - .application_info(&application_info) - .enabled_layer_names(&layers) - .enabled_extension_names(&extensions) - .flags(flags); - - let mut debug_info = vk::DebugUtilsMessengerCreateInfoEXT::builder() - .message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all()) - .message_type(vk::DebugUtilsMessageTypeFlagsEXT::all()) - .user_callback(Some(debug_callback)); - - if VALIDATION_ENABLED { - info = info.push_next(&mut debug_info); - } - - let instance = entry.create_instance(&info, None)?; - - // Messenger - if VALIDATION_ENABLED { - data.messenger = instance.create_debug_utils_messenger_ext(&debug_info, None)?; - } - - Ok(instance) -} - -pub(super) unsafe fn pick_physical_device(instance: &Instance, data: &mut AppData) -> Result<()> { - for physical_device in instance.enumerate_physical_devices()? { - let properties = instance.get_physical_device_properties(physical_device); - - if let Err(error) = check_physical_device(instance, data, physical_device) { - warn!( - "Skipping physical device (`{}`): {}", - properties.device_name, error - ); - } else { - info!("Selected physical device (`{}`).", properties.device_name); - data.physical_device = physical_device; - return Ok(()); - } - } - - Err(anyhow!("Failed to find suitable physical device.")) -} - -unsafe fn check_physical_device( - instance: &Instance, - data: &AppData, - physical_device: vk::PhysicalDevice, -) -> Result<()> { - QueueFamilyIndices::get(instance, data, physical_device)?; - check_physical_device_extensions(instance, physical_device)?; - - let support = SwapchainSupport::get(instance, data, physical_device)?; - if support.formats.is_empty() || support.present_modes.is_empty() { - return Err(anyhow!(SuitabilityError("Insufficient swapchain support."))); - } - - Ok(()) -} - -unsafe fn check_physical_device_extensions( +pub unsafe fn check_physical_device_extensions( instance: &Instance, physical_device: vk::PhysicalDevice, ) -> Result<()> { @@ -175,130 +24,11 @@ unsafe fn check_physical_device_extensions( } } -//================================================ -// Logical Device -//================================================ - -pub(super) unsafe fn create_logical_device( - instance: &Instance, - data: &mut AppData, -) -> Result { - // Queue Create Infos - let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?; - - let mut unique_indices = HashSet::new(); - unique_indices.insert(indices.graphics); - unique_indices.insert(indices.present); - - let queue_priorities = &[1.0]; - let queue_infos = unique_indices - .iter() - .map(|i| { - vk::DeviceQueueCreateInfo::builder() - .queue_family_index(*i) - .queue_priorities(queue_priorities) - }) - .collect::>(); - - // Layers - let layers = if VALIDATION_ENABLED { - vec![VALIDATION_LAYER.as_ptr()] - } else { - vec![] - }; - - // Extensions - let mut extensions = DEVICE_EXTENSIONS - .iter() - .map(|n| n.as_ptr()) - .collect::>(); - - // mac OS Metal -> Vulkan rendering fix - if instance - .enumerate_device_extension_properties(data.physical_device, None)? - .iter() - .any(|e| e.extension_name == vk::KHR_PORTABILITY_SUBSET_EXTENSION.name) - { - extensions.push(vk::KHR_PORTABILITY_SUBSET_EXTENSION.name.as_ptr()); - } - - // Features - let features = vk::PhysicalDeviceFeatures::builder(); - - // Create - let info = vk::DeviceCreateInfo::builder() - .queue_create_infos(&queue_infos) - .enabled_layer_names(&layers) - .enabled_extension_names(&extensions) - .enabled_features(&features); - - let device = instance.create_device(data.physical_device, &info, None)?; - - // Queues - data.graphics_queue = device.get_device_queue(indices.graphics, 0); - data.present_queue = device.get_device_queue(indices.present, 0); - - Ok(device) -} - //================================================ // Swapchain //================================================ -pub(super) unsafe fn create_swapchain( - window: &Window, - instance: &Instance, - device: &Device, - data: &mut AppData, -) -> Result<()> { - let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?; - let support = SwapchainSupport::get(instance, data, data.physical_device)?; - - let surface_format = get_swapchain_surface_format(&support.formats); - let present_mode = get_swapchain_present_mode(&support.present_modes); - let extent = get_swapchain_extent(window, support.capabilities); - - let mut image_count = support.capabilities.min_image_count + 1; - if support.capabilities.max_image_count != 0 - && image_count > support.capabilities.max_image_count - { - image_count = support.capabilities.max_image_count; - } - - let mut queue_family_indices = vec![]; - let image_sharing_mode = if indices.graphics != indices.present { - queue_family_indices.push(indices.graphics); - queue_family_indices.push(indices.present); - vk::SharingMode::CONCURRENT - } else { - vk::SharingMode::EXCLUSIVE - }; - - let info = vk::SwapchainCreateInfoKHR::builder() - .surface(data.surface) - .min_image_count(image_count) - .image_format(surface_format.format) - .image_color_space(surface_format.color_space) - .image_extent(extent) - .image_array_layers(1) - .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) - .image_sharing_mode(image_sharing_mode) - .queue_family_indices(&queue_family_indices) - .pre_transform(support.capabilities.current_transform) - .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) - .present_mode(present_mode) - .clipped(true) - .old_swapchain(vk::SwapchainKHR::null()); - - data.swapchain = device.create_swapchain_khr(&info, None)?; - data.swapchain_images = device.get_swapchain_images_khr(data.swapchain)?; - data.swapchain_format = surface_format.format; - data.swapchain_extent = extent; - - Ok(()) -} - -fn get_swapchain_surface_format(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR { +pub fn get_swapchain_surface_format(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR { formats .iter() .cloned() @@ -309,7 +39,7 @@ fn get_swapchain_surface_format(formats: &[vk::SurfaceFormatKHR]) -> vk::Surface .unwrap_or_else(|| formats[0]) } -fn get_swapchain_present_mode(present_modes: &[vk::PresentModeKHR]) -> vk::PresentModeKHR { +pub fn get_swapchain_present_mode(present_modes: &[vk::PresentModeKHR]) -> vk::PresentModeKHR { present_modes .iter() .cloned() @@ -317,7 +47,10 @@ fn get_swapchain_present_mode(present_modes: &[vk::PresentModeKHR]) -> vk::Prese .unwrap_or(vk::PresentModeKHR::FIFO) } -fn get_swapchain_extent(window: &Window, capabilities: vk::SurfaceCapabilitiesKHR) -> vk::Extent2D { +pub fn get_swapchain_extent( + window: &Window, + capabilities: vk::SurfaceCapabilitiesKHR, +) -> vk::Extent2D { if capabilities.current_extent.width != u32::MAX { capabilities.current_extent } else { @@ -338,192 +71,11 @@ fn get_swapchain_extent(window: &Window, capabilities: vk::SurfaceCapabilitiesKH } } -pub(super) unsafe fn create_swapchain_image_views( - device: &Device, - data: &mut AppData, -) -> Result<()> { - data.swapchain_image_views = data - .swapchain_images - .iter() - .map(|i| { - let components = vk::ComponentMapping::builder() - .r(vk::ComponentSwizzle::IDENTITY) - .g(vk::ComponentSwizzle::IDENTITY) - .b(vk::ComponentSwizzle::IDENTITY) - .a(vk::ComponentSwizzle::IDENTITY); - - let subresource_range = vk::ImageSubresourceRange::builder() - .aspect_mask(vk::ImageAspectFlags::COLOR) - .base_mip_level(0) - .level_count(1) - .base_array_layer(0) - .layer_count(1); - - let info = vk::ImageViewCreateInfo::builder() - .image(*i) - .view_type(vk::ImageViewType::_2D) - .format(data.swapchain_format) - .components(components) - .subresource_range(subresource_range); - - device.create_image_view(&info, None) - }) - .collect::, _>>()?; - - Ok(()) -} - //================================================ // Pipeline //================================================ -pub(super) unsafe fn create_render_pass( - _instance: &Instance, - device: &Device, - data: &mut AppData, -) -> Result<()> { - let color_attachment = vk::AttachmentDescription::builder() - .format(data.swapchain_format) - .samples(vk::SampleCountFlags::_1) - .load_op(vk::AttachmentLoadOp::CLEAR) - .store_op(vk::AttachmentStoreOp::STORE) - .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE) - .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE) - .initial_layout(vk::ImageLayout::UNDEFINED) - .final_layout(vk::ImageLayout::PRESENT_SRC_KHR); - - // Subpasses - let color_attachment_ref = vk::AttachmentReference::builder() - .attachment(0) - .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); - let color_attachments = &[color_attachment_ref]; - let subpass = vk::SubpassDescription::builder() - .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) - .color_attachments(color_attachments); - let dependency = vk::SubpassDependency::builder() - .src_subpass(vk::SUBPASS_EXTERNAL) - .dst_subpass(0) - .src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) - .src_access_mask(vk::AccessFlags::empty()) - .dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) - .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE); - - let attachments = &[color_attachment]; - let subpasses = &[subpass]; - let dependencies = &[dependency]; - let info = vk::RenderPassCreateInfo::builder() - .attachments(attachments) - .subpasses(subpasses) - .dependencies(dependencies); - - data.render_pass = device.create_render_pass(&info, None)?; - - Ok(()) -} - -pub(super) unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> { - let vert = include_bytes!("../../shaders/vert.spv"); - let frag = include_bytes!("../../shaders/frag.spv"); - - let vert_shader_module = create_shader_module(device, &vert[..])?; - let frag_shader_module = create_shader_module(device, &frag[..])?; - - let vert_stage = vk::PipelineShaderStageCreateInfo::builder() - .stage(vk::ShaderStageFlags::VERTEX) - .module(vert_shader_module) - .name(b"main\0"); - - let frag_stage = vk::PipelineShaderStageCreateInfo::builder() - .stage(vk::ShaderStageFlags::FRAGMENT) - .module(frag_shader_module) - .name(b"main\0"); - - let binding_descriptions = &[Vertex::binding_description()]; - let attribute_descriptions = Vertex::attribute_descriptions(); - let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::builder() - .vertex_binding_descriptions(binding_descriptions) - .vertex_attribute_descriptions(&attribute_descriptions); - - let input_assembly_state = vk::PipelineInputAssemblyStateCreateInfo::builder() - .topology(vk::PrimitiveTopology::TRIANGLE_LIST) - .primitive_restart_enable(false); - - let viewport = vk::Viewport::builder() - .x(0.0) - .y(0.0) - .width(data.swapchain_extent.width as f32) - .height(data.swapchain_extent.height as f32) - .min_depth(0.0) - .max_depth(1.0); - - let scissor = vk::Rect2D::builder() - .offset(vk::Offset2D { x: 0, y: 0 }) - .extent(data.swapchain_extent); - - let viewports = &[viewport]; - let scissors = &[scissor]; - let viewport_state = vk::PipelineViewportStateCreateInfo::builder() - .viewports(viewports) - .scissors(scissors); - - let rasterization_state = vk::PipelineRasterizationStateCreateInfo::builder() - .depth_clamp_enable(false) - .rasterizer_discard_enable(false) - .polygon_mode(vk::PolygonMode::FILL) - .line_width(1.0) - .cull_mode(vk::CullModeFlags::BACK) - .front_face(vk::FrontFace::CLOCKWISE) - .depth_bias_enable(false); - - let multisample_state = vk::PipelineMultisampleStateCreateInfo::builder() - .sample_shading_enable(false) - .rasterization_samples(vk::SampleCountFlags::_1); - - let attachment = vk::PipelineColorBlendAttachmentState::builder() - .color_write_mask(vk::ColorComponentFlags::all()) - .blend_enable(false) - .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 attachments = &[attachment]; - let color_blend_state = vk::PipelineColorBlendStateCreateInfo::builder() - .logic_op_enable(false) - .logic_op(vk::LogicOp::COPY) - .attachments(attachments) - .blend_constants([0.0, 0.0, 0.0, 0.0]); - - let layout_info = vk::PipelineLayoutCreateInfo::builder(); - data.pipeline_layout = device.create_pipeline_layout(&layout_info, None)?; - - let stages = &[vert_stage, frag_stage]; - let info = vk::GraphicsPipelineCreateInfo::builder() - .stages(stages) - .vertex_input_state(&vertex_input_state) - .input_assembly_state(&input_assembly_state) - .viewport_state(&viewport_state) - .rasterization_state(&rasterization_state) - .multisample_state(&multisample_state) - .color_blend_state(&color_blend_state) - .layout(data.pipeline_layout) - .render_pass(data.render_pass) - .subpass(0); - - data.pipeline = device - .create_graphics_pipelines(vk::PipelineCache::null(), &[info], None)? - .0; - - // Cleanup - device.destroy_shader_module(vert_shader_module, None); - device.destroy_shader_module(frag_shader_module, None); - - Ok(()) -} - -unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result { +pub 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() { @@ -536,178 +88,3 @@ unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result Result<()> { - data.framebuffers = data - .swapchain_image_views - .iter() - .map(|i| { - let attachments = &[*i]; - let create_info = vk::FramebufferCreateInfo::builder() - .render_pass(data.render_pass) - .attachments(attachments) - .width(data.swapchain_extent.width) - .height(data.swapchain_extent.height) - .layers(1); - - device.create_framebuffer(&create_info, None) - }) - .collect::, _>>()?; - - Ok(()) -} - -//================================================ -// Command Pool -//================================================ - -pub(super) unsafe fn create_command_pool( - instance: &Instance, - device: &Device, - data: &mut AppData, -) -> Result<()> { - let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?; - - let info = vk::CommandPoolCreateInfo::builder() - .flags(vk::CommandPoolCreateFlags::empty()) - .queue_family_index(indices.graphics); - - data.command_pool = device.create_command_pool(&info, None)?; - - Ok(()) -} - -//================================================ -// Command Buffers -//================================================ - -pub(super) unsafe fn create_command_buffers(device: &Device, data: &mut AppData) -> Result<()> { - // Create the buffers - let allocate_info = vk::CommandBufferAllocateInfo::builder() - .command_pool(data.command_pool) - .level(vk::CommandBufferLevel::PRIMARY) - .command_buffer_count(data.framebuffers.len() as u32); - - data.command_buffers = device.allocate_command_buffers(&allocate_info)?; - - // Add commands - for (i, command_buffer) in data.command_buffers.iter().enumerate() { - let inheritance = vk::CommandBufferInheritanceInfo::builder(); - - let info = vk::CommandBufferBeginInfo::builder() - .flags(vk::CommandBufferUsageFlags::empty()) - .inheritance_info(&inheritance); - - device.begin_command_buffer(*command_buffer, &info)?; - - let render_area = vk::Rect2D::builder() - .offset(vk::Offset2D::default()) - .extent(data.swapchain_extent); - - let color_clear_value = vk::ClearValue { - color: vk::ClearColorValue { - float32: [0.0, 0.0, 0.0, 1.0], - }, - }; - - let clear_values = &[color_clear_value]; - let info = vk::RenderPassBeginInfo::builder() - .render_pass(data.render_pass) - .framebuffer(data.framebuffers[i]) - .render_area(render_area) - .clear_values(clear_values); - - device.cmd_begin_render_pass(*command_buffer, &info, vk::SubpassContents::INLINE); - device.cmd_bind_pipeline( - *command_buffer, - vk::PipelineBindPoint::GRAPHICS, - data.pipeline, - ); - device.cmd_bind_vertex_buffers(*command_buffer, 0, &[data.vertex_buffer], &[0]); - device.cmd_draw(*command_buffer, 3, 1, 0, 0); - device.cmd_end_render_pass(*command_buffer); - - device.end_command_buffer(*command_buffer)?; - } - - Ok(()) -} - -pub(super) unsafe fn create_sync_objects(device: &Device, data: &mut AppData) -> Result<()> { - let semaphore_info = vk::SemaphoreCreateInfo::builder(); - let fence_info = vk::FenceCreateInfo::builder().flags(vk::FenceCreateFlags::SIGNALED); - - for _ in 0..MAX_FRAMES_IN_FLIGHT { - data.image_available_semaphores - .push(device.create_semaphore(&semaphore_info, None)?); - data.render_finished_semaphores - .push(device.create_semaphore(&semaphore_info, None)?); - - data.in_flight_fences - .push(device.create_fence(&fence_info, None)?); - } - - data.images_in_flight = data - .swapchain_images - .iter() - .map(|_| vk::Fence::null()) - .collect(); - - Ok(()) -} - -pub(super) unsafe fn create_vertex_buffer( - instance: &Instance, - device: &Device, - data: &mut AppData, -) -> Result<()> { - let buffer_info = vk::BufferCreateInfo::builder() - .size((size_of::() * VERTICES.len()) as u64) - .usage(vk::BufferUsageFlags::VERTEX_BUFFER) - .sharing_mode(vk::SharingMode::EXCLUSIVE); - - data.vertex_buffer = device.create_buffer(&buffer_info, None)?; - - let requirements = device.get_buffer_memory_requirements(data.vertex_buffer); - let memory_info = vk::MemoryAllocateInfo::builder() - .allocation_size(requirements.size) - .memory_type_index(get_memory_type_index( - instance, - data, - vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, - requirements, - )?); - - data.vertex_buffer_memory = device.allocate_memory(&memory_info, None)?; - - device.bind_buffer_memory(data.vertex_buffer, data.vertex_buffer_memory, 0)?; - - let memory = device.map_memory( - data.vertex_buffer_memory, - 0, - buffer_info.size, - vk::MemoryMapFlags::empty(), - )?; - - memcpy(VERTICES.as_ptr(), memory.cast(), VERTICES.len()); - device.unmap_memory(data.vertex_buffer_memory); - - Ok(()) -} - -unsafe fn get_memory_type_index( - instance: &Instance, - data: &AppData, - properties: vk::MemoryPropertyFlags, - requirements: vk::MemoryRequirements, -) -> Result { - let memory = instance.get_physical_device_memory_properties(data.physical_device); - - (0..memory.memory_type_count) - .find(|i| { - let suitable = (requirements.memory_type_bits & (1 << i)) != 0; - let memory_type = memory.memory_types[*i as usize]; - suitable && memory_type.property_flags.contains(properties) - }) - .ok_or_else(|| anyhow!("Failed to find suitable memory type.")) -}