From 34fb4778719b36364998ecbc28bb891e3329d034 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Wed, 5 Apr 2023 10:48:25 -0400 Subject: [PATCH] Refactor to split app/library --- src/app.rs | 128 ++++++++++------------------------------------------ src/lib.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 22 +++------ 3 files changed, 142 insertions(+), 118 deletions(-) create mode 100644 src/lib.rs diff --git a/src/app.rs b/src/app.rs index 63d5d7a..7fa4bfc 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,103 +1,11 @@ -use anyhow::{anyhow, Result}; -use log::*; -use std::collections::HashSet; -use std::ffi::CStr; -use std::os::raw::c_void; -use vulkanalia::loader::{LibloadingLoader, LIBRARY}; -use vulkanalia::prelude::v1_0::*; -use vulkanalia::vk::ExtDebugUtilsExtension; -use vulkanalia::window as vk_window; -use winit::window::Window; - -const VALIDATION_ENABLED: bool = cfg!(debug_assertions); -const VALIDATION_LAYER: vk::ExtensionName = - vk::ExtensionName::from_bytes(b"VK_LAYER_KHRONOS_validation"); - -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 -} - -unsafe fn create_instance(window: &Window, entry: &Entry, data: &mut AppData) -> Result { - 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)); - - 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() - }; - - 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 entry - .enumerate_instance_extension_properties(None)? - .iter() - .any(|e| e.extension_name == vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name) - { - extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr()); - vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR - } else { - vk::InstanceCreateFlags::empty() - }; - - 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)?; - - Ok(instance) -} +use crate::create_instance; +use crate::VALIDATION_ENABLED; +use ::anyhow::{anyhow, Result}; +use ::thiserror::Error; +use ::vulkanalia::loader::{LibloadingLoader, LIBRARY}; +use ::vulkanalia::prelude::v1_0::*; +use ::vulkanalia::vk::ExtDebugUtilsExtension; +use ::winit::window::Window; /// Our Vulkan app. #[derive(Clone, Debug)] @@ -115,7 +23,12 @@ impl App { let mut data = AppData::default(); let instance = create_instance(window, &entry, &mut data)?; - Ok(Self { entry, instance, data }) + pick_physical_device(&instance, &mut data)?; + Ok(Self { + entry, + instance, + data, + }) } /// Renders a frame for our Vulkan app. @@ -126,7 +39,8 @@ impl App { /// Destroys our Vulkan app. pub unsafe fn destroy(&mut self) { if VALIDATION_ENABLED { - self.instance.destroy_debug_utils_messenger_ext(self.data.messenger, None); + self.instance + .destroy_debug_utils_messenger_ext(self.data.messenger, None); } self.instance.destroy_instance(None); @@ -135,6 +49,14 @@ impl App { /// The Vulkan handles and associated properties used by our Vulkan app. #[derive(Clone, Debug, Default)] -struct AppData { +pub struct AppData { messenger: vk::DebugUtilsMessengerEXT, } + +#[derive(Debug, Error)] +#[error("Missing {0}.")] +pub struct SuitabilityError(pub &'static str); + +unsafe fn pick_physical_device(instance: &Instance, data: &mut AppData) -> Result<()> { + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f74b7e9 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,110 @@ +mod app; +pub use app::App; +use app::AppData; + +use ::anyhow::{anyhow, Result}; +use ::log::*; +use ::std::collections::HashSet; +use ::std::ffi::CStr; +use ::std::os::raw::c_void; +use ::vulkanalia::prelude::v1_0::*; +use ::vulkanalia::window as vk_window; +use ::winit::window::Window; + +pub const VALIDATION_ENABLED: bool = cfg!(debug_assertions); +pub const VALIDATION_LAYER: vk::ExtensionName = + vk::ExtensionName::from_bytes(b"VK_LAYER_KHRONOS_validation"); + +pub fn create_app(window: &Window) -> Result { + Ok(unsafe { App::create(&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 +} + +pub(crate) unsafe fn create_instance( + window: &Window, + entry: &Entry, + data: &mut AppData, +) -> Result { + 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)); + + 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() + }; + + 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 entry + .enumerate_instance_extension_properties(None)? + .iter() + .any(|e| e.extension_name == vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name) + { + extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr()); + vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR + } else { + vk::InstanceCreateFlags::empty() + }; + + 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)?; + + Ok(instance) +} diff --git a/src/main.rs b/src/main.rs index 9cd8711..fe35988 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,10 @@ -// #![allow( -// dead_code, -// unused_variables, -// clippy::too_many_arguments, -// clippy::unnecessary_wraps -// )] +use ::anyhow::Result; +use ::winit::dpi::LogicalSize; +use ::winit::event::{Event, WindowEvent}; +use ::winit::event_loop::{ControlFlow, EventLoop}; +use ::winit::window::WindowBuilder; -mod app; -use app::App; - -use anyhow::Result; -use winit::dpi::LogicalSize; -use winit::event::{Event, WindowEvent}; -use winit::event_loop::{ControlFlow, EventLoop}; -use winit::window::WindowBuilder; +use vulkan_tutorial::create_app; fn main() -> Result<()> { pretty_env_logger::init(); @@ -25,7 +17,7 @@ fn main() -> Result<()> { .build(&event_loop)?; // App - let mut app = unsafe { App::create(&window)? }; + let mut app = create_app(&window)?; let mut destroying = false; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll;