Auto-generate extensions and features, check requirements (#1599)

* Migrate to using Ash as a base

* Small change to test, to make it applicable to Vulkan 1.1

* Auto-generate extensions, check extension requirements

* Add documentation to extensions, use vk.xml from Ash 0.32.1

* Remove `RawDeviceExtensions` and `RawInstanceExtensions`

* Add extension conflict checking

* Small fix

* Add auto-generated features, more requirements checks

* Features documentation

* Macrofy required_if_supported_extensions

* Include vulkano-gen tool

* Move autogen imports to macros

* Change autogen into a build script

* Delete leftover file
This commit is contained in:
Rua 2021-06-07 19:45:41 +02:00 committed by GitHub
parent 15fcbafaf9
commit 71191bd24d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 17295 additions and 976 deletions

View File

@ -1,12 +1,3 @@
[workspace]
members = [
"examples",
"vk-sys",
"vulkano",
"vulkano-shaders",
"vulkano-win"
]
exclude = [
"www"
]
members = ["examples", "vk-sys", "vulkano", "vulkano-shaders", "vulkano-win"]
exclude = ["www"]

View File

@ -14,7 +14,9 @@ readme = "../README.md"
build = "build.rs"
[dependencies]
ash = "0.32"
# When updating Ash, also update vk.xml to the same Vulkan patch version that Ash uses.
# All versions of vk.xml can be found at https://github.com/KhronosGroup/Vulkan-Headers/commits/master/registry/vk.xml.
ash = "0.32.1"
crossbeam-queue = "0.3"
fnv = "1.0"
half = "1.7"
@ -22,3 +24,9 @@ lazy_static = "1.4"
parking_lot = { version = "0.11.1", features = ["send_guard"] }
shared_library = "0.1"
smallvec = "1.6"
[build-dependencies]
heck = "0.3"
indexmap = "1.6"
regex = "1.5"
vk-parse = "0.6"

View File

@ -0,0 +1,399 @@
// Copyright (c) 2021 The Vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use heck::SnakeCase;
use indexmap::IndexMap;
use std::io::Write;
use vk_parse::Extension;
// This is not included in vk.xml, so it's added here manually
fn required_if_supported(name: &str) -> bool {
match name {
"VK_KHR_portability_subset" => true,
_ => false,
}
}
fn conflicts_extensions(name: &str) -> &'static [&'static str] {
match name {
"VK_KHR_buffer_device_address" => &["VK_EXT_buffer_device_address"],
"VK_EXT_buffer_device_address" => &["VK_KHR_buffer_device_address"],
_ => &[],
}
}
pub fn write<W: Write>(writer: &mut W, extensions: &IndexMap<&str, &Extension>) {
write_device_extensions(writer, make_vulkano_extensions("device", &extensions));
write!(writer, "\n\n").unwrap();
write_instance_extensions(writer, make_vulkano_extensions("instance", &extensions));
}
#[derive(Clone, Debug)]
struct VulkanoExtension {
member: String,
raw: String,
requires_core: (u16, u16),
requires_device_extensions: Vec<String>,
requires_instance_extensions: Vec<String>,
required_if_supported: bool,
conflicts_device_extensions: Vec<String>,
status: Option<ExtensionStatus>,
}
#[derive(Clone, Debug)]
enum Replacement {
Core((u16, u16)),
DeviceExtension(String),
InstanceExtension(String),
}
#[derive(Clone, Debug)]
enum ExtensionStatus {
Promoted(Replacement),
Deprecated(Option<Replacement>),
}
fn make_vulkano_extensions(
ty: &str,
extensions: &IndexMap<&str, &Extension>,
) -> Vec<VulkanoExtension> {
extensions
.values()
.filter(|ext| ext.ext_type.as_ref().unwrap() == ty)
.map(|ext| {
let raw = ext.name.to_owned();
let member = raw.strip_prefix("VK_").unwrap().to_snake_case();
let (major, minor) = ext
.requires_core
.as_ref()
.map(|s| s.as_str())
.unwrap_or("1.0")
.split_once('.')
.unwrap();
let requires_extensions: Vec<_> = ext
.requires
.as_ref()
.map(|s| s.split(',').collect())
.unwrap_or_default();
let conflicts_extensions = conflicts_extensions(&ext.name);
VulkanoExtension {
member: member.clone(),
raw,
requires_core: (major.parse().unwrap(), minor.parse().unwrap()),
requires_device_extensions: requires_extensions
.iter()
.filter(|&&vk_name| extensions[vk_name].ext_type.as_ref().unwrap() == "device")
.map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
.collect(),
requires_instance_extensions: requires_extensions
.iter()
.filter(|&&vk_name| {
extensions[vk_name].ext_type.as_ref().unwrap() == "instance"
})
.map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
.collect(),
required_if_supported: required_if_supported(ext.name.as_str()),
conflicts_device_extensions: conflicts_extensions
.iter()
.filter(|&&vk_name| extensions[vk_name].ext_type.as_ref().unwrap() == "device")
.map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
.collect(),
status: ext
.promotedto
.as_ref()
.map(|s| s.as_str())
.and_then(|pr| {
if let Some(version) = pr.strip_prefix("VK_VERSION_") {
let (major, minor) = version.split_once('_').unwrap();
Some(ExtensionStatus::Promoted(Replacement::Core((
major.parse().unwrap(),
minor.parse().unwrap(),
))))
} else {
let member = pr.strip_prefix("VK_").unwrap().to_snake_case();
match extensions[pr].ext_type.as_ref().unwrap().as_str() {
"device" => Some(ExtensionStatus::Promoted(
Replacement::DeviceExtension(member),
)),
"instance" => Some(ExtensionStatus::Promoted(
Replacement::InstanceExtension(member),
)),
_ => unreachable!(),
}
}
})
.or_else(|| {
ext.deprecatedby
.as_ref()
.map(|s| s.as_str())
.and_then(|depr| {
if depr.is_empty() {
Some(ExtensionStatus::Deprecated(None))
} else if let Some(version) = depr.strip_prefix("VK_VERSION_") {
let (major, minor) = version.split_once('_').unwrap();
Some(ExtensionStatus::Deprecated(Some(Replacement::Core((
major.parse().unwrap(),
minor.parse().unwrap(),
)))))
} else {
let member = depr.strip_prefix("VK_").unwrap().to_snake_case();
match extensions[depr].ext_type.as_ref().unwrap().as_str() {
"device" => Some(ExtensionStatus::Deprecated(Some(
Replacement::DeviceExtension(member),
))),
"instance" => Some(ExtensionStatus::Deprecated(Some(
Replacement::InstanceExtension(member),
))),
_ => unreachable!(),
}
}
})
}),
}
})
.collect()
}
fn write_device_extensions<W, I>(writer: &mut W, extensions: I)
where
W: Write,
I: IntoIterator<Item = VulkanoExtension>,
{
write!(writer, "crate::device::extensions::device_extensions! {{").unwrap();
for ext in extensions {
write!(writer, "\n\t{} => {{", ext.member).unwrap();
write_doc(writer, &ext);
write!(writer, "\n\t\traw: b\"{}\",", ext.raw).unwrap();
write!(
writer,
"\n\t\trequires_core: crate::Version::V{}_{},",
ext.requires_core.0, ext.requires_core.1
)
.unwrap();
write!(
writer,
"\n\t\trequires_device_extensions: [{}],",
ext.requires_device_extensions.join(", ")
)
.unwrap();
write!(
writer,
"\n\t\trequires_instance_extensions: [{}],",
ext.requires_instance_extensions.join(", ")
)
.unwrap();
write!(
writer,
"\n\t\trequired_if_supported: {},",
ext.required_if_supported
)
.unwrap();
write!(
writer,
"\n\t\tconflicts_device_extensions: [{}],",
ext.conflicts_device_extensions.join(", ")
)
.unwrap();
/*if let Some(promoted_to_core) = ext.promoted_to_core {
write!(
writer,
"\n\t\tpromoted_to_core: Some(Version::V{}_{}),",
promoted_to_core.0, promoted_to_core.1
)
.unwrap();
} else {
write!(writer, "\n\t\tpromoted_to_core: None,",).unwrap();
}*/
write!(writer, "\n\t}},").unwrap();
}
write!(writer, "\n}}").unwrap();
}
fn write_instance_extensions<W, I>(writer: &mut W, extensions: I)
where
W: Write,
I: IntoIterator<Item = VulkanoExtension>,
{
write!(
writer,
"crate::instance::extensions::instance_extensions! {{"
)
.unwrap();
for ext in extensions {
write!(writer, "\n\t{} => {{", ext.member).unwrap();
write_doc(writer, &ext);
write!(writer, "\n\t\traw: b\"{}\",", ext.raw).unwrap();
write!(
writer,
"\n\t\trequires_core: crate::Version::V{}_{},",
ext.requires_core.0, ext.requires_core.1
)
.unwrap();
write!(
writer,
"\n\t\trequires_extensions: [{}],",
ext.requires_instance_extensions.join(", ")
)
.unwrap();
/*if let Some(promoted_to_core) = ext.promoted_to_core {
write!(
writer,
"\n\t\tpromoted_to_core: Some(crate::Version::V{}_{}),",
promoted_to_core.0, promoted_to_core.1
)
.unwrap();
} else {
write!(writer, "\n\t\tpromoted_to_core: None,",).unwrap();
}*/
write!(writer, "\n\t}},").unwrap();
}
write!(writer, "\n}}").unwrap();
}
fn write_doc<W>(writer: &mut W, ext: &VulkanoExtension)
where
W: Write,
{
write!(writer, "\n\t\tdoc: \"\n\t\t\t- [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/{}.html)", ext.raw).unwrap();
if ext.requires_core != (1, 0) {
write!(
writer,
"\n\t\t\t- Requires Vulkan {}.{}",
ext.requires_core.0, ext.requires_core.1
)
.unwrap();
}
if !ext.requires_device_extensions.is_empty() {
let links: Vec<_> = ext
.requires_device_extensions
.iter()
.map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext))
.collect();
write!(
writer,
"\n\t\t\t- Requires device extension{}: {}",
if ext.requires_device_extensions.len() > 1 {
"s"
} else {
""
},
links.join(", ")
)
.unwrap();
}
if !ext.requires_instance_extensions.is_empty() {
let links: Vec<_> = ext
.requires_instance_extensions
.iter()
.map(|ext| format!("[`{}`](crate::instance::InstanceExtensions::{0})", ext))
.collect();
write!(
writer,
"\n\t\t\t- Requires instance extension{}: {}",
if ext.requires_instance_extensions.len() > 1 {
"s"
} else {
""
},
links.join(", ")
)
.unwrap();
}
if ext.required_if_supported {
write!(
writer,
"\n\t\t\t- Must be enabled if it is supported by the physical device",
)
.unwrap();
}
if !ext.conflicts_device_extensions.is_empty() {
let links: Vec<_> = ext
.conflicts_device_extensions
.iter()
.map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext))
.collect();
write!(
writer,
"\n\t\t\t- Conflicts with device extension{}: {}",
if ext.conflicts_device_extensions.len() > 1 {
"s"
} else {
""
},
links.join(", ")
)
.unwrap();
}
if let Some(status) = ext.status.as_ref() {
match status {
ExtensionStatus::Promoted(replacement) => {
write!(writer, "\n\t\t\t- Promoted to ",).unwrap();
match replacement {
Replacement::Core(version) => {
write!(writer, "Vulkan {}.{}", version.0, version.1).unwrap();
}
Replacement::DeviceExtension(ext) => {
write!(writer, "[`{}`](crate::device::DeviceExtensions::{0})", ext)
.unwrap();
}
Replacement::InstanceExtension(ext) => {
write!(
writer,
"[`{}`](crate::instance::InstanceExtensions::{0})",
ext
)
.unwrap();
}
}
}
ExtensionStatus::Deprecated(replacement) => {
write!(writer, "\n\t\t\t- Deprecated ",).unwrap();
match replacement {
Some(Replacement::Core(version)) => {
write!(writer, "by Vulkan {}.{}", version.0, version.1).unwrap();
}
Some(Replacement::DeviceExtension(ext)) => {
write!(
writer,
"by [`{}`](crate::device::DeviceExtensions::{0})",
ext
)
.unwrap();
}
Some(Replacement::InstanceExtension(ext)) => {
write!(
writer,
"by [`{}`](crate::instance::InstanceExtensions::{0})",
ext
)
.unwrap();
}
None => {
write!(writer, "without a replacement").unwrap();
}
}
}
}
}
write!(writer, "\n\t\t\",").unwrap();
}

384
vulkano/autogen/features.rs Normal file
View File

