Merge pull request #494 from Ralith/open-extensions

Support enabling statically unknown extensions
This commit is contained in:
tomaka 2017-06-07 09:40:14 +02:00 committed by GitHub
commit c332d03ca6
4 changed files with 156 additions and 41 deletions

View File

@ -120,7 +120,7 @@ use VulkanPointers;
use check_errors;
use vk;
pub use instance::DeviceExtensions;
pub use instance::{DeviceExtensions, RawDeviceExtensions};
/// Represents a Vulkan context.
pub struct Device {
@ -161,10 +161,11 @@ impl Device {
///
// TODO: return Arc<Queue> and handle synchronization in the Queue
// TODO: should take the PhysicalDevice by value
pub fn new<'a, I>(phys: &'a PhysicalDevice, requested_features: &Features,
extensions: &DeviceExtensions, queue_families: I)
-> Result<(Arc<Device>, QueuesIter), DeviceCreationError>
where I: IntoIterator<Item = (QueueFamily<'a>, f32)>
pub fn new<'a, I, Ext>(phys: &'a PhysicalDevice, requested_features: &Features,
extensions: Ext, queue_families: I)
-> Result<(Arc<Device>, QueuesIter), DeviceCreationError>
where I: IntoIterator<Item = (QueueFamily<'a>, f32)>,
Ext: Into<RawDeviceExtensions>,
{
let queue_families = queue_families.into_iter();
@ -190,8 +191,8 @@ impl Device {
layer.as_ptr()
}).collect::<SmallVec<[_; 16]>>();
let extensions_list = extensions.build_extensions_list();
let extensions_list = extensions_list.iter().map(|extension| {
let extensions = extensions.into();
let extensions_list = extensions.iter().map(|extension| {
extension.as_ptr()
}).collect::<SmallVec<[_; 16]>>();
@ -286,7 +287,7 @@ impl Device {
standard_descriptor_pool: Mutex::new(Weak::new()),
standard_command_pools: Mutex::new(Default::default()),
features: requested_features.clone(),
extensions: extensions.clone(),
extensions: (&extensions).into(),
});
// Iterator for the produced queues.

View File

@ -12,6 +12,7 @@ use std::ffi::{CString, CStr};
use std::fmt;
use std::ptr;
use std::str;
use std::collections::HashSet;
use Error;
use OomError;
@ -24,7 +25,7 @@ use vk;
use check_errors;
macro_rules! extensions {
($sname:ident, $($ext:ident => $s:expr,)*) => (
($sname:ident, $rawname:ident, $($ext:ident => $s:expr,)*) => (
/// List of extensions that are enabled or available.
#[derive(Copy, Clone, PartialEq, Eq)]
#[allow(missing_docs)]
@ -50,13 +51,6 @@ macro_rules! extensions {
}
}
/// Builds a Vec containing the list of extensions.
pub fn build_extensions_list(&self) -> Vec<CString> {
let mut data = Vec::new();
$(if self.$ext { data.push(CString::new(&$s[..]).unwrap()); })*
data
}
/// Returns the intersection of this list and another list.
#[inline]
pub fn intersection(&self, other: &$sname) -> $sname {
@ -87,19 +81,107 @@ macro_rules! extensions {
write!(f, "]")
}
}
/// Set of extensions, not restricted to those vulkano knows about.
///
/// This is useful when interacting with external code that has statically-unknown extension
/// requirements.
#[derive(Clone, Eq, PartialEq)]
pub struct $rawname(HashSet<CString>);
impl $rawname {
/// Constructs an extension set containing the supplied extensions.
pub fn new<'a, I>(extensions: I) -> Self
where I: IntoIterator<Item=CString>
{
$rawname(extensions.into_iter().collect())
}
/// Constructs an empty extension set.
pub fn none() -> Self { $rawname(HashSet::new()) }
/// Adds an extension to the set if it is not already present.
pub fn insert(&mut self, extension: CString) {
self.0.insert(extension);
}
/// Returns the intersection of this set and another.
pub fn intersection(&self, other: &Self) -> Self {
$rawname(self.0.intersection(&other.0).cloned().collect())
}
// TODO: impl Iterator
pub fn iter(&self) -> ::std::collections::hash_set::Iter<CString> { self.0.iter() }
}
impl fmt::Debug for $rawname {
#[allow(unused_assignments)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl<'a> From<&'a $sname> for $rawname {
fn from(x: &'a $sname) -> Self {
let mut data = HashSet::new();
$(if x.$ext { data.insert(CString::new(&$s[..]).unwrap()); })*
$rawname(data)
}
}
impl<'a> From<&'a $rawname> for $sname {
fn from(x: &'a $rawname) -> Self {
let mut extensions = $sname::none();
$(
if x.0.iter().any(|x| x.as_bytes() == &$s[..]) {
extensions.$ext = true;
}
)*
extensions
}
}
);
}
macro_rules! instance_extensions {
($sname:ident, $($ext:ident => $s:expr,)*) => (
($sname:ident, $rawname:ident, $($ext:ident => $s:expr,)*) => (
extensions! {
$sname,
$sname, $rawname,
$( $ext => $s,)*
}
impl $rawname {
/// See the docs of supported_by_core().
pub fn supported_by_core_raw() -> Result<Self, SupportedExtensionsError> {
let entry_points = try!(loader::entry_points());
let properties: Vec<vk::ExtensionProperties> = unsafe {
let mut num = 0;
try!(check_errors(entry_points.EnumerateInstanceExtensionProperties(
ptr::null(), &mut num, ptr::null_mut())));
let mut properties = Vec::with_capacity(num as usize);
try!(check_errors(entry_points.EnumerateInstanceExtensionProperties(
ptr::null(), &mut num, properties.as_mut_ptr())));
properties.set_len(num as usize);
properties
};
Ok($rawname(properties.iter().map(|x| unsafe { CStr::from_ptr(x.extensionName.as_ptr()) }.to_owned()).collect()))
}
/// Returns a `RawExtensions` object with extensions supported by the core driver.
pub fn supported_by_core() -> Result<Self, LoadingError> {
match $rawname::supported_by_core_raw() {
Ok(l) => Ok(l),
Err(SupportedExtensionsError::LoadingError(e)) => Err(e),
Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
}
}
}
impl $sname {
/// See the docs of supported_by_core().
pub fn supported_by_core_raw() -> Result<$sname, SupportedExtensionsError> {
pub fn supported_by_core_raw() -> Result<Self, SupportedExtensionsError> {
let entry_points = try!(loader::entry_points());
let properties: Vec<vk::ExtensionProperties> = unsafe {
@ -124,12 +206,11 @@ macro_rules! instance_extensions {
}
)*
}
Ok(extensions)
}
/// Returns an `Extensions` object with extensions supported by the core driver.
pub fn supported_by_core() -> Result<$sname, LoadingError> {
/// Returns a `RawExtensions` object with extensions supported by the core driver.
pub fn supported_by_core() -> Result<Self, LoadingError> {
match $sname::supported_by_core_raw() {
Ok(l) => Ok(l),
Err(SupportedExtensionsError::LoadingError(e)) => Err(e),
@ -141,15 +222,44 @@ macro_rules! instance_extensions {
}
macro_rules! device_extensions {
($sname:ident, $($ext:ident => $s:expr,)*) => (
($sname:ident, $rawname:ident, $($ext:ident => $s:expr,)*) => (
extensions! {
$sname,
$sname, $rawname,
$( $ext => $s,)*
}
impl $rawname {
/// See the docs of supported_by_device().
pub fn supported_by_device_raw(physical_device: &PhysicalDevice) -> Result<Self, SupportedExtensionsError> {
let vk = physical_device.instance().pointers();
let properties: Vec<vk::ExtensionProperties> = unsafe {
let mut num = 0;
try!(check_errors(vk.EnumerateDeviceExtensionProperties(
physical_device.internal_object(), ptr::null(), &mut num, ptr::null_mut())));
let mut properties = Vec::with_capacity(num as usize);
try!(check_errors(vk.EnumerateDeviceExtensionProperties(
physical_device.internal_object(), ptr::null(), &mut num, properties.as_mut_ptr())));
properties.set_len(num as usize);
properties
};
Ok($rawname(properties.iter().map(|x| unsafe { CStr::from_ptr(x.extensionName.as_ptr()) }.to_owned()).collect()))
}
/// Returns an `Extensions` object with extensions supported by the `PhysicalDevice`.
pub fn supported_by_device(physical_device: &PhysicalDevice) -> Self {
match $rawname::supported_by_device_raw(physical_device) {
Ok(l) => l,
Err(SupportedExtensionsError::LoadingError(e)) => unreachable!(),
Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
}
}
}
impl $sname {
/// See the docs of supported_by_device().
pub fn supported_by_device_raw(physical_device: &PhysicalDevice) -> Result<$sname, SupportedExtensionsError> {
pub fn supported_by_device_raw(physical_device: &PhysicalDevice) -> Result<Self, SupportedExtensionsError> {
let vk = physical_device.instance().pointers();
let properties: Vec<vk::ExtensionProperties> = unsafe {
@ -179,7 +289,7 @@ macro_rules! device_extensions {
}
/// Returns an `Extensions` object with extensions supported by the `PhysicalDevice`.
pub fn supported_by_device(physical_device: &PhysicalDevice) -> $sname {
pub fn supported_by_device(physical_device: &PhysicalDevice) -> Self {
match $sname::supported_by_device_raw(physical_device) {
Ok(l) => l,
Err(SupportedExtensionsError::LoadingError(e)) => unreachable!(),
@ -192,6 +302,7 @@ macro_rules! device_extensions {
instance_extensions! {
InstanceExtensions,
RawInstanceExtensions,
khr_surface => b"VK_KHR_surface",
khr_display => b"VK_KHR_display",
khr_xlib_surface => b"VK_KHR_xlib_surface",
@ -210,6 +321,7 @@ instance_extensions! {
device_extensions! {
DeviceExtensions,
RawDeviceExtensions,
khr_swapchain => b"VK_KHR_swapchain",
khr_display_swapchain => b"VK_KHR_display_swapchain",
khr_sampler_mirror_clamp_to_edge => b"VK_KHR_sampler_mirror_clamp_to_edge",
@ -287,15 +399,15 @@ pub struct Unbuildable(());
#[cfg(test)]
mod tests {
use instance::InstanceExtensions;
use instance::DeviceExtensions;
use instance::{InstanceExtensions, RawInstanceExtensions};
use instance::{DeviceExtensions, RawDeviceExtensions};
#[test]
fn empty_extensions() {
let i = InstanceExtensions::none().build_extensions_list();
assert!(i.is_empty());
let i: RawInstanceExtensions = (&InstanceExtensions::none()).into();
assert!(i.iter().next().is_none());
let d = DeviceExtensions::none().build_extensions_list();
assert!(d.is_empty());
let d: RawDeviceExtensions = (&DeviceExtensions::none()).into();
assert!(d.iter().next().is_none());
}
}

View File

@ -29,7 +29,7 @@ use vk;
use features::Features;
use version::Version;
use instance::InstanceExtensions;
use instance::{InstanceExtensions, RawInstanceExtensions};
/// An instance of a Vulkan context. This is the main object that should be created by an
/// application before everything else.
@ -115,18 +115,19 @@ impl Instance {
// TODO: add a test for these ^
// TODO: if no allocator is specified by the user, use Rust's allocator instead of leaving
// the choice to Vulkan
pub fn new<'a, L>(app_infos: Option<&ApplicationInfo>, extensions: &InstanceExtensions,
layers: L) -> Result<Arc<Instance>, InstanceCreationError>
where L: IntoIterator<Item = &'a &'a str>
pub fn new<'a, L, Ext>(app_infos: Option<&ApplicationInfo>, extensions: Ext,
layers: L) -> Result<Arc<Instance>, InstanceCreationError>
where L: IntoIterator<Item = &'a &'a str>,
Ext: Into<RawInstanceExtensions>,
{
let layers = layers.into_iter().map(|&layer| {
CString::new(layer).unwrap()
}).collect::<SmallVec<[_; 16]>>();
Instance::new_inner(app_infos, extensions, layers)
Instance::new_inner(app_infos, extensions.into(), layers)
}
fn new_inner(app_infos: Option<&ApplicationInfo>, extensions: &InstanceExtensions,
fn new_inner(app_infos: Option<&ApplicationInfo>, extensions: RawInstanceExtensions,
layers: SmallVec<[CString; 16]>) -> Result<Arc<Instance>, InstanceCreationError>
{
// TODO: For now there are still buggy drivers that will segfault if you don't pass any
@ -169,8 +170,7 @@ impl Instance {
layer.as_ptr()
}).collect::<SmallVec<[_; 16]>>();
let extensions_list = extensions.build_extensions_list();
let extensions_list = extensions_list.iter().map(|extension| {
let extensions_list = extensions.iter().map(|extension| {
extension.as_ptr()
}).collect::<SmallVec<[_; 32]>>();
@ -268,7 +268,7 @@ impl Instance {
//alloc: None,
physical_devices: physical_devices,
vk: vk,
extensions: extensions.clone(),
extensions: (&extensions).into(),
layers: layers,
}))
}

View File

@ -107,6 +107,8 @@
pub use features::Features;
pub use self::extensions::DeviceExtensions;
pub use self::extensions::InstanceExtensions;
pub use self::extensions::RawDeviceExtensions;
pub use self::extensions::RawInstanceExtensions;
pub use self::instance::Instance;
pub use self::instance::InstanceCreationError;
pub use self::instance::ApplicationInfo;