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,146 +7,164 @@
// 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()) };
$(
// TODO: Check specVersion?
if name.to_bytes() == &$s[..] {
extensions.$ext = true;
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> {
$(
if self.$member {
if !supported.$member {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::NotSupported,
});
}
)*
}
Ok(extensions)
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(())
}
/// Returns an `Extensions` object with extensions supported by the `PhysicalDevice`.
pub fn supported_by_device(physical_device: PhysicalDevice) -> Self {
match $sname::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`.
/// 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);
let required_if_supported = Self::required_if_supported_extensions();
required_if_supported.intersection(&supported)
}
fn required_if_supported_extensions() -> Self {
pub(crate) fn required_if_supported_extensions() -> Self {
Self {
$(
$ext_req_if_supported: true,
$member: $required_if_supported,
)*
..Self::none()
_unbuildable: crate::extensions::Unbuildable(())
}
}
}
);
);
}
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,
],
pub use crate::autogen::DeviceExtensions;
pub(crate) use device_extensions;
// 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",
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 a `DeviceExtensions` object with extensions supported by the `PhysicalDevice`.
pub fn supported_by_device(physical_device: PhysicalDevice) -> Self {
match DeviceExtensions::supported_by_device_raw(physical_device) {
Ok(l) => l,
Err(SupportedExtensionsError::LoadingError(_)) => unreachable!(),
Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
}
}
/// 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);
let required_if_supported = Self::required_if_supported_extensions();
required_if_supported.intersection(&supported)
}
}
/// 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 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>,
)+
}
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 _;
}
)+
}
pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceFeatures2KHR {
self.features_vulkan10.as_ref().unwrap()
}
pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceFeatures2KHR {
self.features_vulkan10.as_mut().unwrap()
}
}
};
}
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);
}
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);
}
push_struct!(self, ext_buffer_address);
}
pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceFeatures2KHR {
&self.vulkan_1_0
}
pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceFeatures2KHR {
&mut self.vulkan_1_0
}
}
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();
// 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."
// 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.
//
// 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]>>();
// 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;
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
};
// Check if the features are correct
requested_features.check_requirements(
physical_device.supported_features(),
api_version,
requested_extensions,
)?;
// device creation
let device = unsafe {
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(phys.queue_families().len());
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();
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 => {
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::TooManyQueuesForFamily => {
"tried to create too many queues for a given family"
}
DeviceCreationError::FeatureNotPresent => {
"some of the requested features are unsupported by the physical device"
}
DeviceCreationError::PriorityOutOfRange => {
"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"
}
DeviceCreationError::TooManyObjects => {
"you have reached the limit to the number of devices that can be created from the
same physical 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 => {
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 => {
write!(fmt,"some of the requested device extensions are not supported by the physical device")
}
DeviceCreationError::TooManyObjects => {
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();
$(
if x.0.iter().any(|x| x.as_bytes() == &$s[..]) {
extensions.$ext = true;
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() {
$(
$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()) };
$(
// TODO: Check specVersion?
if name.to_bytes() == &$s[..] {
extensions.$ext = true;
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> {
$(
if self.$member {
if !supported.$member {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::NotSupported,
});
}
)*
}
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),
}
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(())
}
}
);
}
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",
match *self {
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,213 +44,254 @@ 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() {
let properties: ash::vk::PhysicalDeviceProperties = unsafe {
let mut output = MaybeUninit::uninit();
fns.v1_0
.get_physical_device_properties(device, output.as_mut_ptr());
output.assume_init()
};
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(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());
let queue_families = unsafe {
let mut num = 0;
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,
&mut num,
families.as_mut_ptr(),
);
families.set_len(num as usize);
families
};
let mut families = Vec::with_capacity(num as usize);
fns.v1_0.get_physical_device_queue_family_properties(
physical_device,
&mut num,
families.as_mut_ptr(),
);
families.set_len(num as usize);
families
};
let memory: ash::vk::PhysicalDeviceMemoryProperties = unsafe {
let mut output = MaybeUninit::uninit();
fns.v1_0
.get_physical_device_memory_properties(device, output.as_mut_ptr());
output.assume_init()
};
let memory: ash::vk::PhysicalDeviceMemoryProperties = unsafe {
let mut output = MaybeUninit::uninit();
fns.v1_0
.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);
Features::from(&output)
};
let available_features: Features = unsafe {
let mut output = FeaturesFfi::default();
fns.v1_0.get_physical_device_features(
physical_device,
&mut output.head_as_mut().features,
);
Features::from(&output)
};
output.push(PhysicalDeviceInfos {
device,
properties,
extended_properties: PhysicalDeviceExtendedProperties::empty(),
memory,
queue_families,
available_features: Features::from(available_features),
});
}
output
PhysicalDeviceInfos {
physical_device,
properties,
extended_properties: PhysicalDeviceExtendedProperties::empty(),
memory,
queue_families,
available_features,
}
})
.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() {
let mut extended_properties = PhysicalDeviceExtendedProperties::empty();
info.into_iter()
.map(|(physical_device, supported_extensions)| {
let mut extended_properties = PhysicalDeviceExtendedProperties::empty();
let properties: ash::vk::PhysicalDeviceProperties = unsafe {
let mut subgroup_properties = ash::vk::PhysicalDeviceSubgroupProperties::default();
let properties: ash::vk::PhysicalDeviceProperties = unsafe {
let mut subgroup_properties = ash::vk::PhysicalDeviceSubgroupProperties::default();
let mut multiview_properties = ash::vk::PhysicalDeviceMultiviewProperties {
p_next: &mut subgroup_properties as *mut _ as *mut c_void,
..Default::default()
};
let mut multiview_properties = ash::vk::PhysicalDeviceMultiviewProperties {
p_next: &mut subgroup_properties as *mut _ as *mut c_void,
..Default::default()
};
let mut output = ash::vk::PhysicalDeviceProperties2 {
p_next: if instance.api_version() >= Version::V1_1 {
&mut multiview_properties as *mut _ as *mut c_void
let mut output = ash::vk::PhysicalDeviceProperties2 {
p_next: if instance.api_version() >= Version::V1_1 {
&mut multiview_properties as *mut _ as *mut c_void
} else {
ptr::null_mut()
},
..Default::default()
};
if instance.api_version() >= Version::V1_1 {
fns.v1_1
.get_physical_device_properties2(physical_device, &mut output);
} else {
ptr::null_mut()
},
..Default::default()
fns.khr_get_physical_device_properties2
.get_physical_device_properties2_khr(physical_device, &mut output);
}
extended_properties = PhysicalDeviceExtendedProperties {
subgroup_size: Some(subgroup_properties.subgroup_size),
max_multiview_view_count: Some(multiview_properties.max_multiview_view_count),
max_multiview_instance_index: Some(
multiview_properties.max_multiview_instance_index,
),
..extended_properties
};
output.properties
};
if instance.api_version() >= Version::V1_1 {
fns.v1_1
.get_physical_device_properties2(device, &mut output);
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_properties2_khr(device, &mut output);
}
let queue_families = unsafe {
let mut num = 0;
extended_properties = PhysicalDeviceExtendedProperties {
subgroup_size: Some(subgroup_properties.subgroup_size),
max_multiview_view_count: Some(multiview_properties.max_multiview_view_count),
max_multiview_instance_index: Some(
multiview_properties.max_multiview_instance_index,
),
..extended_properties
};
output.properties
};
let queue_families = unsafe {
let mut num = 0;
if instance.api_version() >= Version::V1_1 {
fns.v1_1.get_physical_device_queue_family_properties2(
device,
&mut num,
ptr::null_mut(),
);
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_queue_family_properties2_khr(
device,
if instance.api_version() >= Version::V1_1 {
fns.v1_1.get_physical_device_queue_family_properties2(
physical_device,
&mut num,
ptr::null_mut(),
);
}
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_queue_family_properties2_khr(
physical_device,
&mut num,
ptr::null_mut(),
);
}
let mut families = vec![ash::vk::QueueFamilyProperties2::default(); num as usize];
let mut families = vec![ash::vk::QueueFamilyProperties2::default(); num as usize];
if instance.api_version() >= Version::V1_1 {
fns.v1_1.get_physical_device_queue_family_properties2(
device,
&mut num,
families.as_mut_ptr(),
);
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_queue_family_properties2_khr(
device,
if instance.api_version() >= Version::V1_1 {
fns.v1_1.get_physical_device_queue_family_properties2(
physical_device,
&mut num,
families.as_mut_ptr(),
);
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_queue_family_properties2_khr(
physical_device,
&mut num,
families.as_mut_ptr(),
);
}
families
.into_iter()
.map(|family| family.queue_family_properties)
.collect()
};
let memory: ash::vk::PhysicalDeviceMemoryProperties = unsafe {
let mut output = ash::vk::PhysicalDeviceMemoryProperties2KHR::default();
if instance.api_version() >= Version::V1_1 {
fns.v1_1
.get_physical_device_memory_properties2(physical_device, &mut output);
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_memory_properties2_khr(physical_device, &mut output);
}
output.memory_properties
};
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 mut output = FeaturesFfi::default();
output.make_chain(api_version, &supported_extensions);
if instance.api_version() >= Version::V1_1 {
fns.v1_1
.get_physical_device_features2(physical_device, output.head_as_mut());
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_features2_khr(physical_device, output.head_as_mut());
}
Features::from(&output)
};
PhysicalDeviceInfos {
physical_device,
properties,
extended_properties,
memory,
queue_families,
available_features,
}
families
.into_iter()
.map(|family| family.queue_family_properties)
.collect()
};
let memory: ash::vk::PhysicalDeviceMemoryProperties = unsafe {
let mut output = ash::vk::PhysicalDeviceMemoryProperties2KHR::default();
if instance.api_version() >= Version::V1_1 {
fns.v1_1
.get_physical_device_memory_properties2(device, &mut output);
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_memory_properties2_khr(device, &mut output);
}
output.memory_properties
};
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 mut output = FeaturesFfi::default();
output.make_chain(api_version);
if instance.api_version() >= Version::V1_1 {
fns.v1_1
.get_physical_device_features2(device, output.head_as_mut());
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_features2_khr(device, output.head_as_mut());
}
Features::from(&output)
};
output.push(PhysicalDeviceInfos {
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