@ -0,0 +1,384 @@
// Copyright (c) 2021 The Vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use heck::SnakeCase;
use regex::Regex;
use std::{
collections::{hash_map::Entry, HashMap},
io::Write,
};
use vk_parse::{Type, TypeMember, TypeMemberMarkup, TypeSpec};
// This is not included in vk.xml, so it's added here manually
fn requires_features(name: &str) -> &'static [&'static str] {
match name {
"sparseImageInt64Atomics" => &["shaderImageInt64Atomics"],
"sparseImageFloat32Atomics" => &["shaderImageFloat32Atomics"],
"sparseImageFloat32AtomicAdd" => &["shaderImageFloat32AtomicAdd"],
_ => &[],
}
}
fn conflicts_features(name: &str) -> &'static [&'static str] {
match name {
"shadingRateImage" => &[
"pipelineFragmentShadingRate",
"primitiveFragmentShadingRate",
"attachmentFragmentShadingRate",
],
"fragmentDensityMap" => &[
"pipelineFragmentShadingRate",
"primitiveFragmentShadingRate",
"attachmentFragmentShadingRate",
],
"pipelineFragmentShadingRate" => &["shadingRateImage", "fragmentDensityMap"],
"primitiveFragmentShadingRate" => &["shadingRateImage", "fragmentDensityMap"],
"attachmentFragmentShadingRate" => &["shadingRateImage", "fragmentDensityMap"],
_ => &[],
}
}
fn required_by_extensions(name: &str) -> &'static [&'static str] {
match name {
"shaderDrawParameters" => &["VK_KHR_shader_draw_parameters"],
"drawIndirectCount" => &["VK_KHR_draw_indirect_count"],
"samplerMirrorClampToEdge" => &["VK_KHR_sampler_mirror_clamp_to_edge"],
"descriptorIndexing" => &["VK_EXT_descriptor_indexing"],
"samplerFilterMinmax" => &["VK_EXT_sampler_filter_minmax"],
"shaderOutputViewportIndex" => &["VK_EXT_shader_viewport_index_layer"],
"shaderOutputLayer" => &["VK_EXT_shader_viewport_index_layer"],
_ => &[],
}
}
pub fn write<W: Write>(writer: &mut W, types: &HashMap<&str, (&Type, Vec<&str>)>) {
write!(writer, "crate::device::features::features! {{").unwrap();
for feat in make_vulkano_features(&types) {
write!(writer, "\n\t{} => {{", feat.member).unwrap();
write_doc(writer, &feat);
write!(writer, "\n\t\tffi_name: {},", feat.ffi_name).unwrap();
write!(
writer,
"\n\t\tffi_members: [{}],",
feat.ffi_members.join(", ")
)
.unwrap();
write!(
writer,
"\n\t\trequires_features: [{}],",
feat.requires_features.join(", ")
)
.unwrap();
write!(
writer,
"\n\t\tconflicts_features: [{}],",
feat.conflicts_features.join(", ")
)
.unwrap();
write!(
writer,
"\n\t\trequired_by_extensions: [{}],",
feat.required_by_extensions.join(", ")
)
.unwrap();
write!(writer, "\n\t}},").unwrap();
}
write!(
writer,
"\n}}\n\ncrate::device::features::features_ffi! {{\n\tapi_version,\n\textensions,"
)
.unwrap();
for ffi in make_vulkano_features_ffi(&types) {
write!(writer, "\n\t{} => {{", ffi.member).unwrap();
write!(writer, "\n\t\tty: {},", ffi.ty).unwrap();
write!(
writer,
"\n\t\tprovided_by: [{}],",
ffi.provided_by.join(", ")
)
.unwrap();
write!(writer, "\n\t\tconflicts: [{}],", ffi.conflicts.join(", ")).unwrap();
write!(writer, "\n\t}},").unwrap();
}
write!(writer, "\n}}").unwrap();
}
#[derive(Clone, Debug)]
struct VulkanoFeature {
member: String,
vulkan_doc: String,
ffi_name: String,
ffi_members: Vec<String>,
requires_features: Vec<String>,
conflicts_features: Vec<String>,
required_by_extensions: Vec<String>,
}
fn make_vulkano_features(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<VulkanoFeature> {
let mut features = HashMap::new();
std::iter::once(&types["VkPhysicalDeviceFeatures"])
.chain(sorted_structs(types).into_iter())
.filter(|(ty, _)| {
ty.name.as_ref().map(|s| s.as_str()) == Some("VkPhysicalDeviceFeatures")
|| ty.structextends.as_ref().map(|s| s.as_str())
== Some("VkPhysicalDeviceFeatures2,VkDeviceCreateInfo")
})
.for_each(|(ty, _)| {
let vulkan_ty_name = ty.name.as_ref().unwrap();
let ty_name = if vulkan_ty_name == "VkPhysicalDeviceFeatures" {
"features_vulkan10.features".to_owned()
} else {
ffi_member(vulkan_ty_name)
};
members(ty).into_iter().for_each(|name| {
let member = name.to_snake_case();
match features.entry(member.clone()) {
Entry::Vacant(entry) => {
let requires_features = requires_features(name);
let conflicts_features = conflicts_features(name);
let required_by_extensions = required_by_extensions(name);
entry.insert(VulkanoFeature {
member: member.clone(),
vulkan_doc: format!("{}.html#features-{}", vulkan_ty_name, name),
ffi_name: member,
ffi_members: vec![ty_name.to_owned()],
requires_features: requires_features
.into_iter()
.map(|&s| s.to_snake_case())
.collect(),
conflicts_features: conflicts_features
.into_iter()
.map(|&s| s.to_snake_case())
.collect(),
required_by_extensions: required_by_extensions
.iter()
.map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
.collect(),
});
}
Entry::Occupied(entry) => {
entry.into_mut().ffi_members.push(ty_name.to_owned());
}
};
});
});
let mut names: Vec<_> = features.values().map(|feat| feat.member.clone()).collect();
names.sort_unstable();
names
.into_iter()
.map(|name| features.remove(&name).unwrap())
.collect()
}
fn write_doc<W>(writer: &mut W, feat: &VulkanoFeature)
where
W: Write,
{
write!(writer, "\n\t\tdoc: \"\n\t\t\t- [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/{})", feat.vulkan_doc).unwrap();
if !feat.requires_features.is_empty() {
let links: Vec<_> = feat
.requires_features
.iter()
.map(|ext| format!("[`{}`](crate::device::Features::{0})", ext))
.collect();
write!(
writer,
"\n\t\t\t- Requires feature{}: {}",
if feat.requires_features.len() > 1 {
"s"
} else {
""
},
links.join(", ")
)
.unwrap();
}
if !feat.required_by_extensions.is_empty() {
let links: Vec<_> = feat
.required_by_extensions
.iter()
.map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext))
.collect();
write!(
writer,
"\n\t\t\t- Required by device extension{}: {}",
if feat.required_by_extensions.len() > 1 {
"s"
} else {
""
},
links.join(", ")
)
.unwrap();
}
if !feat.conflicts_features.is_empty() {
let links: Vec<_> = feat
.conflicts_features
.iter()
.map(|ext| format!("[`{}`](crate::device::Features::{0})", ext))
.collect();
write!(
writer,
"\n\t\t\t- Conflicts with feature{}: {}",
if feat.conflicts_features.len() > 1 {
"s"
} else {
""
},
links.join(", ")
)
.unwrap();
}
write!(writer, "\n\t\t\",").unwrap();
}
#[derive(Clone, Debug)]
struct VulkanoFeatureFfi {
member: String,
ty: String,
provided_by: Vec<String>,
conflicts: Vec<String>,
}
fn make_vulkano_features_ffi(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<VulkanoFeatureFfi> {
let mut feature_included_in: HashMap<&str, Vec<&str>> = HashMap::new();
sorted_structs(types)
.into_iter()
.map(|(ty, provided_by)| {
let name = ty.name.as_ref().unwrap();
let provided_by = provided_by
.iter()
.map(|provided_by| {
if let Some(version) = provided_by.strip_prefix("VK_VERSION_") {
format!("api_version >= crate::Version::V{}", version)
} else {
format!(
"extensions.{}",
provided_by
.strip_prefix("VK_")
.unwrap()
.to_ascii_lowercase()
)
}
})
.collect();
let mut conflicts = vec![];
members(ty)
.into_iter()
.for_each(|member| match feature_included_in.entry(member) {
Entry::Vacant(entry) => {
entry.insert(vec![name]);
}
Entry::Occupied(entry) => {
let conflicters = entry.into_mut();
conflicters.iter().for_each(|conflicter| {
let conflicter = ffi_member(conflicter);
if !conflicts.contains(&conflicter) {
conflicts.push(conflicter);
}
});
conflicters.push(name);
}
});
VulkanoFeatureFfi {
member: ffi_member(name),
ty: name.strip_prefix("Vk").unwrap().to_owned(),
provided_by,
conflicts,
}
})
.collect()
}
fn sorted_structs<'a>(
types: &'a HashMap<&str, (&'a Type, Vec<&'a str>)>,
) -> Vec<&'a (&'a Type, Vec<&'a str>)> {
let mut structs: Vec<_> = types
.values()
.filter(|(ty, _)| {
ty.structextends.as_ref().map(|s| s.as_str())
== Some("VkPhysicalDeviceFeatures2,VkDeviceCreateInfo")
})
.collect();
let regex = Regex::new(r"^VkPhysicalDeviceVulkan\d+Features$").unwrap();
structs.sort_unstable_by_key(|&(ty, provided_by)| {
let name = ty.name.as_ref().unwrap();
(
!regex.is_match(name),
if let Some(version) = provided_by
.iter()
.find_map(|s| s.strip_prefix("VK_VERSION_"))
{
let (major, minor) = version.split_once('_').unwrap();
major.parse::<i32>().unwrap() << 22 | minor.parse::<i32>().unwrap() << 12
} else if provided_by
.iter()
.find(|s| s.starts_with("VK_KHR_"))
.is_some()
{
i32::MAX - 2
} else if provided_by
.iter()
.find(|s| s.starts_with("VK_EXT_"))
.is_some()
{
i32::MAX - 1
} else {
i32::MAX
},
name,
)
});
structs
}
fn ffi_member(ty_name: &str) -> String {
let ty_name = ty_name
.strip_prefix("VkPhysicalDevice")
.unwrap()
.to_snake_case();
let (base, suffix) = ty_name.rsplit_once("_features").unwrap();
format!("features_{}{}", base, suffix)
}
fn members(ty: &Type) -> Vec<&str> {
if let TypeSpec::Members(members) = &ty.spec {
members
.iter()
.filter_map(|member| {
if let TypeMember::Definition(def) = member {
let name = def.markup.iter().find_map(|markup| match markup {
TypeMemberMarkup::Name(name) => Some(name.as_str()),
_ => None,
});
if name != Some("sType") && name != Some("pNext") {
return name;
}
}
None
})
.collect()
} else {
vec![]
}
}

79
vulkano/autogen/fns.rs Normal file
View File

@ -0,0 +1,79 @@
// Copyright (c) 2021 The Vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use heck::{CamelCase, SnakeCase};
use indexmap::IndexMap;
use std::io::Write;
use vk_parse::{Extension, ExtensionChild, InterfaceItem};
pub fn write<W: Write>(writer: &mut W, extensions: &IndexMap<&str, &Extension>) {
write_fns(writer, std::iter::empty(), "Entry");
write!(writer, "\n\n").unwrap();
write_fns(
writer,
make_vulkano_extension_fns("instance", &extensions),
"Instance",
);
write!(writer, "\n\n").unwrap();
write_fns(
writer,
make_vulkano_extension_fns("device", &extensions),
"Device",
);
}
#[derive(Clone, Debug)]
struct VulkanoFns {
member: String,
fn_struct: String,
}
fn make_vulkano_extension_fns(
ty: &str,
extensions: &IndexMap<&str, &Extension>,
) -> Vec<VulkanoFns> {
extensions
.values()
.filter(|ext| ext.ext_type.as_ref().unwrap() == ty)
// Filter only extensions that have functions
.filter(|ext| {
ext.children.iter().any(|ch| {
if let ExtensionChild::Require { items, .. } = ch {
items
.iter()
.any(|i| matches!(i, InterfaceItem::Command { .. }))
} else {
false
}
})
})
.map(|ext| {
let member = ext.name.strip_prefix("VK_").unwrap().to_snake_case();
let fn_struct = member.to_camel_case() + "Fn";
VulkanoFns { member, fn_struct }
})
.collect()
}
fn write_fns<W, I>(writer: &mut W, extension_fns: I, ty: &str)
where
W: Write,
I: IntoIterator<Item = VulkanoFns>,
{
write!(writer, "crate::fns::fns!({}Functions, {{", ty).unwrap();
for version in std::array::IntoIter::new(["1_0", "1_1", "1_2"]) {
write!(writer, "\n\tv{} => {}FnV{0},", version, ty).unwrap();
}
for ext in extension_fns {
write!(writer, "\n\t{} => {},", ext.member, ext.fn_struct).unwrap();
}
write!(writer, "\n}});").unwrap();
}

212
vulkano/autogen/mod.rs Normal file
View File

@ -0,0 +1,212 @@
// Copyright (c) 2021 The Vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use indexmap::IndexMap;
use std::{collections::HashMap, io::Write, path::Path};
use vk_parse::{
Extension, ExtensionChild, Feature, InterfaceItem, Registry, RegistryChild, Type,
TypeCodeMarkup, TypeSpec, TypesChild,
};
mod extensions;
mod features;
mod fns;
pub fn write<W: Write>(writer: &mut W) {
let registry = get_registry("vk.xml");
let aliases = get_aliases(&registry);
let extensions = get_extensions(&registry);
let features = get_features(&registry);
let types = get_types(&registry, &aliases, &features, &extensions);
let header_version = get_header_version(&registry);
write!(
writer,
"\
// This file is auto-generated by vulkano-gen from vk.xml header version {}.\n\
// It should not be edited manually. Changes should be made by editing vulkano-gen.\n\
\n",
header_version
)
.unwrap();
extensions::write(writer, &extensions);
write!(writer, "\n\n").unwrap();
fns::write(writer, &extensions);
write!(writer, "\n\n").unwrap();
features::write(writer, &types);
write!(writer, "\n").unwrap();
}
fn get_registry<P: AsRef<Path> + ?Sized>(path: &P) -> Registry {
let (registry, errors) = vk_parse::parse_file(path.as_ref()).unwrap();
if !errors.is_empty() {
eprintln!("The following errors were found while parsing the file:");
for error in errors {
eprintln!("{:?}", error);
}
}
registry
}
fn get_aliases(registry: &Registry) -> HashMap<&str, &str> {
registry
.0
.iter()
.filter_map(|child| {
if let RegistryChild::Types(types) = child {
return Some(types.children.iter().filter_map(|ty| {
if let TypesChild::Type(ty) = ty {
if let Some(alias) = ty.alias.as_ref().map(|s| s.as_str()) {
return Some((ty.name.as_ref().unwrap().as_str(), alias));
}
}
None
}));
}
None
})
.flatten()
.collect()
}
fn get_extensions(registry: &Registry) -> IndexMap<&str, &Extension> {
let iter = registry
.0
.iter()
.filter_map(|child| {
if let RegistryChild::Extensions(ext) = child {
return Some(ext.children.iter().filter_map(|ext| {
if ext.supported.as_ref().map(|s| s.as_str()) == Some("vulkan")
&& ext.obsoletedby.is_none()
{
return Some(ext);
}
None
}));
}
None
})
.flatten();
let extensions: HashMap<&str, &Extension> =
iter.clone().map(|ext| (ext.name.as_str(), ext)).collect();
let mut names: Vec<_> = iter.map(|ext| ext.name.as_str()).collect();
names.sort_unstable_by_key(|name| {
if name.starts_with("VK_KHR_") {
(0, name.to_owned())
} else if name.starts_with("VK_EXT_") {
(1, name.to_owned())
} else {
(2, name.to_owned())
}
});
names.iter().map(|&name| (name, extensions[name])).collect()
}
fn get_features(registry: &Registry) -> IndexMap<&str, &Feature> {
registry
.0
.iter()
.filter_map(|child| {
if let RegistryChild::Feature(feat) = child {
return Some((feat.name.as_str(), feat));
}
None
})
.collect()
}
fn get_types<'a>(
registry: &'a Registry,
aliases: &'a HashMap<&str, &str>,
features: &'a IndexMap<&str, &Feature>,
extensions: &'a IndexMap<&str, &Extension>,
) -> HashMap<&'a str, (&'a Type, Vec<&'a str>)> {
let mut types: HashMap<&str, (&Type, Vec<&str>)> = registry
.0
.iter()
.filter_map(|child| {
if let RegistryChild::Types(types) = child {
return Some(types.children.iter().filter_map(|ty| {
if let TypesChild::Type(ty) = ty {
if ty.alias.is_none() {
return ty.name.as_ref().map(|name| (name.as_str(), (ty, vec![])));
}
}
None
}));
}
None
})
.flatten()
.collect();
features
.iter()
.map(|(name, feature)| (name, &feature.children))
.chain(extensions.iter().map(|(name, ext)| (name, &ext.children)))
.for_each(|(provided_by, children)| {
children
.iter()
.filter_map(|child| {
if let ExtensionChild::Require { items, .. } = child {
return Some(items.iter());
}
None
})
.flatten()
.filter_map(|item| {
if let InterfaceItem::Type { name, .. } = item {
return Some(name.as_str());
}
None
})
.for_each(|item_name| {
let item_name = aliases.get(item_name).unwrap_or(&item_name);
if let Some(ty) = types.get_mut(item_name) {
if !ty.1.contains(provided_by) {
ty.1.push(provided_by);
}
}
});
});
types
.into_iter()
.filter(|(_key, val)| !val.1.is_empty())
.collect()
}
fn get_header_version(registry: &Registry) -> u16 {
registry.0.iter()
.find_map(|child| -> Option<u16> {
if let RegistryChild::Types(types) = child {
return types.children.iter().find_map(|ty| -> Option<u16> {
if let TypesChild::Type(ty) = ty {
if let TypeSpec::Code(code) = &ty.spec {
if code.markup.iter().any(|mkup| matches!(mkup, TypeCodeMarkup::Name(name) if name == "VK_HEADER_VERSION")) {
return Some(code.code.rsplit_once(' ').unwrap().1.parse().unwrap());
}
}
}
None
});
}
None
})
.unwrap()
}

