Skip to content

Commit

Permalink
Add swapchain params selection logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Rimpampa committed Apr 3, 2022
1 parent c10f52a commit 03dda6b
Showing 1 changed file with 140 additions and 62 deletions.
202 changes: 140 additions & 62 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ impl<'a> VulkanState<'a> {
// ...
];

let win_size = window.inner_size();
let win_size = vk::Extent2D {
width: win_size.width,
height: win_size.height,
};

let instance = unsafe {
vku::Instance::new(
entry,
Expand All @@ -61,100 +67,170 @@ impl<'a> VulkanState<'a> {

let phy_devs = vku::PhysicalDevList::list(surface)?;

let (dev_idx, indices) = phy_devs
let (dev_idx, create_info) = phy_devs
.iter()
.enumerate()
.map(|(i, dev)| -> AppResult<_> {
let indices = physical_device_suitability(dev, &device_extensions)?;
Ok(Some(i).zip(indices))
})
.filter_map(Result::transpose)
.find(Result::is_ok)
.ok_or(AppError::NoSuitablePhyDev)
.unwrap()?;
.filter_map(|(i, dev)| Some((i, VkCreateInfo::new(dev, &device_extensions, win_size)?)))
.next()
.ok_or(AppError::NoSuitablePhyDev)?;

let queue_create_info = create_info.queue_family_creation_infos();
let dev_exts_ptr: Vec<_> = device_extensions.iter().map(|s| s.as_ptr()).collect();
let logic_dev = unsafe { phy_devs.select(dev_idx, indices.infos(), &dev_exts_ptr)? };
let logic_dev = unsafe { phy_devs.select(dev_idx, queue_create_info, &dev_exts_ptr)? };

Ok(Self(logic_dev))
}
}

/// Checks if the physical device has the right properties for the application
///
/// # Return
///
/// The queues families indices of the needed queue families if all present
fn physical_device_suitability<I: vku::SurfaceHolder>(
dev: vku::PhysicalDevRef<I>,
dev_exts: &[&CStr],
) -> vku::Result<Option<QueueFamiliesIndices>> {
let prop = dev.properties();
let feat = dev.features();
let exts: Vec<_> = dev
.extension_properties()?
.iter()
// SAFETY: This pointer was generated by the Vulkan driver
.map(|prop| unsafe { CStr::from_ptr(prop.extension_name.as_ptr()) })
.collect();

let dev_types = {
use vk::PhysicalDeviceType as devtype;
[devtype::DISCRETE_GPU, devtype::INTEGRATED_GPU]
};
if feat.tessellation_shader == 0 || !dev_types.contains(&prop.device_type) {
return Ok(None);
}
#[derive(Clone, Copy, Default)]
struct VkCreateInfo {
/// The graphics queue family queue index
graphics_queue_id: u32,
/// The present queue family queue index
present_queue_id: u32,
/// The chosen swapchain format
swapchain_fmt: vk::SurfaceFormatKHR,
/// The chosen swapchain presentation mode
swapchain_pmode: vk::PresentModeKHR,
/// The chosen swapchain area
swapchain_extent: vk::Extent2D,
/// The chosen swapchain image count
swapchain_imgs: u32,
}

if !dev_exts.iter().all(|ext_name| exts.contains(ext_name)) {
return Ok(None);
}
impl VkCreateInfo {
/// Checks if the physical device has the right properties for the application
///
/// # Return
///
/// The queues families indices of the needed queue families if all present
fn new<I: vku::SurfaceHolder>(
dev: vku::PhysicalDevRef<I>,
dev_exts: &[&CStr],
win_size: vk::Extent2D,
) -> Option<VkCreateInfo> {
let create_info = Self::default();

if dev_exts.contains(&khr::Swapchain::name()) {
// SAFETY: just checked if the extension is supported
let (_caps, fmts, pmods) = unsafe {
(
dev.surface_capabilities()?,
dev.surface_formats()?,
dev.surface_present_modes()?,
)
let prop = dev.properties();
let feat = dev.features();
let exts: Vec<_> = dev
.extension_properties()
.ok()?
.iter()
// SAFETY: This pointer was generated by the Vulkan driver
.map(|prop| unsafe { CStr::from_ptr(prop.extension_name.as_ptr()) })
.collect();

let dev_types = {
use vk::PhysicalDeviceType as devtype;
[devtype::DISCRETE_GPU, devtype::INTEGRATED_GPU]
};
if feat.tessellation_shader == 0 || !dev_types.contains(&prop.device_type) {
return None;
}

if fmts.is_empty() || pmods.is_empty() {
return Ok(None);
if !dev_exts.iter().all(|ext_name| exts.contains(ext_name)) {
return None;
}

let create_info = match dev_exts.contains(&khr::Swapchain::name()) {
// SAFETY: just checked if the extension is supported
true => unsafe { create_info.get_swapchain_properties(dev, win_size)? },
false => create_info,
};
create_info.get_queue_family_indices(dev)
}

Ok(QueueFamiliesIndices::get(dev))
}
/// # Safety
///
/// This method expects the `VK_KHR_swapchain` extension to be supported
/// by the device
unsafe fn get_swapchain_properties<I: vku::SurfaceHolder>(
self,
dev: vku::PhysicalDevRef<I>,
win_size: vk::Extent2D,
) -> Option<Self> {
let (caps, fmts, pmods) = (
dev.surface_capabilities().ok()?,
dev.surface_formats().ok()?,
dev.surface_present_modes().ok()?,
);

#[derive(Clone, Copy)]
struct QueueFamiliesIndices {
graphics: u32,
present: u32,
}
let format = *fmts
.iter()
.filter(|fmt| fmt.format == vk::Format::R8G8B8A8_SRGB)
.find(|fmt| fmt.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR)
.or_else(|| fmts.first())?;

if pmods.is_empty() {
return None;
}
let pmode = pmods
.contains(&vk::PresentModeKHR::MAILBOX)
.then(|| vk::PresentModeKHR::MAILBOX)
.unwrap_or(vk::PresentModeKHR::FIFO);

let vk::Extent2D {
height: max_height,
width: max_width,
} = caps.max_image_extent;
let vk::Extent2D {
height: min_height,
width: min_width,
} = caps.min_image_extent;

let extent = match caps.current_extent {
vk::Extent2D {
height: u32::MAX,
width: u32::MAX,
} => vk::Extent2D {
height: win_size.height.clamp(min_height, max_height),
width: win_size.width.clamp(min_width, max_width),
},
ext => ext,
};

let imgs = match caps.max_image_count {
0 => caps.min_image_count + 1,
n => n.min(caps.min_image_count + 1),
};

Some(Self {
swapchain_fmt: format,
swapchain_pmode: pmode,
swapchain_extent: extent,
swapchain_imgs: imgs,
..self
})
}

impl QueueFamiliesIndices {
/// Returns the queue families indices needed by the application,
/// or [None] if they are not supported
fn get<I: vku::SurfaceHolder>(dev: vku::PhysicalDevRef<I>) -> Option<Self> {
fn get_queue_family_indices<I: vku::SurfaceHolder>(
self,
dev: vku::PhysicalDevRef<I>,
) -> Option<Self> {
let queue_families = dev.queue_families();
let graphics = queue_families
let graphics_queue_id = queue_families
.iter()
.position(|fam| fam.queue_flags.contains(vk::QueueFlags::GRAPHICS))?
as u32;
let present = (0..queue_families.len())
let present_queue_id = (0..queue_families.len())
// SAFETY:
// The range is based on the length of the Vec returned by `queue_families`
// and the same device is being used
.find(|&fam| unsafe { dev.supports_surface(fam as u32).unwrap_or(false) })?
as u32;
Some(Self { graphics, present })
Some(Self {
graphics_queue_id,
present_queue_id,
..self
})
}

/// Returns the info needed for creating the queues
fn infos(self) -> Vec<vku::QueueFamilyInfo<'static>> {
let arr = [self.graphics, self.present];
fn queue_family_creation_infos(self) -> Vec<vku::QueueFamilyInfo<'static>> {
let arr = [self.graphics_queue_id, self.present_queue_id];
let mut vec = Vec::<vku::QueueFamilyInfo>::with_capacity(arr.len());
arr.into_iter().for_each(|n| {
if vec.iter().any(|i| i.index == n) {
Expand All @@ -169,6 +245,8 @@ impl QueueFamiliesIndices {
}
}

impl VkCreateInfo {}

fn main() {
let event_loop = winit::event_loop::EventLoop::new();
let window = win::WindowBuilder::new()
Expand Down

0 comments on commit 03dda6b

Please sign in to comment.