Add auto-generated device properties (#1605)

* 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

* Autogenerate device properties

* Propagate bugfix in properties chain to features
This commit is contained in:
Rua 2021-06-13 21:47:10 +02:00 committed by GitHub
parent bb4234df45
commit 0d5edc130d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 1421 additions and 617 deletions

View File

@ -50,14 +50,13 @@ vulkano::impl_vertex!(Vertex, position);
fn main() {
let required_extensions = vulkano_win::required_extensions();
let instance =
Instance::new(None, Version::V1_1, &required_extensions, None).unwrap();
let instance = Instance::new(None, Version::V1_1, &required_extensions, None).unwrap();
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
println!(
"Using device: {} (type: {:?})",
physical.name(),
physical.ty()
physical.properties().device_name.as_ref().unwrap(),
physical.properties().device_type.unwrap()
);
let event_loop = EventLoop::new();

View File

@ -105,8 +105,9 @@ fn main() {
let data: Vec<u8> = vec![3, 11, 7];
let min_dynamic_align = device
.physical_device()
.limits()
.min_uniform_buffer_offset_alignment() as usize;
.properties()
.min_uniform_buffer_offset_alignment
.unwrap() as usize;
println!(
"Minimum uniform buffer offset alignment: {}",
min_dynamic_align

View File

@ -125,11 +125,11 @@ fn main() {
// In this case we can find appropriate value in this table: https://vulkan.gpuinfo.org/
// or just use fallback constant for simplicity, but failure to set proper
// local size can lead to significant performance penalty.
let (local_size_x, local_size_y) = match physical.extended_properties().subgroup_size() {
let (local_size_x, local_size_y) = match physical.properties().subgroup_size {
Some(subgroup_size) => {
println!(
"Subgroup size for '{}' device is {}",
physical.name(),
physical.properties().device_name.as_ref().unwrap(),
subgroup_size
);

View File

@ -41,13 +41,12 @@ fn main() {
// `triangle` example if you haven't done so yet.
let required_extensions = vulkano_win::required_extensions();
let instance =
Instance::new(None, Version::V1_1, &required_extensions, None).unwrap();
let instance = Instance::new(None, Version::V1_1, &required_extensions, None).unwrap();
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
println!(
"Using device: {} (type: {:?})",
physical.name(),
physical.ty()
physical.properties().device_name.as_ref().unwrap(),
physical.properties().device_type.unwrap(),
);
let event_loop = EventLoop::new();

View File

@ -65,13 +65,12 @@ impl_vertex!(Vertex, position);
fn main() {
let required_extensions = vulkano_win::required_extensions();
let instance =
Instance::new(None, Version::V1_1, &required_extensions, None).unwrap();
let instance = Instance::new(None, Version::V1_1, &required_extensions, None).unwrap();
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
println!(
"Using device: {} (type: {:?})",
physical.name(),
physical.ty()
physical.properties().device_name.as_ref().unwrap(),
physical.properties().device_type.unwrap(),
);
let event_loop = EventLoop::new();

View File

@ -68,8 +68,8 @@ fn main() {
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
println!(
"Using device: {} (type: {:?})",
physical.name(),
physical.ty()
physical.properties().device_name.as_ref().unwrap(),
physical.properties().device_type.unwrap(),
);
let event_loop = EventLoop::new();

View File

@ -62,12 +62,7 @@ fn main() {
// will lead to a runtime error when creating the `RenderPass`.
// The `max_multiview_view_count` function will return `None`
// when the `VK_KHR_get_physical_device_properties2` instance extension has not been enabled.
if physical
.extended_properties()
.max_multiview_view_count()
.unwrap_or(0)
< 2
{
if physical.properties().max_multiview_view_count.unwrap_or(0) < 2 {
println!("The device doesn't support two multiview views or the VK_KHR_get_physical_device_properties2 instance extension has not been loaded");
// A real application should probably fall back to rendering the framebuffer layers

View File

@ -36,14 +36,13 @@ use winit::window::{Window, WindowBuilder};
fn main() {
let required_extensions = vulkano_win::required_extensions();
let instance =
Instance::new(None, Version::V1_1, &required_extensions, None).unwrap();
let instance = Instance::new(None, Version::V1_1, &required_extensions, None).unwrap();
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
println!(
"Using device: {} (type: {:?})",
physical.name(),
physical.ty()
physical.properties().device_name.as_ref().unwrap(),
physical.properties().device_type.unwrap(),
);
let event_loop = EventLoop::new();

View File

@ -48,8 +48,8 @@ fn main() {
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
println!(
"Using device: {} (type: {:?})",
physical.name(),
physical.ty()
physical.properties().device_name.as_ref().unwrap(),
physical.properties().device_type.unwrap(),
);
let event_loop = EventLoop::new();

View File

@ -142,8 +142,8 @@ fn main() {
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
println!(
"Using device: {} (type: {:?})",
physical.name(),
physical.ty()
physical.properties().device_name.as_ref().unwrap(),
physical.properties().device_type.unwrap()
);
let event_loop = EventLoop::new();

View File

@ -70,8 +70,8 @@ fn main() {
// Some little debug infos.
println!(
"Using device: {} (type: {:?})",
physical.name(),
physical.ty()
physical.properties().device_name.as_ref().unwrap(),
physical.properties().device_type.unwrap(),
);
// The objective of this example is to draw a triangle on a window. To do so, we first need to

View File

@ -240,7 +240,7 @@ where
.unwrap();
write!(
writer,
"\n\t\trequires_extensions: [{}],",
"\n\t\trequires_instance_extensions: [{}],",
ext.requires_instance_extensions.join(", ")
)
.unwrap();

View File

@ -8,12 +8,13 @@
// according to those terms.
use heck::SnakeCase;
use indexmap::IndexMap;
use regex::Regex;
use std::{
collections::{hash_map::Entry, HashMap},
io::Write,
};
use vk_parse::{Type, TypeMember, TypeMemberMarkup, TypeSpec};
use vk_parse::{Extension, 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] {
@ -57,10 +58,14 @@ fn required_by_extensions(name: &str) -> &'static [&'static str] {
}
}
pub fn write<W: Write>(writer: &mut W, types: &HashMap<&str, (&Type, Vec<&str>)>) {
pub fn write<W: Write>(
writer: &mut W,
types: &HashMap<&str, (&Type, Vec<&str>)>,
extensions: &IndexMap<&str, &Extension>,
) {
write!(writer, "crate::device::features::features! {{").unwrap();
for feat in make_vulkano_features(&types) {
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();
@ -93,11 +98,11 @@ pub fn write<W: Write>(writer: &mut W, types: &HashMap<&str, (&Type, Vec<&str>)>
write!(
writer,
"\n}}\n\ncrate::device::features::features_ffi! {{\n\tapi_version,\n\textensions,"
"\n}}\n\ncrate::device::features::features_ffi! {{\n\tapi_version,\n\tdevice_extensions,\n\tinstance_extensions,"
)
.unwrap();
for ffi in make_vulkano_features_ffi(&types) {
for ffi in make_vulkano_features_ffi(types, extensions) {
write!(writer, "\n\t{} => {{", ffi.member).unwrap();
write!(writer, "\n\t\tty: {},", ffi.ty).unwrap();
write!(
@ -258,7 +263,10 @@ struct VulkanoFeatureFfi {
conflicts: Vec<String>,
}
fn make_vulkano_features_ffi(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<VulkanoFeatureFfi> {
fn make_vulkano_features_ffi<'a>(
types: &'a HashMap<&str, (&Type, Vec<&str>)>,
extensions: &IndexMap<&'a str, &Extension>,
) -> Vec<VulkanoFeatureFfi> {
let mut feature_included_in: HashMap<&str, Vec<&str>> = HashMap::new();
sorted_structs(types)
.into_iter()
@ -271,7 +279,8 @@ fn make_vulkano_features_ffi(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<V
format!("api_version >= crate::Version::V{}", version)
} else {
format!(
"extensions.{}",
"{}_extensions.{}",
extensions[provided_by].ext_type.as_ref().unwrap().as_str(),
provided_by
.strip_prefix("VK_")
.unwrap()

View File

@ -17,6 +17,7 @@ use vk_parse::{
mod extensions;
mod features;
mod fns;
mod properties;
pub fn write<W: Write>(writer: &mut W) {
let registry = get_registry("vk.xml");
@ -40,7 +41,9 @@ pub fn write<W: Write>(writer: &mut W) {
write!(writer, "\n\n").unwrap();
fns::write(writer, &extensions);
write!(writer, "\n\n").unwrap();
features::write(writer, &types);
features::write(writer, &types, &extensions);
write!(writer, "\n\n").unwrap();
properties::write(writer, &types, &extensions);
write!(writer, "\n").unwrap();
}

View File

@ -0,0 +1,349 @@
// 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 regex::Regex;
use std::{
collections::{hash_map::Entry, HashMap},
io::Write,
};
use vk_parse::{Extension, Type, TypeMember, TypeMemberMarkup, TypeSpec};
pub fn write<W: Write>(
writer: &mut W,
types: &HashMap<&str, (&Type, Vec<&str>)>,
extensions: &IndexMap<&str, &Extension>,
) {
write!(writer, "crate::device::properties::properties! {{").unwrap();
for feat in make_vulkano_properties(&types) {
write!(writer, "\n\t{} => {{", feat.member).unwrap();
write_doc(writer, &feat);
write!(writer, "\n\t\tty: {},", feat.ty).unwrap();
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}},").unwrap();
}
write!(
writer,
"\n}}\n\ncrate::device::properties::properties_ffi! {{\n\tapi_version,\n\tdevice_extensions,\n\tinstance_extensions,"
)
.unwrap();
for ffi in make_vulkano_properties_ffi(types, extensions) {
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 VulkanoProperty {
member: String,
ty: String,
vulkan_doc: String,
ffi_name: String,
ffi_members: Vec<String>,
}
fn make_vulkano_properties(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<VulkanoProperty> {
let mut properties = HashMap::new();
std::array::IntoIter::new([
&types["VkPhysicalDeviceProperties"],
&types["VkPhysicalDeviceLimits"],
&types["VkPhysicalDeviceSparseProperties"],
])
.chain(sorted_structs(types).into_iter())
.filter(|(ty, _)| {
let name = ty.name.as_ref().map(|s| s.as_str());
name == Some("VkPhysicalDeviceProperties")
|| name == Some("VkPhysicalDeviceLimits")
|| name == Some("VkPhysicalDeviceSparseProperties")
|| ty.structextends.as_ref().map(|s| s.as_str()) == Some("VkPhysicalDeviceProperties2")
})
.for_each(|(ty, _)| {
let vulkan_ty_name = ty.name.as_ref().unwrap();
let ty_name = if vulkan_ty_name == "VkPhysicalDeviceProperties" {
"properties_vulkan10.properties".to_owned()
} else if vulkan_ty_name == "VkPhysicalDeviceLimits" {
"properties_vulkan10.properties.limits".to_owned()
} else if vulkan_ty_name == "VkPhysicalDeviceSparseProperties" {
"properties_vulkan10.properties.sparse_properties".to_owned()
} else {
ffi_member(vulkan_ty_name)
};
members(ty)
.into_iter()
.for_each(|Member { name, ty, len }| {
if ty == "VkPhysicalDeviceLimits" || ty == "VkPhysicalDeviceSparseProperties" {
return;
}
let vulkano_member = name.to_snake_case();
let vulkano_ty = match name {
"apiVersion" => "crate::Version",
_ => vulkano_type(ty, len),
};
match properties.entry(vulkano_member.clone()) {
Entry::Vacant(entry) => {
entry.insert(VulkanoProperty {
member: vulkano_member.clone(),
ty: vulkano_ty.to_owned(),
vulkan_doc: format!("{}.html#limits-{}", vulkan_ty_name, name),
ffi_name: vulkano_member,
ffi_members: vec![ty_name.to_owned()],
});
}
Entry::Occupied(entry) => {
entry.into_mut().ffi_members.push(ty_name.to_owned());
}
};
});
});
let mut names: Vec<_> = properties
.values()
.map(|feat| feat.member.clone())
.collect();
names.sort_unstable();
names
.into_iter()
.map(|name| properties.remove(&name).unwrap())
.collect()
}
fn write_doc<W>(writer: &mut W, feat: &VulkanoProperty)
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();
write!(writer, "\n\t\t\",").unwrap();
}
#[derive(Clone, Debug)]
struct VulkanoPropertyFfi {
member: String,
ty: String,
provided_by: Vec<String>,
conflicts: Vec<String>,
}
fn make_vulkano_properties_ffi<'a>(
types: &'a HashMap<&str, (&Type, Vec<&str>)>,
extensions: &IndexMap<&'a str, &Extension>,
) -> Vec<VulkanoPropertyFfi> {
let mut property_included_in: HashMap<&str, Vec<&str>> = HashMap::new();
sorted_structs(types)
.into_iter()
.map(|(ty, provided_by)| {
let ty_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.{}",
extensions[provided_by].ext_type.as_ref().unwrap().as_str(),
provided_by
.strip_prefix("VK_")
.unwrap()
.to_ascii_lowercase()
)
}
})
.collect();
let mut conflicts = vec![];
members(ty).into_iter().for_each(|Member { name, .. }| {
match property_included_in.entry(name) {
Entry::Vacant(entry) => {
entry.insert(vec![ty_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(ty_name);
}
}
});
VulkanoPropertyFfi {
member: ffi_member(ty_name),
ty: 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("VkPhysicalDeviceProperties2")
})
.collect();
let regex = Regex::new(r"^VkPhysicalDeviceVulkan\d+Properties$").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("_properties").unwrap();
format!("properties_{}{}", base, suffix)
}
struct Member<'a> {
name: &'a str,
ty: &'a str,
len: Option<&'a str>,
}
fn members(ty: &Type) -> Vec<Member> {
let regex = Regex::new(r"\[([A-Za-z0-9_]+)\]\s*$").unwrap();
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,
});
let ty = def.markup.iter().find_map(|markup| match markup {
TypeMemberMarkup::Type(ty) => Some(ty.as_str()),
_ => None,
});
let len = def
.markup
.iter()
.find_map(|markup| match markup {
TypeMemberMarkup::Enum(len) => Some(len.as_str()),
_ => None,
})
.or_else(|| {
regex
.captures(&def.code)
.and_then(|cap| cap.get(1))
.map(|m| m.as_str())
});
if name != Some("sType") && name != Some("pNext") {
return name.map(|name| Member {
name,
ty: ty.unwrap(),
len,
});
}
}
None
})
.collect()
} else {
vec![]
}
}
fn vulkano_type(ty: &str, len: Option<&str>) -> &'static str {
if let Some(len) = len {
match ty {
"char" => "String",
"uint8_t" if len == "VK_LUID_SIZE" => "[u8; 8]",
"uint8_t" if len == "VK_UUID_SIZE" => "[u8; 16]",
"uint32_t" if len == "2" => "[u32; 2]",
"uint32_t" if len == "3" => "[u32; 3]",
"float" if len == "2" => "[f32; 2]",
_ => unimplemented!("{}[{}]", ty, len),
}
} else {
match ty {
"float" => "f32",
"int32_t" => "i32",
"size_t" => "usize",
"uint8_t" => "u8",
"uint32_t" => "u32",
"uint64_t" => "u64",
"VkBool32" => "bool",
"VkConformanceVersion" => "crate::instance::ConformanceVersion",
"VkDeviceSize" => "u64",
"VkDriverId" => "crate::instance::DriverId",
"VkExtent2D" => "[u32; 2]",
"VkPhysicalDeviceType" => "crate::instance::PhysicalDeviceType",
"VkPointClippingBehavior" => "crate::instance::PointClippingBehavior",
"VkResolveModeFlags" => "crate::render_pass::ResolveModes",
"VkSampleCountFlags" => "crate::image::SampleCounts",
"VkSampleCountFlagBits" => "crate::image::SampleCount",
"VkShaderCorePropertiesFlagsAMD" => "crate::instance::ShaderCoreProperties",
"VkShaderFloatControlsIndependence" => {
"crate::instance::ShaderFloatControlsIndependence"
}
"VkShaderStageFlags" => "crate::descriptor::descriptor::ShaderStages",
"VkSubgroupFeatureFlags" => "crate::instance::SubgroupFeatures",
_ => unimplemented!("{}", ty),
}
}
}

View File

@ -25,6 +25,7 @@ fn main() {
}
// Write autogen.rs
println!("cargo:rerun-if-changed=vk.xml");
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

@ -468,16 +468,18 @@ where
if self.usage.uniform_buffer {
self.device()
.physical_device()
.limits()
.min_uniform_buffer_offset_alignment() as usize
.properties()
.min_uniform_buffer_offset_alignment
.unwrap() as usize
} else {
1
},
if self.usage.storage_buffer {
self.device()
.physical_device()
.limits()
.min_storage_buffer_offset_alignment() as usize
.properties()
.min_storage_buffer_offset_alignment
.unwrap() as usize
} else {
1
},

View File

@ -214,25 +214,25 @@ impl UnsafeBuffer {
};
// We have to manually enforce some additional requirements for some buffer types.
let limits = device.physical_device().limits();
let properties = device.physical_device().properties();
if usage.uniform_texel_buffer || usage.storage_texel_buffer {
output.alignment = align(
output.alignment,
limits.min_texel_buffer_offset_alignment() as usize,
properties.min_texel_buffer_offset_alignment.unwrap() as usize,
);
}
if usage.storage_buffer {
output.alignment = align(
output.alignment,
limits.min_storage_buffer_offset_alignment() as usize,
properties.min_storage_buffer_offset_alignment.unwrap() as usize,
);
}
if usage.uniform_buffer {
output.alignment = align(
output.alignment,
limits.min_uniform_buffer_offset_alignment() as usize,
properties.min_uniform_buffer_offset_alignment.unwrap() as usize,
);
}
@ -270,15 +270,21 @@ impl UnsafeBuffer {
// Check for alignment correctness.
{
let limits = self.device().physical_device().limits();
let properties = self.device().physical_device().properties();
if self.usage().uniform_texel_buffer || self.usage().storage_texel_buffer {
debug_assert!(offset % limits.min_texel_buffer_offset_alignment() as usize == 0);
debug_assert!(
offset % properties.min_texel_buffer_offset_alignment.unwrap() as usize == 0
);
}
if self.usage().storage_buffer {
debug_assert!(offset % limits.min_storage_buffer_offset_alignment() as usize == 0);
debug_assert!(
offset % properties.min_storage_buffer_offset_alignment.unwrap() as usize == 0
);
}
if self.usage().uniform_buffer {
debug_assert!(offset % limits.min_uniform_buffer_offset_alignment() as usize == 0);
debug_assert!(
offset % properties.min_uniform_buffer_offset_alignment.unwrap() as usize == 0
);
}
}

View File

@ -96,8 +96,9 @@ where
if (offset
% device
.physical_device()
.limits()
.min_texel_buffer_offset_alignment() as usize)
.properties()
.min_texel_buffer_offset_alignment
.unwrap() as usize)
!= 0
{
return Err(BufferViewCreationError::WrongBufferAlignment);
@ -114,8 +115,9 @@ where
.expect("Can't use a compressed format for buffer views");
let l = device
.physical_device()
.limits()
.max_texel_buffer_elements();
.properties()
.max_texel_buffer_elements
.unwrap();
if nb > l as usize {
return Err(BufferViewCreationError::MaxTexelBufferElementsExceeded);
}

View File

@ -1218,7 +1218,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
///
/// One draw is performed for each [`DrawIndirectCommand`] struct in `indirect_buffer`.
/// The maximum number of draw commands in the buffer is limited by the
/// [`max_draw_indirect_count`](crate::instance::Limits::max_draw_indirect_count) limit.
/// [`max_draw_indirect_count`](crate::device::Properties::max_draw_indirect_count) limit.
/// This limit is 1 unless the
/// [`multi_draw_indirect`](crate::device::Features::multi_draw_indirect) feature has been
/// enabled.
@ -1264,8 +1264,9 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
let limit = self
.device()
.physical_device()
.limits()
.max_draw_indirect_count();
.properties()
.max_draw_indirect_count
.unwrap();
if requested > limit {
return Err(
@ -1397,7 +1398,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
///
/// One draw is performed for each [`DrawIndirectCommand`] struct in `indirect_buffer`.
/// The maximum number of draw commands in the buffer is limited by the
/// [`max_draw_indirect_count`](crate::instance::Limits::max_draw_indirect_count) limit.
/// [`max_draw_indirect_count`](crate::device::Properties::max_draw_indirect_count) limit.
/// This limit is 1 unless the
/// [`multi_draw_indirect`](crate::device::Features::multi_draw_indirect) feature has been
/// enabled.
@ -1448,8 +1449,9 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
let limit = self
.device()
.physical_device()
.limits()
.max_draw_indirect_count();
.properties()
.max_draw_indirect_count
.unwrap();
if requested > limit {
return Err(
@ -2197,9 +2199,9 @@ where
// Ensure that the number of dynamic_offsets is correct and that each
// dynamic offset is a multiple of the minimum offset alignment specified
// by the physical device.
let limits = pipeline_layout.device().physical_device().limits();
let min_uniform_off_align = limits.min_uniform_buffer_offset_alignment() as u32;
let min_storage_off_align = limits.min_storage_buffer_offset_alignment() as u32;
let properties = pipeline_layout.device().physical_device().properties();
let min_uniform_off_align = properties.min_uniform_buffer_offset_alignment.unwrap() as u32;
let min_storage_off_align = properties.min_storage_buffer_offset_alignment.unwrap() as u32;
let mut dynamic_offset_index = 0;
for set in &sets {
for desc_index in 0..set.num_bindings() {

View File

@ -428,8 +428,9 @@ impl UnsafeCommandBufferBuilder {
let max_bindings = self
.device()
.physical_device()
.limits()
.max_vertex_input_bindings();
.properties()
.max_vertex_input_bindings
.unwrap();
first_binding + num_bindings <= max_bindings
});
@ -1018,8 +1019,9 @@ impl UnsafeCommandBufferBuilder {
let max_group_counts = self
.device()
.physical_device()
.limits()
.max_compute_work_group_count();
.properties()
.max_compute_work_group_count
.unwrap();
group_counts[0] <= max_group_counts[0]
&& group_counts[1] <= max_group_counts[1]
&& group_counts[2] <= max_group_counts[2]
@ -1412,7 +1414,12 @@ impl UnsafeCommandBufferBuilder {
|| self.device().enabled_features().multi_viewport
);
debug_assert!({
let max = self.device().physical_device().limits().max_viewports();
let max = self
.device()
.physical_device()
.properties()
.max_viewports
.unwrap();
first_scissor + scissors.len() as u32 <= max
});
@ -1442,7 +1449,12 @@ impl UnsafeCommandBufferBuilder {
|| self.device().enabled_features().multi_viewport
);
debug_assert!({
let max = self.device().physical_device().limits().max_viewports();
let max = self
.device()
.physical_device()
.properties()
.max_viewports
.unwrap();
first_viewport + viewports.len() as u32 <= max
});

View File

@ -16,8 +16,9 @@ use crate::device::Device;
pub fn check_dispatch(device: &Device, dimensions: [u32; 3]) -> Result<(), CheckDispatchError> {
let max = device
.physical_device()
.limits()
.max_compute_work_group_count();
.properties()
.max_compute_work_group_count
.unwrap();
if dimensions[0] > max[0] || dimensions[1] > max[1] || dimensions[2] > max[2] {
return Err(CheckDispatchError::UnsupportedDimensions {
@ -71,8 +72,9 @@ mod tests {
// Just in case the device is some kind of software implementation.
if device
.physical_device()
.limits()
.max_compute_work_group_count()
.properties()
.max_compute_work_group_count
.unwrap()
== attempted
{
return;

View File

@ -46,8 +46,8 @@ where
let max_instance_index = pipeline
.device()
.physical_device()
.extended_properties()
.max_multiview_instance_index()
.properties()
.max_multiview_instance_index
.unwrap_or(0) as usize;
// vulkano currently always uses `0` as the first instance which means the highest

View File

@ -754,7 +754,7 @@ impl ShaderStages {
impl From<ShaderStages> for ash::vk::ShaderStageFlags {
#[inline]
fn from(val: ShaderStages) -> ash::vk::ShaderStageFlags {
fn from(val: ShaderStages) -> Self {
let mut result = ash::vk::ShaderStageFlags::empty();
if val.vertex {
result |= ash::vk::ShaderStageFlags::VERTEX;
@ -778,6 +778,21 @@ impl From<ShaderStages> for ash::vk::ShaderStageFlags {
}
}
impl From<ash::vk::ShaderStageFlags> for ShaderStages {
#[inline]
fn from(val: ash::vk::ShaderStageFlags) -> Self {
Self {
vertex: val.intersects(ash::vk::ShaderStageFlags::VERTEX),
tessellation_control: val.intersects(ash::vk::ShaderStageFlags::TESSELLATION_CONTROL),
tessellation_evaluation: val
.intersects(ash::vk::ShaderStageFlags::TESSELLATION_EVALUATION),
geometry: val.intersects(ash::vk::ShaderStageFlags::GEOMETRY),
fragment: val.intersects(ash::vk::ShaderStageFlags::FRAGMENT),
compute: val.intersects(ash::vk::ShaderStageFlags::COMPUTE),
}
}
}
impl BitOr for ShaderStages {
type Output = ShaderStages;

View File

@ -950,16 +950,18 @@ impl DescriptorWrite {
% buffer
.device()
.physical_device()
.limits()
.min_uniform_buffer_offset_alignment() as usize,
.properties()
.min_uniform_buffer_offset_alignment
.unwrap() as usize,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.limits()
.max_uniform_buffer_range() as usize
.properties()
.max_uniform_buffer_range
.unwrap() as usize
);
DescriptorWrite {
@ -984,16 +986,18 @@ impl DescriptorWrite {
% buffer
.device()
.physical_device()
.limits()
.min_storage_buffer_offset_alignment() as usize,
.properties()
.min_storage_buffer_offset_alignment
.unwrap() as usize,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.limits()
.max_storage_buffer_range() as usize
.properties()
.max_storage_buffer_range
.unwrap() as usize
);
DescriptorWrite {
@ -1022,16 +1026,18 @@ impl DescriptorWrite {
% buffer
.device()
.physical_device()
.limits()
.min_uniform_buffer_offset_alignment() as usize,
.properties()
.min_uniform_buffer_offset_alignment
.unwrap() as usize,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.limits()
.max_uniform_buffer_range() as usize
.properties()
.max_uniform_buffer_range
.unwrap() as usize
);
DescriptorWrite {
@ -1062,16 +1068,18 @@ impl DescriptorWrite {
% buffer
.device()
.physical_device()
.limits()
.min_storage_buffer_offset_alignment() as usize,
.properties()
.min_storage_buffer_offset_alignment
.unwrap() as usize,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.limits()
.max_storage_buffer_range() as usize
.properties()
.max_storage_buffer_range
.unwrap() as usize
);
DescriptorWrite {

View File

@ -179,7 +179,7 @@ macro_rules! features {
}
pub use crate::autogen::Features;
pub(crate) use {crate::autogen::FeaturesFfi, features};
pub(crate) use features;
/// An error that can happen when enabling a feature on a device.
#[derive(Clone, Copy, Debug)]
@ -238,7 +238,8 @@ impl fmt::Display for FeatureRestriction {
macro_rules! features_ffi {
{
$api_version:ident,
$extensions:ident,
$device_extensions:ident,
$instance_extensions:ident,
$($member:ident => {
ty: $ty:ident,
provided_by: [$($provided_by:expr),+],
@ -255,14 +256,22 @@ macro_rules! features_ffi {
}
impl FeaturesFfi {
pub(crate) fn make_chain(&mut self, $api_version: crate::Version, $extensions: &DeviceExtensions) {
pub(crate) fn make_chain(
&mut self,
$api_version: crate::Version,
$device_extensions: &DeviceExtensions,
$instance_extensions: &InstanceExtensions,
) {
self.features_vulkan10 = Some(Default::default());
let head = self.features_vulkan10.as_mut().unwrap();
$(
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 _;
let member = self.$member.as_mut().unwrap();
member.p_next = head.p_next;
head.p_next = member as *mut _ as _;
}
)+
}
@ -278,4 +287,4 @@ macro_rules! features_ffi {
};
}
pub(crate) use features_ffi;
pub(crate) use {crate::autogen::FeaturesFfi, features_ffi};

View File

@ -92,6 +92,8 @@
pub(crate) use self::features::FeaturesFfi;
pub use self::features::{FeatureRestriction, FeatureRestrictionError, Features};
pub use self::properties::Properties;
pub(crate) use self::properties::PropertiesFfi;
pub use crate::autogen::DeviceExtensions;
use crate::check_errors;
use crate::command_buffer::pool::StandardCommandPool;
@ -138,6 +140,7 @@ use std::sync::Weak;
pub(crate) mod extensions;
pub(crate) mod features;
pub(crate) mod properties;
/// Represents a Vulkan context.
pub struct Device {
@ -200,9 +203,7 @@ impl Device {
{
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, physical_device.api_version());
let api_version = physical_device.api_version();
// Check if the extensions are correct
requested_extensions.check_requirements(
@ -286,7 +287,11 @@ impl Device {
.collect::<SmallVec<[_; 16]>>();
let mut features_ffi = FeaturesFfi::default();
features_ffi.make_chain(api_version, requested_extensions);
features_ffi.make_chain(
api_version,
requested_extensions,
instance.loaded_extensions(),
);
features_ffi.write(&requested_features);
// Device layers were deprecated in Vulkan 1.0.13, and device layer requests should be

View File

@ -0,0 +1,282 @@
use crate::descriptor::descriptor::ShaderStages;
use crate::image::{SampleCount, SampleCounts};
use crate::instance::{
ConformanceVersion, DriverId, PhysicalDeviceType, PointClippingBehavior, ShaderCoreProperties,
ShaderFloatControlsIndependence, SubgroupFeatures,
};
use crate::render_pass::ResolveModes;
use crate::Version;
use std::convert::TryInto;
use std::ffi::CStr;
macro_rules! properties {
{
$($member:ident => {
doc: $doc:expr,
ty: $ty:ty,
ffi_name: $ffi_field:ident,
ffi_members: [$($ffi_struct:ident $(.$ffi_struct_field:ident)*),+],
},)*
} => {
/// Represents all the properties of a physical device.
///
/// Depending on the highest version of Vulkan supported by the physical device, and the
/// available extensions, not every property may be available. For that reason, properties
/// are wrapped in an `Option`.
#[derive(Clone, Debug, Default)]
#[allow(missing_docs)]
pub struct Properties {
$(
#[doc = $doc]
pub $member: Option<$ty>,
)*
}
impl From<&PropertiesFfi> for Properties {
fn from(properties_ffi: &PropertiesFfi) -> Self {
use crate::device::properties::FromVulkan;
Properties {
$(
$member: std::array::IntoIter::new([
$(properties_ffi.$ffi_struct.map(|s| s$(.$ffi_struct_field)*.$ffi_field)),+
]).flatten().next().and_then(|x| <$ty>::from_vulkan(x)),
)*
}
}
}
};
}
pub use crate::autogen::Properties;
pub(crate) use properties;
macro_rules! properties_ffi {
{
$api_version:ident,
$device_extensions:ident,
$instance_extensions:ident,
$($member:ident => {
ty: $ty:ident,
provided_by: [$($provided_by:expr),+],
conflicts: [$($conflicts:ident),*],
},)+
} => {
#[derive(Default)]
pub(crate) struct PropertiesFfi {
properties_vulkan10: Option<ash::vk::PhysicalDeviceProperties2KHR>,
$(
$member: Option<ash::vk::$ty>,
)+
}
impl PropertiesFfi {
pub(crate) fn make_chain(
&mut self,
$api_version: crate::Version,
$device_extensions: &crate::device::DeviceExtensions,
$instance_extensions: &crate::instance::InstanceExtensions,
) {
self.properties_vulkan10 = Some(Default::default());
let head = self.properties_vulkan10.as_mut().unwrap();
$(
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());
let member = self.$member.as_mut().unwrap();
member.p_next = head.p_next;
head.p_next = member as *mut _ as _;
}
)+
}
pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceProperties2KHR {
self.properties_vulkan10.as_ref().unwrap()
}
pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceProperties2KHR {
self.properties_vulkan10.as_mut().unwrap()
}
}
};
}
pub(crate) use {crate::autogen::PropertiesFfi, properties_ffi};
// A bit of a hack...
pub(crate) trait FromVulkan<F>
where
Self: Sized,
{
fn from_vulkan(val: F) -> Option<Self>;
}
impl FromVulkan<u8> for u8 {
#[inline]
fn from_vulkan(val: u8) -> Option<Self> {
Some(val)
}
}
impl<const N: usize> FromVulkan<[u8; N]> for [u8; N] {
#[inline]
fn from_vulkan(val: [u8; N]) -> Option<Self> {
Some(val)
}
}
impl FromVulkan<u32> for u32 {
#[inline]
fn from_vulkan(val: u32) -> Option<Self> {
Some(val)
}
}
impl<const N: usize> FromVulkan<[u32; N]> for [u32; N] {
#[inline]
fn from_vulkan(val: [u32; N]) -> Option<Self> {
Some(val)
}
}
impl FromVulkan<u64> for u64 {
#[inline]
fn from_vulkan(val: u64) -> Option<Self> {
Some(val)
}
}
impl FromVulkan<usize> for usize {
#[inline]
fn from_vulkan(val: usize) -> Option<Self> {
Some(val)
}
}
impl FromVulkan<i32> for i32 {
#[inline]
fn from_vulkan(val: i32) -> Option<Self> {
Some(val)
}
}
impl FromVulkan<f32> for f32 {
#[inline]
fn from_vulkan(val: f32) -> Option<Self> {
Some(val)
}
}
impl<const N: usize> FromVulkan<[f32; N]> for [f32; N] {
#[inline]
fn from_vulkan(val: [f32; N]) -> Option<Self> {
Some(val)
}
}
impl<const N: usize> FromVulkan<[std::os::raw::c_char; N]> for String {
#[inline]
fn from_vulkan(val: [i8; N]) -> Option<Self> {
Some(unsafe { CStr::from_ptr(val.as_ptr()).to_string_lossy().into_owned() })
}
}
impl FromVulkan<u32> for Version {
#[inline]
fn from_vulkan(val: u32) -> Option<Self> {
val.try_into().ok()
}
}
impl FromVulkan<ash::vk::Bool32> for bool {
#[inline]
fn from_vulkan(val: ash::vk::Bool32) -> Option<Self> {
Some(val != 0)
}
}
impl FromVulkan<ash::vk::ConformanceVersion> for ConformanceVersion {
#[inline]
fn from_vulkan(val: ash::vk::ConformanceVersion) -> Option<Self> {
Some(val.into())
}
}
impl FromVulkan<ash::vk::DriverId> for DriverId {
#[inline]
fn from_vulkan(val: ash::vk::DriverId) -> Option<Self> {
val.try_into().ok()
}
}
impl FromVulkan<ash::vk::Extent2D> for [u32; 2] {
#[inline]
fn from_vulkan(val: ash::vk::Extent2D) -> Option<Self> {
Some([val.width, val.height])
}
}
impl FromVulkan<ash::vk::PhysicalDeviceType> for PhysicalDeviceType {
#[inline]
fn from_vulkan(val: ash::vk::PhysicalDeviceType) -> Option<Self> {
val.try_into().ok()
}
}
impl FromVulkan<ash::vk::PointClippingBehavior> for PointClippingBehavior {
#[inline]
fn from_vulkan(val: ash::vk::PointClippingBehavior) -> Option<Self> {
val.try_into().ok()
}
}
impl FromVulkan<ash::vk::ResolveModeFlags> for ResolveModes {
#[inline]
fn from_vulkan(val: ash::vk::ResolveModeFlags) -> Option<Self> {
Some(val.into())
}
}
impl FromVulkan<ash::vk::SampleCountFlags> for SampleCounts {
#[inline]
fn from_vulkan(val: ash::vk::SampleCountFlags) -> Option<Self> {
Some(val.into())
}
}
impl FromVulkan<ash::vk::SampleCountFlags> for SampleCount {
#[inline]
fn from_vulkan(val: ash::vk::SampleCountFlags) -> Option<Self> {
val.try_into().ok()
}
}
impl FromVulkan<ash::vk::ShaderCorePropertiesFlagsAMD> for ShaderCoreProperties {
#[inline]
fn from_vulkan(val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Option<Self> {
Some(val.into())
}
}
impl FromVulkan<ash::vk::ShaderFloatControlsIndependence> for ShaderFloatControlsIndependence {
#[inline]
fn from_vulkan(val: ash::vk::ShaderFloatControlsIndependence) -> Option<Self> {
val.try_into().ok()
}
}
impl FromVulkan<ash::vk::ShaderStageFlags> for ShaderStages {
#[inline]
fn from_vulkan(val: ash::vk::ShaderStageFlags) -> Option<Self> {
Some(val.into())
}
}
impl FromVulkan<ash::vk::SubgroupFeatureFlags> for SubgroupFeatures {
#[inline]
fn from_vulkan(val: ash::vk::SubgroupFeatureFlags) -> Option<Self> {
Some(val.into())
}
}

View File

@ -92,6 +92,24 @@ impl From<SampleCount> for ash::vk::SampleCountFlags {
}
}
impl TryFrom<ash::vk::SampleCountFlags> for SampleCount {
type Error = ();
#[inline]
fn try_from(val: ash::vk::SampleCountFlags) -> Result<Self, Self::Error> {
match val {
ash::vk::SampleCountFlags::TYPE_1 => Ok(Self::Sample1),
ash::vk::SampleCountFlags::TYPE_2 => Ok(Self::Sample2),
ash::vk::SampleCountFlags::TYPE_4 => Ok(Self::Sample4),
ash::vk::SampleCountFlags::TYPE_8 => Ok(Self::Sample8),
ash::vk::SampleCountFlags::TYPE_16 => Ok(Self::Sample16),
ash::vk::SampleCountFlags::TYPE_32 => Ok(Self::Sample32),
ash::vk::SampleCountFlags::TYPE_64 => Ok(Self::Sample64),
_ => Err(()),
}
}
}
impl TryFrom<u32> for SampleCount {
type Error = ();

View File

@ -249,41 +249,47 @@ impl UnsafeImage {
FormatTy::Float | FormatTy::Compressed => {
supported_samples &= device
.physical_device()
.limits()
.sampled_image_color_sample_counts()
.properties()
.sampled_image_color_sample_counts
.unwrap()
.into();
}
FormatTy::Uint | FormatTy::Sint => {
supported_samples &= device
.physical_device()
.limits()
.sampled_image_integer_sample_counts()
.properties()
.sampled_image_integer_sample_counts
.unwrap()
.into();
}
FormatTy::Depth => {
supported_samples &= device
.physical_device()
.limits()
.sampled_image_depth_sample_counts()
.properties()
.sampled_image_depth_sample_counts
.unwrap()
.into();
}
FormatTy::Stencil => {
supported_samples &= device
.physical_device()
.limits()
.sampled_image_stencil_sample_counts()
.properties()
.sampled_image_stencil_sample_counts
.unwrap()
.into();
}
FormatTy::DepthStencil => {
supported_samples &= device
.physical_device()
.limits()
.sampled_image_depth_sample_counts()
.properties()
.sampled_image_depth_sample_counts
.unwrap()
.into();
supported_samples &= device
.physical_device()
.limits()
.sampled_image_stencil_sample_counts()
.properties()
.sampled_image_stencil_sample_counts
.unwrap()
.into();
}
FormatTy::Ycbcr => {
@ -299,8 +305,9 @@ impl UnsafeImage {
if usage.storage {
supported_samples &= device
.physical_device()
.limits()
.storage_image_sample_counts()
.properties()
.storage_image_sample_counts
.unwrap()
.into();
}
@ -313,34 +320,39 @@ impl UnsafeImage {
FormatTy::Float | FormatTy::Compressed | FormatTy::Uint | FormatTy::Sint => {
supported_samples &= device
.physical_device()
.limits()
.framebuffer_color_sample_counts()
.properties()
.framebuffer_color_sample_counts
.unwrap()
.into();
}
FormatTy::Depth => {
supported_samples &= device
.physical_device()
.limits()
.framebuffer_depth_sample_counts()
.properties()
.framebuffer_depth_sample_counts
.unwrap()
.into();
}
FormatTy::Stencil => {
supported_samples &= device
.physical_device()
.limits()
.framebuffer_stencil_sample_counts()
.properties()
.framebuffer_stencil_sample_counts
.unwrap()
.into();
}
FormatTy::DepthStencil => {
supported_samples &= device
.physical_device()
.limits()
.framebuffer_depth_sample_counts()
.properties()
.framebuffer_depth_sample_counts
.unwrap()
.into();
supported_samples &= device
.physical_device()
.limits()
.framebuffer_stencil_sample_counts()
.properties()
.framebuffer_stencil_sample_counts
.unwrap()
.into();
}
FormatTy::Ycbcr => {
@ -434,26 +446,46 @@ impl UnsafeImage {
}
// Checking the dimensions against the limits.
if array_layers > device.physical_device().limits().max_image_array_layers() {
if array_layers
> device
.physical_device()
.properties()
.max_image_array_layers
.unwrap()
{
let err = ImageCreationError::UnsupportedDimensions { dimensions };
capabilities_error = Some(err);
}
match ty {
ash::vk::ImageType::TYPE_1D => {
if extent.width > device.physical_device().limits().max_image_dimension_1d() {
if extent.width
> device
.physical_device()
.properties()
.max_image_dimension1_d
.unwrap()
{
let err = ImageCreationError::UnsupportedDimensions { dimensions };
capabilities_error = Some(err);
}
}
ash::vk::ImageType::TYPE_2D => {
let limit = device.physical_device().limits().max_image_dimension_2d();
let limit = device
.physical_device()
.properties()
.max_image_dimension2_d
.unwrap();
if extent.width > limit || extent.height > limit {
let err = ImageCreationError::UnsupportedDimensions { dimensions };
capabilities_error = Some(err);
}
if flags.cube_compatible {
let limit = device.physical_device().limits().max_image_dimension_cube();
let limit = device
.physical_device()
.properties()
.max_image_dimension_cube
.unwrap();
if extent.width > limit {
let err = ImageCreationError::UnsupportedDimensions { dimensions };
capabilities_error = Some(err);
@ -461,7 +493,11 @@ impl UnsafeImage {
}
}
ash::vk::ImageType::TYPE_3D => {
let limit = device.physical_device().limits().max_image_dimension_3d();
let limit = device
.physical_device()
.properties()
.max_image_dimension3_d
.unwrap();
if extent.width > limit || extent.height > limit || extent.depth > limit {
let err = ImageCreationError::UnsupportedDimensions { dimensions };
capabilities_error = Some(err);

View File

@ -22,7 +22,7 @@ macro_rules! instance_extensions {
doc: $doc:expr,
raw: $raw:expr,
requires_core: $requires_core:expr,
requires_extensions: [$($requires_extension:ident),*]$(,)?
requires_instance_extensions: [$($requires_instance_extension:ident),*]$(,)?
},)*
) => (
extensions! {
@ -32,7 +32,7 @@ macro_rules! instance_extensions {
raw: $raw,
requires_core: $requires_core,
requires_device_extensions: [],
requires_instance_extensions: [$($requires_extension),*],
requires_instance_extensions: [$($requires_instance_extension),*],
},)*
}
@ -59,10 +59,10 @@ macro_rules! instance_extensions {
});
} else {
$(
if !self.$requires_extension {
if !self.$requires_instance_extension {
return Err(crate::extensions::ExtensionRestrictionError {
extension: stringify!($member),
restriction: crate::extensions::ExtensionRestriction::RequiresInstanceExtension(stringify!($requires_extension)),
restriction: crate::extensions::ExtensionRestriction::RequiresInstanceExtension(stringify!($requires_instance_extension)),
});
}
)*

View File

@ -1,147 +0,0 @@
// Copyright (c) 2017 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.
//! The `Limits` struct provides a nicer API around `vkPhysicalDeviceLimits`.
use crate::image::SampleCounts;
/// Limits of a physical device.
pub struct Limits<'a> {
limits: &'a ash::vk::PhysicalDeviceLimits,
}
macro_rules! limits_impl {
($($name:ident: $t:ty => $target:ident,)*) => (
impl<'a> Limits<'a> {
/// Builds the `Limits` object.
#[inline]
pub(crate) fn from_vk_limits(limits: &'a ash::vk::PhysicalDeviceLimits) -> Limits<'a> {
Limits {
limits
}
}
$(
#[inline]
pub fn $name(&self) -> $t {
<$t>::from(self.limits.$target)
}
)*
}
)
}
limits_impl! {
max_image_dimension_1d: u32 => max_image_dimension1_d,
max_image_dimension_2d: u32 => max_image_dimension2_d,
max_image_dimension_3d: u32 => max_image_dimension3_d,
max_image_dimension_cube: u32 => max_image_dimension_cube,
max_image_array_layers: u32 => max_image_array_layers,
max_texel_buffer_elements: u32 => max_texel_buffer_elements,
max_uniform_buffer_range: u32 => max_uniform_buffer_range,
max_storage_buffer_range: u32 => max_storage_buffer_range,
max_push_constants_size: u32 => max_push_constants_size,
max_memory_allocation_count: u32 => max_memory_allocation_count,
max_sampler_allocation_count: u32 => max_sampler_allocation_count,
buffer_image_granularity: u64 => buffer_image_granularity,
sparse_address_space_size: u64 => sparse_address_space_size,
max_bound_descriptor_sets: u32 => max_bound_descriptor_sets,
max_per_stage_descriptor_samplers: u32 => max_per_stage_descriptor_samplers,
max_per_stage_descriptor_uniform_buffers: u32 => max_per_stage_descriptor_uniform_buffers,
max_per_stage_descriptor_storage_buffers: u32 => max_per_stage_descriptor_storage_buffers,
max_per_stage_descriptor_sampled_images: u32 => max_per_stage_descriptor_sampled_images,
max_per_stage_descriptor_storage_images: u32 => max_per_stage_descriptor_storage_images,
max_per_stage_descriptor_input_attachments: u32 => max_per_stage_descriptor_input_attachments,
max_per_stage_resources: u32 => max_per_stage_resources,
max_descriptor_set_samplers: u32 => max_descriptor_set_samplers,
max_descriptor_set_uniform_buffers: u32 => max_descriptor_set_uniform_buffers,
max_descriptor_set_uniform_buffers_dynamic: u32 => max_descriptor_set_uniform_buffers_dynamic,
max_descriptor_set_storage_buffers: u32 => max_descriptor_set_storage_buffers,
max_descriptor_set_storage_buffers_dynamic: u32 => max_descriptor_set_storage_buffers_dynamic,
max_descriptor_set_sampled_images: u32 => max_descriptor_set_sampled_images,
max_descriptor_set_storage_images: u32 => max_descriptor_set_storage_images,
max_descriptor_set_input_attachments: u32 => max_descriptor_set_input_attachments,
max_vertex_input_attributes: u32 => max_vertex_input_attributes,
max_vertex_input_bindings: u32 => max_vertex_input_bindings,
max_vertex_input_attribute_offset: u32 => max_vertex_input_attribute_offset,
max_vertex_input_binding_stride: u32 => max_vertex_input_binding_stride,
max_vertex_output_components: u32 => max_vertex_output_components,
max_tessellation_generation_level: u32 => max_tessellation_generation_level,
max_tessellation_patch_size: u32 => max_tessellation_patch_size,
max_tessellation_control_per_vertex_input_components: u32 => max_tessellation_control_per_vertex_input_components,
max_tessellation_control_per_vertex_output_components: u32 => max_tessellation_control_per_vertex_output_components,
max_tessellation_control_per_patch_output_components: u32 => max_tessellation_control_per_patch_output_components,
max_tessellation_control_total_output_components: u32 => max_tessellation_control_total_output_components,
max_tessellation_evaluation_input_components: u32 => max_tessellation_evaluation_input_components,
max_tessellation_evaluation_output_components: u32 => max_tessellation_evaluation_output_components,
max_geometry_shader_invocations: u32 => max_geometry_shader_invocations,
max_geometry_input_components: u32 => max_geometry_input_components,
max_geometry_output_components: u32 => max_geometry_output_components,
max_geometry_output_vertices: u32 => max_geometry_output_vertices,
max_geometry_total_output_components: u32 => max_geometry_total_output_components,
max_fragment_input_components: u32 => max_fragment_input_components,
max_fragment_output_attachments: u32 => max_fragment_output_attachments,
max_fragment_dual_src_attachments: u32 => max_fragment_dual_src_attachments,
max_fragment_combined_output_resources: u32 => max_fragment_combined_output_resources,
max_compute_shared_memory_size: u32 => max_compute_shared_memory_size,
max_compute_work_group_count: [u32; 3] => max_compute_work_group_count,
max_compute_work_group_invocations: u32 => max_compute_work_group_invocations,
max_compute_work_group_size: [u32; 3] => max_compute_work_group_size,
sub_pixel_precision_bits: u32 => sub_pixel_precision_bits,
sub_texel_precision_bits: u32 => sub_texel_precision_bits,
mipmap_precision_bits: u32 => mipmap_precision_bits,
max_draw_indexed_index_value: u32 => max_draw_indexed_index_value,
max_draw_indirect_count: u32 => max_draw_indirect_count,
max_sampler_lod_bias: f32 => max_sampler_lod_bias,
max_sampler_anisotropy: f32 => max_sampler_anisotropy,
max_viewports: u32 => max_viewports,
max_viewport_dimensions: [u32; 2] => max_viewport_dimensions,
viewport_bounds_range: [f32; 2] => viewport_bounds_range,
viewport_sub_pixel_bits: u32 => viewport_sub_pixel_bits,
min_memory_map_alignment: usize => min_memory_map_alignment,
min_texel_buffer_offset_alignment: u64 => min_texel_buffer_offset_alignment,
min_uniform_buffer_offset_alignment: u64 => min_uniform_buffer_offset_alignment,
min_storage_buffer_offset_alignment: u64 => min_storage_buffer_offset_alignment,
min_texel_offset: i32 => min_texel_offset,
max_texel_offset: u32 => max_texel_offset,
min_texel_gather_offset: i32 => min_texel_gather_offset,
max_texel_gather_offset: u32 => max_texel_gather_offset,
min_interpolation_offset: f32 => min_interpolation_offset,
max_interpolation_offset: f32 => max_interpolation_offset,
sub_pixel_interpolation_offset_bits: u32 => sub_pixel_interpolation_offset_bits,
max_framebuffer_width: u32 => max_framebuffer_width,
max_framebuffer_height: u32 => max_framebuffer_height,
max_framebuffer_layers: u32 => max_framebuffer_layers,
framebuffer_color_sample_counts: SampleCounts => framebuffer_color_sample_counts, // FIXME: SampleCountFlag
framebuffer_depth_sample_counts: SampleCounts => framebuffer_depth_sample_counts, // FIXME: SampleCountFlag
framebuffer_stencil_sample_counts: SampleCounts => framebuffer_stencil_sample_counts, // FIXME: SampleCountFlag
framebuffer_no_attachments_sample_counts: SampleCounts => framebuffer_no_attachments_sample_counts, // FIXME: SampleCountFlag
max_color_attachments: u32 => max_color_attachments,
sampled_image_color_sample_counts: SampleCounts => sampled_image_color_sample_counts, // FIXME: SampleCountFlag
sampled_image_integer_sample_counts: SampleCounts => sampled_image_integer_sample_counts, // FIXME: SampleCountFlag
sampled_image_depth_sample_counts: SampleCounts => sampled_image_depth_sample_counts, // FIXME: SampleCountFlag
sampled_image_stencil_sample_counts: SampleCounts => sampled_image_stencil_sample_counts, // FIXME: SampleCountFlag
storage_image_sample_counts: SampleCounts => storage_image_sample_counts, // FIXME: SampleCountFlag
max_sample_mask_words: u32 => max_sample_mask_words,
timestamp_compute_and_graphics: u32 => timestamp_compute_and_graphics, // TODO: these are booleans
timestamp_period: f32 => timestamp_period,
max_clip_distances: u32 => max_clip_distances,
max_cull_distances: u32 => max_cull_distances,
max_combined_clip_and_cull_distances: u32 => max_combined_clip_and_cull_distances,
discrete_queue_priorities: u32 => discrete_queue_priorities,
point_size_range: [f32; 2] => point_size_range,
line_width_range: [f32; 2] => line_width_range,
point_size_granularity: f32 => point_size_granularity,
line_width_granularity: f32 => line_width_granularity,
strict_lines: u32 => strict_lines, // TODO: these are booleans
standard_sample_locations: u32 => standard_sample_locations, // TODO: these are booleans
optimal_buffer_copy_offset_alignment: u64 => optimal_buffer_copy_offset_alignment,
optimal_buffer_copy_row_pitch_alignment: u64 => optimal_buffer_copy_row_pitch_alignment,
non_coherent_atom_size: u64 => non_coherent_atom_size,
}

View File

@ -35,7 +35,7 @@
//!
//! # let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap();
//! for physical_device in PhysicalDevice::enumerate(&instance) {
//! println!("Available device: {}", physical_device.name());
//! println!("Available device: {}", physical_device.properties().device_name.as_ref().unwrap());
//! }
//! ```
//!
@ -59,8 +59,9 @@ pub use self::layers::layers_list;
pub use self::layers::LayerProperties;
pub use self::layers::LayersIterator;
pub use self::layers::LayersListError;
pub use self::limits::Limits;
pub use self::loader::LoadingError;
pub use self::physical_device::ConformanceVersion;
pub use self::physical_device::DriverId;
pub use self::physical_device::MemoryHeap;
pub use self::physical_device::MemoryHeapsIter;
pub use self::physical_device::MemoryType;
@ -68,8 +69,12 @@ pub use self::physical_device::MemoryTypesIter;
pub use self::physical_device::PhysicalDevice;
pub use self::physical_device::PhysicalDeviceType;
pub use self::physical_device::PhysicalDevicesIter;
pub use self::physical_device::PointClippingBehavior;
pub use self::physical_device::QueueFamiliesIter;
pub use self::physical_device::QueueFamily;
pub use self::physical_device::ShaderCoreProperties;
pub use self::physical_device::ShaderFloatControlsIndependence;
pub use self::physical_device::SubgroupFeatures;
pub use crate::extensions::{
ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
};
@ -79,6 +84,5 @@ pub mod debug;
pub(crate) mod extensions;
mod instance;
mod layers;
mod limits;
pub mod loader;
mod physical_device;

View File

@ -8,13 +8,14 @@
// according to those terms.
use crate::check_errors;
use crate::device::{DeviceExtensions, Features, FeaturesFfi};
use crate::instance::limits::Limits;
use crate::device::{DeviceExtensions, Features, FeaturesFfi, Properties, PropertiesFfi};
use crate::instance::{Instance, InstanceCreationError};
use crate::sync::PipelineStage;
use crate::Version;
use crate::VulkanObject;
use std::ffi::{c_void, CStr};
use std::convert::TryFrom;
use std::ffi::CStr;
use std::fmt;
use std::hash::Hash;
use std::mem::MaybeUninit;
use std::ptr;
@ -44,49 +45,55 @@ 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
let info: Vec<_> = physical_devices
.into_iter()
.zip(supported_extensions.into_iter());
.map(|physical_device| -> Result<_, InstanceCreationError> {
let api_version = unsafe {
let mut output = MaybeUninit::uninit();
fns.v1_0
.get_physical_device_properties(physical_device, output.as_mut_ptr());
let api_version = Version::try_from(output.assume_init().api_version).unwrap();
std::cmp::min(instance.max_api_version(), api_version)
};
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
};
let extensions = DeviceExtensions::from(
extension_properties
.iter()
.map(|property| unsafe { CStr::from_ptr(property.extension_name.as_ptr()) }),
);
Ok((physical_device, api_version, extensions))
})
.collect::<Result<_, _>>()?;
// 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
|| instance_extensions.khr_get_physical_device_properties2
{
init_physical_devices_inner2(instance, iter)
init_physical_devices_inner2(instance, info)
} else {
init_physical_devices_inner(instance, iter)
init_physical_devices_inner(instance, info)
};
Ok(physical_devices)
@ -95,17 +102,24 @@ pub(super) fn init_physical_devices(
/// Initialize all physical devices
fn init_physical_devices_inner<I>(instance: &Instance, info: I) -> Vec<PhysicalDeviceInfos>
where
I: IntoIterator<Item = (ash::vk::PhysicalDevice, DeviceExtensions)>,
I: IntoIterator<Item = (ash::vk::PhysicalDevice, Version, DeviceExtensions)>,
{
let fns = instance.fns();
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()
.map(|(physical_device, api_version, supported_extensions)| {
let properties: Properties = unsafe {
let mut output = PropertiesFfi::default();
output.make_chain(
api_version,
&supported_extensions,
instance.loaded_extensions(),
);
fns.v1_0.get_physical_device_properties(
physical_device,
&mut output.head_as_mut().properties,
);
Properties::from(&output)
};
let queue_families = unsafe {
@ -126,7 +140,7 @@ where
families
};
let memory: ash::vk::PhysicalDeviceMemoryProperties = unsafe {
let memory_properties: ash::vk::PhysicalDeviceMemoryProperties = unsafe {
let mut output = MaybeUninit::uninit();
fns.v1_0
.get_physical_device_memory_properties(physical_device, output.as_mut_ptr());
@ -144,9 +158,9 @@ where
PhysicalDeviceInfos {
physical_device,
api_version,
properties,
extended_properties: PhysicalDeviceExtendedProperties::empty(),
memory,
memory_properties,
queue_families,
available_features,
}
@ -158,50 +172,29 @@ where
/// TODO: Query extension-specific physical device properties, once a new instance extension is supported.
fn init_physical_devices_inner2<I>(instance: &Instance, info: I) -> Vec<PhysicalDeviceInfos>
where
I: IntoIterator<Item = (ash::vk::PhysicalDevice, DeviceExtensions)>,
I: IntoIterator<Item = (ash::vk::PhysicalDevice, Version, DeviceExtensions)>,
{
let fns = instance.fns();
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 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
} else {
ptr::null_mut()
},
..Default::default()
};
.map(|(physical_device, api_version, supported_extensions)| {
let properties: Properties = unsafe {
let mut output = PropertiesFfi::default();
output.make_chain(
api_version,
&supported_extensions,
instance.loaded_extensions(),
);
if instance.api_version() >= Version::V1_1 {
fns.v1_1
.get_physical_device_properties2(physical_device, &mut output);
.get_physical_device_properties2(physical_device, output.head_as_mut());
} else {
fns.khr_get_physical_device_properties2
.get_physical_device_properties2_khr(physical_device, &mut output);
.get_physical_device_properties2_khr(physical_device, output.head_as_mut());
}
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
Properties::from(&output)
};
let queue_families = unsafe {
@ -245,7 +238,7 @@ where
.collect()
};
let memory: ash::vk::PhysicalDeviceMemoryProperties = unsafe {
let memory_properties: ash::vk::PhysicalDeviceMemoryProperties = unsafe {
let mut output = ash::vk::PhysicalDeviceMemoryProperties2KHR::default();
if instance.api_version() >= Version::V1_1 {
@ -260,12 +253,12 @@ where
};
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);
output.make_chain(
api_version,
&supported_extensions,
instance.loaded_extensions(),
);
if instance.api_version() >= Version::V1_1 {
fns.v1_1
@ -280,9 +273,9 @@ where
PhysicalDeviceInfos {
physical_device,
api_version,
properties,
extended_properties,
memory,
memory_properties,
queue_families,
available_features,
}
@ -292,60 +285,13 @@ where
pub(super) struct PhysicalDeviceInfos {
physical_device: ash::vk::PhysicalDevice,
properties: ash::vk::PhysicalDeviceProperties,
extended_properties: PhysicalDeviceExtendedProperties,
api_version: Version,
properties: Properties,
queue_families: Vec<ash::vk::QueueFamilyProperties>,
memory: ash::vk::PhysicalDeviceMemoryProperties,
memory_properties: ash::vk::PhysicalDeviceMemoryProperties,
available_features: Features,
}
/// Represents additional information related to Physical Devices fetched from
/// `vkGetPhysicalDeviceProperties` call. Certain features available only when
/// appropriate `Instance` extensions enabled. The core extension required
/// for this features is `InstanceExtensions::khr_get_physical_device_properties2`
///
/// TODO: Only a small subset of available properties(https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties2.html) is implemented at this moment.
pub struct PhysicalDeviceExtendedProperties {
subgroup_size: Option<u32>,
max_multiview_view_count: Option<u32>,
max_multiview_instance_index: Option<u32>,
}
impl PhysicalDeviceExtendedProperties {
fn empty() -> Self {
Self {
subgroup_size: None,
max_multiview_view_count: None,
max_multiview_instance_index: None,
}
}
/// The default number of invocations in each subgroup
///
/// See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupProperties.html for details
#[inline]
pub fn subgroup_size(&self) -> &Option<u32> {
&self.subgroup_size
}
/// The maximum number of views that can be used in a subpass using the multiview feature.
///
/// See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMultiviewProperties.html for details
#[inline]
pub fn max_multiview_view_count(&self) -> &Option<u32> {
&self.max_multiview_view_count
}
/// The maximum number valid value of instance index (for instanced rendering)
/// allowed to be generated by a drawing command using this multiview description.
///
/// See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMultiviewProperties.html for details
#[inline]
pub fn max_multiview_instance_index(&self) -> &Option<u32> {
&self.max_multiview_instance_index
}
}
/// Represents one of the available devices on this machine.
///
/// This struct simply contains a pointer to an instance and a number representing the physical
@ -365,7 +311,7 @@ impl PhysicalDeviceExtendedProperties {
/// }
///
/// fn print_infos(dev: PhysicalDevice) {
/// println!("Name: {}", dev.name());
/// println!("Name: {}", dev.properties().device_name.as_ref().unwrap());
/// }
/// ```
#[derive(Debug, Copy, Clone)]
@ -387,7 +333,7 @@ impl<'a> PhysicalDevice<'a> {
///
/// # let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap();
/// for physical_device in PhysicalDevice::enumerate(&instance) {
/// println!("Available device: {}", physical_device.name());
/// println!("Available device: {}", physical_device.properties().device_name.as_ref().unwrap());
/// }
/// ```
#[inline]
@ -451,53 +397,20 @@ impl<'a> PhysicalDevice<'a> {
self.device
}
/// Returns the human-readable name of the device.
#[inline]
pub fn name(&self) -> &str {
unsafe {
let val = &self.infos().properties.device_name;
let val = CStr::from_ptr(val.as_ptr());
val.to_str()
.expect("physical device name contained non-UTF8 characters")
}
}
/// Returns the type of the device.
///
/// # Example
///
/// ```no_run
/// # use vulkano::instance::Instance;
/// # use vulkano::instance::InstanceExtensions;
/// # use vulkano::Version;
/// use vulkano::instance::PhysicalDevice;
///
/// # let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap();
/// for physical_device in PhysicalDevice::enumerate(&instance) {
/// println!("Available device: {} (type: {:?})",
/// physical_device.name(), physical_device.ty());
/// }
/// ```
#[inline]
pub fn ty(&self) -> PhysicalDeviceType {
match self.instance.physical_devices[self.device]
.properties
.device_type
{
ash::vk::PhysicalDeviceType::OTHER => PhysicalDeviceType::Other,
ash::vk::PhysicalDeviceType::INTEGRATED_GPU => PhysicalDeviceType::IntegratedGpu,
ash::vk::PhysicalDeviceType::DISCRETE_GPU => PhysicalDeviceType::DiscreteGpu,
ash::vk::PhysicalDeviceType::VIRTUAL_GPU => PhysicalDeviceType::VirtualGpu,
ash::vk::PhysicalDeviceType::CPU => PhysicalDeviceType::Cpu,
_ => panic!("Unrecognized Vulkan device type"),
}
}
/// Returns the version of Vulkan supported by this device.
///
/// Unlike the `api_version` property, which is the version reported by the device directly,
/// this function returns the version the device can actually support, based on the instance's,
/// `max_api_version`.
#[inline]
pub fn api_version(&self) -> Version {
let val = self.infos().properties.api_version;
Version::from(val)
self.infos().api_version
}
/// Returns the Vulkan properties reported by the device.
#[inline]
pub fn properties(&self) -> &'a Properties {
&self.infos().properties
}
/// Returns the Vulkan features that are supported by this physical device.
@ -540,7 +453,7 @@ impl<'a> PhysicalDevice<'a> {
/// Returns the memory type with the given index, or `None` if out of range.
#[inline]
pub fn memory_type_by_id(&self, id: u32) -> Option<MemoryType<'a>> {
if id < self.infos().memory.memory_type_count {
if id < self.infos().memory_properties.memory_type_count {
Some(MemoryType {
physical_device: *self,
id,
@ -562,7 +475,7 @@ impl<'a> PhysicalDevice<'a> {
/// Returns the memory heap with the given index, or `None` if out of range.
#[inline]
pub fn memory_heap_by_id(&self, id: u32) -> Option<MemoryHeap<'a>> {
if id < self.infos().memory.memory_heap_count {
if id < self.infos().memory_properties.memory_heap_count {
Some(MemoryHeap {
physical_device: *self,
id,
@ -572,51 +485,6 @@ impl<'a> PhysicalDevice<'a> {
}
}
/// Gives access to the limits of the physical device.
///
/// This function should be zero-cost in release mode. It only exists to not pollute the
/// namespace of `PhysicalDevice` with all the limits-related getters.
#[inline]
pub fn limits(&self) -> Limits<'a> {
Limits::from_vk_limits(&self.infos().properties.limits)
}
/// Returns an opaque number representing the version of the driver of this device.
///
/// The meaning of this number is implementation-specific. It can be used in bug reports, for
/// example.
#[inline]
pub fn driver_version(&self) -> u32 {
self.infos().properties.driver_version
}
/// Returns the PCI ID of the device.
#[inline]
pub fn pci_device_id(&self) -> u32 {
self.infos().properties.device_id
}
/// Returns the PCI ID of the vendor.
#[inline]
pub fn pci_vendor_id(&self) -> u32 {
self.infos().properties.vendor_id
}
/// Returns a unique identifier for the device.
///
/// Can be stored in a configuration file, so that you can retrieve the device again the next
/// time the program is run.
#[inline]
pub fn uuid(&self) -> &[u8; 16] {
// must be equal to ash::vk::UUID_SIZE
&self.infos().properties.pipeline_cache_uuid
}
#[inline]
pub fn extended_properties(&self) -> &PhysicalDeviceExtendedProperties {
&self.infos().extended_properties
}
// Internal function to make it easier to get the infos of this device.
#[inline]
fn infos(&self) -> &'a PhysicalDeviceInfos {
@ -668,19 +536,35 @@ impl<'a> Iterator for PhysicalDevicesIter<'a> {
impl<'a> ExactSizeIterator for PhysicalDevicesIter<'a> {}
/// Type of a physical device.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
#[repr(i32)]
pub enum PhysicalDeviceType {
/// The device is an integrated GPU.
IntegratedGpu = 1,
IntegratedGpu = ash::vk::PhysicalDeviceType::INTEGRATED_GPU.as_raw(),
/// The device is a discrete GPU.
DiscreteGpu = 2,
DiscreteGpu = ash::vk::PhysicalDeviceType::DISCRETE_GPU.as_raw(),
/// The device is a virtual GPU.
VirtualGpu = 3,
VirtualGpu = ash::vk::PhysicalDeviceType::VIRTUAL_GPU.as_raw(),
/// The device is a CPU.
Cpu = 4,
Cpu = ash::vk::PhysicalDeviceType::CPU.as_raw(),
/// The device is something else.
Other = 0,
Other = ash::vk::PhysicalDeviceType::OTHER.as_raw(),
}
impl TryFrom<ash::vk::PhysicalDeviceType> for PhysicalDeviceType {
type Error = ();
#[inline]
fn try_from(val: ash::vk::PhysicalDeviceType) -> Result<Self, Self::Error> {
match val {
ash::vk::PhysicalDeviceType::INTEGRATED_GPU => Ok(Self::IntegratedGpu),
ash::vk::PhysicalDeviceType::DISCRETE_GPU => Ok(Self::DiscreteGpu),
ash::vk::PhysicalDeviceType::VIRTUAL_GPU => Ok(Self::VirtualGpu),
ash::vk::PhysicalDeviceType::CPU => Ok(Self::Cpu),
ash::vk::PhysicalDeviceType::OTHER => Ok(Self::Other),
_ => Err(()),
}
}
}
/// Represents a queue family in a physical device.
@ -845,7 +729,8 @@ impl<'a> MemoryType<'a> {
/// Returns the heap that corresponds to this memory type.
#[inline]
pub fn heap(&self) -> MemoryHeap<'a> {
let heap_id = self.physical_device.infos().memory.memory_types[self.id as usize].heap_index;
let heap_id = self.physical_device.infos().memory_properties.memory_types[self.id as usize]
.heap_index;
MemoryHeap {
physical_device: self.physical_device,
id: heap_id,
@ -897,7 +782,7 @@ impl<'a> MemoryType<'a> {
/// Internal utility function that returns the flags of this queue family.
#[inline]
fn flags(&self) -> ash::vk::MemoryPropertyFlags {
self.physical_device.infos().memory.memory_types[self.id as usize].property_flags
self.physical_device.infos().memory_properties.memory_types[self.id as usize].property_flags
}
}
@ -913,7 +798,13 @@ impl<'a> Iterator for MemoryTypesIter<'a> {
#[inline]
fn next(&mut self) -> Option<MemoryType<'a>> {
if self.current_id >= self.physical_device.infos().memory.memory_type_count {
if self.current_id
>= self
.physical_device
.infos()
.memory_properties
.memory_type_count
{
return None;
}
@ -928,7 +819,11 @@ impl<'a> Iterator for MemoryTypesIter<'a> {
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.physical_device.infos().memory.memory_type_count;
let len = self
.physical_device
.infos()
.memory_properties
.memory_type_count;
let remain = (len - self.current_id) as usize;
(remain, Some(remain))
}
@ -959,13 +854,14 @@ impl<'a> MemoryHeap<'a> {
/// Returns the size in bytes on this heap.
#[inline]
pub fn size(&self) -> usize {
self.physical_device.infos().memory.memory_heaps[self.id as usize].size as usize
self.physical_device.infos().memory_properties.memory_heaps[self.id as usize].size as usize
}
/// Returns true if the heap is local to the GPU.
#[inline]
pub fn is_device_local(&self) -> bool {
let flags = self.physical_device.infos().memory.memory_heaps[self.id as usize].flags;
let flags =
self.physical_device.infos().memory_properties.memory_heaps[self.id as usize].flags;
!(flags & ash::vk::MemoryHeapFlags::DEVICE_LOCAL).is_empty()
}
@ -973,7 +869,8 @@ impl<'a> MemoryHeap<'a> {
/// heap will replicate to each physical-device's instance of heap.
#[inline]
pub fn is_multi_instance(&self) -> bool {
let flags = self.physical_device.infos().memory.memory_heaps[self.id as usize].flags;
let flags =
self.physical_device.infos().memory_properties.memory_heaps[self.id as usize].flags;
!(flags & ash::vk::MemoryHeapFlags::MULTI_INSTANCE).is_empty()
}
}
@ -990,7 +887,13 @@ impl<'a> Iterator for MemoryHeapsIter<'a> {
#[inline]
fn next(&mut self) -> Option<MemoryHeap<'a>> {
if self.current_id >= self.physical_device.infos().memory.memory_heap_count {
if self.current_id
>= self
.physical_device
.infos()
.memory_properties
.memory_heap_count
{
return None;
}
@ -1005,10 +908,179 @@ impl<'a> Iterator for MemoryHeapsIter<'a> {
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.physical_device.infos().memory.memory_heap_count;
let len = self
.physical_device
.infos()
.memory_properties
.memory_heap_count;
let remain = (len - self.current_id) as usize;
(remain, Some(remain))
}
}
impl<'a> ExactSizeIterator for MemoryHeapsIter<'a> {}
/// The version of the Vulkan conformance test that a driver is conformant against.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ConformanceVersion {
pub major: u8,
pub minor: u8,
pub subminor: u8,
pub patch: u8,
}
impl From<ash::vk::ConformanceVersion> for ConformanceVersion {
#[inline]
fn from(val: ash::vk::ConformanceVersion) -> Self {
ConformanceVersion {
major: val.major,
minor: val.minor,
subminor: val.subminor,
patch: val.patch,
}
}
}
impl fmt::Debug for ConformanceVersion {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
impl fmt::Display for ConformanceVersion {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, formatter)
}
}
/// An identifier for the driver of a physical device.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(i32)]
pub enum DriverId {
AMDProprietary = ash::vk::DriverId::AMD_PROPRIETARY.as_raw(),
AMDOpenSource = ash::vk::DriverId::AMD_OPEN_SOURCE.as_raw(),
MesaRADV = ash::vk::DriverId::MESA_RADV.as_raw(),
NvidiaProprietary = ash::vk::DriverId::NVIDIA_PROPRIETARY.as_raw(),
IntelProprietaryWindows = ash::vk::DriverId::INTEL_PROPRIETARY_WINDOWS.as_raw(),
IntelOpenSourceMesa = ash::vk::DriverId::INTEL_OPEN_SOURCE_MESA.as_raw(),
ImaginationProprietary = ash::vk::DriverId::IMAGINATION_PROPRIETARY.as_raw(),
QualcommProprietary = ash::vk::DriverId::QUALCOMM_PROPRIETARY.as_raw(),
ARMProprietary = ash::vk::DriverId::ARM_PROPRIETARY.as_raw(),
GoogleSwiftshader = ash::vk::DriverId::GOOGLE_SWIFTSHADER.as_raw(),
GGPProprietary = ash::vk::DriverId::GGP_PROPRIETARY.as_raw(),
BroadcomProprietary = ash::vk::DriverId::BROADCOM_PROPRIETARY.as_raw(),
MesaLLVMpipe = ash::vk::DriverId::MESA_LLVMPIPE.as_raw(),
MoltenVK = ash::vk::DriverId::MOLTENVK.as_raw(),
}
impl TryFrom<ash::vk::DriverId> for DriverId {
type Error = ();
#[inline]
fn try_from(val: ash::vk::DriverId) -> Result<Self, Self::Error> {
match val {
ash::vk::DriverId::AMD_PROPRIETARY => Ok(Self::AMDProprietary),
ash::vk::DriverId::AMD_OPEN_SOURCE => Ok(Self::AMDOpenSource),
ash::vk::DriverId::MESA_RADV => Ok(Self::MesaRADV),
ash::vk::DriverId::NVIDIA_PROPRIETARY => Ok(Self::NvidiaProprietary),
ash::vk::DriverId::INTEL_PROPRIETARY_WINDOWS => Ok(Self::IntelProprietaryWindows),
ash::vk::DriverId::INTEL_OPEN_SOURCE_MESA => Ok(Self::IntelOpenSourceMesa),
ash::vk::DriverId::IMAGINATION_PROPRIETARY => Ok(Self::ImaginationProprietary),
ash::vk::DriverId::QUALCOMM_PROPRIETARY => Ok(Self::QualcommProprietary),
ash::vk::DriverId::ARM_PROPRIETARY => Ok(Self::ARMProprietary),
ash::vk::DriverId::GOOGLE_SWIFTSHADER => Ok(Self::GoogleSwiftshader),
ash::vk::DriverId::GGP_PROPRIETARY => Ok(Self::GGPProprietary),
ash::vk::DriverId::BROADCOM_PROPRIETARY => Ok(Self::BroadcomProprietary),
ash::vk::DriverId::MESA_LLVMPIPE => Ok(Self::MesaLLVMpipe),
ash::vk::DriverId::MOLTENVK => Ok(Self::MoltenVK),
_ => Err(()),
}
}
}
/// Specifies which subgroup operations are supported.
#[derive(Clone, Copy, Debug)]
pub struct SubgroupFeatures {
pub basic: bool,
pub vote: bool,
pub arithmetic: bool,
pub ballot: bool,
pub shuffle: bool,
pub shuffle_relative: bool,
pub clustered: bool,
pub quad: bool,
}
impl From<ash::vk::SubgroupFeatureFlags> for SubgroupFeatures {
#[inline]
fn from(val: ash::vk::SubgroupFeatureFlags) -> Self {
Self {
basic: val.intersects(ash::vk::SubgroupFeatureFlags::BASIC),
vote: val.intersects(ash::vk::SubgroupFeatureFlags::VOTE),
arithmetic: val.intersects(ash::vk::SubgroupFeatureFlags::ARITHMETIC),
ballot: val.intersects(ash::vk::SubgroupFeatureFlags::BALLOT),
shuffle: val.intersects(ash::vk::SubgroupFeatureFlags::SHUFFLE),
shuffle_relative: val.intersects(ash::vk::SubgroupFeatureFlags::SHUFFLE_RELATIVE),
clustered: val.intersects(ash::vk::SubgroupFeatureFlags::CLUSTERED),
quad: val.intersects(ash::vk::SubgroupFeatureFlags::QUAD),
}
}
}
/// Specifies how the device clips single point primitives.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(i32)]
pub enum PointClippingBehavior {
/// Points are clipped if they lie outside any clip plane, both those bounding the view volume
/// and user-defined clip planes.
AllClipPlanes = ash::vk::PointClippingBehavior::ALL_CLIP_PLANES.as_raw(),
/// Points are clipped only if they lie outside a user-defined clip plane.
UserClipPlanesOnly = ash::vk::PointClippingBehavior::USER_CLIP_PLANES_ONLY.as_raw(),
}
impl TryFrom<ash::vk::PointClippingBehavior> for PointClippingBehavior {
type Error = ();
#[inline]
fn try_from(val: ash::vk::PointClippingBehavior) -> Result<Self, Self::Error> {
match val {
ash::vk::PointClippingBehavior::ALL_CLIP_PLANES => Ok(Self::AllClipPlanes),
ash::vk::PointClippingBehavior::USER_CLIP_PLANES_ONLY => Ok(Self::UserClipPlanesOnly),
_ => Err(()),
}
}
}
/// Specifies whether, and how, shader float controls can be set independently.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(i32)]
pub enum ShaderFloatControlsIndependence {
Float32Only = ash::vk::ShaderFloatControlsIndependence::TYPE_32_ONLY.as_raw(),
All = ash::vk::ShaderFloatControlsIndependence::ALL.as_raw(),
None = ash::vk::ShaderFloatControlsIndependence::NONE.as_raw(),
}
impl TryFrom<ash::vk::ShaderFloatControlsIndependence> for ShaderFloatControlsIndependence {
type Error = ();
#[inline]
fn try_from(val: ash::vk::ShaderFloatControlsIndependence) -> Result<Self, Self::Error> {
match val {
ash::vk::ShaderFloatControlsIndependence::TYPE_32_ONLY => Ok(Self::Float32Only),
ash::vk::ShaderFloatControlsIndependence::ALL => Ok(Self::All),
ash::vk::ShaderFloatControlsIndependence::NONE => Ok(Self::None),
_ => Err(()),
}
}
}
/// Specifies shader core properties.
#[derive(Clone, Copy, Debug)]
pub struct ShaderCoreProperties {}
impl From<ash::vk::ShaderCorePropertiesFlagsAMD> for ShaderCoreProperties {
#[inline]
fn from(val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Self {
Self {}
}
}

View File

@ -335,7 +335,12 @@ impl<'a> DeviceMemoryBuilder<'a> {
.lock()
.expect("Poisoned mutex");
if *allocation_count >= physical_device.limits().max_memory_allocation_count() {
if *allocation_count
>= physical_device
.properties()
.max_memory_allocation_count
.unwrap()
{
return Err(DeviceMemoryAllocError::TooManyObjects);
}
let fns = self.device.fns();

View File

@ -440,17 +440,18 @@ where
if stride
> device
.physical_device()
.limits()
.max_vertex_input_binding_stride() as usize
.properties()
.max_vertex_input_binding_stride
.unwrap() as usize
{
return Err(
GraphicsPipelineCreationError::MaxVertexInputBindingStrideExceeded {
binding: num as usize,
max: device
.physical_device()
.limits()
.max_vertex_input_binding_stride()
as usize,
.properties()
.max_vertex_input_binding_stride
.unwrap() as usize,
obtained: stride,
},
);
@ -470,16 +471,17 @@ where
if info.offset
> device
.physical_device()
.limits()
.max_vertex_input_attribute_offset() as usize
.properties()
.max_vertex_input_attribute_offset
.unwrap() as usize
{
return Err(
GraphicsPipelineCreationError::MaxVertexInputAttributeOffsetExceeded {
max: device
.physical_device()
.limits()
.max_vertex_input_attribute_offset()
as usize,
.properties()
.max_vertex_input_attribute_offset
.unwrap() as usize,
obtained: info.offset,
},
);
@ -504,15 +506,17 @@ where
if binding_descriptions.len()
> device
.physical_device()
.limits()
.max_vertex_input_bindings() as usize
.properties()
.max_vertex_input_bindings
.unwrap() as usize
{
return Err(
GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
max: device
.physical_device()
.limits()
.max_vertex_input_bindings() as usize,
.properties()
.max_vertex_input_bindings
.unwrap() as usize,
obtained: binding_descriptions.len(),
},
);
@ -521,15 +525,17 @@ where
if attribute_descriptions.len()
> device
.physical_device()
.limits()
.max_vertex_input_attributes() as usize
.properties()
.max_vertex_input_attributes
.unwrap() as usize
{
return Err(
GraphicsPipelineCreationError::MaxVertexInputAttributesExceeded {
max: device
.physical_device()
.limits()
.max_vertex_input_attributes() as usize,
.properties()
.max_vertex_input_attributes
.unwrap() as usize,
obtained: attribute_descriptions.len(),
},
);
@ -576,8 +582,9 @@ where
if vertices_per_patch
> device
.physical_device()
.limits()
.max_tessellation_patch_size()
.properties()
.max_tessellation_patch_size
.unwrap()
{
return Err(GraphicsPipelineCreationError::MaxTessellationPatchSizeExceeded);
}
@ -636,24 +643,54 @@ where
return Err(GraphicsPipelineCreationError::MultiViewportFeatureNotEnabled);
}
if vp_num > device.physical_device().limits().max_viewports() {
if vp_num > device.physical_device().properties().max_viewports.unwrap() {
return Err(GraphicsPipelineCreationError::MaxViewportsExceeded {
obtained: vp_num,
max: device.physical_device().limits().max_viewports(),
max: device.physical_device().properties().max_viewports.unwrap(),
});
}
for vp in vp_vp.iter() {
if vp.width > device.physical_device().limits().max_viewport_dimensions()[0] as f32
|| vp.height > device.physical_device().limits().max_viewport_dimensions()[1] as f32
if vp.width
> device
.physical_device()
.properties()
.max_viewport_dimensions
.unwrap()[0] as f32
|| vp.height
> device
.physical_device()
.properties()
.max_viewport_dimensions
.unwrap()[1] as f32
{
return Err(GraphicsPipelineCreationError::MaxViewportDimensionsExceeded);
}
if vp.x < device.physical_device().limits().viewport_bounds_range()[0]
|| vp.x + vp.width > device.physical_device().limits().viewport_bounds_range()[1]
|| vp.y < device.physical_device().limits().viewport_bounds_range()[0]
|| vp.y + vp.height > device.physical_device().limits().viewport_bounds_range()[1]
if vp.x
< device
.physical_device()
.properties()
.viewport_bounds_range
.unwrap()[0]
|| vp.x + vp.width
> device
.physical_device()
.properties()
.viewport_bounds_range
.unwrap()[1]
|| vp.y
< device
.physical_device()
.properties()
.viewport_bounds_range
.unwrap()[0]
|| vp.y + vp.height
> device
.physical_device()
.properties()
.viewport_bounds_range
.unwrap()[1]
{
return Err(GraphicsPipelineCreationError::ViewportBoundsExceeded);
}

View File

@ -227,7 +227,7 @@ impl PipelineLayoutDesc {
&self,
device: &Device,
) -> Result<(), limits_check::PipelineLayoutLimitsError> {
limits_check::check_desc_against_limits(self, device.physical_device().limits())
limits_check::check_desc_against_limits(self, device.physical_device().properties())
}
/// Makes sure that `self` is a superset of `other`. Returns an `Err` if this is not the case.

View File

@ -11,7 +11,7 @@
use crate::descriptor::descriptor::DescriptorType;
use crate::descriptor::descriptor::ShaderStages;
use crate::instance::Limits;
use crate::device::Properties;
use crate::pipeline::layout::PipelineLayoutDesc;
use crate::pipeline::layout::PipelineLayoutDescPcRange;
use std::error;
@ -20,7 +20,7 @@ use std::fmt;
/// Checks whether the pipeline layout description fulfills the device limits requirements.
pub fn check_desc_against_limits(
desc: &PipelineLayoutDesc,
limits: Limits,
properties: &Properties,
) -> Result<(), PipelineLayoutLimitsError> {
let mut num_resources = Counter::default();
let mut num_samplers = Counter::default();
@ -72,140 +72,166 @@ pub fn check_desc_against_limits(
}
}
if desc.descriptor_sets().len() > limits.max_bound_descriptor_sets() as usize {
if desc.descriptor_sets().len() > properties.max_bound_descriptor_sets.unwrap() as usize {
return Err(PipelineLayoutLimitsError::MaxDescriptorSetsLimitExceeded {
limit: limits.max_bound_descriptor_sets() as usize,
limit: properties.max_bound_descriptor_sets.unwrap() as usize,
requested: desc.descriptor_sets().len(),
});
}
if num_resources.max_per_stage() > limits.max_per_stage_resources() {
if num_resources.max_per_stage() > properties.max_per_stage_resources.unwrap() {
return Err(
PipelineLayoutLimitsError::MaxPerStageResourcesLimitExceeded {
limit: limits.max_per_stage_resources(),
limit: properties.max_per_stage_resources.unwrap(),
requested: num_resources.max_per_stage(),
},
);
}
if num_samplers.max_per_stage() > limits.max_per_stage_descriptor_samplers() {
if num_samplers.max_per_stage() > properties.max_per_stage_descriptor_samplers.unwrap() {
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorSamplersLimitExceeded {
limit: limits.max_per_stage_descriptor_samplers(),
limit: properties.max_per_stage_descriptor_samplers.unwrap(),
requested: num_samplers.max_per_stage(),
},
);
}
if num_uniform_buffers.max_per_stage() > limits.max_per_stage_descriptor_uniform_buffers() {
if num_uniform_buffers.max_per_stage()
> properties.max_per_stage_descriptor_uniform_buffers.unwrap()
{
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorUniformBuffersLimitExceeded {
limit: limits.max_per_stage_descriptor_uniform_buffers(),
limit: properties.max_per_stage_descriptor_uniform_buffers.unwrap(),
requested: num_uniform_buffers.max_per_stage(),
},
);
}
if num_storage_buffers.max_per_stage() > limits.max_per_stage_descriptor_storage_buffers() {
if num_storage_buffers.max_per_stage()
> properties.max_per_stage_descriptor_storage_buffers.unwrap()
{
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorStorageBuffersLimitExceeded {
limit: limits.max_per_stage_descriptor_storage_buffers(),
limit: properties.max_per_stage_descriptor_storage_buffers.unwrap(),
requested: num_storage_buffers.max_per_stage(),
},
);
}
if num_sampled_images.max_per_stage() > limits.max_per_stage_descriptor_sampled_images() {
if num_sampled_images.max_per_stage()
> properties.max_per_stage_descriptor_sampled_images.unwrap()
{
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorSampledImagesLimitExceeded {
limit: limits.max_per_stage_descriptor_sampled_images(),
limit: properties.max_per_stage_descriptor_sampled_images.unwrap(),
requested: num_sampled_images.max_per_stage(),
},
);
}
if num_storage_images.max_per_stage() > limits.max_per_stage_descriptor_storage_images() {
if num_storage_images.max_per_stage()
> properties.max_per_stage_descriptor_storage_images.unwrap()
{
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorStorageImagesLimitExceeded {
limit: limits.max_per_stage_descriptor_storage_images(),
limit: properties.max_per_stage_descriptor_storage_images.unwrap(),
requested: num_storage_images.max_per_stage(),
},
);
}
if num_input_attachments.max_per_stage() > limits.max_per_stage_descriptor_input_attachments() {
if num_input_attachments.max_per_stage()
> properties
.max_per_stage_descriptor_input_attachments
.unwrap()
{
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorInputAttachmentsLimitExceeded {
limit: limits.max_per_stage_descriptor_input_attachments(),
limit: properties
.max_per_stage_descriptor_input_attachments
.unwrap(),
requested: num_input_attachments.max_per_stage(),
},
);
}
if num_samplers.total > limits.max_descriptor_set_samplers() {
if num_samplers.total > properties.max_descriptor_set_samplers.unwrap() {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetSamplersLimitExceeded {
limit: limits.max_descriptor_set_samplers(),
limit: properties.max_descriptor_set_samplers.unwrap(),
requested: num_samplers.total,
},
);
}
if num_uniform_buffers.total > limits.max_descriptor_set_uniform_buffers() {
if num_uniform_buffers.total > properties.max_descriptor_set_uniform_buffers.unwrap() {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersLimitExceeded {
limit: limits.max_descriptor_set_uniform_buffers(),
limit: properties.max_descriptor_set_uniform_buffers.unwrap(),
requested: num_uniform_buffers.total,
},
);
}
if num_uniform_buffers_dynamic > limits.max_descriptor_set_uniform_buffers_dynamic() {
if num_uniform_buffers_dynamic
> properties
.max_descriptor_set_uniform_buffers_dynamic
.unwrap()
{
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
limit: limits.max_descriptor_set_uniform_buffers_dynamic(),
limit: properties
.max_descriptor_set_uniform_buffers_dynamic
.unwrap(),
requested: num_uniform_buffers_dynamic,
},
);
}
if num_storage_buffers.total > limits.max_descriptor_set_storage_buffers() {
if num_storage_buffers.total > properties.max_descriptor_set_storage_buffers.unwrap() {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersLimitExceeded {
limit: limits.max_descriptor_set_storage_buffers(),
limit: properties.max_descriptor_set_storage_buffers.unwrap(),
requested: num_storage_buffers.total,
},
);
}
if num_storage_buffers_dynamic > limits.max_descriptor_set_storage_buffers_dynamic() {
if num_storage_buffers_dynamic
> properties
.max_descriptor_set_storage_buffers_dynamic
.unwrap()
{
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
limit: limits.max_descriptor_set_storage_buffers_dynamic(),
limit: properties
.max_descriptor_set_storage_buffers_dynamic
.unwrap(),
requested: num_storage_buffers_dynamic,
},
);
}
if num_sampled_images.total > limits.max_descriptor_set_sampled_images() {
if num_sampled_images.total > properties.max_descriptor_set_sampled_images.unwrap() {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetSampledImagesLimitExceeded {
limit: limits.max_descriptor_set_sampled_images(),
limit: properties.max_descriptor_set_sampled_images.unwrap(),
requested: num_sampled_images.total,
},
);
}
if num_storage_images.total > limits.max_descriptor_set_storage_images() {
if num_storage_images.total > properties.max_descriptor_set_storage_images.unwrap() {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetStorageImagesLimitExceeded {
limit: limits.max_descriptor_set_storage_images(),
limit: properties.max_descriptor_set_storage_images.unwrap(),
requested: num_storage_images.total,
},
);
}
if num_input_attachments.total > limits.max_descriptor_set_input_attachments() {
if num_input_attachments.total > properties.max_descriptor_set_input_attachments.unwrap() {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetInputAttachmentsLimitExceeded {
limit: limits.max_descriptor_set_input_attachments(),
limit: properties.max_descriptor_set_input_attachments.unwrap(),
requested: num_input_attachments.total,
},
);
}
for &PipelineLayoutDescPcRange { offset, size, .. } in desc.push_constants() {
if offset + size > limits.max_push_constants_size() as usize {
if offset + size > properties.max_push_constants_size.unwrap() as usize {
return Err(PipelineLayoutLimitsError::MaxPushConstantsSizeExceeded {
limit: limits.max_push_constants_size() as usize,
limit: properties.max_push_constants_size.unwrap() as usize,
requested: offset + size,
});
}

View File

@ -399,3 +399,36 @@ impl MultiviewDesc {
.count_ones()
}
}
/// Possible resolve modes for depth and stencil attachments.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum ResolveMode {
None = ash::vk::ResolveModeFlags::NONE.as_raw(),
SampleZero = ash::vk::ResolveModeFlags::SAMPLE_ZERO.as_raw(),
Average = ash::vk::ResolveModeFlags::AVERAGE.as_raw(),
Min = ash::vk::ResolveModeFlags::MIN.as_raw(),
Max = ash::vk::ResolveModeFlags::MAX.as_raw(),
}
#[derive(Clone, Copy, Debug)]
pub struct ResolveModes {
pub none: bool,
pub sample_zero: bool,
pub average: bool,
pub min: bool,
pub max: bool,
}
impl From<ash::vk::ResolveModeFlags> for ResolveModes {
#[inline]
fn from(val: ash::vk::ResolveModeFlags) -> Self {
Self {
none: val.intersects(ash::vk::ResolveModeFlags::NONE),
sample_zero: val.intersects(ash::vk::ResolveModeFlags::SAMPLE_ZERO),
average: val.intersects(ash::vk::ResolveModeFlags::AVERAGE),
min: val.intersects(ash::vk::ResolveModeFlags::MIN),
max: val.intersects(ash::vk::ResolveModeFlags::MAX),
}
}
}

View File

@ -280,11 +280,11 @@ where
// Checking the dimensions against the limits.
{
let limits = device.physical_device().limits();
let properties = device.physical_device().properties();
let limits = [
limits.max_framebuffer_width(),
limits.max_framebuffer_height(),
limits.max_framebuffer_layers(),
properties.max_framebuffer_width.unwrap(),
properties.max_framebuffer_height.unwrap(),
properties.max_framebuffer_layers.unwrap(),
];
if dimensions[0] > limits[0] || dimensions[1] > limits[1] || dimensions[2] > limits[2] {
return Err(FramebufferCreationError::DimensionsTooLarge);

View File

@ -30,11 +30,13 @@ pub use self::compat_atch::ensure_image_view_compatible;
pub use self::compat_atch::IncompatibleRenderPassAttachmentError;
pub use self::desc::AttachmentDesc;
pub use self::desc::LoadOp;
pub use self::desc::MultiviewDesc;
pub use self::desc::RenderPassDesc;
pub use self::desc::ResolveMode;
pub use self::desc::ResolveModes;
pub use self::desc::StoreOp;
pub use self::desc::SubpassDependencyDesc;
pub use self::desc::SubpassDesc;
pub use self::desc::MultiviewDesc;
pub use self::framebuffer::Framebuffer;
pub use self::framebuffer::FramebufferAbstract;
pub use self::framebuffer::FramebufferBuilder;

View File

@ -286,7 +286,11 @@ impl RenderPass {
for pass in description.subpasses() {
if pass.color_attachments.len() as u32
> device.physical_device().limits().max_color_attachments()
> device
.physical_device()
.properties()
.max_color_attachments
.unwrap()
{
return Err(RenderPassCreationError::ColorAttachmentsLimitExceeded);
}
@ -383,8 +387,8 @@ impl RenderPass {
debug_assert!(
device
.physical_device()
.extended_properties()
.max_multiview_view_count()
.properties()
.max_multiview_view_count
.unwrap_or(0)
>= multiview.used_layer_count()
);
@ -850,7 +854,13 @@ mod tests {
fn too_many_color_atch() {
let (device, _) = gfx_dev_and_queue!();
if device.physical_device().limits().max_color_attachments() >= 10 {
if device
.physical_device()
.properties()
.max_color_attachments
.unwrap()
>= 10
{
return; // test ignored
}

View File

@ -266,7 +266,11 @@ impl Sampler {
return Err(SamplerCreationError::SamplerAnisotropyFeatureNotEnabled);
}
let limit = device.physical_device().limits().max_sampler_anisotropy();
let limit = device
.physical_device()
.properties()
.max_sampler_anisotropy
.unwrap();
if max_anisotropy > limit {
return Err(SamplerCreationError::AnisotropyLimitExceeded {
requested: max_anisotropy,
@ -277,7 +281,11 @@ impl Sampler {
// Check mip_lod_bias value.
{
let limit = device.physical_device().limits().max_sampler_lod_bias();
let limit = device
.physical_device()
.properties()
.max_sampler_lod_bias
.unwrap();
if mip_lod_bias > limit {
return Err(SamplerCreationError::MipLodBiasLimitExceeded {
requested: mip_lod_bias,

View File

@ -903,7 +903,8 @@ impl<W> SwapchainBuilder<W> {
/// Sets the dimensions of the images.
///
/// The default is `None`, which means the value of [`Capabilities::current_extent`] will be
/// The default is `None`, which means the value of
/// [`Capabilities::current_extent`](crate::swapchain::Capabilities::current_extent) will be
/// used. Setting this will override it with a custom `Some` value.
#[inline]
pub fn dimensions(mut self, dimensions: [u32; 2]) -> Self {

View File

@ -13,7 +13,7 @@ use std::convert::TryFrom;
use std::fmt;
/// Represents an API version of Vulkan.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Version {
/// Major version number.
pub major: u32,