Compare commits
10 commits
6194b4c1f2
...
dd676d762e
Author | SHA1 | Date | |
---|---|---|---|
dd676d762e | |||
c8289cc8dc | |||
cc275989b1 | |||
2d8ded2111 | |||
66be063ce0 | |||
d49b8acede | |||
5e9b12a0a2 | |||
62c01acc7a | |||
ac88544d2f | |||
81ff94485f |
2 changed files with 468 additions and 67 deletions
14
src/ffi.rs
Normal file
14
src/ffi.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#![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_vk_bindings.rs"));
|
||||||
|
|
||||||
|
pub fn VK_MAKE_VERSION(major: u32, minor: u32, patch: u32) -> u32 {
|
||||||
|
(major << 22) | (minor << 12) | patch
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn VK_MAKE_API_VERSION(variant: u32, major: u32, minor: u32, patch: u32) -> u32 {
|
||||||
|
(variant << 29) | (major << 22) | (minor << 12) | patch
|
||||||
|
}
|
525
src/main.rs
525
src/main.rs
|
@ -1,20 +1,6 @@
|
||||||
mod ffi {
|
mod ffi;
|
||||||
#![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_vk_bindings.rs"));
|
|
||||||
|
|
||||||
pub fn VK_MAKE_VERSION(major: u32, minor: u32, patch: u32) -> u32 {
|
|
||||||
(major << 22) | (minor << 12) | patch
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn VK_MAKE_API_VERSION(variant: u32, major: u32, minor: u32, patch: u32) -> u32 {
|
|
||||||
(variant << 29) | (major << 22) | (minor << 12) | patch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
|
|
||||||
const WINDOW_WIDTH: i32 = 800;
|
const WINDOW_WIDTH: i32 = 800;
|
||||||
|
@ -28,6 +14,9 @@ const ENABLE_VALIDATION_LAYERS: bool = false;
|
||||||
const VALIDATION_LAYER_STR_0: &str = "VK_LAYER_KHRONOS_validation\x00";
|
const VALIDATION_LAYER_STR_0: &str = "VK_LAYER_KHRONOS_validation\x00";
|
||||||
const VALIDATION_LAYERS: [*const u8; 1] = [VALIDATION_LAYER_STR_0.as_ptr()];
|
const VALIDATION_LAYERS: [*const u8; 1] = [VALIDATION_LAYER_STR_0.as_ptr()];
|
||||||
|
|
||||||
|
const DEVICE_EXTENSIONS: [*const i8; 1] =
|
||||||
|
[ffi::VK_KHR_SWAPCHAIN_EXTENSION_NAME as *const u8 as *const i8];
|
||||||
|
|
||||||
fn check_validation_layer_support() -> bool {
|
fn check_validation_layer_support() -> bool {
|
||||||
let mut layer_count: u32 = 0;
|
let mut layer_count: u32 = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -123,68 +112,43 @@ fn create_debug_messenger_create_info() -> ffi::VkDebugUtilsMessengerCreateInfoE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_device_suitable(dev: ffi::VkPhysicalDevice) -> bool {
|
|
||||||
let mut dev_props: ffi::VkPhysicalDeviceProperties = unsafe { std::mem::zeroed() };
|
|
||||||
unsafe {
|
|
||||||
ffi::vkGetPhysicalDeviceProperties(dev, std::ptr::addr_of_mut!(dev_props));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut dev_feat: ffi::VkPhysicalDeviceFeatures = unsafe { std::mem::zeroed() };
|
|
||||||
unsafe {
|
|
||||||
ffi::vkGetPhysicalDeviceFeatures(dev, std::ptr::addr_of_mut!(dev_feat));
|
|
||||||
}
|
|
||||||
|
|
||||||
// dev_props.deviceType == ffi::VkPhysicalDeviceType_VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
|
|
||||||
// && dev_feat.geometryShader != 0
|
|
||||||
|
|
||||||
// Use previous checks for specifics, but for now, accept GPUs that support "graphics family".
|
|
||||||
find_queue_families(dev).graphics_family.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
struct QueueFamilyIndices {
|
struct QueueFamilyIndices {
|
||||||
graphics_family: Option<u32>,
|
graphics_family: Option<u32>,
|
||||||
|
present_family: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_queue_families(dev: ffi::VkPhysicalDevice) -> QueueFamilyIndices {
|
impl QueueFamilyIndices {
|
||||||
let mut queue_fam = QueueFamilyIndices {
|
fn is_complete(&self) -> bool {
|
||||||
graphics_family: None,
|
self.graphics_family.is_some() && self.present_family.is_some()
|
||||||
};
|
|
||||||
|
|
||||||
let mut queue_family_count: u32 = 0;
|
|
||||||
unsafe {
|
|
||||||
ffi::vkGetPhysicalDeviceQueueFamilyProperties(
|
|
||||||
dev,
|
|
||||||
std::ptr::addr_of_mut!(queue_family_count),
|
|
||||||
std::ptr::null_mut(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut queue_family_props: Vec<ffi::VkQueueFamilyProperties> =
|
|
||||||
Vec::with_capacity(queue_family_count as usize);
|
|
||||||
queue_family_props.resize(queue_family_count as usize, unsafe { std::mem::zeroed() });
|
|
||||||
unsafe {
|
|
||||||
ffi::vkGetPhysicalDeviceQueueFamilyProperties(
|
|
||||||
dev,
|
|
||||||
std::ptr::addr_of_mut!(queue_family_count),
|
|
||||||
queue_family_props.as_mut_ptr(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (idx, queue_family_prop) in queue_family_props.iter().enumerate() {
|
|
||||||
if queue_family_prop.queueFlags & ffi::VkQueueFlagBits_VK_QUEUE_GRAPHICS_BIT != 0 {
|
|
||||||
queue_fam.graphics_family = Some(idx as u32);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_fam
|
struct SwapChainSupportDetails {
|
||||||
|
capabilities: ffi::VkSurfaceCapabilitiesKHR,
|
||||||
|
formats: Vec<ffi::VkSurfaceFormatKHR>,
|
||||||
|
present_modes: Vec<ffi::VkPresentModeKHR>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SwapChainSupportDetails {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
capabilities: unsafe { std::mem::zeroed() },
|
||||||
|
formats: Vec::new(),
|
||||||
|
present_modes: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VulkanApp {
|
struct VulkanApp {
|
||||||
window: *mut ffi::GLFWwindow,
|
window: *mut ffi::GLFWwindow,
|
||||||
vk_instance: ffi::VkInstance,
|
vk_instance: ffi::VkInstance,
|
||||||
debug_messenger: ffi::VkDebugUtilsMessengerEXT,
|
debug_messenger: ffi::VkDebugUtilsMessengerEXT,
|
||||||
|
surface: ffi::VkSurfaceKHR,
|
||||||
physical_device: ffi::VkPhysicalDevice,
|
physical_device: ffi::VkPhysicalDevice,
|
||||||
|
device: ffi::VkDevice,
|
||||||
|
graphics_queue: ffi::VkQueue,
|
||||||
|
present_queue: ffi::VkQueue,
|
||||||
|
swap_chain: ffi::VkSwapchainKHR,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VulkanApp {
|
impl VulkanApp {
|
||||||
|
@ -193,7 +157,12 @@ impl VulkanApp {
|
||||||
window: std::ptr::null_mut(),
|
window: std::ptr::null_mut(),
|
||||||
vk_instance: std::ptr::null_mut(),
|
vk_instance: std::ptr::null_mut(),
|
||||||
debug_messenger: std::ptr::null_mut(),
|
debug_messenger: std::ptr::null_mut(),
|
||||||
|
surface: std::ptr::null_mut(),
|
||||||
physical_device: std::ptr::null_mut(),
|
physical_device: std::ptr::null_mut(),
|
||||||
|
device: std::ptr::null_mut(),
|
||||||
|
graphics_queue: std::ptr::null_mut(),
|
||||||
|
present_queue: std::ptr::null_mut(),
|
||||||
|
swap_chain: std::ptr::null_mut(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +191,15 @@ impl VulkanApp {
|
||||||
panic!("Validation layers requested, but not available!");
|
panic!("Validation layers requested, but not available!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create instance.
|
self.create_instance();
|
||||||
|
self.setup_debug_messenger();
|
||||||
|
self.create_surface();
|
||||||
|
self.pick_physical_device();
|
||||||
|
self.create_logical_device();
|
||||||
|
self.create_swap_chain();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_instance(&mut self) {
|
||||||
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::VkApplicationInfo {
|
let app_info = ffi::VkApplicationInfo {
|
||||||
|
@ -297,9 +274,6 @@ impl VulkanApp {
|
||||||
if vk_result != ffi::VkResult_VK_SUCCESS {
|
if vk_result != ffi::VkResult_VK_SUCCESS {
|
||||||
panic!("ERROR: Failed to create vk instance!");
|
panic!("ERROR: Failed to create vk instance!");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.setup_debug_messenger();
|
|
||||||
self.pick_physical_device();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_debug_messenger(&mut self) {
|
fn setup_debug_messenger(&mut self) {
|
||||||
|
@ -350,7 +324,7 @@ impl VulkanApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
for phys_dev in phys_dev_handles_vec {
|
for phys_dev in phys_dev_handles_vec {
|
||||||
if is_device_suitable(phys_dev) {
|
if self.is_device_suitable(phys_dev) {
|
||||||
self.physical_device = phys_dev;
|
self.physical_device = phys_dev;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -361,6 +335,91 @@ impl VulkanApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_logical_device(&mut self) {
|
||||||
|
if self.physical_device.is_null() {
|
||||||
|
panic!("\"physical_device\" must be set before calling \"create_logical_device\"!");
|
||||||
|
}
|
||||||
|
|
||||||
|
let indices = self.find_queue_families(self.physical_device);
|
||||||
|
|
||||||
|
let mut dev_queue_create_infos: Vec<ffi::VkDeviceQueueCreateInfo> = Vec::new();
|
||||||
|
let mut unique_queue_families: HashSet<u32> = HashSet::new();
|
||||||
|
unique_queue_families.insert(indices.graphics_family.unwrap());
|
||||||
|
unique_queue_families.insert(indices.present_family.unwrap());
|
||||||
|
|
||||||
|
let queue_priority: f32 = 1.0;
|
||||||
|
|
||||||
|
for queue_family in unique_queue_families {
|
||||||
|
let mut dev_queue_create_info: ffi::VkDeviceQueueCreateInfo =
|
||||||
|
unsafe { std::mem::zeroed() };
|
||||||
|
dev_queue_create_info.sType =
|
||||||
|
ffi::VkStructureType_VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
|
dev_queue_create_info.queueFamilyIndex = queue_family;
|
||||||
|
dev_queue_create_info.queueCount = 1;
|
||||||
|
dev_queue_create_info.pQueuePriorities = std::ptr::addr_of!(queue_priority);
|
||||||
|
dev_queue_create_infos.push(dev_queue_create_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut phys_dev_feat: ffi::VkPhysicalDeviceFeatures = unsafe { std::mem::zeroed() };
|
||||||
|
|
||||||
|
let mut dev_create_info: ffi::VkDeviceCreateInfo = unsafe { std::mem::zeroed() };
|
||||||
|
dev_create_info.sType = ffi::VkStructureType_VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
|
dev_create_info.pQueueCreateInfos = dev_queue_create_infos.as_ptr();
|
||||||
|
dev_create_info.queueCreateInfoCount = dev_queue_create_infos.len() as u32;
|
||||||
|
dev_create_info.pEnabledFeatures = std::ptr::addr_of!(phys_dev_feat);
|
||||||
|
|
||||||
|
dev_create_info.ppEnabledExtensionNames = DEVICE_EXTENSIONS.as_ptr();
|
||||||
|
dev_create_info.enabledExtensionCount = DEVICE_EXTENSIONS.len() as u32;
|
||||||
|
|
||||||
|
if ENABLE_VALIDATION_LAYERS {
|
||||||
|
dev_create_info.enabledLayerCount = VALIDATION_LAYERS.len() as u32;
|
||||||
|
dev_create_info.ppEnabledLayerNames = VALIDATION_LAYERS.as_ptr() as *const *const i8;
|
||||||
|
} else {
|
||||||
|
dev_create_info.enabledLayerCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = unsafe {
|
||||||
|
ffi::vkCreateDevice(
|
||||||
|
self.physical_device,
|
||||||
|
std::ptr::addr_of!(dev_create_info),
|
||||||
|
std::ptr::null(),
|
||||||
|
std::ptr::addr_of_mut!(self.device),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if result != ffi::VkResult_VK_SUCCESS {
|
||||||
|
panic!("Failed to create logical device!");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ffi::vkGetDeviceQueue(
|
||||||
|
self.device,
|
||||||
|
indices.graphics_family.unwrap(),
|
||||||
|
0,
|
||||||
|
std::ptr::addr_of_mut!(self.graphics_queue),
|
||||||
|
);
|
||||||
|
ffi::vkGetDeviceQueue(
|
||||||
|
self.device,
|
||||||
|
indices.present_family.unwrap(),
|
||||||
|
0,
|
||||||
|
std::ptr::addr_of_mut!(self.present_queue),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_surface(&mut self) {
|
||||||
|
let result = unsafe {
|
||||||
|
ffi::glfwCreateWindowSurface(
|
||||||
|
self.vk_instance,
|
||||||
|
self.window,
|
||||||
|
std::ptr::null(),
|
||||||
|
std::ptr::addr_of_mut!(self.surface),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if result != ffi::VkResult_VK_SUCCESS {
|
||||||
|
panic!("Failed to create window surface!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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!");
|
||||||
|
@ -379,10 +438,332 @@ impl VulkanApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_queue_families(&self, dev: ffi::VkPhysicalDevice) -> QueueFamilyIndices {
|
||||||
|
let mut queue_fam = QueueFamilyIndices {
|
||||||
|
graphics_family: None,
|
||||||
|
present_family: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut queue_family_count: u32 = 0;
|
||||||
|
unsafe {
|
||||||
|
ffi::vkGetPhysicalDeviceQueueFamilyProperties(
|
||||||
|
dev,
|
||||||
|
std::ptr::addr_of_mut!(queue_family_count),
|
||||||
|
std::ptr::null_mut(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut queue_family_props: Vec<ffi::VkQueueFamilyProperties> =
|
||||||
|
Vec::with_capacity(queue_family_count as usize);
|
||||||
|
queue_family_props.resize(queue_family_count as usize, unsafe { std::mem::zeroed() });
|
||||||
|
unsafe {
|
||||||
|
ffi::vkGetPhysicalDeviceQueueFamilyProperties(
|
||||||
|
dev,
|
||||||
|
std::ptr::addr_of_mut!(queue_family_count),
|
||||||
|
queue_family_props.as_mut_ptr(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, queue_family_prop) in queue_family_props.iter().enumerate() {
|
||||||
|
let mut present_support: ffi::VkBool32 = ffi::VK_FALSE;
|
||||||
|
unsafe {
|
||||||
|
ffi::vkGetPhysicalDeviceSurfaceSupportKHR(
|
||||||
|
dev,
|
||||||
|
idx as u32,
|
||||||
|
self.surface,
|
||||||
|
std::ptr::addr_of_mut!(present_support),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if present_support != ffi::VK_FALSE {
|
||||||
|
queue_fam.present_family = Some(idx as u32);
|
||||||
|
}
|
||||||
|
if queue_family_prop.queueFlags & ffi::VkQueueFlagBits_VK_QUEUE_GRAPHICS_BIT != 0 {
|
||||||
|
queue_fam.graphics_family = Some(idx as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
if queue_fam.is_complete() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queue_fam
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_device_suitable(&self, dev: ffi::VkPhysicalDevice) -> bool {
|
||||||
|
let mut dev_props: ffi::VkPhysicalDeviceProperties = unsafe { std::mem::zeroed() };
|
||||||
|
unsafe {
|
||||||
|
ffi::vkGetPhysicalDeviceProperties(dev, std::ptr::addr_of_mut!(dev_props));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dev_feat: ffi::VkPhysicalDeviceFeatures = unsafe { std::mem::zeroed() };
|
||||||
|
unsafe {
|
||||||
|
ffi::vkGetPhysicalDeviceFeatures(dev, std::ptr::addr_of_mut!(dev_feat));
|
||||||
|
}
|
||||||
|
|
||||||
|
// dev_props.deviceType == ffi::VkPhysicalDeviceType_VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
|
||||||
|
// && dev_feat.geometryShader != 0
|
||||||
|
|
||||||
|
// Use previous checks for specifics, but for now, accept GPUs with required support.
|
||||||
|
let extensions_supported = self.check_device_extensions_support(dev);
|
||||||
|
|
||||||
|
let mut swap_chain_adequate = false;
|
||||||
|
if extensions_supported {
|
||||||
|
let swap_chain_support = self.query_swap_chain_support(dev);
|
||||||
|
swap_chain_adequate = !swap_chain_support.formats.is_empty()
|
||||||
|
&& !swap_chain_support.present_modes.is_empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.find_queue_families(dev).is_complete() && extensions_supported && swap_chain_adequate
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_device_extensions_support(&self, dev: ffi::VkPhysicalDevice) -> bool {
|
||||||
|
let mut req_extensions: HashSet<CString> = HashSet::new();
|
||||||
|
for dev_ext in DEVICE_EXTENSIONS {
|
||||||
|
let cstr = unsafe { CStr::from_ptr(dev_ext) };
|
||||||
|
req_extensions.insert(cstr.to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut extension_count: u32 = 0;
|
||||||
|
unsafe {
|
||||||
|
ffi::vkEnumerateDeviceExtensionProperties(
|
||||||
|
dev,
|
||||||
|
std::ptr::null(),
|
||||||
|
std::ptr::addr_of_mut!(extension_count),
|
||||||
|
std::ptr::null_mut(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut available_extensions: Vec<ffi::VkExtensionProperties> =
|
||||||
|
Vec::with_capacity(extension_count as usize);
|
||||||
|
available_extensions.resize(extension_count as usize, unsafe { std::mem::zeroed() });
|
||||||
|
unsafe {
|
||||||
|
ffi::vkEnumerateDeviceExtensionProperties(
|
||||||
|
dev,
|
||||||
|
std::ptr::null(),
|
||||||
|
std::ptr::addr_of_mut!(extension_count),
|
||||||
|
available_extensions.as_mut_ptr(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for available in available_extensions {
|
||||||
|
let cstr = unsafe { CStr::from_ptr(&available.extensionName as *const i8) };
|
||||||
|
let cstring = cstr.to_owned();
|
||||||
|
req_extensions.remove(&cstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
req_extensions.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_swap_chain_support(&self, device: ffi::VkPhysicalDevice) -> SwapChainSupportDetails {
|
||||||
|
if self.surface.is_null() {
|
||||||
|
panic!("surface must be initialized before calling query_swap_chain_support!");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut swap_chain_support_details = SwapChainSupportDetails::default();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ffi::vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
||||||
|
device,
|
||||||
|
self.surface,
|
||||||
|
std::ptr::addr_of_mut!(swap_chain_support_details.capabilities),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut format_count: u32 = 0;
|
||||||
|
unsafe {
|
||||||
|
ffi::vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||||
|
device,
|
||||||
|
self.surface,
|
||||||
|
std::ptr::addr_of_mut!(format_count),
|
||||||
|
std::ptr::null_mut(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if format_count != 0 {
|
||||||
|
swap_chain_support_details
|
||||||
|
.formats
|
||||||
|
.resize(format_count as usize, unsafe { std::mem::zeroed() });
|
||||||
|
unsafe {
|
||||||
|
ffi::vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||||
|
device,
|
||||||
|
self.surface,
|
||||||
|
std::ptr::addr_of_mut!(format_count),
|
||||||
|
swap_chain_support_details.formats.as_mut_ptr(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut present_mode_count: u32 = 0;
|
||||||
|
unsafe {
|
||||||
|
ffi::vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||||
|
device,
|
||||||
|
self.surface,
|
||||||
|
std::ptr::addr_of_mut!(present_mode_count),
|
||||||
|
std::ptr::null_mut(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if present_mode_count != 0 {
|
||||||
|
swap_chain_support_details
|
||||||
|
.present_modes
|
||||||
|
.resize(present_mode_count as usize, unsafe { std::mem::zeroed() });
|
||||||
|
unsafe {
|
||||||
|
ffi::vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||||
|
device,
|
||||||
|
self.surface,
|
||||||
|
std::ptr::addr_of_mut!(present_mode_count),
|
||||||
|
swap_chain_support_details.present_modes.as_mut_ptr(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swap_chain_support_details
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_swap_surface_format(
|
||||||
|
&self,
|
||||||
|
available_formats: &Vec<ffi::VkSurfaceFormatKHR>,
|
||||||
|
) -> Option<usize> {
|
||||||
|
if available_formats.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, format) in available_formats.iter().enumerate() {
|
||||||
|
if format.format == ffi::VkFormat_VK_FORMAT_B8G8R8A8_SRGB
|
||||||
|
&& format.colorSpace == ffi::VkColorSpaceKHR_VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
|
||||||
|
{
|
||||||
|
return Some(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_swap_present_mode(
|
||||||
|
&self,
|
||||||
|
available_present_modes: &Vec<ffi::VkPresentModeKHR>,
|
||||||
|
) -> ffi::VkPresentModeKHR {
|
||||||
|
for mode in available_present_modes {
|
||||||
|
if *mode == ffi::VkPresentModeKHR_VK_PRESENT_MODE_MAILBOX_KHR {
|
||||||
|
return ffi::VkPresentModeKHR_VK_PRESENT_MODE_MAILBOX_KHR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ffi::VkPresentModeKHR_VK_PRESENT_MODE_FIFO_KHR
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_swap_extent(&self, capabilities: &ffi::VkSurfaceCapabilitiesKHR) -> ffi::VkExtent2D {
|
||||||
|
if capabilities.currentExtent.width != u32::MAX {
|
||||||
|
return capabilities.currentExtent.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut width: i32 = 0;
|
||||||
|
let mut height: i32 = 0;
|
||||||
|
unsafe {
|
||||||
|
ffi::glfwGetFramebufferSize(
|
||||||
|
self.window,
|
||||||
|
std::ptr::addr_of_mut!(width),
|
||||||
|
std::ptr::addr_of_mut!(height),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut actual_extent = ffi::VkExtent2D {
|
||||||
|
width: width as u32,
|
||||||
|
height: height as u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
actual_extent.width = actual_extent.width.clamp(
|
||||||
|
capabilities.minImageExtent.width,
|
||||||
|
capabilities.maxImageExtent.width,
|
||||||
|
);
|
||||||
|
actual_extent.height = actual_extent.height.clamp(
|
||||||
|
capabilities.minImageExtent.height,
|
||||||
|
capabilities.maxImageExtent.height,
|
||||||
|
);
|
||||||
|
|
||||||
|
actual_extent
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_swap_chain(&mut self) {
|
||||||
|
let swap_chain_support = self.query_swap_chain_support(self.physical_device);
|
||||||
|
|
||||||
|
let surface_format_idx = self
|
||||||
|
.choose_swap_surface_format(&swap_chain_support.formats)
|
||||||
|
.expect("surface format must exist");
|
||||||
|
let present_mode = self.choose_swap_present_mode(&swap_chain_support.present_modes);
|
||||||
|
let extent = self.choose_swap_extent(&swap_chain_support.capabilities);
|
||||||
|
|
||||||
|
let mut image_count: u32 = swap_chain_support.capabilities.minImageCount + 1;
|
||||||
|
if swap_chain_support.capabilities.maxImageCount > 0
|
||||||
|
&& image_count > swap_chain_support.capabilities.maxImageCount
|
||||||
|
{
|
||||||
|
image_count = swap_chain_support.capabilities.maxImageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut create_info: ffi::VkSwapchainCreateInfoKHR = unsafe { std::mem::zeroed() };
|
||||||
|
create_info.sType = ffi::VkStructureType_VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||||
|
create_info.surface = self.surface;
|
||||||
|
|
||||||
|
create_info.minImageCount = image_count;
|
||||||
|
create_info.imageFormat = swap_chain_support.formats[surface_format_idx].format;
|
||||||
|
create_info.imageColorSpace = swap_chain_support.formats[surface_format_idx].colorSpace;
|
||||||
|
create_info.imageExtent = extent;
|
||||||
|
create_info.imageArrayLayers = 1;
|
||||||
|
create_info.imageUsage = ffi::VkImageUsageFlagBits_VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
|
||||||
|
let indices = self.find_queue_families(self.physical_device);
|
||||||
|
let indices_arr: [u32; 2] = [
|
||||||
|
indices.graphics_family.unwrap(),
|
||||||
|
indices.present_family.unwrap(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if indices.graphics_family != indices.present_family {
|
||||||
|
create_info.imageSharingMode = ffi::VkSharingMode_VK_SHARING_MODE_CONCURRENT;
|
||||||
|
create_info.queueFamilyIndexCount = 2;
|
||||||
|
create_info.pQueueFamilyIndices = indices_arr.as_ptr();
|
||||||
|
} else {
|
||||||
|
create_info.imageSharingMode = ffi::VkSharingMode_VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
create_info.queueFamilyIndexCount = 0;
|
||||||
|
create_info.pQueueFamilyIndices = std::ptr::null();
|
||||||
|
}
|
||||||
|
|
||||||
|
create_info.preTransform = swap_chain_support.capabilities.currentTransform;
|
||||||
|
|
||||||
|
create_info.compositeAlpha =
|
||||||
|
ffi::VkCompositeAlphaFlagBitsKHR_VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
|
||||||
|
create_info.presentMode = present_mode;
|
||||||
|
create_info.clipped = ffi::VK_TRUE;
|
||||||
|
|
||||||
|
create_info.oldSwapchain = std::ptr::null_mut();
|
||||||
|
|
||||||
|
let result = unsafe {
|
||||||
|
ffi::vkCreateSwapchainKHR(
|
||||||
|
self.device,
|
||||||
|
std::ptr::addr_of!(create_info),
|
||||||
|
std::ptr::null(),
|
||||||
|
std::ptr::addr_of_mut!(self.swap_chain),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if result != ffi::VkResult_VK_SUCCESS {
|
||||||
|
panic!("Failed to create swap chain!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for VulkanApp {
|
impl Drop for VulkanApp {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
if !self.swap_chain.is_null() {
|
||||||
|
unsafe {
|
||||||
|
ffi::vkDestroySwapchainKHR(self.device, self.swap_chain, std::ptr::null());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.device.is_null() {
|
||||||
|
unsafe {
|
||||||
|
ffi::vkDestroyDevice(self.device, std::ptr::null());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ENABLE_VALIDATION_LAYERS && !self.debug_messenger.is_null() {
|
if ENABLE_VALIDATION_LAYERS && !self.debug_messenger.is_null() {
|
||||||
let func_opt: ffi::PFN_vkDestroyDebugUtilsMessengerEXT = unsafe {
|
let func_opt: ffi::PFN_vkDestroyDebugUtilsMessengerEXT = unsafe {
|
||||||
std::mem::transmute(ffi::vkGetInstanceProcAddr(
|
std::mem::transmute(ffi::vkGetInstanceProcAddr(
|
||||||
|
@ -400,6 +781,12 @@ impl Drop for VulkanApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.surface.is_null() {
|
||||||
|
unsafe {
|
||||||
|
ffi::vkDestroySurfaceKHR(self.vk_instance, self.surface, std::ptr::null());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !self.vk_instance.is_null() {
|
if !self.vk_instance.is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
ffi::vkDestroyInstance(self.vk_instance, std::ptr::null());
|
ffi::vkDestroyInstance(self.vk_instance, std::ptr::null());
|
||||||
|
|
Loading…
Reference in a new issue