Add logical device struct and surface handling for Vulkan
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 0s
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 0s
Introduce the VkLogicalDevice struct and add surface creation logic in VkInstance. Also, import necessary extensions and refine Vulkan physical device and window handling. Included a dependency on 'anyhow' for error management.
This commit is contained in:
parent
4048937a6c
commit
da0be47b14
14 changed files with 258 additions and 153 deletions
|
@ -1,6 +1,8 @@
|
|||
pub(self) mod vk_instance;
|
||||
pub(self) mod vk_physical_device;
|
||||
pub(self) mod vk_logical_device;
|
||||
mod utils;
|
||||
mod vk_surface;
|
||||
|
||||
pub use vk_instance::VkInstance;
|
||||
pub use vk_physical_device::VkPhysicalDevice;
|
|
@ -1,74 +0,0 @@
|
|||
use std::ffi::CString;
|
||||
|
||||
pub fn use_layers(
|
||||
entry: &ash::Entry,
|
||||
layers_to_select: Vec<&str>,
|
||||
) -> Vec<CString> {
|
||||
let layers_available = get_layers_available(entry);
|
||||
|
||||
log_layers_available(&layers_available);
|
||||
|
||||
let selected_layers = select_layers(&layers_available, &layers_to_select);
|
||||
|
||||
log_layers_wanted(&layers_to_select, &selected_layers);
|
||||
|
||||
selected_layers
|
||||
.iter()
|
||||
.map(|sl| CString::new(sl.clone().as_bytes()).unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn get_layers_available(entry: &ash::Entry) -> Vec<ash::vk::LayerProperties> {
|
||||
unsafe { entry.enumerate_instance_layer_properties().unwrap_or_default() }
|
||||
}
|
||||
|
||||
fn log_layers_available(layers_available: &[ash::vk::LayerProperties]) {
|
||||
log::info!("Available layers ({}):", layers_available.len());
|
||||
for l in layers_available {
|
||||
log::info!(
|
||||
"\t{:?}\tImplementation version: {}\tVulkan Version: {}\tDescription: {:?}",
|
||||
l.layer_name_as_c_str().unwrap_or_default(),
|
||||
l.implementation_version,
|
||||
print_version(l.spec_version),
|
||||
l.description_as_c_str().unwrap_or_default()
|
||||
);
|
||||
}
|
||||
log::info!(""); // Add blank line
|
||||
}
|
||||
|
||||
fn select_layers(
|
||||
layers_available: &[ash::vk::LayerProperties],
|
||||
layers_to_select: &[&str],
|
||||
) -> Vec<String> {
|
||||
layers_available
|
||||
.iter()
|
||||
.filter_map(|l| {
|
||||
let layer_name = l
|
||||
.layer_name_as_c_str()
|
||||
.unwrap_or_default()
|
||||
.to_string_lossy();
|
||||
layers_to_select
|
||||
.iter()
|
||||
.find(|&&ln| ln == layer_name)
|
||||
.map(|_| layer_name.into_owned())
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn log_layers_wanted(layers_to_select: &[&str], selected_layers: &[String]) {
|
||||
log::info!("Layers wanted ({}):", layers_to_select.len());
|
||||
for ol in layers_to_select {
|
||||
let selected = selected_layers.iter().any(|sl| sl == ol);
|
||||
log::info!("\t{:?}\tSelected: {}", ol, selected);
|
||||
}
|
||||
log::info!(""); // Add blank line
|
||||
}
|
||||
|
||||
pub fn print_version(version: u32) -> String {
|
||||
format!(
|
||||
"{}.{}.{}",
|
||||
ash::vk::api_version_major(version),
|
||||
ash::vk::api_version_minor(version),
|
||||
ash::vk::api_version_patch(version)
|
||||
)
|
||||
}
|
38
src/vulkan/utils/layers.rs
Normal file
38
src/vulkan/utils/layers.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use std::ffi::CString;
|
||||
|
||||
pub fn use_layers(
|
||||
entry: &ash::Entry,
|
||||
layers_to_select: Vec<&str>,
|
||||
) -> Vec<CString> {
|
||||
let layers_available = get_layers_available(entry);
|
||||
|
||||
let selected_layers = select_layers(&layers_available, &layers_to_select);
|
||||
|
||||
selected_layers
|
||||
.iter()
|
||||
.map(|sl| CString::new(sl.clone().as_bytes()).unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn get_layers_available(entry: &ash::Entry) -> Vec<ash::vk::LayerProperties> {
|
||||
unsafe { entry.enumerate_instance_layer_properties().unwrap_or_default() }
|
||||
}
|
||||
|
||||
fn select_layers(
|
||||
layers_available: &[ash::vk::LayerProperties],
|
||||
layers_to_select: &[&str],
|
||||
) -> Vec<String> {
|
||||
layers_available
|
||||
.iter()
|
||||
.filter_map(|l| {
|
||||
let layer_name = l
|
||||
.layer_name_as_c_str()
|
||||
.unwrap_or_default()
|
||||
.to_string_lossy();
|
||||
layers_to_select
|
||||
.iter()
|
||||
.find(|&&ln| ln == layer_name)
|
||||
.map(|_| layer_name.into_owned())
|
||||
})
|
||||
.collect()
|
||||
}
|
11
src/vulkan/utils/mod.rs
Normal file
11
src/vulkan/utils/mod.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
mod layers;
|
||||
pub use layers::use_layers;
|
||||
|
||||
pub fn print_version(version: u32) -> String {
|
||||
format!(
|
||||
"{}.{}.{}",
|
||||
ash::vk::api_version_major(version),
|
||||
ash::vk::api_version_minor(version),
|
||||
ash::vk::api_version_patch(version)
|
||||
)
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
use std::ffi::CString;
|
||||
use std::ffi::{c_char, CString};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use ash::{Instance, vk, Entry};
|
||||
use winit::raw_window_handle::{HasDisplayHandle};
|
||||
use ash::khr::surface;
|
||||
use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||
use crate::vulkan::utils::use_layers;
|
||||
use crate::vulkan::vk_surface::VkSurface;
|
||||
use crate::vulkan::VkPhysicalDevice;
|
||||
|
||||
pub struct VkInstance {
|
||||
|
@ -10,7 +13,9 @@ pub struct VkInstance {
|
|||
}
|
||||
|
||||
impl VkInstance {
|
||||
pub fn new(window: &impl HasDisplayHandle) -> Self {
|
||||
pub fn new(
|
||||
required_extensions: &Vec<*const c_char>,
|
||||
) -> Self {
|
||||
let entry = Entry::linked();
|
||||
|
||||
// Layers
|
||||
|
@ -21,19 +26,6 @@ impl VkInstance {
|
|||
]);
|
||||
let layers_raw = layers.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
|
||||
|
||||
// Extensions
|
||||
let mut extension_names =
|
||||
ash_window::enumerate_required_extensions(window.display_handle().expect("No display handle").as_raw())
|
||||
.unwrap()
|
||||
.to_vec();
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
{
|
||||
extension_names.push(ash::khr::portability_enumeration::NAME.as_ptr());
|
||||
// Enabling this extension is a requirement when using `VK_KHR_portability_subset`
|
||||
extension_names.push(ash::khr::get_physical_device_properties2::NAME.as_ptr());
|
||||
}
|
||||
|
||||
// App Info
|
||||
let app_name = CString::new("VulkanTriangle").unwrap();
|
||||
let appinfo = vk::ApplicationInfo::default()
|
||||
|
@ -53,7 +45,7 @@ impl VkInstance {
|
|||
let create_info = vk::InstanceCreateInfo::default()
|
||||
.application_info(&appinfo)
|
||||
.enabled_layer_names(&layers_raw)
|
||||
.enabled_extension_names(&extension_names)
|
||||
.enabled_extension_names(&required_extensions)
|
||||
.flags(create_flags);
|
||||
|
||||
let instance: Instance = unsafe {
|
||||
|
@ -75,6 +67,31 @@ impl VkInstance {
|
|||
.iter().map(|physical_device| VkPhysicalDevice::new(&self.handle, *physical_device))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn create_surface(
|
||||
&self,
|
||||
window: &crate::display::Window
|
||||
) -> anyhow::Result<VkSurface> {
|
||||
let window_handle = window.handle()
|
||||
.ok_or_else(|| anyhow::anyhow!("Window handle is not available."))?;
|
||||
|
||||
let surface_loader = surface::Instance::new(&self.entry, &self.handle);
|
||||
|
||||
let surface = unsafe {
|
||||
ash_window::create_surface(
|
||||
&self.entry,
|
||||
&self.handle,
|
||||
window_handle.display_handle()?.as_raw(),
|
||||
window_handle.window_handle()?.as_raw(),
|
||||
None,
|
||||
)?
|
||||
};
|
||||
|
||||
Ok(VkSurface::new(
|
||||
surface_loader,
|
||||
surface,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VkInstance {
|
||||
|
@ -83,4 +100,10 @@ impl Drop for VkInstance {
|
|||
self.handle.destroy_instance(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for VkInstance {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Vulkan Version:")
|
||||
}
|
||||
}
|
3
src/vulkan/vk_logical_device.rs
Normal file
3
src/vulkan/vk_logical_device.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub struct VkLogicalDevice {
|
||||
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use ash::vk;
|
||||
use crate::display::App;
|
||||
use crate::vulkan::vk_surface::VkSurface;
|
||||
|
||||
pub struct VkPhysicalDevice {
|
||||
// Vulkan properties
|
||||
handle: vk::PhysicalDevice,
|
||||
pub(super) handle: vk::PhysicalDevice,
|
||||
pub properties: vk::PhysicalDeviceProperties,
|
||||
pub features: vk::PhysicalDeviceFeatures,
|
||||
pub queue_family_properties: Vec<vk::QueueFamilyProperties>,
|
||||
|
@ -26,33 +27,16 @@ impl VkPhysicalDevice {
|
|||
}
|
||||
|
||||
pub fn priority(&self) -> usize {
|
||||
let mut priority = 0;
|
||||
|
||||
let has_graphics_support = self.queue_family_properties.iter().any(|qf| qf.queue_flags.contains(vk::QueueFlags::GRAPHICS));
|
||||
let has_compute_support = self.queue_family_properties.iter().any(|qf| qf.queue_flags.contains(vk::QueueFlags::COMPUTE));
|
||||
let has_transfer_support = self.queue_family_properties.iter().any(|qf| qf.queue_flags.contains(vk::QueueFlags::TRANSFER));
|
||||
let has_sparse_binding_support = self.queue_family_properties.iter().any(|qf| qf.queue_flags.contains(vk::QueueFlags::SPARSE_BINDING));
|
||||
let physical_device_type = self.properties.device_type;
|
||||
|
||||
priority |= has_graphics_support as usize;
|
||||
priority |= (has_sparse_binding_support as usize) << 1;
|
||||
priority |= (has_transfer_support as usize) << 2;
|
||||
priority |= (has_compute_support as usize) << 3;
|
||||
|
||||
let weight : usize = match physical_device_type {
|
||||
match self.properties.device_type {
|
||||
vk::PhysicalDeviceType::CPU => 1,
|
||||
vk::PhysicalDeviceType::VIRTUAL_GPU => 2,
|
||||
vk::PhysicalDeviceType::INTEGRATED_GPU => 3,
|
||||
vk::PhysicalDeviceType::DISCRETE_GPU => 4,
|
||||
_ => 0
|
||||
};
|
||||
priority |= weight << 4;
|
||||
|
||||
priority
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Display for VkPhysicalDevice {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "\tNom: {:?}, Priorité: {}", self.properties.device_name_as_c_str().unwrap_or_default(), self.priority())
|
||||
|
|
29
src/vulkan/vk_surface.rs
Normal file
29
src/vulkan/vk_surface.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use ash::prelude::VkResult;
|
||||
use crate::vulkan::VkPhysicalDevice;
|
||||
|
||||
pub struct VkSurface {
|
||||
surface_loader: ash::khr::surface::Instance,
|
||||
surface: ash::vk::SurfaceKHR,
|
||||
}
|
||||
|
||||
impl VkSurface {
|
||||
pub fn new(
|
||||
surface_loader: ash::khr::surface::Instance,
|
||||
surface: ash::vk::SurfaceKHR,
|
||||
) -> Self {
|
||||
Self {
|
||||
surface_loader,
|
||||
surface
|
||||
}
|
||||
}
|
||||
|
||||
pub fn physical_device_queue_supported(&self, physical_device: &VkPhysicalDevice, queue_index: u32) -> VkResult<bool> {
|
||||
unsafe {
|
||||
self.surface_loader.get_physical_device_surface_support(
|
||||
physical_device.handle,
|
||||
queue_index,
|
||||
self.surface
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue