mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 23:05:43 +00:00
Merge pull request #494 from Ralith/open-extensions
Support enabling statically unknown extensions
This commit is contained in:
commit
c332d03ca6
@ -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.
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}))
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user