init
This commit is contained in:
		
							
								
								
									
										30
									
								
								src/utility/constants.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/utility/constants.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
use crate::utility::debug::ValidationInfo;
 | 
			
		||||
use crate::utility::structures::DeviceExtension;
 | 
			
		||||
use ash::vk_make_version;
 | 
			
		||||
 | 
			
		||||
use std::os::raw::c_char;
 | 
			
		||||
 | 
			
		||||
pub const APPLICATION_VERSION: u32 = vk_make_version!(1, 0, 0);
 | 
			
		||||
pub const ENGINE_VERSION: u32 = vk_make_version!(1, 0, 0);
 | 
			
		||||
pub const API_VERSION: u32 = vk_make_version!(1, 0, 92);
 | 
			
		||||
 | 
			
		||||
pub const WINDOW_WIDTH: u32 = 800;
 | 
			
		||||
pub const WINDOW_HEIGHT: u32 = 600;
 | 
			
		||||
pub const VALIDATION: ValidationInfo = ValidationInfo {
 | 
			
		||||
    is_enable: true,
 | 
			
		||||
    required_validation_layers: ["VK_LAYER_KHRONOS_validation"],
 | 
			
		||||
};
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
impl DeviceExtension {
 | 
			
		||||
    pub fn get_extensions_raw_names(&self) -> [*const c_char; 1] {
 | 
			
		||||
        [
 | 
			
		||||
            // currently just enable the Swapchain extension.
 | 
			
		||||
            ash::extensions::khr::Swapchain::name().as_ptr(),
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								src/utility/debug.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/utility/debug.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,109 @@
 | 
			
		||||
use ash::version::EntryV1_0;
 | 
			
		||||
use ash::vk;
 | 
			
		||||
 | 
			
		||||
use std::ffi::CStr;
 | 
			
		||||
use std::os::raw::c_void;
 | 
			
		||||
use std::ptr;
 | 
			
		||||
 | 
			
		||||
unsafe extern "system" fn vulkan_debug_utils_callback(
 | 
			
		||||
    message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
 | 
			
		||||
    message_type: vk::DebugUtilsMessageTypeFlagsEXT,
 | 
			
		||||
    p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT,
 | 
			
		||||
    _p_user_data: *mut c_void,
 | 
			
		||||
) -> vk::Bool32 {
 | 
			
		||||
    let severity = match message_severity {
 | 
			
		||||
        vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => "[Verbose]",
 | 
			
		||||
        vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => "[Warning]",
 | 
			
		||||
        vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => "[Error]",
 | 
			
		||||
        vk::DebugUtilsMessageSeverityFlagsEXT::INFO => "[Info]",
 | 
			
		||||
        _ => "[Unknown]",
 | 
			
		||||
    };
 | 
			
		||||
    let types = match message_type {
 | 
			
		||||
        vk::DebugUtilsMessageTypeFlagsEXT::GENERAL => "[General]",
 | 
			
		||||
        vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE => "[Performance]",
 | 
			
		||||
        vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION => "[Validation]",
 | 
			
		||||
        _ => "[Unknown]",
 | 
			
		||||
    };
 | 
			
		||||
    let message = CStr::from_ptr((*p_callback_data).p_message);
 | 
			
		||||
    println!("[Debug]{}{}{:?}", severity, types, message);
 | 
			
		||||
 | 
			
		||||
    vk::FALSE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct ValidationInfo {
 | 
			
		||||
    pub is_enable: bool,
 | 
			
		||||
    pub required_validation_layers: [&'static str; 1],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn check_validation_layer_support(
 | 
			
		||||
    entry: &ash::Entry,
 | 
			
		||||
    required_validation_layers: &Vec<&str>,
 | 
			
		||||
) -> bool {
 | 
			
		||||
    // if support validation layer, then return true
 | 
			
		||||
 | 
			
		||||
    let layer_properties = entry
 | 
			
		||||
        .enumerate_instance_layer_properties()
 | 
			
		||||
        .expect("Failed to enumerate Instance Layers Properties");
 | 
			
		||||
 | 
			
		||||
    if layer_properties.len() <= 0 {
 | 
			
		||||
        eprintln!("No available layers.");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for required_layer_name in required_validation_layers.iter() {
 | 
			
		||||
        let mut is_layer_found = false;
 | 
			
		||||
 | 
			
		||||
        for layer_property in layer_properties.iter() {
 | 
			
		||||
            let test_layer_name = super::tools::vk_to_string(&layer_property.layer_name);
 | 
			
		||||
            if (*required_layer_name) == test_layer_name {
 | 
			
		||||
                is_layer_found = true;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if is_layer_found == false {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn setup_debug_utils(
 | 
			
		||||
    is_enable_debug: bool,
 | 
			
		||||
    entry: &ash::Entry,
 | 
			
		||||
    instance: &ash::Instance,
 | 
			
		||||
) -> (ash::extensions::ext::DebugUtils, vk::DebugUtilsMessengerEXT) {
 | 
			
		||||
    let debug_utils_loader = ash::extensions::ext::DebugUtils::new(entry, instance);
 | 
			
		||||
 | 
			
		||||
    if is_enable_debug == false {
 | 
			
		||||
        (debug_utils_loader, ash::vk::DebugUtilsMessengerEXT::null())
 | 
			
		||||
    } else {
 | 
			
		||||
        let messenger_ci = populate_debug_messenger_create_info();
 | 
			
		||||
 | 
			
		||||
        let utils_messenger = unsafe {
 | 
			
		||||
            debug_utils_loader
 | 
			
		||||
                .create_debug_utils_messenger(&messenger_ci, None)
 | 
			
		||||
                .expect("Debug Utils Callback")
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        (debug_utils_loader, utils_messenger)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn populate_debug_messenger_create_info() -> vk::DebugUtilsMessengerCreateInfoEXT {
 | 
			
		||||
    vk::DebugUtilsMessengerCreateInfoEXT {
 | 
			
		||||
        s_type: vk::StructureType::DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
 | 
			
		||||
        p_next: ptr::null(),
 | 
			
		||||
        flags: vk::DebugUtilsMessengerCreateFlagsEXT::empty(),
 | 
			
		||||
        message_severity: vk::DebugUtilsMessageSeverityFlagsEXT::WARNING |
 | 
			
		||||
            // vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE |
 | 
			
		||||
            // vk::DebugUtilsMessageSeverityFlagsEXT::INFO |
 | 
			
		||||
            vk::DebugUtilsMessageSeverityFlagsEXT::ERROR,
 | 
			
		||||
        message_type: vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
 | 
			
		||||
            | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE
 | 
			
		||||
            | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION,
 | 
			
		||||
        pfn_user_callback: Some(vulkan_debug_utils_callback),
 | 
			
		||||
        p_user_data: ptr::null_mut(),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								src/utility/fps_limiter.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/utility/fps_limiter.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,67 @@
 | 
			
		||||
use std::thread;
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
use std::time::Instant;
 | 
			
		||||
 | 
			
		||||
const SAMPLE_COUNT: usize = 5;
 | 
			
		||||
const SAMPLE_COUNT_FLOAT: f32 = SAMPLE_COUNT as f32;
 | 
			
		||||
 | 
			
		||||
pub struct FPSLimiter {
 | 
			
		||||
    counter: Instant,
 | 
			
		||||
    frame_time_prefer: u32, // unit microseconds
 | 
			
		||||
    samples: [u32; SAMPLE_COUNT],
 | 
			
		||||
    current_frame: usize,
 | 
			
		||||
    delta_frame: u32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl FPSLimiter {
 | 
			
		||||
    pub fn new() -> FPSLimiter {
 | 
			
		||||
        const DEFAULT_PREFER_FPS: f32 = 60.0;
 | 
			
		||||
 | 
			
		||||
        FPSLimiter {
 | 
			
		||||
            counter: Instant::now(),
 | 
			
		||||
            frame_time_prefer: (1000_000.0_f32 / DEFAULT_PREFER_FPS) as u32,
 | 
			
		||||
            samples: [0; SAMPLE_COUNT],
 | 
			
		||||
            current_frame: 0,
 | 
			
		||||
            delta_frame: 0,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn set_prefer_fps(&mut self, prefer_fps: f32) {
 | 
			
		||||
        self.frame_time_prefer = (1000_000.0_f32 / prefer_fps) as u32;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Call this function in game loop to update its inner status.
 | 
			
		||||
    pub fn tick_frame(&mut self) {
 | 
			
		||||
        let time_elapsed = self.counter.elapsed();
 | 
			
		||||
        self.counter = Instant::now();
 | 
			
		||||
 | 
			
		||||
        self.delta_frame = time_elapsed.subsec_micros();
 | 
			
		||||
        self.samples[self.current_frame] = self.delta_frame;
 | 
			
		||||
        self.current_frame = (self.current_frame + 1) % SAMPLE_COUNT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: this function seems not work.
 | 
			
		||||
    pub fn keep_fps(&self) {
 | 
			
		||||
        if self.frame_time_prefer > self.delta_frame {
 | 
			
		||||
            let delay = Duration::from_micros((self.frame_time_prefer - self.delta_frame) as u64);
 | 
			
		||||
 | 
			
		||||
            thread::sleep(delay);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Calculate the current FPS.
 | 
			
		||||
    pub fn fps(&self) -> f32 {
 | 
			
		||||
        let mut sum = 0_u32;
 | 
			
		||||
        self.samples.iter().for_each(|val| {
 | 
			
		||||
            sum += val;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        1000_000.0_f32 / (sum as f32 / SAMPLE_COUNT_FLOAT)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Return current delta time in seconds
 | 
			
		||||
    /// this function ignore its second part, since the second is mostly zero.
 | 
			
		||||
    pub fn delta_time(&self) -> f32 {
 | 
			
		||||
        self.delta_frame as f32 / 1000_000.0_f32 // time in second
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										134
									
								
								src/utility/platforms.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								src/utility/platforms.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,134 @@
 | 
			
		||||
use ash::version::{EntryV1_0, InstanceV1_0};
 | 
			
		||||
use ash::vk;
 | 
			
		||||
 | 
			
		||||
#[cfg(target_os = "windows")]
 | 
			
		||||
use ash::extensions::khr::Win32Surface;
 | 
			
		||||
#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
 | 
			
		||||
use ash::extensions::khr::XlibSurface;
 | 
			
		||||
#[cfg(target_os = "macos")]
 | 
			
		||||
use ash::extensions::mvk::MacOSSurface;
 | 
			
		||||
 | 
			
		||||
use ash::extensions::ext::DebugUtils;
 | 
			
		||||
use ash::extensions::khr::Surface;
 | 
			
		||||
 | 
			
		||||
#[cfg(target_os = "macos")]
 | 
			
		||||
use cocoa::appkit::{NSView, NSWindow};
 | 
			
		||||
#[cfg(target_os = "macos")]
 | 
			
		||||
use cocoa::base::id as cocoa_id;
 | 
			
		||||
#[cfg(target_os = "macos")]
 | 
			
		||||
use metal::CoreAnimationLayer;
 | 
			
		||||
#[cfg(target_os = "macos")]
 | 
			
		||||
use objc::runtime::YES;
 | 
			
		||||
 | 
			
		||||
// required extension ------------------------------------------------------
 | 
			
		||||
#[cfg(target_os = "macos")]
 | 
			
		||||
pub fn required_extension_names() -> Vec<*const i8> {
 | 
			
		||||
    vec![
 | 
			
		||||
        Surface::name().as_ptr(),
 | 
			
		||||
        MacOSSurface::name().as_ptr(),
 | 
			
		||||
        DebugUtils::name().as_ptr(),
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(all(windows))]
 | 
			
		||||
pub fn required_extension_names() -> Vec<*const i8> {
 | 
			
		||||
    vec![
 | 
			
		||||
        Surface::name().as_ptr(),
 | 
			
		||||
        Win32Surface::name().as_ptr(),
 | 
			
		||||
        DebugUtils::name().as_ptr(),
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
 | 
			
		||||
pub fn required_extension_names() -> Vec<*const i8> {
 | 
			
		||||
    vec![
 | 
			
		||||
        Surface::name().as_ptr(),
 | 
			
		||||
        XlibSurface::name().as_ptr(),
 | 
			
		||||
        DebugUtils::name().as_ptr(),
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// create surface ---------------------------------------------------------
 | 
			
		||||
#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
 | 
			
		||||
pub unsafe fn create_surface<E: EntryV1_0, I: InstanceV1_0>(
 | 
			
		||||
    entry: &E,
 | 
			
		||||
    instance: &I,
 | 
			
		||||
    window: &winit::window::Window,
 | 
			
		||||
) -> Result<vk::SurfaceKHR, vk::Result> {
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
    use winit::platform::unix::WindowExtUnix;
 | 
			
		||||
 | 
			
		||||
    let x11_display = window.xlib_display().unwrap();
 | 
			
		||||
    let x11_window = window.xlib_window().unwrap();
 | 
			
		||||
    let x11_create_info = vk::XlibSurfaceCreateInfoKHR {
 | 
			
		||||
        s_type: vk::StructureType::XLIB_SURFACE_CREATE_INFO_KHR,
 | 
			
		||||
        p_next: ptr::null(),
 | 
			
		||||
        flags: Default::default(),
 | 
			
		||||
        window: x11_window as vk::Window,
 | 
			
		||||
        dpy: x11_display as *mut vk::Display,
 | 
			
		||||
    };
 | 
			
		||||
    let xlib_surface_loader = XlibSurface::new(entry, instance);
 | 
			
		||||
    xlib_surface_loader.create_xlib_surface(&x11_create_info, None)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(target_os = "macos")]
 | 
			
		||||
pub unsafe fn create_surface<E: EntryV1_0, I: InstanceV1_0>(
 | 
			
		||||
    entry: &E,
 | 
			
		||||
    instance: &I,
 | 
			
		||||
    window: &winit::window::Window,
 | 
			
		||||
) -> Result<vk::SurfaceKHR, vk::Result> {
 | 
			
		||||
    use std::mem;
 | 
			
		||||
    use std::os::raw::c_void;
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
    use winit::platform::macos::WindowExtMacOS;
 | 
			
		||||
 | 
			
		||||
    let wnd: cocoa_id = mem::transmute(window.ns_window());
 | 
			
		||||
 | 
			
		||||
    let layer = CoreAnimationLayer::new();
 | 
			
		||||
 | 
			
		||||
    layer.set_edge_antialiasing_mask(0);
 | 
			
		||||
    layer.set_presents_with_transaction(false);
 | 
			
		||||
    layer.remove_all_animations();
 | 
			
		||||
 | 
			
		||||
    let view = wnd.contentView();
 | 
			
		||||
 | 
			
		||||
    layer.set_contents_scale(view.backingScaleFactor());
 | 
			
		||||
    view.setLayer(mem::transmute(layer.as_ref()));
 | 
			
		||||
    view.setWantsLayer(YES);
 | 
			
		||||
 | 
			
		||||
    let create_info = vk::MacOSSurfaceCreateInfoMVK {
 | 
			
		||||
        s_type: vk::StructureType::MACOS_SURFACE_CREATE_INFO_M,
 | 
			
		||||
        p_next: ptr::null(),
 | 
			
		||||
        flags: Default::default(),
 | 
			
		||||
        p_view: window.ns_view() as *const c_void,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let macos_surface_loader = MacOSSurface::new(entry, instance);
 | 
			
		||||
    macos_surface_loader.create_mac_os_surface_mvk(&create_info, None)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(target_os = "windows")]
 | 
			
		||||
pub unsafe fn create_surface<E: EntryV1_0, I: InstanceV1_0>(
 | 
			
		||||
    entry: &E,
 | 
			
		||||
    instance: &I,
 | 
			
		||||
    window: &winit::window::Window,
 | 
			
		||||
) -> Result<vk::SurfaceKHR, vk::Result> {
 | 
			
		||||
    use std::os::raw::c_void;
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
    use winapi::shared::windef::HWND;
 | 
			
		||||
    use winapi::um::libloaderapi::GetModuleHandleW;
 | 
			
		||||
    use winit::platform::windows::WindowExtWindows;
 | 
			
		||||
 | 
			
		||||
    let hwnd = window.hwnd() as HWND;
 | 
			
		||||
    let hinstance = GetModuleHandleW(ptr::null()) as *const c_void;
 | 
			
		||||
    let win32_create_info = vk::Win32SurfaceCreateInfoKHR {
 | 
			
		||||
        s_type: vk::StructureType::WIN32_SURFACE_CREATE_INFO_KHR,
 | 
			
		||||
        p_next: ptr::null(),
 | 
			
		||||
        flags: Default::default(),
 | 
			
		||||
        hinstance,
 | 
			
		||||
        hwnd: hwnd as *const c_void,
 | 
			
		||||
    };
 | 
			
		||||
    let win32_surface_loader = Win32Surface::new(entry, instance);
 | 
			
		||||
    win32_surface_loader.create_win32_surface(&win32_create_info, None)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2169
									
								
								src/utility/share.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2169
									
								
								src/utility/share.rs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										155
									
								
								src/utility/structures.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/utility/structures.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,155 @@
 | 
			
		||||
use ash::vk;
 | 
			
		||||
use cgmath::Matrix4;
 | 
			
		||||
 | 
			
		||||
use memoffset::offset_of;
 | 
			
		||||
 | 
			
		||||
pub struct DeviceExtension {
 | 
			
		||||
    pub names: [&'static str; 1],
 | 
			
		||||
    //    pub raw_names: [*const i8; 1],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct SurfaceStuff {
 | 
			
		||||
    pub surface_loader: ash::extensions::khr::Surface,
 | 
			
		||||
    pub surface: vk::SurfaceKHR,
 | 
			
		||||
 | 
			
		||||
    pub screen_width: u32,
 | 
			
		||||
    pub screen_height: u32,
 | 
			
		||||
}
 | 
			
		||||
pub struct SwapChainStuff {
 | 
			
		||||
    pub swapchain_loader: ash::extensions::khr::Swapchain,
 | 
			
		||||
    pub swapchain: vk::SwapchainKHR,
 | 
			
		||||
    pub swapchain_images: Vec<vk::Image>,
 | 
			
		||||
    pub swapchain_format: vk::Format,
 | 
			
		||||
    pub swapchain_extent: vk::Extent2D,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct SwapChainSupportDetail {
 | 
			
		||||
    pub capabilities: vk::SurfaceCapabilitiesKHR,
 | 
			
		||||
    pub formats: Vec<vk::SurfaceFormatKHR>,
 | 
			
		||||
    pub present_modes: Vec<vk::PresentModeKHR>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct QueueFamilyIndices {
 | 
			
		||||
    pub graphics_family: Option<u32>,
 | 
			
		||||
    pub present_family: Option<u32>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl QueueFamilyIndices {
 | 
			
		||||
    pub fn new() -> QueueFamilyIndices {
 | 
			
		||||
        QueueFamilyIndices {
 | 
			
		||||
            graphics_family: None,
 | 
			
		||||
            present_family: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn is_complete(&self) -> bool {
 | 
			
		||||
        self.graphics_family.is_some() && self.present_family.is_some()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct SyncObjects {
 | 
			
		||||
    pub image_available_semaphores: Vec<vk::Semaphore>,
 | 
			
		||||
    pub render_finished_semaphores: Vec<vk::Semaphore>,
 | 
			
		||||
    pub inflight_fences: Vec<vk::Fence>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
#[derive(Clone, Debug, Copy)]
 | 
			
		||||
pub struct UniformBufferObject {
 | 
			
		||||
    pub model: Matrix4<f32>,
 | 
			
		||||
    pub view: Matrix4<f32>,
 | 
			
		||||
    pub proj: Matrix4<f32>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
#[derive(Clone, Debug, Copy)]
 | 
			
		||||
pub struct VertexV1 {
 | 
			
		||||
    pub pos: [f32; 2],
 | 
			
		||||
    pub color: [f32; 3],
 | 
			
		||||
}
 | 
			
		||||
impl VertexV1 {
 | 
			
		||||
    pub fn get_binding_description() -> [vk::VertexInputBindingDescription; 1] {
 | 
			
		||||
        [vk::VertexInputBindingDescription {
 | 
			
		||||
            binding: 0,
 | 
			
		||||
            stride: ::std::mem::size_of::<VertexV1>() 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!(VertexV1, pos) as u32,
 | 
			
		||||
            },
 | 
			
		||||
            vk::VertexInputAttributeDescription {
 | 
			
		||||
                binding: 0,
 | 
			
		||||
                location: 1,
 | 
			
		||||
                format: vk::Format::R32G32B32_SFLOAT,
 | 
			
		||||
                offset: offset_of!(VertexV1, color) as u32,
 | 
			
		||||
            },
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
pub struct VertexV3 {
 | 
			
		||||
    pub pos: [f32; 4],
 | 
			
		||||
    pub color: [f32; 4],
 | 
			
		||||
    pub tex_coord: [f32; 2],
 | 
			
		||||
}
 | 
			
		||||
impl VertexV3 {
 | 
			
		||||
    pub fn get_binding_descriptions() -> [vk::VertexInputBindingDescription; 1] {
 | 
			
		||||
        [vk::VertexInputBindingDescription {
 | 
			
		||||
            binding: 0,
 | 
			
		||||
            stride: ::std::mem::size_of::<Self>() as u32,
 | 
			
		||||
            input_rate: vk::VertexInputRate::VERTEX,
 | 
			
		||||
        }]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 3] {
 | 
			
		||||
        [
 | 
			
		||||
            vk::VertexInputAttributeDescription {
 | 
			
		||||
                binding: 0,
 | 
			
		||||
                location: 0,
 | 
			
		||||
                format: vk::Format::R32G32B32A32_SFLOAT,
 | 
			
		||||
                offset: offset_of!(Self, pos) as u32,
 | 
			
		||||
            },
 | 
			
		||||
            vk::VertexInputAttributeDescription {
 | 
			
		||||
                binding: 0,
 | 
			
		||||
                location: 1,
 | 
			
		||||
                format: vk::Format::R32G32B32A32_SFLOAT,
 | 
			
		||||
                offset: offset_of!(Self, color) as u32,
 | 
			
		||||
            },
 | 
			
		||||
            vk::VertexInputAttributeDescription {
 | 
			
		||||
                binding: 0,
 | 
			
		||||
                location: 2,
 | 
			
		||||
                format: vk::Format::R32G32_SFLOAT,
 | 
			
		||||
                offset: offset_of!(Self, tex_coord) as u32,
 | 
			
		||||
            },
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub const RECT_VERTICES_DATA: [VertexV1; 4] = [
 | 
			
		||||
    VertexV1 {
 | 
			
		||||
        pos: [-0.5, -0.5],
 | 
			
		||||
        color: [1.0, 0.0, 0.0],
 | 
			
		||||
    },
 | 
			
		||||
    VertexV1 {
 | 
			
		||||
        pos: [0.5, -0.5],
 | 
			
		||||
        color: [0.0, 1.0, 0.0],
 | 
			
		||||
    },
 | 
			
		||||
    VertexV1 {
 | 
			
		||||
        pos: [0.5, 0.5],
 | 
			
		||||
        color: [0.0, 0.0, 1.0],
 | 
			
		||||
    },
 | 
			
		||||
    VertexV1 {
 | 
			
		||||
        pos: [-0.5, 0.5],
 | 
			
		||||
        color: [1.0, 1.0, 1.0],
 | 
			
		||||
    },
 | 
			
		||||
];
 | 
			
		||||
pub const RECT_INDICES_DATA: [u32; 6] = [0, 1, 2, 2, 3, 0];
 | 
			
		||||
							
								
								
									
										46
									
								
								src/utility/tools.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/utility/tools.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
			
		||||
use std::ffi::CStr;
 | 
			
		||||
use std::os::raw::c_char;
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
 | 
			
		||||
/// Helper function to convert [c_char; SIZE] to string
 | 
			
		||||
pub fn vk_to_string(raw_string_array: &[c_char]) -> String {
 | 
			
		||||
    // Implementation 1
 | 
			
		||||
    //    let end = '\0' as u8;
 | 
			
		||||
    //
 | 
			
		||||
    //    let mut content: Vec<u8> = vec![];
 | 
			
		||||
    //
 | 
			
		||||
    //    for ch in raw_string_array.iter() {
 | 
			
		||||
    //        let ch = (*ch) as u8;
 | 
			
		||||
    //
 | 
			
		||||
    //        if ch != end {
 | 
			
		||||
    //            content.push(ch);
 | 
			
		||||
    //        } else {
 | 
			
		||||
    //            break
 | 
			
		||||
    //        }
 | 
			
		||||
    //    }
 | 
			
		||||
    //
 | 
			
		||||
    //    String::from_utf8(content)
 | 
			
		||||
    //        .expect("Failed to convert vulkan raw string")
 | 
			
		||||
 | 
			
		||||
    // Implementation 2
 | 
			
		||||
    let raw_string = unsafe {
 | 
			
		||||
        let pointer = raw_string_array.as_ptr();
 | 
			
		||||
        CStr::from_ptr(pointer)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    raw_string
 | 
			
		||||
        .to_str()
 | 
			
		||||
        .expect("Failed to convert vulkan raw string.")
 | 
			
		||||
        .to_owned()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn read_shader_code(shader_path: &Path) -> Vec<u8> {
 | 
			
		||||
    use std::fs::File;
 | 
			
		||||
    use std::io::Read;
 | 
			
		||||
 | 
			
		||||
    let spv_file =
 | 
			
		||||
        File::open(shader_path).expect(&format!("Failed to find spv file at {:?}", shader_path));
 | 
			
		||||
    let bytes_code: Vec<u8> = spv_file.bytes().filter_map(|byte| byte.ok()).collect();
 | 
			
		||||
 | 
			
		||||
    bytes_code
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										97
									
								
								src/utility/window.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/utility/window.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,97 @@
 | 
			
		||||
use winit::event::{Event, VirtualKeyCode, ElementState, KeyboardInput, WindowEvent};
 | 
			
		||||
use winit::event_loop::{EventLoop, ControlFlow};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const IS_PAINT_FPS_COUNTER: bool = true;
 | 
			
		||||
 | 
			
		||||
pub fn init_window(
 | 
			
		||||
    event_loop: &EventLoop<()>,
 | 
			
		||||
    title: &str,
 | 
			
		||||
    width: u32,
 | 
			
		||||
    height: u32,
 | 
			
		||||
) -> winit::window::Window {
 | 
			
		||||
    winit::window::WindowBuilder::new()
 | 
			
		||||
        .with_title(title)
 | 
			
		||||
        .with_inner_size(winit::dpi::LogicalSize::new(width, height))
 | 
			
		||||
        .build(event_loop)
 | 
			
		||||
        .expect("Failed to create window.")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait VulkanApp {
 | 
			
		||||
    fn draw_frame(&mut self, delta_time: f32);
 | 
			
		||||
    fn recreate_swapchain(&mut self);
 | 
			
		||||
    fn cleanup_swapchain(&self);
 | 
			
		||||
    fn wait_device_idle(&self);
 | 
			
		||||
    fn resize_framebuffer(&mut self);
 | 
			
		||||
    fn window_ref(&self) -> &winit::window::Window;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct ProgramProc {
 | 
			
		||||
    pub event_loop: EventLoop<()>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ProgramProc {
 | 
			
		||||
 | 
			
		||||
    pub fn new() -> ProgramProc {
 | 
			
		||||
        // init window stuff
 | 
			
		||||
        let event_loop = EventLoop::new();
 | 
			
		||||
 | 
			
		||||
        ProgramProc { event_loop }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn main_loop<A: 'static + VulkanApp>(self, mut vulkan_app: A) {
 | 
			
		||||
 | 
			
		||||
        let mut tick_counter = super::fps_limiter::FPSLimiter::new();
 | 
			
		||||
 | 
			
		||||
        self.event_loop.run(move |event, _, control_flow| {
 | 
			
		||||
 | 
			
		||||
            match event {
 | 
			
		||||
                | Event::WindowEvent { event, .. } => {
 | 
			
		||||
                    match event {
 | 
			
		||||
                        | WindowEvent::CloseRequested => {
 | 
			
		||||
                            vulkan_app.wait_device_idle();
 | 
			
		||||
                            *control_flow = ControlFlow::Exit
 | 
			
		||||
                        },
 | 
			
		||||
                        | WindowEvent::KeyboardInput { input, .. } => {
 | 
			
		||||
                            match input {
 | 
			
		||||
                                | KeyboardInput { virtual_keycode, state, .. } => {
 | 
			
		||||
                                    match (virtual_keycode, state) {
 | 
			
		||||
                                        | (Some(VirtualKeyCode::Escape), ElementState::Pressed) => {
 | 
			
		||||
                                            vulkan_app.wait_device_idle();
 | 
			
		||||
                                            *control_flow = ControlFlow::Exit
 | 
			
		||||
                                        },
 | 
			
		||||
                                        | _ => {},
 | 
			
		||||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        | WindowEvent::Resized(_new_size) => {
 | 
			
		||||
                            vulkan_app.wait_device_idle();
 | 
			
		||||
                            vulkan_app.resize_framebuffer();
 | 
			
		||||
                        },
 | 
			
		||||
                        | _ => {},
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                | Event::MainEventsCleared => {
 | 
			
		||||
                    vulkan_app.window_ref().request_redraw();
 | 
			
		||||
                },
 | 
			
		||||
                | Event::RedrawRequested(_window_id) => {
 | 
			
		||||
                    let delta_time = tick_counter.delta_time();
 | 
			
		||||
                    vulkan_app.draw_frame(delta_time);
 | 
			
		||||
 | 
			
		||||
                    if IS_PAINT_FPS_COUNTER {
 | 
			
		||||
                        print!("FPS: {}\r", tick_counter.fps());
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    tick_counter.tick_frame();
 | 
			
		||||
                },
 | 
			
		||||
                | Event::LoopDestroyed => {
 | 
			
		||||
                    vulkan_app.wait_device_idle();
 | 
			
		||||
                },
 | 
			
		||||
                _ => (),
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user