Compare commits

..

2 commits

Author SHA1 Message Date
0e523e13ba WIP validation layers implementation
TODO: Rest of https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers
2024-03-04 12:25:12 +09:00
9bbc5e156a Unify C headers
Both headers are actually included at the same time by glfw3.h .
2024-03-04 12:08:25 +09:00
2 changed files with 87 additions and 48 deletions

View file

@ -7,24 +7,14 @@ fn main() {
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let vk_bindings = bindgen::Builder::default() let glfw_vk_bindings = bindgen::Builder::default()
.header("/usr/include/vulkan/vulkan.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.generate()
.expect("Unable to generate vulkan bindings");
vk_bindings
.write_to_file(out_path.join("vk_bindings.rs"))
.expect("Couldn't write vk bindings!");
let glfw_bindings = bindgen::Builder::default()
.header_contents("glfw_defines", "#define GLFW_INCLUDE_VULKAN") .header_contents("glfw_defines", "#define GLFW_INCLUDE_VULKAN")
.header("/usr/include/GLFW/glfw3.h") .header("/usr/include/GLFW/glfw3.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.generate() .generate()
.expect("Unable to generate glfw bindings"); .expect("Unable to generate glfw bindings");
glfw_bindings glfw_vk_bindings
.write_to_file(out_path.join("glfw_bindings.rs")) .write_to_file(out_path.join("glfw_vk_bindings.rs"))
.expect("Couldn't write glfw bindings!"); .expect("Couldn't write glfw bindings!");
} }

View file

@ -1,36 +1,36 @@
mod ffi_vk { mod ffi {
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(non_snake_case)] #![allow(non_snake_case)]
#![allow(unused_imports)] #![allow(unused_imports)]
#![allow(dead_code)] #![allow(dead_code)]
include!(concat!(env!("OUT_DIR"), "/vk_bindings.rs")); include!(concat!(env!("OUT_DIR"), "/glfw_vk_bindings.rs"));
pub fn VK_MAKE_VERSION(major: u32, minor: u32, patch: u32) -> u32 { pub fn VK_MAKE_VERSION(major: u32, minor: u32, patch: u32) -> u32 {
(major << 22) | (minor << 12) | patch (major << 22) | (minor << 12) | patch
} }
pub fn VK_MAKE_API_VERSION(variant: u32, major: u32, minor: u32, patch: u32) -> u32 { pub fn VK_MAKE_API_VERSION(variant: u32, major: u32, minor: u32, patch: u32) -> u32 {
(variant << 29) | (major << 22) | (minor << 12) | patch (variant << 29) | (major << 22) | (minor << 12) | patch
} }
} }
mod ffi_glfw { use std::ffi::{CStr, CString};
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused_imports)]
#![allow(dead_code)]
include!(concat!(env!("OUT_DIR"), "/glfw_bindings.rs"));
}
use std::ffi::CString;
const WINDOW_WIDTH: i32 = 800; const WINDOW_WIDTH: i32 = 800;
const WINDOW_HEIGHT: i32 = 600; const WINDOW_HEIGHT: i32 = 600;
#[cfg(debug_assertions)]
const ENABLE_VALIDATION_LAYERS: bool = true;
#[cfg(not(debug_assertions))]
const ENABLE_VALIDATION_LAYERS: bool = false;
const VALIDATION_LAYER_STR_0: &str = "VK_LAYER_KHRONOS_validation\x00";
const VALIDATION_LAYERS: [&str; 1] = [VALIDATION_LAYER_STR_0];
struct VulkanApp { struct VulkanApp {
window: *mut ffi_glfw::GLFWwindow, window: *mut ffi::GLFWwindow,
vk_instance: ffi_vk::VkInstance, vk_instance: ffi::VkInstance,
} }
impl VulkanApp { impl VulkanApp {
@ -44,13 +44,13 @@ impl VulkanApp {
fn init_glfw(&mut self) { fn init_glfw(&mut self) {
let app_title = CString::new("Vulkan").unwrap(); let app_title = CString::new("Vulkan").unwrap();
unsafe { unsafe {
ffi_glfw::glfwInit(); ffi::glfwInit();
ffi_glfw::glfwWindowHint( ffi::glfwWindowHint(
ffi_glfw::GLFW_CLIENT_API as i32, ffi::GLFW_CLIENT_API as i32,
ffi_glfw::GLFW_NO_API as i32, ffi::GLFW_NO_API as i32,
); );
ffi_glfw::glfwWindowHint(ffi_glfw::GLFW_RESIZABLE as i32, ffi_glfw::GLFW_FALSE as i32); ffi::glfwWindowHint(ffi::GLFW_RESIZABLE as i32, ffi::GLFW_FALSE as i32);
self.window = ffi_glfw::glfwCreateWindow( self.window = ffi::glfwCreateWindow(
WINDOW_WIDTH, WINDOW_WIDTH,
WINDOW_HEIGHT, WINDOW_HEIGHT,
app_title.as_ptr(), app_title.as_ptr(),
@ -64,17 +64,22 @@ impl VulkanApp {
} }
fn init_vulkan(&mut self) { fn init_vulkan(&mut self) {
// Check validation layers before creating instance.
if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() {
panic!("Validation layers requested, but not available!");
}
// Create instance. // Create instance.
let app_name = CString::new("Vulkan Triangle").unwrap(); let app_name = CString::new("Vulkan Triangle").unwrap();
let engine_name = CString::new("No Engine").unwrap(); let engine_name = CString::new("No Engine").unwrap();
let app_info = ffi_vk::VkApplicationInfo { let app_info = ffi::VkApplicationInfo {
sType: ffi_vk::VkStructureType_VK_STRUCTURE_TYPE_APPLICATION_INFO, sType: ffi::VkStructureType_VK_STRUCTURE_TYPE_APPLICATION_INFO,
pNext: std::ptr::null_mut(), pNext: std::ptr::null_mut(),
pApplicationName: app_name.as_ptr(), pApplicationName: app_name.as_ptr(),
applicationVersion: ffi_vk::VK_MAKE_VERSION(1, 0, 0), applicationVersion: ffi::VK_MAKE_VERSION(1, 0, 0),
pEngineName: engine_name.as_ptr(), pEngineName: engine_name.as_ptr(),
engineVersion: ffi_vk::VK_MAKE_VERSION(1, 0, 0), engineVersion: ffi::VK_MAKE_VERSION(1, 0, 0),
apiVersion: ffi_vk::VK_MAKE_API_VERSION(0, 1, 0, 0), apiVersion: ffi::VK_MAKE_API_VERSION(0, 1, 0, 0),
}; };
// Populate VkInstanceCreateInfo. // Populate VkInstanceCreateInfo.
@ -83,12 +88,12 @@ impl VulkanApp {
let mut ext_count: u32 = 0; let mut ext_count: u32 = 0;
let exts: *mut *const std::ffi::c_char; let exts: *mut *const std::ffi::c_char;
unsafe { unsafe {
exts = ffi_glfw::glfwGetRequiredInstanceExtensions(std::ptr::addr_of_mut!(ext_count)); exts = ffi::glfwGetRequiredInstanceExtensions(std::ptr::addr_of_mut!(ext_count));
} }
// Second populate the struct with necessary info. // Second populate the struct with necessary info.
let create_info = ffi_vk::VkInstanceCreateInfo { let create_info = ffi::VkInstanceCreateInfo {
sType: ffi_vk::VkStructureType_VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, sType: ffi::VkStructureType_VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
pNext: std::ptr::null(), pNext: std::ptr::null(),
flags: 0, flags: 0,
pApplicationInfo: std::ptr::addr_of!(app_info), pApplicationInfo: std::ptr::addr_of!(app_info),
@ -99,18 +104,62 @@ impl VulkanApp {
}; };
let vk_result = unsafe { let vk_result = unsafe {
ffi_vk::vkCreateInstance( ffi::vkCreateInstance(
std::ptr::addr_of!(create_info), std::ptr::addr_of!(create_info),
std::ptr::null(), std::ptr::null(),
std::ptr::addr_of_mut!(self.vk_instance), std::ptr::addr_of_mut!(self.vk_instance),
) )
}; };
if vk_result != ffi_vk::VkResult_VK_SUCCESS { if vk_result != ffi::VkResult_VK_SUCCESS {
panic!("ERROR: Failed to create vk instance!"); panic!("ERROR: Failed to create vk instance!");
} }
} }
fn check_validation_layer_support() -> bool {
let mut layer_count: u32 = 0;
unsafe {
ffi::vkEnumerateInstanceLayerProperties(
std::ptr::addr_of_mut!(layer_count),
std::ptr::null_mut(),
);
}
let mut layers: Vec<ffi::VkLayerProperties> = Vec::with_capacity(layer_count as usize);
layers.resize(
layer_count as usize,
ffi::VkLayerProperties {
layerName: [0; 256],
specVersion: 0,
implementationVersion: 0,
description: [0; 256],
},
);
unsafe {
ffi::vkEnumerateInstanceLayerProperties(std::ptr::addr_of_mut!(layer_count), layers.as_mut_ptr());
}
for layer_name in VALIDATION_LAYERS {
let mut layer_found = false;
let ln_cstr = unsafe { CStr::from_ptr(layer_name.as_ptr() as *const i8) };
for layer_prop in &layers {
let lp_cstr: &CStr = unsafe { CStr::from_ptr(layer_prop.layerName.as_ptr()) };
if ln_cstr == lp_cstr {
layer_found = true;
break;
}
}
if !layer_found {
return false;
}
}
println!("Validation layers available");
true
}
fn main_loop(&mut self) { fn main_loop(&mut self) {
if self.window.is_null() { if self.window.is_null() {
panic!("ERROR: Cannot execute main loop if window is null!"); panic!("ERROR: Cannot execute main loop if window is null!");
@ -122,10 +171,10 @@ impl VulkanApp {
loop { loop {
unsafe { unsafe {
if ffi_glfw::glfwWindowShouldClose(self.window) != 0 { if ffi::glfwWindowShouldClose(self.window) != 0 {
return; return;
} }
ffi_glfw::glfwPollEvents(); ffi::glfwPollEvents();
} }
} }
} }
@ -135,18 +184,18 @@ impl Drop for VulkanApp {
fn drop(&mut self) { fn drop(&mut self) {
if !self.vk_instance.is_null() { if !self.vk_instance.is_null() {
unsafe { unsafe {
ffi_vk::vkDestroyInstance(self.vk_instance, std::ptr::null()); ffi::vkDestroyInstance(self.vk_instance, std::ptr::null());
} }
} }
if !self.window.is_null() { if !self.window.is_null() {
unsafe { unsafe {
ffi_glfw::glfwDestroyWindow(self.window); ffi::glfwDestroyWindow(self.window);
} }
} }
unsafe { unsafe {
ffi_glfw::glfwTerminate(); ffi::glfwTerminate();
} }
} }
} }