View File

@ -7,7 +7,9 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::env;
use std::{env, fs::File, io::BufWriter, path::Path};
mod autogen;
fn main() {
let target = env::var("TARGET").unwrap();
@ -21,4 +23,9 @@ fn main() {
println!("cargo:rustc-link-lib=framework=UIKit");
println!("cargo:rustc-link-lib=framework=Foundation");
}
// Write autogen.rs
let path = Path::new(&env::var_os("OUT_DIR").unwrap()).join("autogen.rs");
let mut writer = BufWriter::new(File::create(path).unwrap());
autogen::write(&mut writer);
}

View File

@ -102,10 +102,7 @@ impl UnsafeBuffer {
ash::vk::BufferCreateFlags::empty()
};
if usage.device_address
&& !(device.enabled_features().buffer_device_address
|| device.enabled_features().ext_buffer_device_address)
{
if usage.device_address && !device.enabled_features().buffer_device_address {
usage.device_address = false;
if ash::vk::BufferUsageFlags::from(usage).is_empty() {
// return an error iff device_address was the only requested usage and the

View File

@ -7,99 +7,157 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::collections::HashSet;
use std::ffi::{CStr, CString};
use std::fmt;
use std::iter::FromIterator;
use std::ptr;
use std::str;
use crate::check_errors;
use crate::extensions::SupportedExtensionsError;
pub use crate::extensions::{
ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
};
use crate::instance::PhysicalDevice;
use crate::VulkanObject;
use std::ffi::CStr;
use std::ptr;
macro_rules! device_extensions {
($sname:ident, $rawname:ident, [$($ext_req_if_supported:ident,)*], $($ext:ident => $s:expr,)*) => (
(
$($member:ident => {
doc: $doc:expr,
raw: $raw:expr,
requires_core: $requires_core:expr,
requires_device_extensions: [$($requires_device_extension:ident),*],
requires_instance_extensions: [$($requires_instance_extension:ident),*],
required_if_supported: $required_if_supported:expr,
conflicts_device_extensions: [$($conflicts_device_extension:ident),*],
},)*
) => (
extensions! {
$sname, $rawname,
$( $ext => $s,)*
DeviceExtensions,
$( $member => {
doc: $doc,
raw: $raw,
requires_core: $requires_core,
requires_device_extensions: [$($requires_device_extension),*],
requires_instance_extensions: [$($requires_instance_extension),*],
},)*
}
impl $rawname {
/// See the docs of supported_by_device().
pub fn supported_by_device_raw(physical_device: PhysicalDevice) -> Result<Self, SupportedExtensionsError> {
let fns = physical_device.instance().fns();
let properties: Vec<ash::vk::ExtensionProperties> = unsafe {
let mut num = 0;
check_errors(fns.v1_0.enumerate_device_extension_properties(
physical_device.internal_object(), ptr::null(), &mut num, ptr::null_mut()
))?;
let mut properties = Vec::with_capacity(num as usize);
check_errors(fns.v1_0.enumerate_device_extension_properties(
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.extension_name.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(_)) => 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<Self, SupportedExtensionsError> {
let fns = physical_device.instance().fns();
let properties: Vec<ash::vk::ExtensionProperties> = unsafe {
let mut num = 0;
check_errors(fns.v1_0.enumerate_device_extension_properties(
physical_device.internal_object(), ptr::null(), &mut num, ptr::null_mut()
))?;
let mut properties = Vec::with_capacity(num as usize);
check_errors(fns.v1_0.enumerate_device_extension_properties(
physical_device.internal_object(), ptr::null(), &mut num, properties.as_mut_ptr()
))?;
properties.set_len(num as usize);
properties
};
let mut extensions = $sname::none();
for property in properties {
let name = unsafe { CStr::from_ptr(property.extension_name.as_ptr()) };
impl DeviceExtensions {
/// Checks enabled extensions against the device version, instance extensions and each other.
pub(super) fn check_requirements(
&self,
supported: &DeviceExtensions,
api_version: crate::Version,
instance_extensions: &InstanceExtensions,
) -> Result<(), crate::extensions::ExtensionRestrictionError> {
$(
// TODO: Check specVersion?
if name.to_bytes() == &$s[..] {
extensions.$ext = true;
if self.$member {
if !supported.$member {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::NotSupported,
});
}
if api_version < $requires_core {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::RequiresCore($requires_core),
});
}
$(
if !self.$requires_device_extension {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::RequiresDeviceExtension(stringify!($requires_device_extension)),
});
}
)*
$(
if !instance_extensions.$requires_instance_extension {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::RequiresInstanceExtension(stringify!($requires_instance_extension)),
});
}
)*
$(
if self.$conflicts_device_extension {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::ConflictsDeviceExtension(stringify!($conflicts_device_extension)),
});
}
)*
} else {
if $required_if_supported && supported.$member {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::RequiredIfSupported,
});
}
}
)*
Ok(())
}
Ok(extensions)
pub(crate) fn required_if_supported_extensions() -> Self {
Self {
$(
$member: $required_if_supported,
)*
_unbuildable: crate::extensions::Unbuildable(())
}
}
}
);
}
pub use crate::autogen::DeviceExtensions;
pub(crate) use device_extensions;
impl DeviceExtensions {
/// See the docs of supported_by_device().
pub fn supported_by_device_raw(
physical_device: PhysicalDevice,
) -> Result<Self, SupportedExtensionsError> {
let fns = physical_device.instance().fns();
let properties: Vec<ash::vk::ExtensionProperties> = unsafe {
let mut num = 0;
check_errors(fns.v1_0.enumerate_device_extension_properties(
physical_device.internal_object(),
ptr::null(),
&mut num,
ptr::null_mut(),
))?;
let mut properties = Vec::with_capacity(num as usize);
check_errors(fns.v1_0.enumerate_device_extension_properties(
physical_device.internal_object(),
ptr::null(),
&mut num,
properties.as_mut_ptr(),
))?;
properties.set_len(num as usize);
properties
};
Ok(Self::from(properties.iter().map(|property| unsafe {
CStr::from_ptr(property.extension_name.as_ptr())
})))
}
/// Returns an `Extensions` object with extensions supported by the `PhysicalDevice`.
/// Returns a `DeviceExtensions` object with extensions supported by the `PhysicalDevice`.
pub fn supported_by_device(physical_device: PhysicalDevice) -> Self {
match $sname::supported_by_device_raw(physical_device) {
match DeviceExtensions::supported_by_device_raw(physical_device) {
Ok(l) => l,
Err(SupportedExtensionsError::LoadingError(_)) => unreachable!(),
Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
}
}
/// Returns an `Extensions` object with extensions required as well as supported by the `PhysicalDevice`.
/// Returns a `DeviceExtensions` object with extensions required as well as supported by the `PhysicalDevice`.
/// They are needed to be passed to `Device::new(...)`.
pub fn required_extensions(physical_device: PhysicalDevice) -> Self {
let supported = Self::supported_by_device(physical_device);
@ -107,46 +165,6 @@ macro_rules! device_extensions {
required_if_supported.intersection(&supported)
}
fn required_if_supported_extensions() -> Self {
Self {
$(
$ext_req_if_supported: true,
)*
..Self::none()
}
}
}
);
}
device_extensions! {
DeviceExtensions,
RawDeviceExtensions,
[ // required if supported extensions
// https://vulkan.lunarg.com/doc/view/1.2.162.1/mac/1.2-extensions/vkspec.html#VUID-VkDeviceCreateInfo-pProperties-04451
khr_portability_subset,
],
// List in order: khr, ext, then alphabetical
khr_16bit_storage => b"VK_KHR_16bit_storage",
khr_8bit_storage => b"VK_KHR_8bit_storage",
khr_dedicated_allocation => b"VK_KHR_dedicated_allocation",
khr_display_swapchain => b"VK_KHR_display_swapchain",
khr_external_memory => b"VK_KHR_external_memory",
khr_external_memory_fd => b"VK_KHR_external_memory_fd",
khr_get_memory_requirements2 => b"VK_KHR_get_memory_requirements2",
khr_incremental_present => b"VK_KHR_incremental_present",
khr_maintenance1 => b"VK_KHR_maintenance1",
khr_multiview => b"VK_KHR_multiview",
khr_portability_subset => b"VK_KHR_portability_subset",
khr_sampler_mirror_clamp_to_edge => b"VK_KHR_sampler_mirror_clamp_to_edge",
khr_spirv_1_4 => b"VK_KHR_spirv_1_4",
khr_storage_buffer_storage_class => b"VK_KHR_storage_buffer_storage_class",
khr_swapchain => b"VK_KHR_swapchain",
ext_debug_utils => b"VK_EXT_debug_utils",
ext_external_memory_dmabuf => b"VK_EXT_external_memory_dma_buf",
ext_full_screen_exclusive => b"VK_EXT_full_screen_exclusive",
}
/// This helper type can only be instantiated inside this module.
@ -157,11 +175,12 @@ pub struct Unbuildable(());
#[cfg(test)]
mod tests {
use crate::device::{DeviceExtensions, RawDeviceExtensions};
use crate::device::DeviceExtensions;
use std::ffi::CString;
#[test]
fn empty_extensions() {
let d: RawDeviceExtensions = (&DeviceExtensions::none()).into();
let d: Vec<CString> = (&DeviceExtensions::none()).into();
assert!(d.iter().next().is_none());
}

View File

@ -7,13 +7,19 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::Version;
use std::marker::PhantomPinned;
use std::ptr::addr_of_mut;
use std::error;
use std::fmt;
macro_rules! features {
{
$({ $member:ident => $($ffi_struct:ident.$($ffi_field:ident).+)|+ },)*
$($member:ident => {
doc: $doc:expr,
ffi_name: $ffi_field:ident,
ffi_members: [$($ffi_struct:ident $(.$ffi_struct_field:ident)?),+],
requires_features: [$($requires_feature:ident),*],
conflicts_features: [$($conflicts_feature:ident),*],
required_by_extensions: [$($required_by_extension:ident),*],
},)*
} => {
/// Represents all the features that are available on a physical device or enabled on
/// a logical device.
@ -48,10 +54,61 @@ macro_rules! features {
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
#[allow(missing_docs)]
pub struct Features {
$(pub $member: bool,)*
$(
#[doc = $doc]
pub $member: bool,
)*
}
impl Features {
/// Checks enabled features against the device version, device extensions and each other.
pub(super) fn check_requirements(
&self,
supported: &Features,
api_version:
crate::Version,
extensions: &crate::device::DeviceExtensions,
) -> Result<(), crate::device::features::FeatureRestrictionError> {
$(
if self.$member {
if !supported.$member {
return Err(crate::device::features::FeatureRestrictionError {
feature: stringify!($member),
restriction: crate::device::features::FeatureRestriction::NotSupported,
});
}
$(
if !self.$requires_feature {
return Err(crate::device::features::FeatureRestrictionError {
feature: stringify!($member),
restriction: crate::device::features::FeatureRestriction::RequiresFeature(stringify!($requires_feature)),
});
}
)*
$(
if self.$conflicts_feature {
return Err(crate::device::features::FeatureRestrictionError {
feature: stringify!($member),
restriction: crate::device::features::FeatureRestriction::ConflictsFeature(stringify!($conflicts_feature)),
});
}
)*
} else {
$(
if extensions.$required_by_extension {
return Err(crate::device::features::FeatureRestrictionError {
feature: stringify!($member),
restriction: crate::device::features::FeatureRestriction::RequiredByExtension(stringify!($required_by_extension)),
});
}
)*
}
)*
Ok(())
}
/// Builds a `Features` object with all values to false.
pub fn none() -> Features {
Features {
@ -97,235 +154,128 @@ macro_rules! features {
}
}
impl From<&Features> for FeaturesFfi {
#[inline(always)]
fn from(features: &Features) -> Self {
let mut features_ffi = FeaturesFfi::default();
impl FeaturesFfi {
pub(crate) fn write(&mut self, features: &Features) {
$(
$(features_ffi.$ffi_struct.$($ffi_field).+ |= features.$member as ash::vk::Bool32;)*
)+
features_ffi
std::array::IntoIter::new([
$(self.$ffi_struct.as_mut().map(|s| &mut s$(.$ffi_struct_field)?.$ffi_field)),+
]).flatten().next().map(|f| *f = features.$member as ash::vk::Bool32);
)*
}
}
impl From<&FeaturesFfi> for Features {
#[inline(always)]
fn from(features_ffi: &FeaturesFfi) -> Self {
Features {
$($member: $(features_ffi.$ffi_struct.$($ffi_field).+ != 0)||+,)*
$(
$member: std::array::IntoIter::new([
$(features_ffi.$ffi_struct.map(|s| s$(.$ffi_struct_field)?.$ffi_field)),+
]).flatten().next().unwrap_or(0) != 0,
)*
}
}
}
};
}
features! {
// Vulkan 1.0
{robust_buffer_access => vulkan_1_0.features.robust_buffer_access},
{full_draw_index_uint32 => vulkan_1_0.features.full_draw_index_uint32},
{image_cube_array => vulkan_1_0.features.image_cube_array},
{independent_blend => vulkan_1_0.features.independent_blend},
{geometry_shader => vulkan_1_0.features.geometry_shader},
{tessellation_shader => vulkan_1_0.features.tessellation_shader},
{sample_rate_shading => vulkan_1_0.features.sample_rate_shading},
{dual_src_blend => vulkan_1_0.features.dual_src_blend},
{logic_op => vulkan_1_0.features.logic_op},
{multi_draw_indirect => vulkan_1_0.features.multi_draw_indirect},
{draw_indirect_first_instance => vulkan_1_0.features.draw_indirect_first_instance},
{depth_clamp => vulkan_1_0.features.depth_clamp},
{depth_bias_clamp => vulkan_1_0.features.depth_bias_clamp},
{fill_mode_non_solid => vulkan_1_0.features.fill_mode_non_solid},
{depth_bounds => vulkan_1_0.features.depth_bounds},
{wide_lines => vulkan_1_0.features.wide_lines},
{large_points => vulkan_1_0.features.large_points},
{alpha_to_one => vulkan_1_0.features.alpha_to_one},
{multi_viewport => vulkan_1_0.features.multi_viewport},
{sampler_anisotropy => vulkan_1_0.features.sampler_anisotropy},
{texture_compression_etc2 => vulkan_1_0.features.texture_compression_etc2},
{texture_compression_astc_ldr => vulkan_1_0.features.texture_compression_astc_ldr},
{texture_compression_bc => vulkan_1_0.features.texture_compression_bc},
{occlusion_query_precise => vulkan_1_0.features.occlusion_query_precise},
{pipeline_statistics_query => vulkan_1_0.features.pipeline_statistics_query},
{vertex_pipeline_stores_and_atomics => vulkan_1_0.features.vertex_pipeline_stores_and_atomics},
{fragment_stores_and_atomics => vulkan_1_0.features.fragment_stores_and_atomics},
{shader_tessellation_and_geometry_point_size => vulkan_1_0.features.shader_tessellation_and_geometry_point_size},
{shader_image_gather_extended => vulkan_1_0.features.shader_image_gather_extended},
{shader_storage_image_extended_formats => vulkan_1_0.features.shader_storage_image_extended_formats},
{shader_storage_image_multisample => vulkan_1_0.features.shader_storage_image_multisample},
{shader_storage_image_read_without_format => vulkan_1_0.features.shader_storage_image_read_without_format},
{shader_storage_image_write_without_format => vulkan_1_0.features.shader_storage_image_write_without_format},
{shader_uniform_buffer_array_dynamic_indexing => vulkan_1_0.features.shader_uniform_buffer_array_dynamic_indexing},
{shader_sampled_image_array_dynamic_indexing => vulkan_1_0.features.shader_sampled_image_array_dynamic_indexing},
{shader_storage_buffer_array_dynamic_indexing => vulkan_1_0.features.shader_storage_buffer_array_dynamic_indexing},
{shader_storage_image_array_dynamic_indexing => vulkan_1_0.features.shader_storage_image_array_dynamic_indexing},
{shader_clip_distance => vulkan_1_0.features.shader_clip_distance},
{shader_cull_distance => vulkan_1_0.features.shader_cull_distance},
{shader_float64 => vulkan_1_0.features.shader_float64},
{shader_int64 => vulkan_1_0.features.shader_int64},
{shader_int16 => vulkan_1_0.features.shader_int16},
{shader_resource_residency => vulkan_1_0.features.shader_resource_residency},
{shader_resource_min_lod => vulkan_1_0.features.shader_resource_min_lod},
{sparse_binding => vulkan_1_0.features.sparse_binding},
{sparse_residency_buffer => vulkan_1_0.features.sparse_residency_buffer},
{sparse_residency_image2d => vulkan_1_0.features.sparse_residency_image2_d},
{sparse_residency_image3d => vulkan_1_0.features.sparse_residency_image3_d},
{sparse_residency2_samples => vulkan_1_0.features.sparse_residency2_samples},
{sparse_residency4_samples => vulkan_1_0.features.sparse_residency4_samples},
{sparse_residency8_samples => vulkan_1_0.features.sparse_residency8_samples},
{sparse_residency16_samples => vulkan_1_0.features.sparse_residency16_samples},
{sparse_residency_aliased => vulkan_1_0.features.sparse_residency_aliased},
{variable_multisample_rate => vulkan_1_0.features.variable_multisample_rate},
{inherited_queries => vulkan_1_0.features.inherited_queries},
pub use crate::autogen::Features;
pub(crate) use {crate::autogen::FeaturesFfi, features};
// Vulkan 1.1
{storage_buffer_16bit => vulkan_1_1.storage_buffer16_bit_access | khr_16bit_storage.storage_buffer16_bit_access},
{storage_uniform_16bit => vulkan_1_1.uniform_and_storage_buffer16_bit_access | khr_16bit_storage.uniform_and_storage_buffer16_bit_access},
{storage_push_constant_16bit => vulkan_1_1.storage_push_constant16 | khr_16bit_storage.storage_push_constant16},
{storage_input_output_16bit => vulkan_1_1.storage_input_output16 | khr_16bit_storage.storage_input_output16},
{multiview => vulkan_1_1.multiview | khr_multiview.multiview},
{multiview_geometry_shader => vulkan_1_1.multiview_geometry_shader | khr_multiview.multiview_geometry_shader},
{multiview_tessellation_shader => vulkan_1_1.multiview_tessellation_shader | khr_multiview.multiview_tessellation_shader},
{variable_pointers_storage_buffer => vulkan_1_1.variable_pointers_storage_buffer | khr_variable_pointers.variable_pointers_storage_buffer},
{variable_pointers => vulkan_1_1.variable_pointers | khr_variable_pointers.variable_pointers},
{protected_memory => vulkan_1_1.protected_memory | protected_memory.protected_memory},
{sampler_ycbcr_conversion => vulkan_1_1.sampler_ycbcr_conversion | khr_sampler_ycbcr_conversion.sampler_ycbcr_conversion},
{shader_draw_parameters => vulkan_1_1.shader_draw_parameters | shader_draw_parameters.shader_draw_parameters},
// Vulkan 1.2
{sampler_mirror_clamp_to_edge => vulkan_1_2.sampler_mirror_clamp_to_edge},
{draw_indirect_count => vulkan_1_2.draw_indirect_count},
{storage_buffer_8bit => vulkan_1_2.storage_buffer8_bit_access | khr_8bit_storage.storage_buffer8_bit_access},
{storage_uniform_8bit => vulkan_1_2.uniform_and_storage_buffer8_bit_access | khr_8bit_storage.uniform_and_storage_buffer8_bit_access},
{storage_push_constant_8bit => vulkan_1_2.storage_push_constant8 | khr_8bit_storage.storage_push_constant8},
{shader_buffer_int64_atomics => vulkan_1_2.shader_buffer_int64_atomics | khr_shader_atomic_int64.shader_buffer_int64_atomics},
{shader_shared_int64_atomics => vulkan_1_2.shader_shared_int64_atomics | khr_shader_atomic_int64.shader_shared_int64_atomics},
{shader_float16 => vulkan_1_2.shader_float16 | khr_shader_float16_int8.shader_float16},
{shader_int8 => vulkan_1_2.shader_int8 | khr_shader_float16_int8.shader_int8},
{descriptor_indexing => vulkan_1_2.descriptor_indexing},
{shader_input_attachment_array_dynamic_indexing => vulkan_1_2.shader_input_attachment_array_dynamic_indexing | ext_descriptor_indexing.shader_input_attachment_array_dynamic_indexing},
{shader_uniform_texel_buffer_array_dynamic_indexing => vulkan_1_2.shader_uniform_texel_buffer_array_dynamic_indexing | ext_descriptor_indexing.shader_uniform_texel_buffer_array_dynamic_indexing},
{shader_storage_texel_buffer_array_dynamic_indexing => vulkan_1_2.shader_storage_texel_buffer_array_dynamic_indexing | ext_descriptor_indexing.shader_storage_texel_buffer_array_dynamic_indexing},
{shader_uniform_buffer_array_non_uniform_indexing => vulkan_1_2.shader_uniform_buffer_array_non_uniform_indexing | ext_descriptor_indexing.shader_uniform_buffer_array_non_uniform_indexing},
{shader_sampled_image_array_non_uniform_indexing => vulkan_1_2.shader_sampled_image_array_non_uniform_indexing | ext_descriptor_indexing.shader_sampled_image_array_non_uniform_indexing},
{shader_storage_buffer_array_non_uniform_indexing => vulkan_1_2.shader_storage_buffer_array_non_uniform_indexing | ext_descriptor_indexing.shader_storage_buffer_array_non_uniform_indexing},
{shader_storage_image_array_non_uniform_indexing => vulkan_1_2.shader_storage_image_array_non_uniform_indexing | ext_descriptor_indexing.shader_storage_image_array_non_uniform_indexing},
{shader_input_attachment_array_non_uniform_indexing => vulkan_1_2.shader_input_attachment_array_non_uniform_indexing | ext_descriptor_indexing.shader_input_attachment_array_non_uniform_indexing},
{shader_uniform_texel_buffer_array_non_uniform_indexing => vulkan_1_2.shader_uniform_texel_buffer_array_non_uniform_indexing | ext_descriptor_indexing.shader_uniform_texel_buffer_array_non_uniform_indexing},
{shader_storage_texel_buffer_array_non_uniform_indexing => vulkan_1_2.shader_storage_texel_buffer_array_non_uniform_indexing | ext_descriptor_indexing.shader_storage_texel_buffer_array_non_uniform_indexing},
{descriptor_binding_uniform_buffer_update_after_bind => vulkan_1_2.descriptor_binding_uniform_buffer_update_after_bind | ext_descriptor_indexing.descriptor_binding_uniform_buffer_update_after_bind},
{descriptor_binding_sampled_image_update_after_bind => vulkan_1_2.descriptor_binding_sampled_image_update_after_bind | ext_descriptor_indexing.descriptor_binding_sampled_image_update_after_bind},
{descriptor_binding_storage_image_update_after_bind => vulkan_1_2.descriptor_binding_storage_image_update_after_bind | ext_descriptor_indexing.descriptor_binding_storage_image_update_after_bind},
{descriptor_binding_storage_buffer_update_after_bind => vulkan_1_2.descriptor_binding_storage_buffer_update_after_bind | ext_descriptor_indexing.descriptor_binding_storage_buffer_update_after_bind},
{descriptor_binding_uniform_texel_buffer_update_after_bind => vulkan_1_2.descriptor_binding_uniform_texel_buffer_update_after_bind | ext_descriptor_indexing.descriptor_binding_uniform_texel_buffer_update_after_bind},
{descriptor_binding_storage_texel_buffer_update_after_bind => vulkan_1_2.descriptor_binding_storage_texel_buffer_update_after_bind | ext_descriptor_indexing.descriptor_binding_storage_texel_buffer_update_after_bind},
{descriptor_binding_update_unused_while_pending => vulkan_1_2.descriptor_binding_update_unused_while_pending | ext_descriptor_indexing.descriptor_binding_update_unused_while_pending},
{descriptor_binding_partially_bound => vulkan_1_2.descriptor_binding_partially_bound | ext_descriptor_indexing.descriptor_binding_partially_bound},
{descriptor_binding_variable_descriptor_count => vulkan_1_2.descriptor_binding_variable_descriptor_count | ext_descriptor_indexing.descriptor_binding_variable_descriptor_count},
{runtime_descriptor_array => vulkan_1_2.runtime_descriptor_array | ext_descriptor_indexing.runtime_descriptor_array},
{sampler_filter_minmax => vulkan_1_2.sampler_filter_minmax},
{scalar_block_layout => vulkan_1_2.scalar_block_layout | ext_scalar_block_layout.scalar_block_layout},
{imageless_framebuffer => vulkan_1_2.imageless_framebuffer | khr_imageless_framebuffer.imageless_framebuffer},
{uniform_buffer_standard_layout => vulkan_1_2.uniform_buffer_standard_layout | khr_uniform_buffer_standard_layout.uniform_buffer_standard_layout},
{shader_subgroup_extended_types => vulkan_1_2.shader_subgroup_extended_types | khr_shader_subgroup_extended_types.shader_subgroup_extended_types},
{separate_depth_stencil_layouts => vulkan_1_2.separate_depth_stencil_layouts | khr_separate_depth_stencil_layouts.separate_depth_stencil_layouts},
{host_query_reset => vulkan_1_2.host_query_reset | ext_host_query_reset.host_query_reset},
{timeline_semaphore => vulkan_1_2.timeline_semaphore | khr_timeline_semaphore.timeline_semaphore},
{buffer_device_address => vulkan_1_2.buffer_device_address | khr_buffer_device_address.buffer_device_address},
{buffer_device_address_capture_replay => vulkan_1_2.buffer_device_address_capture_replay | khr_buffer_device_address.buffer_device_address_capture_replay},
{buffer_device_address_multi_device => vulkan_1_2.buffer_device_address_multi_device | khr_buffer_device_address.buffer_device_address_multi_device},
{vulkan_memory_model => vulkan_1_2.vulkan_memory_model | khr_vulkan_memory_model.vulkan_memory_model},
{vulkan_memory_model_device_scope => vulkan_1_2.vulkan_memory_model_device_scope | khr_vulkan_memory_model.vulkan_memory_model_device_scope},
{vulkan_memory_model_availability_visibility_chains => vulkan_1_2.vulkan_memory_model_availability_visibility_chains | khr_vulkan_memory_model.vulkan_memory_model_availability_visibility_chains},
{shader_output_viewport_index => vulkan_1_2.shader_output_viewport_index},
{shader_output_layer => vulkan_1_2.shader_output_layer},
{subgroup_broadcast_dynamic_id => vulkan_1_2.subgroup_broadcast_dynamic_id},
// Extensions
{ext_buffer_device_address => ext_buffer_address.buffer_device_address},
{ext_buffer_device_address_capture_replay => ext_buffer_address.buffer_device_address_capture_replay},
{ext_buffer_device_address_multi_device => ext_buffer_address.buffer_device_address_multi_device},
/// An error that can happen when enabling a feature on a device.
#[derive(Clone, Copy, Debug)]
pub struct FeatureRestrictionError {
/// The feature in question.
pub feature: &'static str,
/// The restriction that was not met.
pub restriction: FeatureRestriction,
}
#[derive(Default)]
pub(crate) struct FeaturesFfi {
_pinned: PhantomPinned,
impl error::Error for FeatureRestrictionError {}
vulkan_1_0: ash::vk::PhysicalDeviceFeatures2KHR,
vulkan_1_1: ash::vk::PhysicalDeviceVulkan11Features,
vulkan_1_2: ash::vk::PhysicalDeviceVulkan12Features,
protected_memory: ash::vk::PhysicalDeviceProtectedMemoryFeatures,
shader_draw_parameters: ash::vk::PhysicalDeviceShaderDrawParametersFeatures,
khr_16bit_storage: ash::vk::PhysicalDevice16BitStorageFeaturesKHR,
khr_8bit_storage: ash::vk::PhysicalDevice8BitStorageFeaturesKHR,
khr_buffer_device_address: ash::vk::PhysicalDeviceBufferDeviceAddressFeaturesKHR,
khr_imageless_framebuffer: ash::vk::PhysicalDeviceImagelessFramebufferFeaturesKHR,
khr_multiview: ash::vk::PhysicalDeviceMultiviewFeaturesKHR,
khr_sampler_ycbcr_conversion: ash::vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR,
khr_separate_depth_stencil_layouts:
ash::vk::PhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR,
khr_shader_atomic_int64: ash::vk::PhysicalDeviceShaderAtomicInt64FeaturesKHR,
khr_shader_float16_int8: ash::vk::PhysicalDeviceShaderFloat16Int8FeaturesKHR,
khr_shader_subgroup_extended_types:
ash::vk::PhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR,
khr_timeline_semaphore: ash::vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR,
khr_uniform_buffer_standard_layout:
ash::vk::PhysicalDeviceUniformBufferStandardLayoutFeaturesKHR,
khr_variable_pointers: ash::vk::PhysicalDeviceVariablePointersFeaturesKHR,
khr_vulkan_memory_model: ash::vk::PhysicalDeviceVulkanMemoryModelFeaturesKHR,
ext_buffer_address: ash::vk::PhysicalDeviceBufferAddressFeaturesEXT,
ext_descriptor_indexing: ash::vk::PhysicalDeviceDescriptorIndexingFeaturesEXT,
ext_host_query_reset: ash::vk::PhysicalDeviceHostQueryResetFeaturesEXT,
ext_scalar_block_layout: ash::vk::PhysicalDeviceScalarBlockLayoutFeaturesEXT,
impl fmt::Display for FeatureRestrictionError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"a restriction for the feature {} was not met: {}",
self.feature, self.restriction,
)
}
}
macro_rules! push_struct {
($self:ident, $struct:ident) => {
$self.$struct.p_next = $self.vulkan_1_0.p_next;
$self.vulkan_1_0.p_next = addr_of_mut!($self.$struct) as _;
};
#[derive(Clone, Copy, Debug)]
pub enum FeatureRestriction {
/// Not supported by the physical device.
NotSupported,
/// Requires a feature to be enabled.
RequiresFeature(&'static str),
/// Requires a feature to be disabled.
ConflictsFeature(&'static str),
/// An extension requires this feature to be enabled.
RequiredByExtension(&'static str),
}
impl FeaturesFfi {
pub(crate) fn make_chain(&mut self, api_version: Version) {
if api_version >= Version::V1_2 {
push_struct!(self, vulkan_1_1);
push_struct!(self, vulkan_1_2);
} else {
if api_version >= Version::V1_1 {
push_struct!(self, protected_memory);
push_struct!(self, shader_draw_parameters);
impl fmt::Display for FeatureRestriction {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
FeatureRestriction::NotSupported => {
write!(fmt, "not supported by the physical device")
}
FeatureRestriction::RequiresFeature(feat) => {
write!(fmt, "requires feature {} to be enabled", feat)
}
FeatureRestriction::ConflictsFeature(feat) => {
write!(fmt, "requires feature {} to be disabled", feat)
}
FeatureRestriction::RequiredByExtension(ext) => {
write!(fmt, "required to be enabled by extension {}", ext)
}
}
}
}
macro_rules! features_ffi {
{
$api_version:ident,
$extensions:ident,
$($member:ident => {
ty: $ty:ident,
provided_by: [$($provided_by:expr),+],
conflicts: [$($conflicts:ident),*],
},)+
} => {
#[derive(Default)]
pub(crate) struct FeaturesFfi {
features_vulkan10: Option<ash::vk::PhysicalDeviceFeatures2KHR>,
$(
$member: Option<ash::vk::$ty>,
)+
}
push_struct!(self, khr_16bit_storage);
push_struct!(self, khr_8bit_storage);
push_struct!(self, khr_buffer_device_address);
push_struct!(self, khr_imageless_framebuffer);
push_struct!(self, khr_multiview);
push_struct!(self, khr_sampler_ycbcr_conversion);
push_struct!(self, khr_separate_depth_stencil_layouts);
push_struct!(self, khr_shader_atomic_int64);
push_struct!(self, khr_shader_float16_int8);
push_struct!(self, khr_shader_subgroup_extended_types);
push_struct!(self, khr_timeline_semaphore);
push_struct!(self, khr_uniform_buffer_standard_layout);
push_struct!(self, khr_variable_pointers);
push_struct!(self, khr_vulkan_memory_model);
push_struct!(self, ext_descriptor_indexing);
push_struct!(self, ext_host_query_reset);
push_struct!(self, ext_scalar_block_layout);
impl FeaturesFfi {
pub(crate) fn make_chain(&mut self, $api_version: crate::Version, $extensions: &DeviceExtensions) {
self.features_vulkan10 = Some(Default::default());
$(
if std::array::IntoIter::new([$($provided_by),+]).any(|x| x) &&
std::array::IntoIter::new([$(self.$conflicts.is_none()),*]).all(|x| x) {
self.$member = Some(Default::default());
self.$member.unwrap().p_next = self.features_vulkan10.unwrap().p_next;
self.features_vulkan10.unwrap().p_next = self.$member.as_mut().unwrap() as *mut _ as _;
}
push_struct!(self, ext_buffer_address);
)+
}
pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceFeatures2KHR {
&self.vulkan_1_0
self.features_vulkan10.as_ref().unwrap()
}
pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceFeatures2KHR {
&mut self.vulkan_1_0
self.features_vulkan10.as_mut().unwrap()
}
}
};
}
pub(crate) use features_ffi;

View File

@ -90,13 +90,15 @@
//!
//! TODO: write
pub use self::extensions::DeviceExtensions;
pub use self::extensions::RawDeviceExtensions;
pub use self::features::Features;
pub(crate) use self::features::FeaturesFfi;
pub use self::features::{FeatureRestriction, FeatureRestrictionError, Features};
pub use crate::autogen::DeviceExtensions;
use crate::check_errors;
use crate::command_buffer::pool::StandardCommandPool;
use crate::descriptor::descriptor_set::StdDescriptorPool;
pub use crate::extensions::{
ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
};
use crate::fns::DeviceFunctions;
use crate::format::Format;
use crate::image::ImageCreateFlags;
@ -120,6 +122,7 @@ use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::error;
use std::ffi::CStr;
use std::ffi::CString;
use std::fmt;
use std::hash::BuildHasherDefault;
use std::hash::Hash;
@ -133,8 +136,8 @@ use std::sync::Mutex;
use std::sync::MutexGuard;
use std::sync::Weak;
mod extensions;
mod features;
pub(crate) mod extensions;
pub(crate) mod features;
/// Represents a Vulkan context.
pub struct Device {
@ -186,68 +189,70 @@ impl Device {
///
// TODO: return Arc<Queue> and handle synchronization in the Queue
// TODO: should take the PhysicalDevice by value
pub fn new<'a, I, Ext>(
phys: PhysicalDevice,
pub fn new<'a, I>(
physical_device: PhysicalDevice,
requested_features: &Features,
extensions: Ext,
requested_extensions: &DeviceExtensions,
queue_families: I,
) -> Result<(Arc<Device>, QueuesIter), DeviceCreationError>
where
I: IntoIterator<Item = (QueueFamily<'a>, f32)>,
Ext: Into<RawDeviceExtensions>,
{
let instance = phys.instance();
let instance = physical_device.instance();
let fns_i = instance.fns();
let max_api_version = instance.max_api_version();
let api_version = std::cmp::min(max_api_version, phys.api_version());
let api_version = std::cmp::min(max_api_version, physical_device.api_version());
let queue_families = queue_families.into_iter();
// Check if the extensions are correct
requested_extensions.check_requirements(
&DeviceExtensions::supported_by_device(physical_device),
api_version,
instance.loaded_extensions(),
)?;
if !phys.supported_features().superset_of(&requested_features) {
return Err(DeviceCreationError::FeatureNotPresent);
}
let mut requested_features = requested_features.clone();
// TODO: The plan regarding `robust_buffer_access` is to check the shaders' code to see
// if they can possibly perform out-of-bounds reads and writes. If the user tries
// to use a shader that can perform out-of-bounds operations without having
// `robust_buffer_access` enabled, an error is returned.
//
// However for the moment this verification isn't performed. In order to be safe,
// we always enable the `robust_buffer_access` feature as it is guaranteed to be
// supported everywhere.
//
// The only alternative (while waiting for shaders introspection to work) is to
// make all shaders depend on `robust_buffer_access`. But since usually the
// majority of shaders don't need this feature, it would be very annoying to have
// to enable it manually when you don't need it.
//
// Note that if we ever remove this, don't forget to adjust the change in
// `Device`'s construction below.
requested_features.robust_buffer_access = true;
// Check if the features are correct
requested_features.check_requirements(
physical_device.supported_features(),
api_version,
requested_extensions,
)?;
// device creation
let (device, queues) = unsafe {
// each element of `queues` is a `(queue_family, priorities)`
// each queue family must only have one entry in `queues`
let mut queues: Vec<(u32, Vec<f32>)> =
Vec::with_capacity(physical_device.queue_families().len());
// this variable will contain the queue family ID and queue ID of each requested queue
let mut output_queues: SmallVec<[(u32, u32); 8]> = SmallVec::new();
// Device layers were deprecated in Vulkan 1.0.13, and device layer requests should be
// ignored by the driver. For backwards compatibility, the spec recommends passing the
// exact instance layers to the device as well. There's no need to support separate
// requests at device creation time for legacy drivers: the spec claims that "[at] the
// time of deprecation there were no known device-only layers."
//
// Because there's no way to query the list of layers enabled for an instance, we need
// to save it alongside the instance. (`vkEnumerateDeviceLayerProperties` should get
// the right list post-1.0.13, but not pre-1.0.13, so we can't use it here.)
let layers_ptr = instance
.loaded_layers()
.map(|layer| layer.as_ptr())
.collect::<SmallVec<[_; 16]>>();
let extensions = extensions.into();
let extensions_list = extensions
.iter()
.map(|extension| extension.as_ptr())
.collect::<SmallVec<[_; 16]>>();
let requested_features = Features {
// Always enabled; see below.
robust_buffer_access: true,
..*requested_features
};
// device creation
let device = unsafe {
// each element of `queues` is a `(queue_family, priorities)`
// each queue family must only have one entry in `queues`
let mut queues: Vec<(u32, Vec<f32>)> = Vec::with_capacity(phys.queue_families().len());
for (queue_family, priority) in queue_families {
// checking the parameters
assert_eq!(
queue_family.physical_device().internal_object(),
phys.internal_object()
physical_device.internal_object()
);
if priority < 0.0 || priority > 1.0 {
return Err(DeviceCreationError::PriorityOutOfRange);
@ -280,25 +285,29 @@ impl Device {
)
.collect::<SmallVec<[_; 16]>>();
// TODO: The plan regarding `robust_buffer_access` is to check the shaders' code to see
// if they can possibly perform out-of-bounds reads and writes. If the user tries
// to use a shader that can perform out-of-bounds operations without having
// `robust_buffer_access` enabled, an error is returned.
//
// However for the moment this verification isn't performed. In order to be safe,
// we always enable the `robust_buffer_access` feature as it is guaranteed to be
// supported everywhere.
//
// The only alternative (while waiting for shaders introspection to work) is to
// make all shaders depend on `robust_buffer_access`. But since usually the
// majority of shaders don't need this feature, it would be very annoying to have
// to enable it manually when you don't need it.
//
// Note that if we ever remove this, don't forget to adjust the change in
// `Device`'s construction below.
let mut features_ffi = FeaturesFfi::default();
features_ffi.make_chain(api_version, requested_extensions);
features_ffi.write(&requested_features);
let mut features_ffi = <FeaturesFfi>::from(&requested_features);
features_ffi.make_chain(api_version);
// Device layers were deprecated in Vulkan 1.0.13, and device layer requests should be
// ignored by the driver. For backwards compatibility, the spec recommends passing the
// exact instance layers to the device as well. There's no need to support separate
// requests at device creation time for legacy drivers: the spec claims that "[at] the
// time of deprecation there were no known device-only layers."
//
// Because there's no way to query the list of layers enabled for an instance, we need
// to save it alongside the instance. (`vkEnumerateDeviceLayerProperties` should get
// the right list post-1.0.13, but not pre-1.0.13, so we can't use it here.)
let layers_ptrs = instance
.loaded_layers()
.map(|layer| layer.as_ptr())
.collect::<SmallVec<[_; 16]>>();
let extensions_strings: Vec<CString> = requested_extensions.into();
let extensions_ptrs = extensions_strings
.iter()
.map(|extension| extension.as_ptr())
.collect::<SmallVec<[_; 16]>>();
let has_khr_get_physical_device_properties2 = instance
.loaded_extensions()
@ -313,10 +322,10 @@ impl Device {
flags: ash::vk::DeviceCreateFlags::empty(),
queue_create_info_count: queues.len() as u32,
p_queue_create_infos: queues.as_ptr(),
enabled_layer_count: layers_ptr.len() as u32,
pp_enabled_layer_names: layers_ptr.as_ptr(),
enabled_extension_count: extensions_list.len() as u32,
pp_enabled_extension_names: extensions_list.as_ptr(),
enabled_layer_count: layers_ptrs.len() as u32,
pp_enabled_layer_names: layers_ptrs.as_ptr(),
enabled_extension_count: extensions_ptrs.len() as u32,
pp_enabled_extension_names: extensions_ptrs.as_ptr(),
p_enabled_features: if has_khr_get_physical_device_properties2 {
ptr::null()
} else {
@ -327,12 +336,13 @@ impl Device {
let mut output = MaybeUninit::uninit();
check_errors(fns_i.v1_0.create_device(
phys.internal_object(),
physical_device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr(),
))?;
output.assume_init()
(output.assume_init(), output_queues)
};
// loading the function pointers of the newly-created device
@ -341,7 +351,7 @@ impl Device {
});
let mut active_queue_families: SmallVec<[u32; 8]> = SmallVec::new();
for (queue_family, _) in output_queues.iter() {
for (queue_family, _) in queues.iter() {
if let None = active_queue_families
.iter()
.find(|&&qf| qf == *queue_family)
@ -351,8 +361,8 @@ impl Device {
}
let device = Arc::new(Device {
instance: phys.instance().clone(),
physical_device: phys.index(),
instance: physical_device.instance().clone(),
physical_device: physical_device.index(),
device: device,
api_version,
fns,
@ -364,7 +374,7 @@ impl Device {
robust_buffer_access: true,
..requested_features.clone()
},
extensions: (&extensions).into(),
extensions: requested_extensions.clone(),
active_queue_families,
allocation_count: Mutex::new(0),
fence_pool: Mutex::new(Vec::new()),
@ -373,16 +383,16 @@ impl Device {
});
// Iterator for the produced queues.
let output_queues = QueuesIter {
let queues = QueuesIter {
next_queue: 0,
device: device.clone(),
families_and_ids: output_queues,
families_and_ids: queues,
};
Ok((device, output_queues))
Ok((device, queues))
}
/// Returns the Vulkan version supported by this `Device`.
/// Returns the Vulkan version supported by the device.
///
/// This is the lower of the
/// [physical device's supported version](crate::instance::PhysicalDevice::api_version) and
@ -442,13 +452,13 @@ impl Device {
)
}
/// Returns the features that are enabled in the device.
/// Returns the features that have been enabled on the device.
#[inline]
pub fn enabled_features(&self) -> &Features {
&self.features
}
/// Returns the list of extensions that have been loaded.
/// Returns the extensions that have been enabled on the device.
#[inline]
pub fn loaded_extensions(&self) -> &DeviceExtensions {
&self.extensions
@ -742,7 +752,7 @@ impl Iterator for QueuesIter {
impl ExactSizeIterator for QueuesIter {}
/// Error that can be returned when creating a device.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug)]
pub enum DeviceCreationError {
/// Failed to create the device for an implementation-specific reason.
InitializationFailed,
@ -763,6 +773,10 @@ pub enum DeviceCreationError {
OutOfHostMemory,
/// There is no memory available on the device (ie. video memory).
OutOfDeviceMemory,
/// A restriction for an extension was not met.
ExtensionRestrictionNotMet(ExtensionRestrictionError),
/// A restriction for a feature was not met.
FeatureRestrictionNotMet(FeatureRestrictionError),
}
impl error::Error for DeviceCreationError {}
@ -770,35 +784,42 @@ impl error::Error for DeviceCreationError {}
impl fmt::Display for DeviceCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
DeviceCreationError::InitializationFailed => {
write!(
fmt,
"failed to create the device for an implementation-specific reason"
)
}
DeviceCreationError::OutOfHostMemory => "no memory available on the host",
DeviceCreationError::OutOfDeviceMemory =>
"no memory available on the graphical device",
DeviceCreationError::DeviceLost => "failed to connect to the device",
DeviceCreationError::OutOfHostMemory => write!(fmt, "no memory available on the host"),
DeviceCreationError::OutOfDeviceMemory => {
write!(fmt, "no memory available on the graphical device")
}
DeviceCreationError::DeviceLost => write!(fmt, "failed to connect to the device"),
DeviceCreationError::TooManyQueuesForFamily => {
"tried to create too many queues for a given family"
write!(fmt, "tried to create too many queues for a given family")
}
DeviceCreationError::FeatureNotPresent => {
write!(
fmt,
"some of the requested features are unsupported by the physical device"
)
}
DeviceCreationError::PriorityOutOfRange => {
write!(
fmt,
"the priority of one of the queues is out of the [0.0; 1.0] range"
)
}
DeviceCreationError::ExtensionNotPresent => {
"some of the requested device extensions are not supported by the physical device"
write!(fmt,"some of the requested device extensions are not supported by the physical device")
}
DeviceCreationError::TooManyObjects => {
"you have reached the limit to the number of devices that can be created from the
same physical device"
write!(fmt,"you have reached the limit to the number of devices that can be created from the same physical device")
}
DeviceCreationError::ExtensionRestrictionNotMet(err) => err.fmt(fmt),
DeviceCreationError::FeatureRestrictionNotMet(err) => err.fmt(fmt),
}
)
}
}
@ -818,6 +839,20 @@ impl From<Error> for DeviceCreationError {
}
}
impl From<ExtensionRestrictionError> for DeviceCreationError {
#[inline]
fn from(err: ExtensionRestrictionError) -> Self {
Self::ExtensionRestrictionNotMet(err)
}
}
impl From<FeatureRestrictionError> for DeviceCreationError {
#[inline]
fn from(err: FeatureRestrictionError) -> Self {
Self::FeatureRestrictionNotMet(err)
}
}
/// Represents a queue where commands can be submitted.
// TODO: should use internal synchronization?
#[derive(Debug)]
@ -900,7 +935,7 @@ mod tests {
use crate::device::Device;
use crate::device::DeviceCreationError;
use crate::device::DeviceExtensions;
use crate::device::Features;
use crate::device::{FeatureRestriction, FeatureRestrictionError, Features};
use crate::instance;
use std::sync::Arc;
@ -954,7 +989,10 @@ mod tests {
&DeviceExtensions::none(),
Some((family, 1.0)),
) {
Err(DeviceCreationError::FeatureNotPresent) => return, // Success
Err(DeviceCreationError::FeatureRestrictionNotMet(FeatureRestrictionError {
restriction: FeatureRestriction::NotSupported,
..
})) => return, // Success
_ => panic!(),
};
}

View File

@ -7,28 +7,37 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::error;
use std::fmt;
use crate::instance::loader::LoadingError;
use crate::Error;
use crate::OomError;
use crate::Version;
use std::error;
use std::fmt;
macro_rules! extensions {
($sname:ident, $rawname:ident, $($ext:ident => $s:expr,)*) => (
(
$sname:ident,
$($member:ident => {
doc: $doc:expr,
raw: $raw:expr,
requires_core: $requires_core:expr,
requires_device_extensions: [$($requires_device_extension:ident),*],
requires_instance_extensions: [$($requires_instance_extension:ident),*]$(,)?
},)*
) => (
/// List of extensions that are enabled or available.
#[derive(Copy, Clone, PartialEq, Eq)]
#[allow(missing_docs)]
pub struct $sname {
$(
pub $ext: bool,
#[doc = $doc]
pub $member: bool,
)*
/// This field ensures that an instance of this `Extensions` struct
/// can only be created through Vulkano functions and the update
/// syntax. This way, extensions can be added to Vulkano without
/// breaking existing code.
pub _unbuildable: Unbuildable,
pub _unbuildable: crate::extensions::Unbuildable,
}
impl $sname {
@ -36,8 +45,8 @@ macro_rules! extensions {
#[inline]
pub const fn none() -> $sname {
$sname {
$($ext: false,)*
_unbuildable: Unbuildable(())
$($member: false,)*
_unbuildable: crate::extensions::Unbuildable(())
}
}
@ -46,9 +55,9 @@ macro_rules! extensions {
pub const fn union(&self, other: &$sname) -> $sname {
$sname {
$(
$ext: self.$ext || other.$ext,
$member: self.$member || other.$member,
)*
_unbuildable: Unbuildable(())
_unbuildable: crate::extensions::Unbuildable(())
}
}
@ -57,9 +66,9 @@ macro_rules! extensions {
pub const fn intersection(&self, other: &$sname) -> $sname {
$sname {
$(
$ext: self.$ext && other.$ext,
$member: self.$member && other.$member,
)*
_unbuildable: Unbuildable(())
_unbuildable: crate::extensions::Unbuildable(())
}
}
@ -68,25 +77,25 @@ macro_rules! extensions {
pub const fn difference(&self, other: &$sname) -> $sname {
$sname {
$(
$ext: self.$ext && !other.$ext,
$member: self.$member && !other.$member,
)*
_unbuildable: Unbuildable(())
_unbuildable: crate::extensions::Unbuildable(())
}
}
}
impl fmt::Debug for $sname {
impl std::fmt::Debug for $sname {
#[allow(unused_assignments)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "[")?;
let mut first = true;
$(
if self.$ext {
if self.$member {
if !first { write!(f, ", ")? }
else { first = false; }
f.write_str(str::from_utf8($s).unwrap())?;
f.write_str(std::str::from_utf8($raw).unwrap())?;
}
)*
@ -94,82 +103,28 @@ macro_rules! extensions {
}
}
/// 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<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())
}
/// Returns the difference of another set from this one.
pub fn difference(&self, other: &Self) -> Self {
$rawname(self.0.difference(&other.0).cloned().collect())
}
/// Returns the union of both extension sets
pub fn union(&self, other: &Self) -> Self {
$rawname(self.0.union(&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 FromIterator<CString> for $rawname {
fn from_iter<T>(iter: T) -> Self
where T: IntoIterator<Item = CString>
{
$rawname(iter.into_iter().collect())
}
}
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();
impl<'a, I> From<I> for $sname where I: IntoIterator<Item = &'a std::ffi::CStr> {
fn from(names: I) -> Self {
let mut extensions = Self::none();
for name in names {
match name.to_bytes() {
$(
if x.0.iter().any(|x| x.as_bytes() == &$s[..]) {
extensions.$ext = true;
}
$raw => { extensions.$member = true; }
)*
_ => (),
}
}
extensions
}
}
impl<'a> From<&'a $sname> for Vec<std::ffi::CString> {
fn from(x: &'a $sname) -> Self {
let mut data = Self::new();
$(if x.$member { data.push(std::ffi::CString::new(&$raw[..]).unwrap()); })*
data
}
}
);
}
@ -233,3 +188,76 @@ impl From<Error> for SupportedExtensionsError {
}
}
}
/// An error that can happen when enabling an extension on an instance or device.
#[derive(Clone, Copy, Debug)]
pub struct ExtensionRestrictionError {
/// The extension in question.
pub extension: &'static str,
/// The restriction that was not met.
pub restriction: ExtensionRestriction,
}
impl error::Error for ExtensionRestrictionError {}
impl fmt::Display for ExtensionRestrictionError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"a restriction for the extension {} was not met: {}",
self.extension, self.restriction,
)
}
}
#[derive(Clone, Copy, Debug)]
pub enum ExtensionRestriction {
/// Not supported by the loader or physical device.
NotSupported,
/// Requires a minimum Vulkan API version.
RequiresCore(Version),
/// Requires a device extension to be enabled.
RequiresDeviceExtension(&'static str),
/// Requires an instance extension to be enabled.
RequiresInstanceExtension(&'static str),
/// Required to be enabled by the physical device.
RequiredIfSupported,
/// Requires a device extension to be disabled.
ConflictsDeviceExtension(&'static str),
}
impl fmt::Display for ExtensionRestriction {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
ExtensionRestriction::NotSupported => {
write!(fmt, "not supported by the loader or physical device")
}
ExtensionRestriction::RequiresCore(version) => {
write!(
fmt,
"requires Vulkan API version {}.{}",
version.major, version.minor
)
}
ExtensionRestriction::RequiresDeviceExtension(ext) => {
write!(fmt, "requires device extension {} to be enabled", ext)
}
ExtensionRestriction::RequiresInstanceExtension(ext) => {
write!(fmt, "requires instance extension {} to be enabled", ext)
}
ExtensionRestriction::RequiredIfSupported => {
write!(fmt, "required to be enabled by the physical device")
}
ExtensionRestriction::ConflictsDeviceExtension(ext) => {
write!(fmt, "requires device extension {} to be disabled", ext)
}
}
}
}
/// This helper type can only be instantiated inside this module.
#[doc(hidden)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Unbuildable(pub(crate) ());

View File

@ -7,21 +7,17 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use ash::vk::*;
use std::ffi::CStr;
use std::os::raw::c_void;
macro_rules! fns {
($struct_name:ident, { $($member:ident => $fn_struct:ident,)+ }) => {
pub struct $struct_name {
$(
pub $member: $fn_struct,
pub $member: ash::vk::$fn_struct,
)+
}
impl $struct_name {
pub fn load<F>(mut load_fn: F) -> $struct_name
where F: FnMut(&CStr) -> *const c_void
where F: FnMut(&std::ffi::CStr) -> *const std::ffi::c_void
{
$struct_name {
$(
@ -33,50 +29,5 @@ macro_rules! fns {
};
}
// TODO: would be nice if these could be generated automatically from Vulkano's list of extensions
fns!(EntryFunctions, {
v1_0 => EntryFnV1_0,
v1_1 => EntryFnV1_1,
v1_2 => EntryFnV1_2,
});
fns!(InstanceFunctions, {
v1_0 => InstanceFnV1_0,
v1_1 => InstanceFnV1_1,
v1_2 => InstanceFnV1_2,
khr_android_surface => KhrAndroidSurfaceFn,
khr_display => KhrDisplayFn,
khr_get_physical_device_properties2 => KhrGetPhysicalDeviceProperties2Fn, // Promoted
khr_surface => KhrSurfaceFn,
khr_wayland_surface => KhrWaylandSurfaceFn,
khr_win32_surface => KhrWin32SurfaceFn,
khr_xcb_surface => KhrXcbSurfaceFn,
khr_xlib_surface => KhrXlibSurfaceFn,
// This is an instance extension, so it should be loaded with `vkGetInstanceProcAddr`, despite
// having device-level functions. This is an unfortunate exception in the spec that even causes
// the LunarG people headaches:
// https://github.com/KhronosGroup/Vulkan-Loader/issues/116#issuecomment-580982393
ext_debug_utils => ExtDebugUtilsFn,
mvk_ios_surface => MvkIosSurfaceFn,
mvk_macos_surface => MvkMacosSurfaceFn,
nn_vi_surface => NnViSurfaceFn,
});
fns!(DeviceFunctions, {
v1_0 => DeviceFnV1_0,
v1_1 => DeviceFnV1_1,
v1_2 => DeviceFnV1_2,
khr_external_memory_fd => KhrExternalMemoryFdFn,
khr_get_memory_requirements2 => KhrGetMemoryRequirements2Fn, // Promoted
khr_maintenance1 => KhrMaintenance1Fn, // Promoted
khr_swapchain => KhrSwapchainFn,
ext_buffer_device_address => ExtBufferDeviceAddressFn,
ext_full_screen_exclusive => ExtFullScreenExclusiveFn,
});
pub use crate::autogen::{DeviceFunctions, EntryFunctions, InstanceFunctions};
pub(crate) use fns;

View File

@ -7,184 +7,147 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::collections::HashSet;
use std::ffi::{CStr, CString};
use std::fmt;
use std::iter::FromIterator;
use std::ptr;
use std::str;
use crate::check_errors;
use crate::extensions::SupportedExtensionsError;
pub use crate::extensions::{
ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
};
use crate::instance::loader;
use crate::instance::loader::LoadingError;
use std::ffi::CStr;
use std::ptr;
macro_rules! instance_extensions {
($sname:ident, $rawname:ident, $($ext:ident => $s:expr,)*) => (
(
$($member:ident => {
doc: $doc:expr,
raw: $raw:expr,
requires_core: $requires_core:expr,
requires_extensions: [$($requires_extension:ident),*]$(,)?
},)*
) => (
extensions! {
$sname, $rawname,
$( $ext => $s,)*
InstanceExtensions,
$($member => {
doc: $doc,
raw: $raw,
requires_core: $requires_core,
requires_device_extensions: [],
requires_instance_extensions: [$($requires_extension),*],
},)*
}
impl $rawname {
/// See the docs of supported_by_core().
pub fn supported_by_core_raw() -> Result<Self, SupportedExtensionsError> {
$rawname::supported_by_core_raw_with_loader(loader::auto_loader()?)
}
/// Same as `supported_by_core_raw()`, but allows specifying a loader.
pub fn supported_by_core_raw_with_loader<L>(ptrs: &loader::FunctionPointers<L>)
-> Result<Self, SupportedExtensionsError>
where L: loader::Loader
{
let fns = ptrs.fns();
let properties: Vec<ash::vk::ExtensionProperties> = unsafe {
let mut num = 0;
check_errors(fns.v1_0.enumerate_instance_extension_properties(
ptr::null(), &mut num, ptr::null_mut()
))?;
let mut properties = Vec::with_capacity(num as usize);
check_errors(fns.v1_0.enumerate_instance_extension_properties(
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.extension_name.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),
}
}
/// Same as `supported_by_core`, but allows specifying a loader.
pub fn supported_by_core_with_loader<L>(ptrs: &loader::FunctionPointers<L>)
-> Result<Self, LoadingError>
where L: loader::Loader
{
match $rawname::supported_by_core_raw_with_loader(ptrs) {
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<Self, SupportedExtensionsError> {
$sname::supported_by_core_raw_with_loader(loader::auto_loader()?)
}
/// See the docs of supported_by_core().
pub fn supported_by_core_raw_with_loader<L>(ptrs: &loader::FunctionPointers<L>)
-> Result<Self, SupportedExtensionsError>
where L: loader::Loader
{
let fns = ptrs.fns();
let properties: Vec<ash::vk::ExtensionProperties> = unsafe {
let mut num = 0;
check_errors(fns.v1_0.enumerate_instance_extension_properties(
ptr::null(), &mut num, ptr::null_mut()
))?;
let mut properties = Vec::with_capacity(num as usize);
check_errors(fns.v1_0.enumerate_instance_extension_properties(
ptr::null(), &mut num, properties.as_mut_ptr()
))?;
properties.set_len(num as usize);
properties
};
let mut extensions = $sname::none();
for property in properties {
let name = unsafe { CStr::from_ptr(property.extension_name.as_ptr()) };
impl InstanceExtensions {
/// Checks enabled extensions against the instance version and each other.
pub(super) fn check_requirements(
&self,
supported: &InstanceExtensions,
api_version: crate::Version,
) -> Result<(), crate::extensions::ExtensionRestrictionError> {
$(
// TODO: Check specVersion?
if name.to_bytes() == &$s[..] {
extensions.$ext = true;
if self.$member {
if !supported.$member {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::NotSupported,
});
}
if api_version < $requires_core {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::RequiresCore($requires_core),
});
} else {
$(
if !self.$requires_extension {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::RequiresInstanceExtension(stringify!($requires_extension)),
});
}
)*
}
Ok(extensions)
}
/// 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),
Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
}
}
/// Same as `supported_by_core`, but allows specifying a loader.
pub fn supported_by_core_with_loader<L>(ptrs: &loader::FunctionPointers<L>)
-> Result<Self, LoadingError>
where L: loader::Loader
{
match $sname::supported_by_core_raw_with_loader(ptrs) {
Ok(l) => Ok(l),
Err(SupportedExtensionsError::LoadingError(e)) => Err(e),
Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
}
)*
Ok(())
}
}
);
}
instance_extensions! {
InstanceExtensions,
RawInstanceExtensions,
pub use crate::autogen::InstanceExtensions;
pub(crate) use instance_extensions;
// List in order: khr, ext, then alphabetical
khr_android_surface => b"VK_KHR_android_surface",
khr_device_group_creation => b"VK_KHR_device_group_creation",
khr_display => b"VK_KHR_display",
khr_external_fence_capabilities => b"VK_KHR_external_fence_capabilities",
khr_external_memory_capabilities => b"VK_KHR_external_memory_capabilities",
khr_external_semaphore_capabilities => b"VK_KHR_external_semaphore_capabilities",
khr_get_display_properties2 => b"VK_KHR_get_display_properties2",
khr_get_physical_device_properties2 => b"VK_KHR_get_physical_device_properties2",
khr_get_surface_capabilities2 => b"VK_KHR_get_surface_capabilities2",
khr_surface => b"VK_KHR_surface",
khr_wayland_surface => b"VK_KHR_wayland_surface",
khr_win32_surface => b"VK_KHR_win32_surface",
khr_xcb_surface => b"VK_KHR_xcb_surface",
khr_xlib_surface => b"VK_KHR_xlib_surface",
ext_acquire_xlib_display => b"VK_EXT_acquire_xlib_display",
ext_debug_report => b"VK_EXT_debug_report",
ext_debug_utils => b"VK_EXT_debug_utils",
ext_direct_mode_display => b"VK_EXT_direct_mode_display",
ext_display_surface_counter => b"VK_EXT_display_surface_counter",
ext_swapchain_colorspace => b"VK_EXT_swapchain_colorspace",
mvk_ios_surface => b"VK_MVK_ios_surface",
mvk_macos_surface => b"VK_MVK_macos_surface",
mvk_moltenvk => b"VK_MVK_moltenvk", // TODO: confirm that it's an instance extension
nn_vi_surface => b"VK_NN_vi_surface",
impl InstanceExtensions {
/// See the docs of supported_by_core().
pub fn supported_by_core_raw() -> Result<Self, SupportedExtensionsError> {
InstanceExtensions::supported_by_core_raw_with_loader(loader::auto_loader()?)
}
/// Returns an `InstanceExtensions` object with extensions supported by the core driver.
pub fn supported_by_core() -> Result<Self, LoadingError> {
match InstanceExtensions::supported_by_core_raw() {
Ok(l) => Ok(l),
Err(SupportedExtensionsError::LoadingError(e)) => Err(e),
Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
}
}
/// Same as `supported_by_core`, but allows specifying a loader.
pub fn supported_by_core_with_loader<L>(
ptrs: &loader::FunctionPointers<L>,
) -> Result<Self, LoadingError>
where
L: loader::Loader,
{
match InstanceExtensions::supported_by_core_raw_with_loader(ptrs) {
Ok(l) => Ok(l),
Err(SupportedExtensionsError::LoadingError(e)) => Err(e),
Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
}
}
/// See the docs of supported_by_core().
pub fn supported_by_core_raw_with_loader<L>(
ptrs: &loader::FunctionPointers<L>,
) -> Result<Self, SupportedExtensionsError>
where
L: loader::Loader,
{
let fns = ptrs.fns();
let properties: Vec<ash::vk::ExtensionProperties> = unsafe {
let mut num = 0;
check_errors(fns.v1_0.enumerate_instance_extension_properties(
ptr::null(),
&mut num,
ptr::null_mut(),
))?;
let mut properties = Vec::with_capacity(num as usize);
check_errors(fns.v1_0.enumerate_instance_extension_properties(
ptr::null(),
&mut num,
properties.as_mut_ptr(),
))?;
properties.set_len(num as usize);
properties
};
Ok(Self::from(properties.iter().map(|property| unsafe {
CStr::from_ptr(property.extension_name.as_ptr())
})))
}
}
/// This helper type can only be instantiated inside this module.
/// See `*Extensions::_unbuildable`.
#[doc(hidden)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Unbuildable(());
#[cfg(test)]
mod tests {
use crate::instance::{InstanceExtensions, RawInstanceExtensions};
use crate::instance::InstanceExtensions;
use std::ffi::CString;
#[test]
fn empty_extensions() {
let i: RawInstanceExtensions = (&InstanceExtensions::none()).into();
let i: Vec<CString> = (&InstanceExtensions::none()).into();
assert!(i.iter().next().is_none());
}
}

View File

@ -8,13 +8,14 @@
// according to those terms.
use crate::check_errors;
use crate::extensions::ExtensionRestrictionError;
use crate::fns::InstanceFunctions;
use crate::instance::loader;
use crate::instance::loader::FunctionPointers;
use crate::instance::loader::Loader;
use crate::instance::loader::LoadingError;
use crate::instance::physical_device::{init_physical_devices, PhysicalDeviceInfos};
use crate::instance::{InstanceExtensions, RawInstanceExtensions};
use crate::instance::InstanceExtensions;
use crate::Error;
use crate::OomError;
use crate::Version;
@ -181,7 +182,7 @@ pub struct Instance {
pub(super) physical_devices: Vec<PhysicalDeviceInfos>,
fns: InstanceFunctions,
extensions: RawInstanceExtensions,
extensions: InstanceExtensions,
layers: SmallVec<[CString; 16]>,
function_pointers: OwnedOrRef<FunctionPointers<Box<dyn Loader + Send + Sync>>>,
}
@ -217,15 +218,14 @@ 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, Ext>(
pub fn new<'a, L>(
app_infos: Option<&ApplicationInfo>,
max_api_version: Version,
extensions: Ext,
extensions: &InstanceExtensions,
layers: L,
) -> Result<Arc<Instance>, InstanceCreationError>
where
L: IntoIterator<Item = &'a str>,
Ext: Into<RawInstanceExtensions>,
{
let layers = layers
.into_iter()
@ -235,23 +235,22 @@ impl Instance {
Instance::new_inner(
app_infos,
max_api_version,
extensions.into(),
extensions,
layers,
OwnedOrRef::Ref(loader::auto_loader()?),
)
}
/// Same as `new`, but allows specifying a loader where to load Vulkan from.
pub fn with_loader<'a, L, Ext>(
pub fn with_loader<'a, L>(
loader: FunctionPointers<Box<dyn Loader + Send + Sync>>,
app_infos: Option<&ApplicationInfo>,
max_api_version: Version,
extensions: Ext,
extensions: &InstanceExtensions,
layers: L,
) -> Result<Arc<Instance>, InstanceCreationError>
where
L: IntoIterator<Item = &'a str>,
Ext: Into<RawInstanceExtensions>,
{
let layers = layers
.into_iter()
@ -261,7 +260,7 @@ impl Instance {
Instance::new_inner(
app_infos,
max_api_version,
extensions.into(),
extensions,
layers,
OwnedOrRef::Owned(loader),
)
@ -270,10 +269,18 @@ impl Instance {
fn new_inner(
app_infos: Option<&ApplicationInfo>,
max_api_version: Version,
extensions: RawInstanceExtensions,
extensions: &InstanceExtensions,
layers: SmallVec<[CString; 16]>,
function_pointers: OwnedOrRef<FunctionPointers<Box<dyn Loader + Send + Sync>>>,
) -> Result<Arc<Instance>, InstanceCreationError> {
let api_version = std::cmp::min(max_api_version, function_pointers.api_version()?);
// Check if the extensions are correct
extensions.check_requirements(
&InstanceExtensions::supported_by_core_with_loader(&function_pointers)?,
api_version,
)?;
// TODO: For now there are still buggy drivers that will segfault if you don't pass any
// appinfos. Therefore for now we ensure that it can't be `None`.
let def = Default::default();
@ -299,8 +306,6 @@ impl Instance {
None
};
let api_version = std::cmp::min(max_api_version, function_pointers.api_version()?);
// Building the `vk::ApplicationInfo` if required.
let app_infos = if let Some(app_infos) = app_infos {
Some(ash::vk::ApplicationInfo {
@ -334,12 +339,13 @@ impl Instance {
};
// FIXME: check whether each layer is supported
let layers_ptr = layers
let layers_ptrs = layers
.iter()
.map(|layer| layer.as_ptr())
.collect::<SmallVec<[_; 16]>>();
let extensions_list = extensions
let extensions_list: Vec<CString> = extensions.into();
let extensions_ptrs = extensions_list
.iter()
.map(|extension| extension.as_ptr())
.collect::<SmallVec<[_; 32]>>();
@ -354,10 +360,10 @@ impl Instance {
} else {
ptr::null()
},
enabled_layer_count: layers_ptr.len() as u32,
pp_enabled_layer_names: layers_ptr.as_ptr(),
enabled_extension_count: extensions_list.len() as u32,
pp_enabled_extension_names: extensions_list.as_ptr(),
enabled_layer_count: layers_ptrs.len() as u32,
pp_enabled_layer_names: layers_ptrs.as_ptr(),
enabled_extension_count: extensions_ptrs.len() as u32,
pp_enabled_extension_names: extensions_ptrs.as_ptr(),
..Default::default()
};
@ -383,7 +389,7 @@ impl Instance {
//alloc: None,
physical_devices: Vec::new(),
fns,
extensions,
extensions: extensions.clone(),
layers,
function_pointers,
};
@ -402,7 +408,7 @@ impl Instance {
unimplemented!()
}*/
/// Returns the Vulkan version supported by this `Instance`.
/// Returns the Vulkan version supported by the instance.
///
/// This is the lower of the
/// [driver's supported version](crate::instance::loader::FunctionPointers::api_version) and
@ -412,7 +418,7 @@ impl Instance {
self.api_version
}
/// Returns the maximum Vulkan version that was specified when creating this `Instance`.
/// Returns the maximum Vulkan version that was specified when creating the instance.
#[inline]
pub fn max_api_version(&self) -> Version {
self.max_api_version
@ -424,7 +430,7 @@ impl Instance {
&self.fns
}
/// Returns the list of extensions that have been loaded.
/// Returns the extensions that have been enabled on the instance.
///
/// This list is equal to what was passed to `Instance::new()`.
///
@ -437,19 +443,14 @@ impl Instance {
///
/// let extensions = InstanceExtensions::supported_by_core().unwrap();
/// let instance = Instance::new(None, Version::V1_1, &extensions, None).unwrap();
/// assert_eq!(instance.loaded_extensions(), extensions);
/// assert_eq!(instance.loaded_extensions(), &extensions);
/// ```
#[inline]
pub fn loaded_extensions(&self) -> InstanceExtensions {
InstanceExtensions::from(&self.extensions)
}
#[inline]
pub fn raw_loaded_extensions(&self) -> &RawInstanceExtensions {
pub fn loaded_extensions(&self) -> &InstanceExtensions {
&self.extensions
}
/// Returns the list of layers requested when creating this instance.
/// Returns the layers that have been enabled on the instance.
#[doc(hidden)]
#[inline]
pub fn loaded_layers(&self) -> slice::Iter<CString> {
@ -605,11 +606,12 @@ pub enum InstanceCreationError {
InitializationFailed,
/// One of the requested layers is missing.
LayerNotPresent,
/// One of the requested extensions is missing.
/// One of the requested extensions is not supported by the implementation.
ExtensionNotPresent,
/// The version requested is not supported by the implementation.
// TODO: more info about this once the question of the version has been resolved
IncompatibleDriver,
/// A restriction for an extension was not met.
ExtensionRestrictionNotMet(ExtensionRestrictionError),
}
impl error::Error for InstanceCreationError {
@ -626,19 +628,17 @@ impl error::Error for InstanceCreationError {
impl fmt::Display for InstanceCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
InstanceCreationError::LoadingError(_) =>
"failed to load the Vulkan shared library",
InstanceCreationError::OomError(_) => "not enough memory available",
InstanceCreationError::InitializationFailed => "initialization failed",
InstanceCreationError::LayerNotPresent => "layer not present",
InstanceCreationError::ExtensionNotPresent => "extension not present",
InstanceCreationError::IncompatibleDriver => "incompatible driver",
InstanceCreationError::LoadingError(_) => {
write!(fmt, "failed to load the Vulkan shared library")
}
InstanceCreationError::OomError(_) => write!(fmt, "not enough memory available"),
InstanceCreationError::InitializationFailed => write!(fmt, "initialization failed"),
InstanceCreationError::LayerNotPresent => write!(fmt, "layer not present"),
InstanceCreationError::ExtensionNotPresent => write!(fmt, "extension not present"),
InstanceCreationError::IncompatibleDriver => write!(fmt, "incompatible driver"),
InstanceCreationError::ExtensionRestrictionNotMet(err) => err.fmt(fmt),
}
)
}
}
@ -656,6 +656,13 @@ impl From<LoadingError> for InstanceCreationError {
}
}
impl From<ExtensionRestrictionError> for InstanceCreationError {
#[inline]
fn from(err: ExtensionRestrictionError) -> Self {
Self::ExtensionRestrictionNotMet(err)
}
}
impl From<Error> for InstanceCreationError {
#[inline]
fn from(err: Error) -> InstanceCreationError {

View File

@ -52,7 +52,6 @@
//! `device` module for more info.
pub use self::extensions::InstanceExtensions;
pub use self::extensions::RawInstanceExtensions;
pub use self::instance::ApplicationInfo;
pub use self::instance::Instance;
pub use self::instance::InstanceCreationError;
@ -71,10 +70,13 @@ pub use self::physical_device::PhysicalDeviceType;
pub use self::physical_device::PhysicalDevicesIter;
pub use self::physical_device::QueueFamiliesIter;
pub use self::physical_device::QueueFamily;
pub use crate::extensions::{
ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
};
pub use crate::version::Version;
pub mod debug;
mod extensions;
pub(crate) mod extensions;
mod instance;
mod layers;
mod limits;

View File

@ -8,7 +8,7 @@
// according to those terms.
use crate::check_errors;
use crate::device::{Features, FeaturesFfi};
use crate::device::{DeviceExtensions, Features, FeaturesFfi};
use crate::instance::limits::Limits;
use crate::instance::{Instance, InstanceCreationError};
use crate::sync::PipelineStage;
@ -24,7 +24,7 @@ pub(super) fn init_physical_devices(
instance: &Instance,
) -> Result<Vec<PhysicalDeviceInfos>, InstanceCreationError> {
let fns = instance.fns();
let extensions = instance.loaded_extensions();
let instance_extensions = instance.loaded_extensions();
let physical_devices: Vec<ash::vk::PhysicalDevice> = unsafe {
let mut num = 0;
@ -44,43 +44,81 @@ pub(super) fn init_physical_devices(
devices
};
let supported_extensions: Vec<DeviceExtensions> = physical_devices
.iter()
.map(
|&physical_device| -> Result<DeviceExtensions, InstanceCreationError> {
let extension_properties: Vec<ash::vk::ExtensionProperties> = unsafe {
let mut num = 0;
check_errors(fns.v1_0.enumerate_device_extension_properties(
physical_device,
ptr::null(),
&mut num,
ptr::null_mut(),
))?;
let mut properties = Vec::with_capacity(num as usize);
check_errors(fns.v1_0.enumerate_device_extension_properties(
physical_device,
ptr::null(),
&mut num,
properties.as_mut_ptr(),
))?;
properties.set_len(num as usize);
properties
};
Ok(DeviceExtensions::from(extension_properties.iter().map(
|property| unsafe { CStr::from_ptr(property.extension_name.as_ptr()) },
)))
},
)
.collect::<Result<_, _>>()?;
let iter = physical_devices
.into_iter()
.zip(supported_extensions.into_iter());
// Getting the properties of all physical devices.
// If possible, we use VK_KHR_get_physical_device_properties2.
let physical_devices = if instance.api_version() >= Version::V1_1
|| extensions.khr_get_physical_device_properties2
|| instance_extensions.khr_get_physical_device_properties2
{
init_physical_devices_inner2(instance, physical_devices)
init_physical_devices_inner2(instance, iter)
} else {
init_physical_devices_inner(instance, physical_devices)
init_physical_devices_inner(instance, iter)
};
Ok(physical_devices)
}
/// Initialize all physical devices
fn init_physical_devices_inner(
instance: &Instance,
physical_devices: Vec<ash::vk::PhysicalDevice>,
) -> Vec<PhysicalDeviceInfos> {
fn init_physical_devices_inner<I>(instance: &Instance, info: I) -> Vec<PhysicalDeviceInfos>
where
I: IntoIterator<Item = (ash::vk::PhysicalDevice, DeviceExtensions)>,
{
let fns = instance.fns();
let mut output = Vec::with_capacity(physical_devices.len());
for device in physical_devices.into_iter() {
info.into_iter()
.map(|(physical_device, supported_extensions)| {
let properties: ash::vk::PhysicalDeviceProperties = unsafe {
let mut output = MaybeUninit::uninit();
fns.v1_0
.get_physical_device_properties(device, output.as_mut_ptr());
.get_physical_device_properties(physical_device, output.as_mut_ptr());
output.assume_init()
};
let queue_families = unsafe {
let mut num = 0;
fns.v1_0
.get_physical_device_queue_family_properties(device, &mut num, ptr::null_mut());
fns.v1_0.get_physical_device_queue_family_properties(
physical_device,
&mut num,
ptr::null_mut(),
);
let mut families = Vec::with_capacity(num as usize);
fns.v1_0.get_physical_device_queue_family_properties(
device,
physical_device,
&mut num,
families.as_mut_ptr(),
);
@ -91,39 +129,41 @@ fn init_physical_devices_inner(
let memory: ash::vk::PhysicalDeviceMemoryProperties = unsafe {
let mut output = MaybeUninit::uninit();
fns.v1_0
.get_physical_device_memory_properties(device, output.as_mut_ptr());
.get_physical_device_memory_properties(physical_device, output.as_mut_ptr());
output.assume_init()
};
let available_features: Features = unsafe {
let mut output = FeaturesFfi::default();
fns.v1_0
.get_physical_device_features(device, &mut output.head_as_mut().features);
fns.v1_0.get_physical_device_features(
physical_device,
&mut output.head_as_mut().features,
);
Features::from(&output)
};
output.push(PhysicalDeviceInfos {
device,
PhysicalDeviceInfos {
physical_device,
properties,
extended_properties: PhysicalDeviceExtendedProperties::empty(),
memory,
queue_families,
available_features: Features::from(available_features),
});
available_features,
}
output
})
.collect()
}
/// Initialize all physical devices, but use VK_KHR_get_physical_device_properties2
/// TODO: Query extension-specific physical device properties, once a new instance extension is supported.
fn init_physical_devices_inner2(
instance: &Instance,
physical_devices: Vec<ash::vk::PhysicalDevice>,
) -> Vec<PhysicalDeviceInfos> {
fn init_physical_devices_inner2<I>(instance: &Instance, info: I) -> Vec<PhysicalDeviceInfos>
where
I: IntoIterator<Item = (ash::vk::PhysicalDevice, DeviceExtensions)>,
{
let fns = instance.fns();
let mut output = Vec::with_capacity(physical_devices.len());
for device in physical_devices.into_iter() {
info.into_iter()
.map(|(physical_device, supported_extensions)| {
let mut extended_properties = PhysicalDeviceExtendedProperties::empty();
let properties: ash::vk::PhysicalDeviceProperties = unsafe {
@ -145,10 +185,10 @@ fn init_physical_devices_inner2(
if instance.api_version() >= Version::V1_1 {
fns.v1_1
.get_physical_device_properties2(device, &mut output);
.get_physical_device_properties2(physical_device, &mut output);
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_properties2_khr(device, &mut output);
.get_physical_device_properties2_khr(physical_device, &mut output);
}
extended_properties = PhysicalDeviceExtendedProperties {
@ -169,14 +209,14 @@ fn init_physical_devices_inner2(
if instance.api_version() >= Version::V1_1 {
fns.v1_1.get_physical_device_queue_family_properties2(
device,
physical_device,
&mut num,
ptr::null_mut(),
);
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_queue_family_properties2_khr(
device,
physical_device,
&mut num,
ptr::null_mut(),
);
@ -186,14 +226,14 @@ fn init_physical_devices_inner2(
if instance.api_version() >= Version::V1_1 {
fns.v1_1.get_physical_device_queue_family_properties2(
device,
physical_device,
&mut num,
families.as_mut_ptr(),
);
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_queue_family_properties2_khr(
device,
physical_device,
&mut num,
families.as_mut_ptr(),
);
@ -210,10 +250,10 @@ fn init_physical_devices_inner2(
if instance.api_version() >= Version::V1_1 {
fns.v1_1
.get_physical_device_memory_properties2(device, &mut output);
.get_physical_device_memory_properties2(physical_device, &mut output);
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_memory_properties2_khr(device, &mut output);
.get_physical_device_memory_properties2_khr(physical_device, &mut output);
}
output.memory_properties
@ -221,36 +261,37 @@ fn init_physical_devices_inner2(
let available_features: Features = unsafe {
let max_api_version = instance.max_api_version();
let api_version = std::cmp::min(max_api_version, Version::from(properties.api_version));
let api_version =
std::cmp::min(max_api_version, Version::from(properties.api_version));
let mut output = FeaturesFfi::default();
output.make_chain(api_version);
output.make_chain(api_version, &supported_extensions);
if instance.api_version() >= Version::V1_1 {
fns.v1_1
.get_physical_device_features2(device, output.head_as_mut());
.get_physical_device_features2(physical_device, output.head_as_mut());
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_features2_khr(device, output.head_as_mut());
.get_physical_device_features2_khr(physical_device, output.head_as_mut());
}
Features::from(&output)
};
output.push(PhysicalDeviceInfos {
device,
PhysicalDeviceInfos {
physical_device,
properties,
extended_properties,
memory,
queue_families,
available_features,
});
}
output
})
.collect()
}
pub(super) struct PhysicalDeviceInfos {
device: ash::vk::PhysicalDevice,
physical_device: ash::vk::PhysicalDevice,
properties: ash::vk::PhysicalDeviceProperties,
extended_properties: PhysicalDeviceExtendedProperties,
queue_families: Vec<ash::vk::QueueFamilyProperties>,
@ -588,7 +629,7 @@ unsafe impl<'a> VulkanObject for PhysicalDevice<'a> {
#[inline]
fn internal_object(&self) -> ash::vk::PhysicalDevice {
self.infos().device
self.infos().physical_device
}
}

View File

@ -93,6 +93,11 @@ pub mod sampler;
pub mod swapchain;
pub mod sync;
mod autogen {
// Generated by build.rs
include!(concat!(env!("OUT_DIR"), "/autogen.rs"));
}
/// Alternative to the `Deref` trait. Contrary to `Deref`, must always return the same object.
pub unsafe trait SafeDeref: Deref {}
unsafe impl<'a, T: ?Sized> SafeDeref for &'a T {}

View File

@ -291,7 +291,7 @@ impl<'a> DeviceMemoryBuilder<'a> {
if !(export_handle_bits & ash::vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT)
.is_empty()
{
if !self.device.loaded_extensions().ext_external_memory_dmabuf {
if !self.device.loaded_extensions().ext_external_memory_dma_buf {
return Err(DeviceMemoryAllocError::MissingExtension(
"ext_external_memory_dmabuf",
));
@ -310,7 +310,7 @@ impl<'a> DeviceMemoryBuilder<'a> {
if !(import_handle_bits & ash::vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT)
.is_empty()
{
if !self.device.loaded_extensions().ext_external_memory_dmabuf {
if !self.device.loaded_extensions().ext_external_memory_dma_buf {
return Err(DeviceMemoryAllocError::MissingExtension(
"ext_external_memory_dmabuf",
));

15238
vulkano/vk.xml Normal file

File diff suppressed because it is too large Load Diff