Make graphics support non-optional for Vulkan

This also removes the new present flag, deletes some commented code and explains the lack of surface validation in device selection.
This commit is contained in:
Chad Brokaw 2022-07-15 13:14:12 -04:00
parent fb952de1f3
commit d6ffe970f9
5 changed files with 41 additions and 67 deletions

View file

@ -49,8 +49,6 @@ bitflags! {
pub struct InstanceFlags: u32 { pub struct InstanceFlags: u32 {
/// Prefer DX12 over Vulkan. /// Prefer DX12 over Vulkan.
const DX12 = 0x1; const DX12 = 0x1;
/// Support presentation to a surface.
const PRESENT = 0x2;
// TODO: discrete vs integrated selection // TODO: discrete vs integrated selection
} }
} }

View file

@ -131,7 +131,7 @@ impl Instance {
mux_cfg! { mux_cfg! {
#[cfg(vk)] #[cfg(vk)]
{ {
if let Ok(instance) = vulkan::VkInstance::new(flags.contains(InstanceFlags::PRESENT)) { if let Ok(instance) = vulkan::VkInstance::new() {
return Ok(Instance::Vk(instance)); return Ok(Instance::Vk(instance));
} }
} }
@ -179,7 +179,7 @@ impl Instance {
/// a "session" which is similar but provides many conveniences. /// a "session" which is similar but provides many conveniences.
pub unsafe fn device(&self) -> Result<Device, Error> { pub unsafe fn device(&self) -> Result<Device, Error> {
mux_match! { self; mux_match! { self;
Instance::Vk(i) => i.device(true).map(Device::Vk), Instance::Vk(i) => i.device().map(Device::Vk),
Instance::Dx12(i) => i.device().map(Device::Dx12), Instance::Dx12(i) => i.device().map(Device::Dx12),
Instance::Mtl(i) => i.device().map(Device::Mtl), Instance::Mtl(i) => i.device().map(Device::Mtl),
} }

View file

@ -154,10 +154,7 @@ impl VkInstance {
/// ///
/// There's more to be done to make this suitable for integration with other /// There's more to be done to make this suitable for integration with other
/// systems, but for now the goal is to make things simple. /// systems, but for now the goal is to make things simple.
/// pub fn new() -> Result<VkInstance, Error> {
/// The caller is responsible for making sure that window which owns the raw window handle
/// outlives the surface.
pub fn new(support_present: bool) -> Result<VkInstance, Error> {
unsafe { unsafe {
let app_name = CString::new("VkToy").unwrap(); let app_name = CString::new("VkToy").unwrap();
let entry = Entry::new()?; let entry = Entry::new()?;
@ -174,34 +171,31 @@ impl VkInstance {
has_debug_ext = exts.try_add(DebugUtils::name()); has_debug_ext = exts.try_add(DebugUtils::name());
} }
// Enable platform specific surface extensions if presentation // Enable platform specific surface extensions.
// support is requested. exts.try_add(khr::Surface::name());
if support_present {
exts.try_add(khr::Surface::name());
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
exts.try_add(khr::Win32Surface::name()); exts.try_add(khr::Win32Surface::name());
#[cfg(any( #[cfg(any(
target_os = "linux", target_os = "linux",
target_os = "dragonfly", target_os = "dragonfly",
target_os = "freebsd", target_os = "freebsd",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd" target_os = "openbsd"
))] ))]
{ {
exts.try_add(khr::XlibSurface::name()); exts.try_add(khr::XlibSurface::name());
exts.try_add(khr::XcbSurface::name()); exts.try_add(khr::XcbSurface::name());
exts.try_add(khr::WaylandSurface::name()); exts.try_add(khr::WaylandSurface::name());
}
#[cfg(any(target_os = "android"))]
exts.try_add(khr::AndroidSurface::name());
#[cfg(any(target_os = "macos", target_os = "ios"))]
exts.try_add(kkr::MetalSurface::name());
} }
#[cfg(any(target_os = "android"))]
exts.try_add(khr::AndroidSurface::name());
#[cfg(any(target_os = "macos", target_os = "ios"))]
exts.try_add(kkr::MetalSurface::name());
let supported_version = entry let supported_version = entry
.try_enumerate_instance_version()? .try_enumerate_instance_version()?
.unwrap_or(vk::make_api_version(0, 1, 0, 0)); .unwrap_or(vk::make_api_version(0, 1, 0, 0));
@ -256,9 +250,9 @@ impl VkInstance {
} }
/// Create a surface from the instance for the specified window handle. /// Create a surface from the instance for the specified window handle.
/// ///
/// # Safety /// # Safety
/// ///
/// The caller is responsible for making sure that the instance outlives the surface. /// The caller is responsible for making sure that the instance outlives the surface.
pub unsafe fn surface( pub unsafe fn surface(
&self, &self,
@ -270,18 +264,17 @@ impl VkInstance {
}) })
} }
/// Create a device from the instance, suitable for compute, with an optional presentation /// Create a device from the instance, suitable for compute and graphics.
/// support.
/// ///
/// # Safety /// # Safety
/// ///
/// The caller is responsible for making sure that the instance outlives the device /// The caller is responsible for making sure that the instance outlives the device.
/// and surface. We could enforce that, for example having an `Arc` of the raw instance, /// We could enforce that, for example having an `Arc` of the raw instance,
/// but for now keep things simple. /// but for now keep things simple.
pub unsafe fn device(&self, support_present: bool) -> Result<VkDevice, Error> { pub unsafe fn device(&self) -> Result<VkDevice, Error> {
let devices = self.instance.enumerate_physical_devices()?; let devices = self.instance.enumerate_physical_devices()?;
let (pdevice, qfi) = let (pdevice, qfi) =
choose_device(&self.instance, &devices, support_present).ok_or("no suitable device")?; choose_device(&self.instance, &devices).ok_or("no suitable device")?;
let mut has_descriptor_indexing = false; let mut has_descriptor_indexing = false;
let vk1_1 = self.vk_version >= vk::make_api_version(0, 1, 1, 0); let vk1_1 = self.vk_version >= vk::make_api_version(0, 1, 1, 0);
@ -317,9 +310,7 @@ impl VkInstance {
self.instance self.instance
.enumerate_device_extension_properties(pdevice)?, .enumerate_device_extension_properties(pdevice)?,
); );
if support_present { extensions.try_add(khr::Swapchain::name());
extensions.try_add(khr::Swapchain::name());
}
if has_descriptor_indexing { if has_descriptor_indexing {
extensions.try_add(vk::KhrMaintenance3Fn::name()); extensions.try_add(vk::KhrMaintenance3Fn::name());
extensions.try_add(vk::ExtDescriptorIndexingFn::name()); extensions.try_add(vk::ExtDescriptorIndexingFn::name());
@ -1453,32 +1444,17 @@ impl Layers {
unsafe fn choose_device( unsafe fn choose_device(
instance: &Instance, instance: &Instance,
devices: &[vk::PhysicalDevice], devices: &[vk::PhysicalDevice],
support_graphics: bool,
) -> Option<(vk::PhysicalDevice, u32)> { ) -> Option<(vk::PhysicalDevice, u32)> {
let mut desired_flags = vk::QueueFlags::COMPUTE;
if support_graphics {
desired_flags |= vk::QueueFlags::GRAPHICS;
}
for pdevice in devices { for pdevice in devices {
let props = instance.get_physical_device_queue_family_properties(*pdevice); let props = instance.get_physical_device_queue_family_properties(*pdevice);
for (ix, info) in props.iter().enumerate() { for (ix, info) in props.iter().enumerate() {
// TODO: is this strictly necessary? We'll need a queue supporting graphics // Select a device that supports both compute and graphics workloads.
// for image rendering regardless, and I'm leaning on the assumption that // This function used to check for surface compatibility but that was removed
// all physical device + queue family combinations that support graphics also // to allow device creation without an instantiated surface. This follows from
// support presentation particularly when the appropriate extensions are enabled // both Metal and DX12 which do not require such validation. It might be worth
// at instance creation. This may be faulty. // exposing this to the user in a future device enumeration API, which would
// also allow selection between discrete and integrated devices.
// Check for surface presentation support if info.queue_flags.contains(vk::QueueFlags::COMPUTE | vk::QueueFlags::GRAPHICS) {
// if let Some(surface) = surface {
// if !surface
// .surface_fn
// .get_physical_device_surface_support(*pdevice, ix as u32, surface.surface)
// .unwrap()
// {
// continue;
// }
// }
if info.queue_flags.contains(desired_flags) {
return Some((*pdevice, ix as u32)); return Some((*pdevice, ix as u32));
} }
} }

View file

@ -54,7 +54,7 @@ fn my_main() -> Result<(), Error> {
let width = window.width() as usize; let width = window.width() as usize;
let height = window.height() as usize; let height = window.height() as usize;
let handle = get_handle(window); let handle = get_handle(window);
let instance = Instance::new(InstanceFlags::PRESENT)?; let instance = Instance::new(InstanceFlags::default())?;
let surface = unsafe { instance.surface(&handle)? }; let surface = unsafe { instance.surface(&handle)? };
gfx_state = Some(GfxState::new(&instance, Some(&surface), width, height)?); gfx_state = Some(GfxState::new(&instance, Some(&surface), width, height)?);
} else { } else {

View file

@ -57,7 +57,7 @@ fn main() -> Result<(), Error> {
.with_resizable(false) // currently not supported .with_resizable(false) // currently not supported
.build(&event_loop)?; .build(&event_loop)?;
let instance = Instance::new(InstanceFlags::PRESENT)?; let instance = Instance::new(InstanceFlags::default())?;
let mut info_string = "info".to_string(); let mut info_string = "info".to_string();
unsafe { unsafe {
let surface = instance.surface(&window)?; let surface = instance.surface(&window)?;