From 2a64cccec67a49b0e0882d4c031db3c6edf6ec5a Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 18 Jun 2023 09:37:38 +0200 Subject: [PATCH 1/6] Add `RequiresAllOf`, automatically enable required extensions and features --- vulkano/autogen/extensions.rs | 618 +++++++++++------ vulkano/autogen/formats.rs | 158 ++--- vulkano/src/acceleration_structure.rs | 81 ++- vulkano/src/buffer/mod.rs | 25 +- vulkano/src/buffer/sys.rs | 26 +- vulkano/src/buffer/usage.rs | 116 ++-- vulkano/src/command_buffer/auto/builder.rs | 30 +- .../commands/acceleration_structure.rs | 7 +- .../src/command_buffer/commands/bind_push.rs | 17 +- vulkano/src/command_buffer/commands/clear.rs | 10 +- vulkano/src/command_buffer/commands/debug.rs | 23 +- .../command_buffer/commands/dynamic_state.rs | 247 +++---- .../src/command_buffer/commands/pipeline.rs | 26 +- vulkano/src/command_buffer/commands/query.rs | 87 ++- .../command_buffer/commands/render_pass.rs | 28 +- .../src/command_buffer/commands/secondary.rs | 9 +- vulkano/src/command_buffer/pool.rs | 33 +- vulkano/src/deferred.rs | 9 +- vulkano/src/descriptor_set/layout.rs | 143 ++-- vulkano/src/descriptor_set/pool.rs | 12 +- vulkano/src/descriptor_set/update.rs | 30 +- vulkano/src/device/mod.rs | 314 ++++----- vulkano/src/device/physical.rs | 156 +++-- vulkano/src/device/queue.rs | 52 +- vulkano/src/format.rs | 286 +++++--- vulkano/src/image/aspect.rs | 48 +- vulkano/src/image/layout.rs | 149 ++-- vulkano/src/image/mod.rs | 139 ++-- vulkano/src/image/sys.rs | 58 +- vulkano/src/image/usage.rs | 84 ++- vulkano/src/image/view.rs | 33 +- vulkano/src/instance/debug.rs | 10 +- vulkano/src/instance/mod.rs | 51 +- vulkano/src/lib.rs | 136 ++-- vulkano/src/macros.rs | 232 ++++--- vulkano/src/memory/allocator/mod.rs | 11 +- vulkano/src/memory/device_memory.rs | 107 ++- vulkano/src/memory/mod.rs | 37 +- vulkano/src/pipeline/graphics/color_blend.rs | 322 +++++---- vulkano/src/pipeline/graphics/mod.rs | 475 ++++++------- .../src/pipeline/graphics/rasterization.rs | 7 +- vulkano/src/pipeline/layout.rs | 7 +- vulkano/src/pipeline/mod.rs | 634 +++++++++-------- vulkano/src/query.rs | 52 +- vulkano/src/render_pass/mod.rs | 130 ++-- vulkano/src/sampler/mod.rs | 140 ++-- vulkano/src/sampler/ycbcr.rs | 17 +- vulkano/src/shader/mod.rs | 89 ++- vulkano/src/swapchain/surface.rs | 270 ++++---- vulkano/src/swapchain/swapchain.rs | 22 +- vulkano/src/sync/event.rs | 7 +- vulkano/src/sync/fence.rs | 41 +- vulkano/src/sync/pipeline.rs | 645 +++++++++++------- vulkano/src/sync/semaphore.rs | 62 +- 54 files changed, 3491 insertions(+), 3067 deletions(-) diff --git a/vulkano/autogen/extensions.rs b/vulkano/autogen/extensions.rs index de014f5680..8f28d651d2 100644 --- a/vulkano/autogen/extensions.rs +++ b/vulkano/autogen/extensions.rs @@ -11,7 +11,7 @@ use super::{write_file, IndexMap, VkRegistryData}; use heck::ToSnakeCase; use proc_macro2::{Ident, Literal, TokenStream}; use quote::{format_ident, quote}; -use std::fmt::Write as _; +use std::{cmp::Ordering, fmt::Write as _}; use vk_parse::Extension; // This is not included in vk.xml, so it's added here manually @@ -42,29 +42,64 @@ struct ExtensionsMember { doc: String, raw: String, required_if_supported: bool, - requires: Vec, + requires_all_of: Vec, conflicts_device_extensions: Vec, status: Option, } #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct RequiresOneOf { - pub api_version: Option<(String, String)>, - pub device_extensions: Vec, - pub instance_extensions: Vec, + pub api_version: Option<(u32, u32)>, + pub device_extensions: Vec, + pub instance_extensions: Vec, } -#[derive(Clone, Debug)] -enum Replacement { - Core((String, String)), - DeviceExtension(Ident), - InstanceExtension(Ident), +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +pub struct RequiresAllOf(pub Vec); + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum Requires { + APIVersion(u32, u32), + DeviceExtension(String), + InstanceExtension(String), +} + +impl PartialOrd for Requires { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Requires { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + ( + Requires::APIVersion(self_major, self_minor), + Requires::APIVersion(other_major, other_minor), + ) => self_major + .cmp(other_major) + .then_with(|| self_minor.cmp(other_minor)) + .reverse(), + (Requires::DeviceExtension(self_ext), Requires::DeviceExtension(other_ext)) => { + self_ext.cmp(other_ext) + } + (Requires::InstanceExtension(self_ext), Requires::InstanceExtension(other_ext)) => { + self_ext.cmp(other_ext) + } + (Requires::APIVersion(_, _), Requires::DeviceExtension(_)) + | (Requires::APIVersion(_, _), Requires::InstanceExtension(_)) + | (Requires::DeviceExtension(_), Requires::InstanceExtension(_)) => Ordering::Less, + (Requires::DeviceExtension(_), Requires::APIVersion(_, _)) + | (Requires::InstanceExtension(_), Requires::APIVersion(_, _)) + | (Requires::InstanceExtension(_), Requires::DeviceExtension(_)) => Ordering::Greater, + } + } } #[derive(Clone, Debug)] enum ExtensionStatus { - Promoted(Replacement), - Deprecated(Option), + PromotedTo(Requires), + DeprecatedBy(Option), } fn write_device_extensions(vk_data: &VkRegistryData) { @@ -92,91 +127,178 @@ fn write_instance_extensions(vk_data: &VkRegistryData) { fn device_extensions_output(members: &[ExtensionsMember]) -> TokenStream { let common = extensions_common_output(format_ident!("DeviceExtensions"), members); - let check_requirements_items = - members - .iter() - .map(|ExtensionsMember { name, requires, .. }| { - let name_string = name.to_string(); - - let requires_items = requires.iter().map(|require| { - let require_items = require - .api_version - .iter() - .map(|version| { + let check_requirements_items = members.iter().map( + |ExtensionsMember { + name, + requires_all_of, + .. + }| { + let name_string = name.to_string(); + + let dependency_check_items = requires_all_of.iter().filter_map( + |RequiresOneOf { + api_version, + device_extensions: _, + instance_extensions, + }| { + (api_version.is_some() || !instance_extensions.is_empty()).then(|| { + let condition_items = (api_version.iter().map(|version| { let version = format_ident!("V{}_{}", version.0, version.1); quote! { api_version >= crate::Version::#version } - }) - .chain(require.instance_extensions.iter().map(|ext| { - quote! { instance_extensions.#ext } })) - .chain(require.device_extensions.iter().map(|ext| { - quote! { device_extensions.#ext } + .chain(instance_extensions.iter().map(|ext_name| { + let ident = format_ident!("{}", ext_name); + quote! { instance_extensions.#ident } })); - - let api_version_items = require - .api_version - .as_ref() - .map(|version| { - let version = format_ident!("V{}_{}", version.0, version.1); - quote! { Some(crate::Version::#version) } - }) - .unwrap_or_else(|| quote! { None }); - let device_extensions_items = - require.device_extensions.iter().map(|ext| ext.to_string()); - let instance_extensions_items = require - .instance_extensions - .iter() - .map(|ext| ext.to_string()); - - quote! { - if !(#(#require_items)||*) { - return Err(crate::ValidationError { - problem: format!("contains `{}`", #name_string).into(), - requires_one_of: crate::RequiresOneOf { - api_version: #api_version_items, - device_extensions: &[#(#device_extensions_items),*], - instance_extensions: &[#(#instance_extensions_items),*], + let requires_one_of_items = (api_version.iter().map(|(major, minor)| { + let version = format_ident!("V{}_{}", major, minor); + quote! { + crate::RequiresAllOf(&[ + crate::Requires::APIVersion(crate::Version::#version), + ]), + } + })) + .chain(instance_extensions.iter().map(|ext_name| { + quote! { + crate::RequiresAllOf(&[ + crate::Requires::InstanceExtension(#ext_name), + ]), + } + })); + let problem = format!("contains `{}`", name_string); + + quote! { + if !(#(#condition_items)||*) { + return Err(crate::ValidationError { + problem: #problem.into(), + requires_one_of: crate::RequiresOneOf(&[ + #(#requires_one_of_items)* + ]), ..Default::default() - }, - ..Default::default() - }); + }); + } } + }) + }, + ); + let problem = format!( + "contains `{}`, but this extension is not supported by the physical device", + name_string, + ); + + quote! { + if self.#name { + if !supported.#name { + return Err(crate::ValidationError { + problem: #problem.into(), + ..Default::default() + }); } - }); + + #(#dependency_check_items)* + } + } + }, + ); + + let enable_dependencies_items = members.iter().filter_map( + |ExtensionsMember { + name, + requires_all_of, + .. + }| { + (!requires_all_of.is_empty()).then(|| { + let requires_all_of_items = requires_all_of.iter().filter_map( + |RequiresOneOf { + api_version, + device_extensions, + instance_extensions: _, + }| { + (!device_extensions.is_empty()).then(|| { + let condition_items = api_version + .iter() + .map(|(major, minor)| { + let version = format_ident!("V{}_{}", major, minor); + quote! { api_version >= crate::Version::#version } + }) + .chain(device_extensions.iter().map(|ext_name| { + let ident = format_ident!("{}", ext_name); + quote! { self.#ident } + })); + + let (base_requirement, promoted_requirements) = + device_extensions.split_last().unwrap(); + + let base_requirement_item = { + let ident = format_ident!("{}", base_requirement); + quote! { + self.#ident = true; + } + }; + + if promoted_requirements.is_empty() { + quote! { + if !(#(#condition_items)||*) { + #base_requirement_item + } + } + } else { + let promoted_requirement_items = + promoted_requirements.iter().map(|name| { + let ident = format_ident!("{}", name); + quote! { + if supported.#ident { + self.#ident = true; + } + } + }); + + quote! { + if !(#(#condition_items)||*) { + #(#promoted_requirement_items)else* + else { + #base_requirement_item + } + } + } + } + }) + }, + ); quote! { if self.#name { - if !supported.#name { - return Err(crate::ValidationError { - problem: format!( - "contains `{}`, but this extension is not supported \ - by the physical device", - #name_string, - ).into(), - ..Default::default() - }); - } - - #(#requires_items)* + #(#requires_all_of_items)* } } - }); + }) + }, + ); quote! { #common impl DeviceExtensions { - /// Checks enabled extensions against the device version, instance extensions and each other. + /// Checks enabled extensions against the physical device support, + /// and checks for required API version and instance extensions. pub(super) fn check_requirements( &self, supported: &DeviceExtensions, api_version: crate::Version, instance_extensions: &crate::instance::InstanceExtensions, ) -> Result<(), crate::ValidationError> { - let device_extensions = self; #(#check_requirements_items)* Ok(()) } + + /// Enables all the extensions that the extensions in `self` currently depend on. + pub(super) fn enable_dependencies( + &mut self, + api_version: crate::Version, + supported: &DeviceExtensions + ) { + #(#enable_dependencies_items)* + } } } } @@ -184,91 +306,157 @@ fn device_extensions_output(members: &[ExtensionsMember]) -> TokenStream { fn instance_extensions_output(members: &[ExtensionsMember]) -> TokenStream { let common = extensions_common_output(format_ident!("InstanceExtensions"), members); - let check_requirements_items = - members - .iter() - .map(|ExtensionsMember { name, requires, .. }| { - let name_string = name.to_string(); - - let requires_items = requires.iter().map(|require| { - let require_items = require - .api_version - .iter() - .map(|version| { - let version = format_ident!("V{}_{}", version.0, version.1); - quote! { api_version >= crate::Version::#version } - }) - .chain(require.instance_extensions.iter().map(|ext| { - quote! { instance_extensions.#ext } - })) - .chain(require.device_extensions.iter().map(|ext| { - quote! { device_extensions.#ext } - })); - - let api_version_items = require - .api_version - .as_ref() - .map(|version| { - let version = format_ident!("V{}_{}", version.0, version.1); - quote! { Some(crate::Version::#version) } - }) - .unwrap_or_else(|| quote! { None }); - let device_extensions_items = - require.device_extensions.iter().map(|ext| ext.to_string()); - let instance_extensions_items = require - .instance_extensions - .iter() - .map(|ext| ext.to_string()); - - quote! { - if !(#(#require_items)||*) { - return Err(crate::ValidationError { - problem: format!("contains `{}`", #name_string).into(), - requires_one_of: crate::RequiresOneOf { - api_version: #api_version_items, - device_extensions: &[#(#device_extensions_items),*], - instance_extensions: &[#(#instance_extensions_items),*], + let check_requirements_items = members.iter().map( + |ExtensionsMember { + name, + requires_all_of, + .. + }| { + let name_string = name.to_string(); + + let dependency_check_items = requires_all_of.iter().filter_map( + |RequiresOneOf { + api_version, + device_extensions: _, + instance_extensions: _, + }| { + api_version.map(|(major, minor)| { + let version = format_ident!("V{}_{}", major, minor); + let problem = format!("contains `{}`", name_string); + + quote! { + if !(api_version >= crate::Version::#version) { + return Err(crate::ValidationError { + problem: #problem.into(), + requires_one_of: crate::RequiresOneOf(&[ + crate::RequiresAllOf(&[ + crate::Requires::APIVersion(crate::Version::#version), + ]), + ]), ..Default::default() - }, - ..Default::default() - }); + }); + } } + }) + }, + ); + let problem = format!( + "contains `{}`, but this extension is not supported by the library", + name_string, + ); + + quote! { + if self.#name { + if !supported.#name { + return Err(crate::ValidationError { + problem: #problem.into(), + ..Default::default() + }); } - }); + + #(#dependency_check_items)* + } + } + }, + ); + + let enable_dependencies_items = members.iter().filter_map( + |ExtensionsMember { + name, + requires_all_of, + .. + }| { + (!requires_all_of.is_empty()).then(|| { + let requires_all_of_items = requires_all_of.iter().filter_map( + |RequiresOneOf { + api_version, + device_extensions: _, + instance_extensions, + }| { + (!instance_extensions.is_empty()).then(|| { + let condition_items = api_version + .iter() + .map(|(major, minor)| { + let version = format_ident!("V{}_{}", major, minor); + quote! { api_version >= crate::Version::#version } + }) + .chain(instance_extensions.iter().map(|ext_name| { + let ident = format_ident!("{}", ext_name); + quote! { self.#ident } + })); + + let (base_requirement, promoted_requirements) = + instance_extensions.split_last().unwrap(); + + let base_requirement_item = { + let ident = format_ident!("{}", base_requirement); + quote! { + self.#ident = true; + } + }; + + if promoted_requirements.is_empty() { + quote! { + if !(#(#condition_items)||*) { + #base_requirement_item + } + } + } else { + let promoted_requirement_items = + promoted_requirements.iter().map(|name| { + let ident = format_ident!("{}", name); + quote! { + if supported.#ident { + self.#ident = true; + } + } + }); + + quote! { + if !(#(#condition_items)||*) { + #(#promoted_requirement_items)else* + else { + #base_requirement_item + } + } + } + } + }) + }, + ); quote! { if self.#name { - if !supported.#name { - return Err(crate::ValidationError { - problem: format!( - "contains `{}`, but this extension is not supported \ - by the library", - #name_string, - ) - .into(), - ..Default::default() - }); - } - - #(#requires_items)* + #(#requires_all_of_items)* } } - }); + }) + }, + ); quote! { #common impl InstanceExtensions { - /// Checks enabled extensions against the instance version and each other. + /// Checks enabled extensions against the library support, + /// and checks for required API version. pub(super) fn check_requirements( &self, supported: &InstanceExtensions, api_version: crate::Version, ) -> Result<(), crate::ValidationError> { - let instance_extensions = self; #(#check_requirements_items)* Ok(()) } + + /// Enables all the extensions that the extensions in `self` currently depend on. + pub(super) fn enable_dependencies( + &mut self, + #[allow(unused_variables)] api_version: crate::Version, + #[allow(unused_variables)]supported: &InstanceExtensions + ) { + #(#enable_dependencies_items)* + } } } } @@ -563,50 +751,54 @@ fn extensions_members(ty: &str, extensions: &IndexMap<&str, &Extension>) -> Vec< let raw = ext.name.to_owned(); let name = raw.strip_prefix("VK_").unwrap().to_snake_case(); - let mut requires = Vec::new(); - - if let Some(core) = ext.requires_core.as_ref() { - let (major, minor) = core.split_once('.').unwrap(); - requires.push(RequiresOneOf { - api_version: Some((major.to_owned(), minor.to_owned())), - ..Default::default() - }); - } + let requires_all_of = { + let mut requires_all_of = Vec::new(); - if let Some(req) = ext.requires.as_ref() { - requires.extend(req.split(',').map(|mut vk_name| { - let mut dependencies = RequiresOneOf::default(); + if let Some(core) = ext.requires_core.as_ref() { + let (major, minor) = core.split_once('.').unwrap(); + requires_all_of.push(RequiresOneOf { + api_version: Some((major.parse().unwrap(), minor.parse().unwrap())), + ..Default::default() + }); + } - loop { - if let Some(version) = vk_name.strip_prefix("VK_VERSION_") { - let (major, minor) = version.split_once('_').unwrap(); - dependencies.api_version = Some((major.to_owned(), minor.to_owned())); - break; - } else { - let ident = format_ident!( - "{}", - vk_name.strip_prefix("VK_").unwrap().to_snake_case() - ); - let extension = extensions[vk_name]; - - match extension.ext_type.as_deref() { - Some("device") => &mut dependencies.device_extensions, - Some("instance") => &mut dependencies.instance_extensions, - _ => unreachable!(), - } - .insert(0, ident); + if let Some(req) = ext.requires.as_ref() { + requires_all_of.extend(req.split(',').map(|mut vk_name| { + let mut requires_one_of = RequiresOneOf::default(); - if let Some(promotedto) = extension.promotedto.as_ref() { - vk_name = promotedto.as_str(); - } else { + loop { + if let Some(version) = vk_name.strip_prefix("VK_VERSION_") { + let (major, minor) = version.split_once('_').unwrap(); + requires_one_of.api_version = + Some((major.parse().unwrap(), minor.parse().unwrap())); break; + } else { + let ext_name = vk_name.strip_prefix("VK_").unwrap().to_snake_case(); + let extension = extensions[vk_name]; + + match extension.ext_type.as_deref() { + Some("device") => &mut requires_one_of.device_extensions, + Some("instance") => &mut requires_one_of.instance_extensions, + _ => unreachable!(), + } + .push(ext_name); + + if let Some(promotedto) = extension.promotedto.as_ref() { + vk_name = promotedto.as_str(); + } else { + break; + } } } - } - dependencies - })); - } + requires_one_of.device_extensions.reverse(); + requires_one_of.instance_extensions.reverse(); + requires_one_of + })); + } + + requires_all_of + }; let conflicts_extensions = conflicts_extensions(&ext.name); @@ -615,7 +807,7 @@ fn extensions_members(ty: &str, extensions: &IndexMap<&str, &Extension>) -> Vec< doc: String::new(), raw, required_if_supported: required_if_supported(ext.name.as_str()), - requires, + requires_all_of, conflicts_device_extensions: conflicts_extensions .iter() .filter(|&&vk_name| extensions[vk_name].ext_type.as_ref().unwrap() == "device") @@ -629,18 +821,18 @@ fn extensions_members(ty: &str, extensions: &IndexMap<&str, &Extension>) -> Vec< .and_then(|pr| { if let Some(version) = pr.strip_prefix("VK_VERSION_") { let (major, minor) = version.split_once('_').unwrap(); - Some(ExtensionStatus::Promoted(Replacement::Core(( - major.to_owned(), - minor.to_owned(), - )))) + Some(ExtensionStatus::PromotedTo(Requires::APIVersion( + major.parse().unwrap(), + minor.parse().unwrap(), + ))) } else { - let member = pr.strip_prefix("VK_").unwrap().to_snake_case(); + let ext_name = pr.strip_prefix("VK_").unwrap().to_snake_case(); match extensions[pr].ext_type.as_ref().unwrap().as_str() { - "device" => Some(ExtensionStatus::Promoted( - Replacement::DeviceExtension(format_ident!("{}", member)), + "device" => Some(ExtensionStatus::PromotedTo( + Requires::DeviceExtension(ext_name), )), - "instance" => Some(ExtensionStatus::Promoted( - Replacement::InstanceExtension(format_ident!("{}", member)), + "instance" => Some(ExtensionStatus::PromotedTo( + Requires::InstanceExtension(ext_name), )), _ => unreachable!(), } @@ -649,21 +841,21 @@ fn extensions_members(ty: &str, extensions: &IndexMap<&str, &Extension>) -> Vec< .or_else(|| { ext.deprecatedby.as_deref().and_then(|depr| { if depr.is_empty() { - Some(ExtensionStatus::Deprecated(None)) + Some(ExtensionStatus::DeprecatedBy(None)) } else if let Some(version) = depr.strip_prefix("VK_VERSION_") { let (major, minor) = version.split_once('_').unwrap(); - Some(ExtensionStatus::Deprecated(Some(Replacement::Core(( + Some(ExtensionStatus::DeprecatedBy(Some(Requires::APIVersion( major.parse().unwrap(), minor.parse().unwrap(), - ))))) + )))) } else { - let member = depr.strip_prefix("VK_").unwrap().to_snake_case(); + let ext_name = depr.strip_prefix("VK_").unwrap().to_snake_case(); match extensions[depr].ext_type.as_ref().unwrap().as_str() { - "device" => Some(ExtensionStatus::Deprecated(Some( - Replacement::DeviceExtension(format_ident!("{}", member)), + "device" => Some(ExtensionStatus::DeprecatedBy(Some( + Requires::DeviceExtension(ext_name), ))), - "instance" => Some(ExtensionStatus::Deprecated(Some( - Replacement::InstanceExtension(format_ident!("{}", member)), + "instance" => Some(ExtensionStatus::DeprecatedBy(Some( + Requires::InstanceExtension(ext_name), ))), _ => unreachable!(), } @@ -691,47 +883,51 @@ fn make_doc(ext: &mut ExtensionsMember) { if let Some(status) = ext.status.as_ref() { match status { - ExtensionStatus::Promoted(replacement) => { + ExtensionStatus::PromotedTo(replacement) => { write!(writer, "\n- Promoted to ",).unwrap(); match replacement { - Replacement::Core(version) => { - write!(writer, "Vulkan {}.{}", version.0, version.1).unwrap(); + Requires::APIVersion(major, minor) => { + write!(writer, "Vulkan {}.{}", major, minor).unwrap(); } - Replacement::DeviceExtension(ext) => { - write!(writer, "[`{}`](crate::device::DeviceExtensions::{0})", ext) - .unwrap(); + Requires::DeviceExtension(ext_name) => { + write!( + writer, + "[`{}`](crate::device::DeviceExtensions::{0})", + ext_name + ) + .unwrap(); } - Replacement::InstanceExtension(ext) => { + Requires::InstanceExtension(ext_name) => { write!( writer, "[`{}`](crate::instance::InstanceExtensions::{0})", - ext + ext_name ) .unwrap(); } } } - ExtensionStatus::Deprecated(replacement) => { + ExtensionStatus::DeprecatedBy(replacement) => { write!(writer, "\n- Deprecated ",).unwrap(); match replacement { - Some(Replacement::Core(version)) => { - write!(writer, "by Vulkan {}.{}", version.0, version.1).unwrap(); + Some(Requires::APIVersion(major, minor)) => { + write!(writer, "by Vulkan {}.{}", major, minor).unwrap(); } - Some(Replacement::DeviceExtension(ext)) => { + Some(Requires::DeviceExtension(ext_name)) => { write!( writer, "by [`{}`](crate::device::DeviceExtensions::{0})", - ext + ext_name ) .unwrap(); } - Some(Replacement::InstanceExtension(ext)) => { + Some(Requires::InstanceExtension(ext_name)) => { write!( writer, "by [`{}`](crate::instance::InstanceExtensions::{0})", - ext + ext_name ) .unwrap(); } @@ -743,11 +939,11 @@ fn make_doc(ext: &mut ExtensionsMember) { } } - if !ext.requires.is_empty() { - write!(writer, "\n- Requires:").unwrap(); + if !ext.requires_all_of.is_empty() { + write!(writer, "\n- Requires all of:").unwrap(); } - for require in &ext.requires { + for require in &ext.requires_all_of { let mut line = Vec::new(); if let Some((major, minor)) = require.api_version.as_ref() { @@ -767,11 +963,7 @@ fn make_doc(ext: &mut ExtensionsMember) { ) })); - if line.len() == 1 { - write!(writer, "\n - {}", line[0]).unwrap(); - } else { - write!(writer, "\n - One of: {}", line.join(", ")).unwrap(); - } + write!(writer, "\n - {}", line.join(" or ")).unwrap(); } if !ext.conflicts_device_extensions.is_empty() { diff --git a/vulkano/autogen/formats.rs b/vulkano/autogen/formats.rs index 3e1f399221..49532a8509 100644 --- a/vulkano/autogen/formats.rs +++ b/vulkano/autogen/formats.rs @@ -36,7 +36,7 @@ pub fn write(vk_data: &VkRegistryData) { struct FormatMember { name: Ident, ffi_name: Ident, - requires: Vec, + requires_all_of: Vec, aspect_color: bool, aspect_depth: bool, @@ -248,60 +248,13 @@ fn formats_output(members: &[FormatMember]) -> TokenStream { }, ); - let validate_device_items = members.iter().map(|FormatMember { name, requires, .. }| { - let requires_items = requires.iter().map( - |RequiresOneOf { - api_version, - device_extensions, - instance_extensions, - }| { - let condition_items = (api_version.iter().map(|(major, minor)| { - let version = format_ident!("V{}_{}", major, minor); - quote! { device.api_version() >= crate::Version::#version } - })) - .chain(device_extensions.iter().map(|ext| { - quote! { device.enabled_extensions().#ext } - })) - .chain(instance_extensions.iter().map(|ext| { - quote! { device.instance().enabled_extensions().#ext } - })); - let required_for = format!("`Format::{}`", name); - let requires_one_of_items = (api_version.iter().map(|(major, minor)| { - let version = format_ident!("V{}_{}", major, minor); - quote! { api_version: Some(crate::Version::#version), } - })) - .chain((!device_extensions.is_empty()).then(|| { - let items = device_extensions.iter().map(|ext| ext.to_string()); - quote! { device_extensions: &[#(#items),*], } - })) - .chain((!instance_extensions.is_empty()).then(|| { - let items = instance_extensions.iter().map(|ext| ext.to_string()); - quote! { instance_extensions: &[#(#items),*], } - })); - - quote! { - if !(#(#condition_items)||*) { - return Err(crate::RequirementNotMet { - required_for: #required_for, - requires_one_of: crate::RequiresOneOf { - #(#requires_one_of_items)* - ..Default::default() - }, - }); - } - } - }, - ); - - quote! { - Self::#name => { - #(#requires_items)* - } - } - }); - let validate_physical_device_items = - members.iter().map(|FormatMember { name, requires, .. }| { - let requires_items = requires.iter().map( + let validate_device_items = members.iter().map( + |FormatMember { + name, + requires_all_of, + .. + }| { + let requires_items = requires_all_of.iter().map( |RequiresOneOf { api_version, device_extensions, @@ -309,36 +262,47 @@ fn formats_output(members: &[FormatMember]) -> TokenStream { }| { let condition_items = (api_version.iter().map(|(major, minor)| { let version = format_ident!("V{}_{}", major, minor); - quote! { physical_device.api_version() >= crate::Version::#version } + quote! { device_api_version >= crate::Version::#version } })) - .chain(device_extensions.iter().map(|ext| { - quote! { physical_device.supported_extensions().#ext } + .chain(device_extensions.iter().map(|ext_name| { + let ident = format_ident!("{}", ext_name); + quote! { device_extensions.#ident } })) - .chain(instance_extensions.iter().map(|ext| { - quote! { physical_device.instance().enabled_extensions().#ext } + .chain(instance_extensions.iter().map(|ext_name| { + let ident = format_ident!("{}", ext_name); + quote! { instance_extensions.#ident } })); let required_for = format!("`Format::{}`", name); let requires_one_of_items = (api_version.iter().map(|(major, minor)| { let version = format_ident!("V{}_{}", major, minor); - quote! { api_version: Some(crate::Version::#version), } + quote! { + crate::RequiresAllOf(&[ + crate::Requires::APIVersion(crate::Version::#version), + ]), + } })) - .chain((!device_extensions.is_empty()).then(|| { - let items = device_extensions.iter().map(|ext| ext.to_string()); - quote! { device_extensions: &[#(#items),*], } + .chain(device_extensions.iter().map(|ext_name| { + quote! { + crate::RequiresAllOf(&[ + crate::Requires::DeviceExtension(#ext_name), + ]), + } })) - .chain((!instance_extensions.is_empty()).then(|| { - let items = instance_extensions.iter().map(|ext| ext.to_string()); - quote! { instance_extensions: &[#(#items),*], } + .chain(instance_extensions.iter().map(|ext_name| { + quote! { + crate::RequiresAllOf(&[ + crate::Requires::InstanceExtension(#ext_name), + ]), + } })); quote! { if !(#(#condition_items)||*) { return Err(crate::RequirementNotMet { required_for: #required_for, - requires_one_of: crate::RequiresOneOf { + requires_one_of: crate::RequiresOneOf(&[ #(#requires_one_of_items)* - ..Default::default() - }, + ]), }); } } @@ -350,7 +314,8 @@ fn formats_output(members: &[FormatMember]) -> TokenStream { #(#requires_items)* } } - }); + }, + ); quote! { /// An enumeration of all the possible formats. @@ -502,20 +467,37 @@ fn formats_output(members: &[FormatMember]) -> TokenStream { self, #[allow(unused_variables)] device: &crate::device::Device, ) -> Result<(), crate::RequirementNotMet> { - match self { - #(#validate_device_items)* - } - - Ok(()) + self.validate_device_raw( + device.api_version(), + device.enabled_features(), + device.enabled_extensions(), + device.instance().enabled_extensions(), + ) } #[allow(dead_code)] pub(crate) fn validate_physical_device( self, #[allow(unused_variables)] physical_device: &crate::device::physical::PhysicalDevice, + ) -> Result<(), crate::RequirementNotMet> { + self.validate_device_raw( + physical_device.api_version(), + physical_device.supported_features(), + physical_device.supported_extensions(), + physical_device.instance().enabled_extensions(), + ) + } + + #[allow(dead_code)] + pub(crate) fn validate_device_raw( + self, + #[allow(unused_variables)] device_api_version: crate::Version, + #[allow(unused_variables)] device_features: &crate::device::Features, + #[allow(unused_variables)] device_extensions: &crate::device::DeviceExtensions, + #[allow(unused_variables)] instance_extensions: &crate::instance::InstanceExtensions, ) -> Result<(), crate::RequirementNotMet> { match self { - #(#validate_physical_device_items)* + #(#validate_device_items)* } Ok(()) @@ -611,7 +593,7 @@ fn formats_members( let mut member = FormatMember { name, ffi_name, - requires: Vec::new(), + requires_all_of: Vec::new(), aspect_color: false, aspect_depth: false, @@ -821,10 +803,10 @@ fn formats_members( if let Some(version) = feature.name.strip_prefix("VK_VERSION_") { let (major, minor) = version.split_once('_').unwrap(); - member.requires.push(RequiresOneOf { + member.requires_all_of.push(RequiresOneOf { api_version: Some(( - major.to_string(), - minor.to_string(), + major.parse().unwrap(), + minor.parse().unwrap(), )), ..Default::default() }); @@ -859,22 +841,22 @@ fn formats_members( let extension_name = extension.name.strip_prefix("VK_").unwrap().to_snake_case(); - if member.requires.is_empty() { - member.requires.push(Default::default()); + if member.requires_all_of.is_empty() { + member.requires_all_of.push(Default::default()); }; - let requires = member.requires.first_mut().unwrap(); + let requires_one_of = member.requires_all_of.first_mut().unwrap(); match extension.ext_type.as_deref() { Some("device") => { - requires + requires_one_of .device_extensions - .push(format_ident!("{}", extension_name)); + .push(extension_name); } Some("instance") => { - requires + requires_one_of .instance_extensions - .push(format_ident!("{}", extension_name)); + .push(extension_name); } _ => (), } diff --git a/vulkano/src/acceleration_structure.rs b/vulkano/src/acceleration_structure.rs index 27eb294431..52286c576a 100644 --- a/vulkano/src/acceleration_structure.rs +++ b/vulkano/src/acceleration_structure.rs @@ -96,8 +96,8 @@ use crate::{ device::{Device, DeviceOwned}, format::{Format, FormatFeatures}, macros::{impl_id_counter, vulkan_bitflags, vulkan_enum}, - DeviceSize, NonZeroDeviceSize, Packed24_8, RequiresOneOf, RuntimeError, ValidationError, - VulkanError, VulkanObject, + DeviceSize, NonZeroDeviceSize, Packed24_8, Requires, RequiresAllOf, RequiresOneOf, + RuntimeError, ValidationError, VulkanError, VulkanObject, }; use bytemuck::{Pod, Zeroable}; use std::{fmt::Debug, hash::Hash, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc}; @@ -141,20 +141,18 @@ impl AccelerationStructure { ) -> Result<(), ValidationError> { if !device.enabled_extensions().khr_acceleration_structure { return Err(ValidationError { - requires_one_of: RequiresOneOf { - device_extensions: &["khr_acceleration_structure"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_acceleration_structure", + )])]), ..Default::default() }); } if !device.enabled_features().acceleration_structure { return Err(ValidationError { - requires_one_of: RequiresOneOf { - features: &["acceleration_structure"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "acceleration_structure", + )])]), vuids: &["VUID-vkCreateAccelerationStructureKHR-accelerationStructure-03611"], ..Default::default() }); @@ -436,15 +434,17 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - DESCRIPTOR_BUFFER_CAPTURE_REPLAY = DESCRIPTOR_BUFFER_CAPTURE_REPLAY_EXT { - device_extensions: [ext_descriptor_buffer], - },*/ + DESCRIPTOR_BUFFER_CAPTURE_REPLAY = DESCRIPTOR_BUFFER_CAPTURE_REPLAY_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_descriptor_buffer)]), + ]),*/ /* TODO: enable // TODO: document - MOTION = MOTION_NV { - device_extensions: [nv_ray_tracing_motion_blur], - },*/ + MOTION = MOTION_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_ray_tracing_motion_blur)]), + ]),*/ } /// Geometries and other parameters for an acceleration structure build operation. @@ -805,33 +805,38 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - MOTION = MOTION_NV { - device_extensions: [nv_ray_tracing_motion_blur], - }, */ + MOTION = MOTION_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_ray_tracing_motion_blur)]), + ]), */ /* TODO: enable // TODO: document - ALLOW_OPACITY_MICROMAP_UPDATE = ALLOW_OPACITY_MICROMAP_UPDATE_EXT { - device_extensions: [ext_opacity_micromap], - }, */ + ALLOW_OPACITY_MICROMAP_UPDATE = ALLOW_OPACITY_MICROMAP_UPDATE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_opacity_micromap)]), + ]), */ /* TODO: enable // TODO: document - ALLOW_DISABLE_OPACITY_MICROMAPS = ALLOW_DISABLE_OPACITY_MICROMAPS_EXT { - device_extensions: [ext_opacity_micromap], - }, */ + ALLOW_DISABLE_OPACITY_MICROMAPS = ALLOW_DISABLE_OPACITY_MICROMAPS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_opacity_micromap)]), + ]), */ /* TODO: enable // TODO: document - ALLOW_OPACITY_MICROMAP_DATA_UPDATE = ALLOW_OPACITY_MICROMAP_DATA_UPDATE_EXT { - device_extensions: [ext_opacity_micromap], - }, */ + ALLOW_OPACITY_MICROMAP_DATA_UPDATE = ALLOW_OPACITY_MICROMAP_DATA_UPDATE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_opacity_micromap)]), + ]), */ /* TODO: enable // TODO: document - ALLOW_DISPLACEMENT_MICROMAP_UPDATE = ALLOW_DISPLACEMENT_MICROMAP_UPDATE_NV { - device_extensions: [nv_displacement_micromap], - }, */ + ALLOW_DISPLACEMENT_MICROMAP_UPDATE = ALLOW_DISPLACEMENT_MICROMAP_UPDATE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_displacement_micromap)]), + ]), */ } /// What mode an acceleration structure build command should operate in. @@ -1300,15 +1305,17 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - FORCE_OPACITY_MICROMAP_2_STATE = FORCE_OPACITY_MICROMAP_2_STATE_EXT { - device_extensions: [ext_opacity_micromap], - }, */ + FORCE_OPACITY_MICROMAP_2_STATE = FORCE_OPACITY_MICROMAP_2_STATE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_opacity_micromap)]), + ]), */ /* TODO: enable // TODO: document - DISABLE_OPACITY_MICROMAPS = DISABLE_OPACITY_MICROMAPS_EXT { - device_extensions: [ext_opacity_micromap], - }, */ + DISABLE_OPACITY_MICROMAPS = DISABLE_OPACITY_MICROMAPS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_opacity_micromap)]), + ]), */ } impl From for u8 { diff --git a/vulkano/src/buffer/mod.rs b/vulkano/src/buffer/mod.rs index b5a2da1b09..42ecf7ec34 100644 --- a/vulkano/src/buffer/mod.rs +++ b/vulkano/src/buffer/mod.rs @@ -123,8 +123,8 @@ use crate::{ }, range_map::RangeMap, sync::{future::AccessError, CurrentAccess, Sharing}, - DeviceSize, NonZeroDeviceSize, RequirementNotMet, RequiresOneOf, RuntimeError, ValidationError, - Version, VulkanObject, + DeviceSize, NonZeroDeviceSize, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, + RuntimeError, ValidationError, Version, VulkanObject, }; use parking_lot::{Mutex, MutexGuard}; use smallvec::SmallVec; @@ -506,10 +506,9 @@ impl Buffer { if !device.enabled_features().buffer_device_address { return Err(BufferError::RequirementNotMet { required_for: "`Buffer::device_address`", - requires_one_of: RequiresOneOf { - features: &["buffer_device_address"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "buffer_device_address", + )])]), }); } @@ -1072,9 +1071,10 @@ vulkan_bitflags! { /// protected objects. /// /// The device API version must be at least 1.1. - PROTECTED = PROTECTED { - api_version: V1_1, - },*/ + PROTECTED = PROTECTED + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + ]),*/ /* TODO: enable /// The buffer's device address can be saved and reused on a subsequent run. @@ -1167,9 +1167,10 @@ vulkan_enum! { IndexType = IndexType(i32); /// Indices are 8-bit unsigned integers. - U8 = UINT8_EXT { - device_extensions: [ext_index_type_uint8], - }, + U8 = UINT8_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_index_type_uint8)]), + ]), /// Indices are 16-bit unsigned integers. U16 = UINT16, diff --git a/vulkano/src/buffer/sys.rs b/vulkano/src/buffer/sys.rs index f4bb28b4f6..f2f634986e 100644 --- a/vulkano/src/buffer/sys.rs +++ b/vulkano/src/buffer/sys.rs @@ -23,7 +23,7 @@ use crate::{ MemoryPropertyFlags, MemoryRequirements, }, sync::Sharing, - DeviceSize, RequiresOneOf, RuntimeError, Version, VulkanObject, + DeviceSize, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, Version, VulkanObject, }; use smallvec::SmallVec; use std::{mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc}; @@ -104,10 +104,7 @@ impl RawBuffer { if !device.enabled_features().sparse_binding { return Err(BufferError::RequirementNotMet { required_for: "`create_info.sparse` is `Some`", - requires_one_of: RequiresOneOf { - features: &["sparse_binding"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("sparse_binding")])]), }); } @@ -116,10 +113,7 @@ impl RawBuffer { return Err(BufferError::RequirementNotMet { required_for: "`create_info.sparse` is `Some(sparse_level)`, where \ `sparse_level` contains `BufferCreateFlags::SPARSE_RESIDENCY`", - requires_one_of: RequiresOneOf { - features: &["sparse_residency_buffer"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("sparse_residency_buffer")])]), }); } @@ -128,10 +122,7 @@ impl RawBuffer { return Err(BufferError::RequirementNotMet { required_for: "`create_info.sparse` is `Some(sparse_level)`, where \ `sparse_level` contains `BufferCreateFlags::SPARSE_ALIASED`", - requires_one_of: RequiresOneOf { - features: &["sparse_residency_aliased"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("sparse_residency_aliased")])]), }); } @@ -178,11 +169,10 @@ impl RawBuffer { { return Err(BufferError::RequirementNotMet { required_for: "`create_info.external_memory_handle_types` is not empty", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_external_memory"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_external_memory")]), + ]), }); } diff --git a/vulkano/src/buffer/usage.rs b/vulkano/src/buffer/usage.rs index cfddcd27b6..083d2afba5 100644 --- a/vulkano/src/buffer/usage.rs +++ b/vulkano/src/buffer/usage.rs @@ -52,96 +52,114 @@ vulkan_bitflags! { /// /// [`MemoryAllocateFlags::DEVICE_ADDRESS`]: crate::memory::MemoryAllocateFlags::DEVICE_ADDRESS /// [`ext_buffer_device_address`]: crate::device::DeviceExtensions::ext_buffer_device_address - SHADER_DEVICE_ADDRESS = SHADER_DEVICE_ADDRESS { - api_version: V1_2, - device_extensions: [khr_buffer_device_address, ext_buffer_device_address], - }, + SHADER_DEVICE_ADDRESS = SHADER_DEVICE_ADDRESS + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(khr_buffer_device_address)]), + RequiresAllOf([DeviceExtension(ext_buffer_device_address)]), + ]), /* TODO: enable // TODO: document - VIDEO_DECODE_SRC = VIDEO_DECODE_SRC_KHR { - device_extensions: [khr_video_decode_queue], - },*/ + VIDEO_DECODE_SRC = VIDEO_DECODE_SRC_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]),*/ /* TODO: enable // TODO: document - VIDEO_DECODE_DST = VIDEO_DECODE_DST_KHR { - device_extensions: [khr_video_decode_queue], - },*/ + VIDEO_DECODE_DST = VIDEO_DECODE_DST_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]),*/ /* TODO: enable // TODO: document - TRANSFORM_FEEDBACK_BUFFER = TRANSFORM_FEEDBACK_BUFFER_EXT { - device_extensions: [ext_transform_feedback], - },*/ + TRANSFORM_FEEDBACK_BUFFER = TRANSFORM_FEEDBACK_BUFFER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_transform_feedback)]), + ]),*/ /* TODO: enable // TODO: document - TRANSFORM_FEEDBACK_COUNTER_BUFFER = TRANSFORM_FEEDBACK_COUNTER_BUFFER_EXT { - device_extensions: [ext_transform_feedback], - },*/ + TRANSFORM_FEEDBACK_COUNTER_BUFFER = TRANSFORM_FEEDBACK_COUNTER_BUFFER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_transform_feedback)]), + ]),*/ /* TODO: enable // TODO: document - CONDITIONAL_RENDERING = CONDITIONAL_RENDERING_EXT { - device_extensions: [ext_conditional_rendering], - },*/ + CONDITIONAL_RENDERING = CONDITIONAL_RENDERING_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_conditional_rendering)]), + ]),*/ /// The buffer can be used as input data for an acceleration structure build operation. - ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY = ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR { - device_extensions: [khr_acceleration_structure], - }, + ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY = ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_acceleration_structure)]), + ]), /// An acceleration structure can be created from the buffer. - ACCELERATION_STRUCTURE_STORAGE = ACCELERATION_STRUCTURE_STORAGE_KHR { - device_extensions: [khr_acceleration_structure], - }, + ACCELERATION_STRUCTURE_STORAGE = ACCELERATION_STRUCTURE_STORAGE_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_acceleration_structure)]), + ]), /* TODO: enable // TODO: document - SHADER_BINDING_TABLE = SHADER_BINDING_TABLE_KHR { - device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing], - },*/ + SHADER_BINDING_TABLE = SHADER_BINDING_TABLE_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]),*/ /* TODO: enable // TODO: document - VIDEO_ENCODE_DST = VIDEO_ENCODE_DST_KHR { - device_extensions: [khr_video_encode_queue], - },*/ + VIDEO_ENCODE_DST = VIDEO_ENCODE_DST_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]),*/ /* TODO: enable // TODO: document - VIDEO_ENCODE_SRC = VIDEO_ENCODE_SRC_KHR { - device_extensions: [khr_video_encode_queue], - },*/ + VIDEO_ENCODE_SRC = VIDEO_ENCODE_SRC_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]),*/ /* TODO: enable // TODO: document - SAMPLER_DESCRIPTOR_BUFFER = SAMPLER_DESCRIPTOR_BUFFER_EXT { - device_extensions: [ext_descriptor_buffer], - },*/ + SAMPLER_DESCRIPTOR_BUFFER = SAMPLER_DESCRIPTOR_BUFFER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_descriptor_buffer)]), + ]),*/ /* TODO: enable // TODO: document - RESOURCE_DESCRIPTOR_BUFFER = RESOURCE_DESCRIPTOR_BUFFER_EXT { - device_extensions: [ext_descriptor_buffer], - },*/ + RESOURCE_DESCRIPTOR_BUFFER = RESOURCE_DESCRIPTOR_BUFFER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_descriptor_buffer)]), + ]),*/ /* TODO: enable // TODO: document - PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER = PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_EXT { - device_extensions: [ext_descriptor_buffer], - },*/ + PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER = PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_descriptor_buffer)]), + ]),*/ /* TODO: enable // TODO: document - MICROMAP_BUILD_INPUT_READ_ONLY = MICROMAP_BUILD_INPUT_READ_ONLY_EXT { - device_extensions: [ext_opacity_micromap], - },*/ + MICROMAP_BUILD_INPUT_READ_ONLY = MICROMAP_BUILD_INPUT_READ_ONLY_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_opacity_micromap)]), + ]),*/ /* TODO: enable // TODO: document - MICROMAP_STORAGE = MICROMAP_STORAGE_EXT { - device_extensions: [ext_opacity_micromap], - },*/ + MICROMAP_STORAGE = MICROMAP_STORAGE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_opacity_micromap)]), + ]),*/ } diff --git a/vulkano/src/command_buffer/auto/builder.rs b/vulkano/src/command_buffer/auto/builder.rs index c9727aa50f..bfe35935c8 100644 --- a/vulkano/src/command_buffer/auto/builder.rs +++ b/vulkano/src/command_buffer/auto/builder.rs @@ -50,7 +50,7 @@ use crate::{ AccessFlags, BufferMemoryBarrier, DependencyInfo, ImageMemoryBarrier, PipelineStageAccessFlags, PipelineStages, }, - DeviceSize, OomError, RequirementNotMet, RequiresOneOf, + DeviceSize, OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, }; use ahash::HashMap; use parking_lot::Mutex; @@ -274,10 +274,9 @@ where required_for: "`inheritance_info.render_pass` is \ `CommandBufferInheritanceRenderPassType::BeginRendering`, \ where `view_mask` is not `0`", - requires_one_of: RequiresOneOf { - features: &["multiview"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("multiview"), + ])]), }); } @@ -387,10 +386,9 @@ where if !device.enabled_features().inherited_queries { return Err(CommandBufferBeginError::RequirementNotMet { required_for: "`inheritance_info.occlusion_query` is `Some`", - requires_one_of: RequiresOneOf { - features: &["inherited_queries"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "inherited_queries", + )])]), }); } @@ -402,10 +400,9 @@ where required_for: "`inheritance_info.occlusion_query` is \ `Some(control_flags)`, where `control_flags` contains \ `QueryControlFlags::PRECISE`", - requires_one_of: RequiresOneOf { - features: &["occlusion_query_precise"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "occlusion_query_precise", + )])]), }); } } @@ -419,10 +416,9 @@ where { return Err(CommandBufferBeginError::RequirementNotMet { required_for: "`inheritance_info.query_statistics_flags` is not empty", - requires_one_of: RequiresOneOf { - features: &["pipeline_statistics_query"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "pipeline_statistics_query", + )])]), }); } } else { diff --git a/vulkano/src/command_buffer/commands/acceleration_structure.rs b/vulkano/src/command_buffer/commands/acceleration_structure.rs index 387e915e4b..c7f751c6c0 100644 --- a/vulkano/src/command_buffer/commands/acceleration_structure.rs +++ b/vulkano/src/command_buffer/commands/acceleration_structure.rs @@ -28,7 +28,7 @@ use crate::{ device::{DeviceOwned, QueueFlags}, query::{QueryPool, QueryType}, sync::PipelineStageAccessFlags, - DeviceSize, RequiresOneOf, ValidationError, VulkanObject, + DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError, VulkanObject, }; use smallvec::SmallVec; use std::{mem::size_of, sync::Arc}; @@ -894,10 +894,7 @@ where .acceleration_structure_indirect_build { return Err(ValidationError { - requires_one_of: RequiresOneOf { - features: &["acceleration_structure_indirect_build"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("acceleration_structure_indirect_build")])]), vuids: &["VUID-vkCmdBuildAccelerationStructuresIndirectKHR-accelerationStructureIndirectBuild-03650"], ..Default::default() }); diff --git a/vulkano/src/command_buffer/commands/bind_push.rs b/vulkano/src/command_buffer/commands/bind_push.rs index b3efba72e5..2e6061c969 100644 --- a/vulkano/src/command_buffer/commands/bind_push.rs +++ b/vulkano/src/command_buffer/commands/bind_push.rs @@ -27,7 +27,8 @@ use crate::{ graphics::{subpass::PipelineSubpassType, vertex_input::VertexBuffersCollection}, ComputePipeline, GraphicsPipeline, PipelineBindPoint, PipelineLayout, }, - DeviceSize, RequirementNotMet, RequiresOneOf, ValidationError, VulkanObject, + DeviceSize, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, ValidationError, + VulkanObject, }; use smallvec::SmallVec; use std::{ @@ -317,10 +318,9 @@ where { return Err(BindPushError::RequirementNotMet { required_for: "`index_buffer` is `IndexBuffer::U8`", - requires_one_of: RequiresOneOf { - features: &["index_type_uint8"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "index_type_uint8", + )])]), }); } @@ -769,10 +769,9 @@ where ) -> Result<(), ValidationError> { if !self.device().enabled_extensions().khr_push_descriptor { return Err(ValidationError { - requires_one_of: RequiresOneOf { - device_extensions: &["khr_push_descriptor"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_push_descriptor", + )])]), ..Default::default() }); } diff --git a/vulkano/src/command_buffer/commands/clear.rs b/vulkano/src/command_buffer/commands/clear.rs index a14f00fcae..46180a6fcd 100644 --- a/vulkano/src/command_buffer/commands/clear.rs +++ b/vulkano/src/command_buffer/commands/clear.rs @@ -17,7 +17,8 @@ use crate::{ format::{ClearColorValue, ClearDepthStencilValue, Format, FormatFeatures}, image::{ImageAccess, ImageAspects, ImageLayout, ImageSubresourceRange, ImageUsage}, sync::PipelineStageAccessFlags, - DeviceSize, RequirementNotMet, RequiresOneOf, SafeDeref, Version, VulkanObject, + DeviceSize, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, SafeDeref, Version, + VulkanObject, }; use smallvec::{smallvec, SmallVec}; use std::{ @@ -301,10 +302,9 @@ where return Err(ClearError::RequirementNotMet { required_for: "`clear_info.clear_value.depth` is not between `0.0` and `1.0` \ inclusive", - requires_one_of: RequiresOneOf { - device_extensions: &["ext_depth_range_unrestricted"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_depth_range_unrestricted", + )])]), }); } diff --git a/vulkano/src/command_buffer/commands/debug.rs b/vulkano/src/command_buffer/commands/debug.rs index 3a2c3975a6..8c2c4593ef 100644 --- a/vulkano/src/command_buffer/commands/debug.rs +++ b/vulkano/src/command_buffer/commands/debug.rs @@ -14,7 +14,7 @@ use crate::{ }, device::{DeviceOwned, QueueFlags}, instance::debug::DebugUtilsLabel, - RequiresOneOf, VulkanObject, + Requires, RequiresAllOf, RequiresOneOf, VulkanObject, }; use std::{ error::Error, @@ -57,10 +57,9 @@ where { return Err(DebugUtilsError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::begin_debug_utils_label`", - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_debug_utils"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ext_debug_utils", + )])]), }); } @@ -117,10 +116,9 @@ where { return Err(DebugUtilsError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::end_debug_utils_label`", - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_debug_utils"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ext_debug_utils", + )])]), }); } @@ -182,10 +180,9 @@ where { return Err(DebugUtilsError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::insert_debug_utils_label`", - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_debug_utils"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ext_debug_utils", + )])]), }); } diff --git a/vulkano/src/command_buffer/commands/dynamic_state.rs b/vulkano/src/command_buffer/commands/dynamic_state.rs index 508946ed3d..5e3b306ed6 100644 --- a/vulkano/src/command_buffer/commands/dynamic_state.rs +++ b/vulkano/src/command_buffer/commands/dynamic_state.rs @@ -23,7 +23,7 @@ use crate::{ }, DynamicState, }, - RequirementNotMet, RequiresOneOf, Version, VulkanObject, + RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, Version, VulkanObject, }; use smallvec::SmallVec; use std::{ @@ -149,10 +149,9 @@ where if !self.device().enabled_features().color_write_enable { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_color_write_enable`", - requires_one_of: RequiresOneOf { - device_extensions: &["ext_color_write_enable"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_color_write_enable", + )])]), }); } @@ -235,11 +234,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_cull_mode`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -306,10 +304,9 @@ where if clamp != 0.0 && !self.device().enabled_features().depth_bias_clamp { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`clamp` is not `0.0`", - requires_one_of: RequiresOneOf { - features: &["depth_bias_clamp"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "depth_bias_clamp", + )])]), }); } @@ -377,11 +374,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_depth_bias_enable`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state2")]), + ]), }); } @@ -448,10 +444,9 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`bounds` is not between `0.0` and `1.0` inclusive", - requires_one_of: RequiresOneOf { - device_extensions: &["ext_depth_range_unrestricted"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_depth_range_unrestricted", + )])]), }); } @@ -513,11 +508,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_depth_bounds_test_enable`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -582,11 +576,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_depth_compare_op`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -645,11 +638,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_depth_test_enable`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -708,11 +700,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_depth_write_enable`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -780,10 +771,9 @@ where if self.device().enabled_extensions().ext_discard_rectangles { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_discard_rectangle`", - requires_one_of: RequiresOneOf { - device_extensions: &["ext_discard_rectangles"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_discard_rectangles", + )])]), }); } @@ -873,11 +863,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_front_face`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -937,10 +926,9 @@ where if !self.device().enabled_extensions().ext_line_rasterization { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_line_stipple`", - requires_one_of: RequiresOneOf { - device_extensions: &["ext_line_rasterization"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_line_rasterization", + )])]), }); } @@ -1001,10 +989,9 @@ where if !self.device().enabled_features().wide_lines && line_width != 1.0 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`line_width` is not `1.0`", - requires_one_of: RequiresOneOf { - features: &["wide_lines"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "wide_lines", + )])]), }); } @@ -1068,10 +1055,9 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_logic_op`", - requires_one_of: RequiresOneOf { - features: &["extended_dynamic_state2_logic_op"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "extended_dynamic_state2_logic_op", + )])]), }); } @@ -1136,10 +1122,9 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_patch_control_points`", - requires_one_of: RequiresOneOf { - features: &["extended_dynamic_state2_patch_control_points"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "extended_dynamic_state2_patch_control_points", + )])]), }); } @@ -1222,11 +1207,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_primitive_restart_enable`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state2")]), + ]), }); } @@ -1295,11 +1279,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_primitive_topology`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -1314,10 +1297,9 @@ where return Err(SetDynamicStateError::RequirementNotMet { required_for: "this device is a portability subset device, and `topology` \ is `PrimitiveTopology::TriangleFan`", - requires_one_of: RequiresOneOf { - features: &["triangle_fans"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "triangle_fans", + )])]), }); } } @@ -1328,10 +1310,9 @@ where if !self.device().enabled_features().geometry_shader { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`topology` is `PrimitiveTopology::*WithAdjacency`", - requires_one_of: RequiresOneOf { - features: &["geometry_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "geometry_shader", + )])]), }); } } @@ -1339,10 +1320,9 @@ where if !self.device().enabled_features().tessellation_shader { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`topology` is `PrimitiveTopology::PatchList`", - requires_one_of: RequiresOneOf { - features: &["tessellation_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "tessellation_shader", + )])]), }); } } @@ -1410,11 +1390,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_rasterizer_discard_enable`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state2")]), + ]), }); } @@ -1491,10 +1470,9 @@ where if first_scissor != 0 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`first_scissor` is not `0`", - requires_one_of: RequiresOneOf { - features: &["multi_viewport"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multi_viewport", + )])]), }); } @@ -1502,10 +1480,9 @@ where if scissors.len() > 1 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`scissors.len()` is greater than `1`", - requires_one_of: RequiresOneOf { - features: &["multi_viewport"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multi_viewport", + )])]), }); } } @@ -1582,11 +1559,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_scissor_with_count`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -1602,10 +1578,9 @@ where if !self.device().enabled_features().multi_viewport && scissors.len() > 1 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`scissors.len()` is greater than `1`", - requires_one_of: RequiresOneOf { - features: &["multi_viewport"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multi_viewport", + )])]), }); } @@ -1768,11 +1743,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_stencil_op`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -1924,11 +1898,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_stencil_test_enable`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -2073,10 +2046,9 @@ where if first_viewport != 0 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`first_scissors` is not `0`", - requires_one_of: RequiresOneOf { - features: &["multi_viewport"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multi_viewport", + )])]), }); } @@ -2084,10 +2056,9 @@ where if viewports.len() > 1 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`viewports.len()` is greater than `1`", - requires_one_of: RequiresOneOf { - features: &["multi_viewport"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multi_viewport", + )])]), }); } } @@ -2162,11 +2133,10 @@ where { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::set_viewport_with_count`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -2182,10 +2152,9 @@ where if !self.device().enabled_features().multi_viewport && viewports.len() > 1 { return Err(SetDynamicStateError::RequirementNotMet { required_for: "`viewports.len()` is greater than `1`", - requires_one_of: RequiresOneOf { - features: &["multi_viewport"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multi_viewport", + )])]), }); } diff --git a/vulkano/src/command_buffer/commands/pipeline.rs b/vulkano/src/command_buffer/commands/pipeline.rs index 2d7adc7d85..aeacbed0e9 100644 --- a/vulkano/src/command_buffer/commands/pipeline.rs +++ b/vulkano/src/command_buffer/commands/pipeline.rs @@ -37,7 +37,7 @@ use crate::{ sampler::Sampler, shader::{DescriptorBindingRequirements, ShaderScalarType, ShaderStage, ShaderStages}, sync::{PipelineStageAccess, PipelineStageAccessFlags}, - DeviceSize, RequiresOneOf, ValidationError, VulkanObject, + DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError, VulkanObject, }; use std::{ cmp::min, @@ -382,10 +382,9 @@ where if draw_count > 1 && !self.device().enabled_features().multi_draw_indirect { return Err(PipelineExecutionError::RequirementNotMet { required_for: "`draw_count` is greater than `1`", - requires_one_of: RequiresOneOf { - features: &["multi_draw_indirect"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multi_draw_indirect", + )])]), }); } @@ -642,10 +641,9 @@ where if draw_count > 1 && !self.device().enabled_features().multi_draw_indirect { return Err(PipelineExecutionError::RequirementNotMet { required_for: "`draw_count` is greater than `1`", - requires_one_of: RequiresOneOf { - features: &["multi_draw_indirect"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multi_draw_indirect", + )])]), }); } @@ -1404,10 +1402,7 @@ where `DynamicState::PrimitiveRestartEnable` and the \ current primitive topology is \ `PrimitiveTopology::*List`", - requires_one_of: RequiresOneOf { - features: &["primitive_topology_list_restart"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("primitive_topology_list_restart")])]), }); } } @@ -1422,10 +1417,7 @@ where `DynamicState::PrimitiveRestartEnable` and the \ current primitive topology is \ `PrimitiveTopology::PatchList`", - requires_one_of: RequiresOneOf { - features: &["primitive_topology_patch_list_restart"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("primitive_topology_patch_list_restart")])]), }); } } diff --git a/vulkano/src/command_buffer/commands/query.rs b/vulkano/src/command_buffer/commands/query.rs index d2db38af47..4fa287fd05 100644 --- a/vulkano/src/command_buffer/commands/query.rs +++ b/vulkano/src/command_buffer/commands/query.rs @@ -18,7 +18,7 @@ use crate::{ device::{DeviceOwned, QueueFlags}, query::{QueryControlFlags, QueryPool, QueryResultElement, QueryResultFlags, QueryType}, sync::{PipelineStage, PipelineStageAccessFlags, PipelineStages}, - DeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanObject, + DeviceSize, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, Version, VulkanObject, }; use std::{ error::Error, @@ -97,10 +97,9 @@ where { return Err(QueryError::RequirementNotMet { required_for: "`flags` contains `QueryControlFlags::PRECISE`", - requires_one_of: RequiresOneOf { - features: &["occlusion_query_precise"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "occlusion_query_precise", + )])]), }); } } @@ -298,10 +297,9 @@ where { return Err(QueryError::RequirementNotMet { required_for: "`stage` has flags set from `VkPipelineStageFlagBits2`", - requires_one_of: RequiresOneOf { - features: &["synchronization2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "synchronization2", + )])]), }); } @@ -337,10 +335,9 @@ where if !device.enabled_features().geometry_shader { return Err(QueryError::RequirementNotMet { required_for: "`stage` is `PipelineStage::GeometryShader`", - requires_one_of: RequiresOneOf { - features: &["geometry_shadere"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "geometry_shadere", + )])]), }); } } @@ -351,10 +348,9 @@ where return Err(QueryError::RequirementNotMet { required_for: "`stage` is `PipelineStage::TessellationControlShader` or \ `PipelineStage::TessellationEvaluationShader`", - requires_one_of: RequiresOneOf { - features: &["tessellation_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "tessellation_shader", + )])]), }); } } @@ -363,10 +359,9 @@ where if !device.enabled_features().conditional_rendering { return Err(QueryError::RequirementNotMet { required_for: "`stage` is `PipelineStage::ConditionalRendering`", - requires_one_of: RequiresOneOf { - features: &["conditional_rendering"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "conditional_rendering", + )])]), }); } } @@ -375,10 +370,9 @@ where if !device.enabled_features().fragment_density_map { return Err(QueryError::RequirementNotMet { required_for: "`stage` is `PipelineStage::FragmentDensityProcess`", - requires_one_of: RequiresOneOf { - features: &["fragment_density_map"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "fragment_density_map", + )])]), }); } } @@ -387,10 +381,9 @@ where if !device.enabled_features().transform_feedback { return Err(QueryError::RequirementNotMet { required_for: "`stage` is `PipelineStage::TransformFeedback`", - requires_one_of: RequiresOneOf { - features: &["transform_feedback"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "transform_feedback", + )])]), }); } } @@ -399,10 +392,9 @@ where if !device.enabled_features().mesh_shader { return Err(QueryError::RequirementNotMet { required_for: "`stage` is `PipelineStage::MeshShader`", - requires_one_of: RequiresOneOf { - features: &["mesh_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "mesh_shader", + )])]), }); } } @@ -411,10 +403,9 @@ where if !device.enabled_features().task_shader { return Err(QueryError::RequirementNotMet { required_for: "`stage` is `PipelineStage::TaskShader`", - requires_one_of: RequiresOneOf { - features: &["task_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "task_shader", + )])]), }); } } @@ -425,10 +416,10 @@ where { return Err(QueryError::RequirementNotMet { required_for: "`stage` is `PipelineStage::FragmentShadingRateAttachment`", - requires_one_of: RequiresOneOf { - features: &["attachment_fragment_shading_rate", "shading_rate_image"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::Feature("attachment_fragment_shading_rate")]), + RequiresAllOf(&[Requires::Feature("shading_rate_image")]), + ]), }); } } @@ -437,10 +428,9 @@ where if !device.enabled_features().subpass_shading { return Err(QueryError::RequirementNotMet { required_for: "`stage` is `PipelineStage::SubpassShading`", - requires_one_of: RequiresOneOf { - features: &["subpass_shading"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "subpass_shading", + )])]), }); } } @@ -449,10 +439,9 @@ where if !device.enabled_features().invocation_mask { return Err(QueryError::RequirementNotMet { required_for: "`stage` is `PipelineStage::InvocationMask`", - requires_one_of: RequiresOneOf { - features: &["invocation_mask"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "invocation_mask", + )])]), }); } } diff --git a/vulkano/src/command_buffer/commands/render_pass.rs b/vulkano/src/command_buffer/commands/render_pass.rs index 7a082ba59d..91f198df21 100644 --- a/vulkano/src/command_buffer/commands/render_pass.rs +++ b/vulkano/src/command_buffer/commands/render_pass.rs @@ -26,7 +26,7 @@ use crate::{ ResolveMode, SubpassDescription, }, sync::PipelineStageAccessFlags, - RequirementNotMet, RequiresOneOf, Version, VulkanObject, + RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, Version, VulkanObject, }; use smallvec::SmallVec; use std::{ @@ -698,10 +698,9 @@ where if !device.enabled_features().dynamic_rendering { return Err(RenderPassError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::begin_rendering`", - requires_one_of: RequiresOneOf { - features: &["dynamic_rendering"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "dynamic_rendering", + )])]), }); } @@ -751,10 +750,7 @@ where if view_mask != 0 && !device.enabled_features().multiview { return Err(RenderPassError::RequirementNotMet { required_for: "`rendering_info.viewmask` is not `0`", - requires_one_of: RequiresOneOf { - features: &["multiview"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("multiview")])]), }); } @@ -1267,10 +1263,9 @@ where `rendering_info.stencil_attachment` are both \ `Some`, and `rendering_info.depth_attachment.image_layout` does not \ equal `rendering_info.stencil_attachment.attachment_ref.layout`", - requires_one_of: RequiresOneOf { - features: &["separate_depth_stencil_layouts"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "separate_depth_stencil_layouts", + )])]), }); } @@ -1300,10 +1295,9 @@ where `rendering_info.depth_attachment.resolve_info.image_layout` \ does not equal \ `rendering_info.stencil_attachment.resolve_info.image_layout`", - requires_one_of: RequiresOneOf { - features: &["separate_depth_stencil_layouts"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "separate_depth_stencil_layouts", + )])]), }); } diff --git a/vulkano/src/command_buffer/commands/secondary.rs b/vulkano/src/command_buffer/commands/secondary.rs index e39ccbe3b1..a48c0f52e6 100644 --- a/vulkano/src/command_buffer/commands/secondary.rs +++ b/vulkano/src/command_buffer/commands/secondary.rs @@ -20,7 +20,7 @@ use crate::{ format::Format, image::SampleCount, query::{QueryControlFlags, QueryPipelineStatisticFlags, QueryType}, - RequiresOneOf, SafeDeref, VulkanObject, + Requires, RequiresAllOf, RequiresOneOf, SafeDeref, VulkanObject, }; use smallvec::{smallvec, SmallVec}; use std::{ @@ -303,10 +303,9 @@ where { return Err(ExecuteCommandsError::RequirementNotMet { required_for: "`AutoCommandBufferBuilder::execute_commands` when a query is active", - requires_one_of: RequiresOneOf { - features: &["inherited_queries"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "inherited_queries", + )])]), }); } diff --git a/vulkano/src/command_buffer/pool.rs b/vulkano/src/command_buffer/pool.rs index 4124d956e4..5bbf8f44f9 100644 --- a/vulkano/src/command_buffer/pool.rs +++ b/vulkano/src/command_buffer/pool.rs @@ -19,7 +19,7 @@ use crate::{ command_buffer::CommandBufferLevel, device::{Device, DeviceOwned}, macros::impl_id_counter, - OomError, RequiresOneOf, RuntimeError, Version, VulkanObject, + OomError, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, Version, VulkanObject, }; use smallvec::SmallVec; use std::{ @@ -286,11 +286,10 @@ impl CommandPool { { return Err(CommandPoolTrimError::RequirementNotMet { required_for: "`CommandPool::trim`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_maintenance1"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_maintenance1")]), + ]), }); } @@ -535,7 +534,7 @@ mod tests { }; use crate::{ command_buffer::{pool::CommandBufferAllocateInfo, CommandBufferLevel}, - RequiresOneOf, Version, + Requires, RequiresAllOf, RequiresOneOf, Version, }; #[test] @@ -596,11 +595,11 @@ mod tests { if matches!( pool.trim(), Err(CommandPoolTrimError::RequirementNotMet { - requires_one_of: RequiresOneOf { - device_extensions, - .. - }, .. - }) if device_extensions.contains(&"khr_maintenance1") + requires_one_of: RequiresOneOf(&[RequiresAllOf([Requires::DeviceExtension( + "khr_maintenance1" + )]),]), + .. + }) ) { panic!() } @@ -608,11 +607,11 @@ mod tests { if !matches!( pool.trim(), Err(CommandPoolTrimError::RequirementNotMet { - requires_one_of: RequiresOneOf { - device_extensions, - .. - }, .. - }) if device_extensions.contains(&"khr_maintenance1") + requires_one_of: RequiresOneOf(&[RequiresAllOf([Requires::DeviceExtension( + "khr_maintenance1" + )]),]), + .. + }) ) { panic!() } diff --git a/vulkano/src/deferred.rs b/vulkano/src/deferred.rs index 4fc1fa0669..9714da97bd 100644 --- a/vulkano/src/deferred.rs +++ b/vulkano/src/deferred.rs @@ -18,7 +18,7 @@ use crate::{ device::{Device, DeviceOwned}, - RequiresOneOf, RuntimeError, VulkanObject, + Requires, RequiresAllOf, RequiresOneOf, RuntimeError, VulkanObject, }; use std::{ error::Error, @@ -55,10 +55,9 @@ impl DeferredOperation { if !device.enabled_extensions().khr_deferred_host_operations { return Err(DeferredOperationCreateError::RequirementNotMet { required_for: "`DeferredOperation::new`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_deferred_host_operations"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_deferred_host_operations", + )])]), }); } diff --git a/vulkano/src/descriptor_set/layout.rs b/vulkano/src/descriptor_set/layout.rs index d8423a70a2..613e2f269b 100644 --- a/vulkano/src/descriptor_set/layout.rs +++ b/vulkano/src/descriptor_set/layout.rs @@ -17,7 +17,8 @@ use crate::{ macros::{impl_id_counter, vulkan_bitflags, vulkan_enum}, sampler::Sampler, shader::{DescriptorBindingRequirements, ShaderStages}, - RequiresOneOf, RuntimeError, ValidationError, Version, VulkanError, VulkanObject, + Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, Version, VulkanError, + VulkanObject, }; use ahash::HashMap; use std::{ @@ -471,10 +472,11 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - UPDATE_AFTER_BIND_POOL = UPDATE_AFTER_BIND_POOL { - api_version: V1_2, - device_extensions: [ext_descriptor_indexing], - }, */ + UPDATE_AFTER_BIND_POOL = UPDATE_AFTER_BIND_POOL + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(ext_descriptor_indexing)]), + ]), */ /// Whether the descriptor set layout should be created for push descriptors. /// @@ -487,27 +489,32 @@ vulkan_bitflags! { /// - There must be no bindings with `variable_descriptor_count` enabled. /// - The total number of descriptors across all bindings must be less than the /// [`max_push_descriptors`](crate::device::Properties::max_push_descriptors) limit. - PUSH_DESCRIPTOR = PUSH_DESCRIPTOR_KHR { - device_extensions: [khr_push_descriptor], - }, + PUSH_DESCRIPTOR = PUSH_DESCRIPTOR_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_push_descriptor)]), + ]), /* TODO: enable // TODO: document - DESCRIPTOR_BUFFER = DESCRIPTOR_BUFFER_EXT { - device_extensions: [ext_descriptor_buffer], - }, */ + DESCRIPTOR_BUFFER = DESCRIPTOR_BUFFER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_descriptor_buffer)]), + ]), */ /* TODO: enable // TODO: document - EMBEDDED_IMMUTABLE_SAMPLERS = EMBEDDED_IMMUTABLE_SAMPLERS_EXT { - device_extensions: [ext_descriptor_buffer], - }, */ + EMBEDDED_IMMUTABLE_SAMPLERS = EMBEDDED_IMMUTABLE_SAMPLERS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_descriptor_buffer)]), + ]), */ /* TODO: enable // TODO: document - HOST_ONLY_POOL = HOST_ONLY_POOL_EXT { - device_extensions: [ext_mutable_descriptor_type, valve_mutable_descriptor_type], - }, */ + HOST_ONLY_POOL = HOST_ONLY_POOL_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_mutable_descriptor_type)]), + RequiresAllOf([DeviceExtension(valve_mutable_descriptor_type)]), + ]), */ } /// A binding in a descriptor set layout. @@ -642,10 +649,9 @@ impl DescriptorSetLayoutBinding { return Err(ValidationError { context: "descriptor_type".into(), problem: "DescriptorType::InlineUniformBlock".into(), - requires_one_of: RequiresOneOf { - features: &["inline_uniform_block"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "inline_uniform_block", + )])]), vuids: &["VUID-VkDescriptorSetLayoutBinding-descriptorType-04604"], }); } @@ -754,10 +760,9 @@ impl DescriptorSetLayoutBinding { return Err(ValidationError { context: "binding_flags".into(), problem: "contains `DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT`".into(), - requires_one_of: RequiresOneOf { - features: &["descriptor_binding_variable_descriptor_count"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::Feature("descriptor_binding_variable_descriptor_count")]) + ]), vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingVariableDescriptorCount-03014"], }); } @@ -806,24 +811,27 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - UPDATE_AFTER_BIND = UPDATE_AFTER_BIND { - api_version: V1_2, - device_extensions: [ext_descriptor_indexing], - }, */ + UPDATE_AFTER_BIND = UPDATE_AFTER_BIND + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(ext_descriptor_indexing)]), + ]), */ /* TODO: enable // TODO: document - UPDATE_UNUSED_WHILE_PENDING = UPDATE_UNUSED_WHILE_PENDING { - api_version: V1_2, - device_extensions: [ext_descriptor_indexing], - }, */ + UPDATE_UNUSED_WHILE_PENDING = UPDATE_UNUSED_WHILE_PENDING + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(ext_descriptor_indexing)]), + ]), */ /* TODO: enable // TODO: document - PARTIALLY_BOUND = PARTIALLY_BOUND { - api_version: V1_2, - device_extensions: [ext_descriptor_indexing], - }, */ + PARTIALLY_BOUND = PARTIALLY_BOUND + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(ext_descriptor_indexing)]), + ]), */ /// Whether the binding has a variable number of descriptors. /// @@ -836,10 +844,11 @@ vulkan_bitflags! { /// [`DescriptorType::UniformBufferDynamic`] or [`DescriptorType::StorageBufferDynamic`]. /// /// [`descriptor_binding_variable_descriptor_count`]: crate::device::Features::descriptor_binding_variable_descriptor_count - VARIABLE_DESCRIPTOR_COUNT = VARIABLE_DESCRIPTOR_COUNT { - api_version: V1_2, - device_extensions: [ext_descriptor_indexing], - }, + VARIABLE_DESCRIPTOR_COUNT = VARIABLE_DESCRIPTOR_COUNT + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(ext_descriptor_indexing)]), + ]), } vulkan_enum! { @@ -905,39 +914,53 @@ vulkan_enum! { /// - The `first_array_element` value when writing a descriptor set specifies the byte offset /// into the inline buffer. /// These values must always be a multiple of 4. - InlineUniformBlock = INLINE_UNIFORM_BLOCK { - api_version: V1_3, - device_extensions: [ext_inline_uniform_block], - }, + InlineUniformBlock = INLINE_UNIFORM_BLOCK + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_inline_uniform_block)]), + ]), + + /* TODO: enable + // TODO: document + InlineUniformBlock = INLINE_UNIFORM_BLOCK + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_inline_uniform_block)]), + ]),*/ /// Gives read access to an acceleration structure, for performing ray queries and ray tracing. - AccelerationStructure = ACCELERATION_STRUCTURE_KHR { - device_extensions: [khr_acceleration_structure], - }, + AccelerationStructure = ACCELERATION_STRUCTURE_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_acceleration_structure)]), + ]), /* TODO: enable // TODO: document - AccelerationStructureNV = ACCELERATION_STRUCTURE_NV { - device_extensions: [nv_ray_tracing], - },*/ + AccelerationStructureNV = ACCELERATION_STRUCTURE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]),*/ /* TODO: enable // TODO: document - SampleWeightImage = SAMPLE_WEIGHT_IMAGE_QCOM { - device_extensions: [qcom_image_processing], - },*/ + SampleWeightImage = SAMPLE_WEIGHT_IMAGE_QCOM + RequiresOneOf([ + RequiresAllOf([DeviceExtension(qcom_image_processing)]), + ]),*/ /* TODO: enable // TODO: document - BlockMatchImage = BLOCK_MATCH_IMAGE_QCOM { - device_extensions: [qcom_image_processing], - },*/ + BlockMatchImage = BLOCK_MATCH_IMAGE_QCOM + RequiresOneOf([ + RequiresAllOf([DeviceExtension(qcom_image_processing)]), + ]),*/ /* TODO: enable // TODO: document - Mutable = MUTABLE_VALVE { - device_extensions: [valve_mutable_descriptor_type], - },*/ + Mutable = MUTABLE_VALVE + RequiresOneOf([ + RequiresAllOf([DeviceExtension(valve_mutable_descriptor_type)]), + ]),*/ } impl DescriptorType { diff --git a/vulkano/src/descriptor_set/pool.rs b/vulkano/src/descriptor_set/pool.rs index 82a2dad486..ae303ff9d6 100644 --- a/vulkano/src/descriptor_set/pool.rs +++ b/vulkano/src/descriptor_set/pool.rs @@ -14,7 +14,8 @@ use crate::{ }, device::{Device, DeviceOwned}, macros::{impl_id_counter, vulkan_bitflags}, - RequiresOneOf, RuntimeError, ValidationError, Version, VulkanError, VulkanObject, + Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, Version, VulkanError, + VulkanObject, }; use ahash::HashMap; use smallvec::SmallVec; @@ -468,11 +469,10 @@ impl DescriptorPoolCreateInfo { return Err(ValidationError { context: "max_inline_uniform_block_bindings".into(), problem: "is not zero".into(), - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - device_extensions: &["ext_inline_uniform_block"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::DeviceExtension("ext_inline_uniform_block")]), + ]), // vuids? ..Default::default() }); diff --git a/vulkano/src/descriptor_set/update.rs b/vulkano/src/descriptor_set/update.rs index 996e7939da..db7ef65953 100644 --- a/vulkano/src/descriptor_set/update.rs +++ b/vulkano/src/descriptor_set/update.rs @@ -20,7 +20,7 @@ use crate::{ view::ImageViewType, ImageAspects, ImageLayout, ImageType, ImageUsage, ImageViewAbstract, }, sampler::Sampler, - DeviceSize, RequiresOneOf, ValidationError, VulkanObject, + DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError, VulkanObject, }; use smallvec::SmallVec; use std::{ops::Range, ptr, sync::Arc}; @@ -452,10 +452,9 @@ impl WriteDescriptorSet { layout_binding.descriptor_type, ) .into(), - requires_one_of: RequiresOneOf { - features: &["image2_d_view_of3_d"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("image2_d_view_of3_d"), + ])]), vuids: &["VUID-VkDescriptorImageInfo-descriptorType-06713"], }); } @@ -471,10 +470,9 @@ impl WriteDescriptorSet { layout_binding.descriptor_type, ) .into(), - requires_one_of: RequiresOneOf { - features: &["sampler2_d_view_of3_d"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("sampler2_d_view_of3_d"), + ])]), vuids: &["VUID-VkDescriptorImageInfo-descriptorType-06714"], }); } @@ -593,10 +591,9 @@ impl WriteDescriptorSet { problem: "this device is a portability subset device, and \ the sampler has depth comparison enabled" .into(), - requires_one_of: RequiresOneOf { - features: &["mutable_comparison_samplers"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "mutable_comparison_samplers", + )])]), vuids: &["VUID-VkDescriptorImageInfo-mutableComparisonSamplers-04450"], }); } @@ -680,10 +677,9 @@ impl WriteDescriptorSet { problem: "this device is a portability subset device, and \ the sampler has depth comparison enabled" .into(), - requires_one_of: RequiresOneOf { - features: &["mutable_comparison_samplers"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("mutable_comparison_samplers"), + ])]), vuids: &[ "VUID-VkDescriptorImageInfo-mutableComparisonSamplers-04450", ], diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index f3b8ce2b00..c1138cd582 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -119,7 +119,8 @@ use crate::{ instance::Instance, macros::{impl_id_counter, vulkan_bitflags}, memory::ExternalMemoryHandleType, - OomError, RequiresOneOf, RuntimeError, ValidationError, Version, VulkanError, VulkanObject, + OomError, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, Version, + VulkanError, VulkanObject, }; use ash::vk::Handle; use parking_lot::Mutex; @@ -172,27 +173,11 @@ pub struct Device { impl Device { /// Creates a new `Device`. - /// - /// # Panics - /// - /// - Panics if `create_info.queues` is empty. - /// - Panics if one of the queue families in `create_info.queues` doesn't belong to the given - /// physical device. - /// - Panics if `create_info.queues` contains multiple elements for the same queue family. - /// - Panics if `create_info.queues` contains an element where `queues` is empty. - /// - Panics if `create_info.queues` contains an element where `queues` contains a value that is - /// not between 0.0 and 1.0 inclusive. + #[inline] pub fn new( physical_device: Arc, - mut create_info: DeviceCreateInfo, + create_info: DeviceCreateInfo, ) -> Result<(Arc, impl ExactSizeIterator>), VulkanError> { - if physical_device - .supported_extensions() - .khr_portability_subset - { - create_info.enabled_extensions.khr_portability_subset = true; - } - Self::validate_new(&physical_device, &create_info)?; unsafe { Ok(Self::new_unchecked(physical_device, create_info)?) } @@ -208,25 +193,12 @@ impl Device { let &DeviceCreateInfo { queue_create_infos: _, - ref enabled_extensions, + enabled_extensions: _, enabled_features: _, ref physical_devices, _ne: _, } = create_info; - enabled_extensions - .check_requirements( - physical_device.supported_extensions(), - physical_device.api_version(), - physical_device.instance().enabled_extensions(), - ) - .map_err(|err| ValidationError { - context: "create_info.enabled_extensions".into(), - problem: err.to_string().into(), - vuids: &["VUID-vkCreateDevice-ppEnabledExtensionNames-01387"], - ..Default::default() - })?; - if !physical_devices.is_empty() && !physical_devices .iter() @@ -249,6 +221,13 @@ impl Device { physical_device: Arc, mut create_info: DeviceCreateInfo, ) -> Result<(Arc, impl ExactSizeIterator>), RuntimeError> { + // VUID-vkCreateDevice-ppEnabledExtensionNames-01387 + create_info.enabled_extensions.enable_dependencies( + physical_device.api_version(), + physical_device.supported_extensions(), + ); + + // VUID-VkDeviceCreateInfo-pProperties-04451 if physical_device .supported_extensions() .khr_portability_subset @@ -256,6 +235,47 @@ impl Device { create_info.enabled_extensions.khr_portability_subset = true; } + if physical_device.api_version() >= Version::V1_1 { + // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-04476 + if create_info.enabled_extensions.khr_shader_draw_parameters { + create_info.enabled_features.shader_draw_parameters = true; + } + } + + if physical_device.api_version() >= Version::V1_2 { + // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02831 + if create_info.enabled_extensions.khr_draw_indirect_count { + create_info.enabled_features.draw_indirect_count = true; + } + + // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02832 + if create_info + .enabled_extensions + .khr_sampler_mirror_clamp_to_edge + { + create_info.enabled_features.sampler_mirror_clamp_to_edge = true; + } + + // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02833 + if create_info.enabled_extensions.ext_descriptor_indexing { + create_info.enabled_features.descriptor_indexing = true; + } + + // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02834 + if create_info.enabled_extensions.ext_sampler_filter_minmax { + create_info.enabled_features.sampler_filter_minmax = true; + } + + // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02835 + if create_info + .enabled_extensions + .ext_shader_viewport_index_layer + { + create_info.enabled_features.shader_output_viewport_index = true; + create_info.enabled_features.shader_output_layer = true; + } + } + let &DeviceCreateInfo { ref queue_create_infos, ref enabled_extensions, @@ -394,15 +414,8 @@ impl Device { pub unsafe fn from_handle( physical_device: Arc, handle: ash::vk::Device, - mut create_info: DeviceCreateInfo, + create_info: DeviceCreateInfo, ) -> (Arc, impl ExactSizeIterator>) { - if physical_device - .supported_extensions() - .khr_portability_subset - { - create_info.enabled_extensions.khr_portability_subset = true; - } - let DeviceCreateInfo { queue_create_infos, enabled_features, @@ -533,12 +546,18 @@ impl Device { } /// Returns the extensions that have been enabled on the device. + /// + /// This includes both the extensions specified in [`DeviceCreateInfo::enabled_extensions`], + /// and any extensions that are required by those extensions. #[inline] pub fn enabled_extensions(&self) -> &DeviceExtensions { &self.enabled_extensions } /// Returns the features that have been enabled on the device. + /// + /// This includes both the features specified in [`DeviceCreateInfo::enabled_features`], + /// and any features that are required by the enabled extensions. #[inline] pub fn enabled_features(&self) -> &Features { &self.enabled_features @@ -597,20 +616,19 @@ impl Device { ) -> Result<(), ValidationError> { if !self.enabled_extensions().khr_acceleration_structure { return Err(ValidationError { - requires_one_of: RequiresOneOf { - device_extensions: &["khr_acceleration_structure"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_acceleration_structure", + )])]), ..Default::default() }); } if !(self.enabled_features().ray_tracing_pipeline || self.enabled_features().ray_query) { return Err(ValidationError { - requires_one_of: RequiresOneOf { - features: &["ray_tracing_pipeline", "ray_query"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::Feature("ray_tracing_pipeline")]), + RequiresAllOf(&[Requires::Feature("ray_query")]), + ]), vuids: &["VUID-vkGetAccelerationStructureBuildSizesKHR-rayTracingPipeline-03617"], ..Default::default() }); @@ -752,20 +770,19 @@ impl Device { ) -> Result<(), ValidationError> { if !self.enabled_extensions().khr_acceleration_structure { return Err(ValidationError { - requires_one_of: RequiresOneOf { - device_extensions: &["khr_acceleration_structure"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_acceleration_structure", + )])]), ..Default::default() }); } if !(self.enabled_features().ray_tracing_pipeline || self.enabled_features().ray_query) { return Err(ValidationError { - requires_one_of: RequiresOneOf { - features: &["ray_tracing_pipeline", "ray_query"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::Feature("ray_tracing_pipeline")]), + RequiresAllOf(&[Requires::Feature("ray_query")]), + ]), vuids: &["VUID-vkGetDeviceAccelerationStructureCompatibilityKHR-rayTracingPipeline-03661"], ..Default::default() }); @@ -825,11 +842,10 @@ impl Device { ) -> Result<(), ValidationError> { if !(self.api_version() >= Version::V1_1 || self.enabled_extensions().khr_maintenance3) { return Err(ValidationError { - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_maintenance3"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_maintenance3")]), + ]), ..Default::default() }); } @@ -972,10 +988,9 @@ impl Device { ) -> Result<(), ValidationError> { if !self.enabled_extensions().khr_external_memory_fd { return Err(ValidationError { - requires_one_of: RequiresOneOf { - device_extensions: &["khr_external_memory_fd"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_external_memory_fd", + )])]), ..Default::default() }); } @@ -1125,6 +1140,9 @@ pub struct DeviceCreateInfo { /// The extensions to enable on the device. /// + /// You only need to enable the extensions that you need. If the extensions you specified + /// require additional extensions to be enabled, they will be automatically enabled as well. + /// /// If the [`khr_portability_subset`](DeviceExtensions::khr_portability_subset) extension is /// available, it will be enabled automatically, so you do not have to do this yourself. /// You are responsible for ensuring that your program can work correctly on such devices. @@ -1136,6 +1154,9 @@ pub struct DeviceCreateInfo { /// The features to enable on the device. /// + /// You only need to enable the features that you need. If the extensions you specified + /// require certain features to be enabled, they will be automatically enabled as well. + /// /// The default value is [`Features::empty()`]. pub enabled_features: Features, @@ -1231,6 +1252,19 @@ impl DeviceCreateInfo { } } + enabled_extensions + .check_requirements( + physical_device.supported_extensions(), + physical_device.api_version(), + physical_device.instance().enabled_extensions(), + ) + .map_err(|err| ValidationError { + context: "enabled_extensions".into(), + problem: err.to_string().into(), + vuids: &["VUID-vkCreateDevice-ppEnabledExtensionNames-01387"], + ..Default::default() + })?; + enabled_features .check_requirements(physical_device.supported_features()) .map_err(|err| ValidationError { @@ -1239,135 +1273,49 @@ impl DeviceCreateInfo { ..Default::default() })?; + let mut dependency_extensions = *enabled_extensions; + dependency_extensions.enable_dependencies( + physical_device.api_version(), + physical_device.supported_extensions(), + ); + // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-01840 // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-00374 // Ensured because `DeviceExtensions` doesn't contain obsoleted extensions. - if enabled_extensions.khr_buffer_device_address - && enabled_extensions.ext_buffer_device_address - { - return Err(ValidationError { - context: "enabled_extensions".into(), - problem: "contains both `khr_buffer_device_address` and \ - `ext_buffer_device_address`" - .into(), - vuids: &["VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-03328"], - ..Default::default() - }); - } - - if enabled_features.buffer_device_address && enabled_extensions.ext_buffer_device_address { - return Err(ValidationError { - problem: "`enabled_features` contains `buffer_device_address`, and \ - `enabled_extensions` contains `ext_buffer_device_address`" - .into(), - vuids: &["VUID-VkDeviceCreateInfo-pNext-04748"], - ..Default::default() - }); - } - - if physical_device.api_version() >= Version::V1_1 { - if enabled_extensions.khr_shader_draw_parameters - && !enabled_features.shader_draw_parameters - { - return Err(ValidationError { - problem: "the physical device API version is at least 1.1, and \ - `enabled_extensions` contains `khr_shader_draw_parameters`, but \ - `enabled_features` does not contain `shader_draw_parameters`" - .into(), - vuids: &["VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-04476"], - ..Default::default() - }); - } - } - - if physical_device.api_version() >= Version::V1_2 { - if enabled_extensions.khr_draw_indirect_count && !enabled_features.draw_indirect_count { + if enabled_extensions.ext_buffer_device_address { + if enabled_extensions.khr_buffer_device_address { return Err(ValidationError { - problem: "the physical device API version is at least 1.2, and \ - `enabled_extensions` contains `khr_draw_indirect_count`, but \ - `enabled_features` does not contain `draw_indirect_count`" + context: "enabled_extensions".into(), + problem: "contains `khr_buffer_device_address`, \ + but also contains `ext_buffer_device_address`" .into(), - vuids: &["VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02831"], + vuids: &["VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-03328"], ..Default::default() }); - } - - if enabled_extensions.khr_sampler_mirror_clamp_to_edge - && !enabled_features.sampler_mirror_clamp_to_edge - { + } else if dependency_extensions.khr_buffer_device_address { return Err(ValidationError { - problem: "the physical device API version is at least 1.2, and \ - `enabled_extensions` contains `khr_sampler_mirror_clamp_to_edge`, but \ - `enabled_features` does not contain `sampler_mirror_clamp_to_edge`" + context: "enabled_extensions".into(), + problem: "contains an extension that requires `khr_buffer_device_address`, \ + but also contains `ext_buffer_device_address`" .into(), - vuids: &["VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02832"], + vuids: &["VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-03328"], ..Default::default() }); } - if enabled_extensions.ext_descriptor_indexing && !enabled_features.descriptor_indexing { - return Err(ValidationError { - problem: "the physical device API version is at least 1.2, and \ - `enabled_extensions` contains `ext_descriptor_indexing`, but \ - `enabled_features` does not contain `descriptor_indexing`" - .into(), - vuids: &["VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02833"], - ..Default::default() - }); - } - - if enabled_extensions.ext_sampler_filter_minmax - && !enabled_features.sampler_filter_minmax + if physical_device.api_version() >= Version::V1_2 + && enabled_features.buffer_device_address { return Err(ValidationError { - problem: "the physical device API version is at least 1.2, and \ - `enabled_extensions` contains `ext_sampler_filter_minmax`, but \ - `enabled_features` does not contain `sampler_filter_minmax`" + problem: "the physical device API version is at least 1.2, \ + `enabled_features` contains `buffer_device_address`, and \ + `enabled_extensions` contains `ext_buffer_device_address`" .into(), - vuids: &["VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02834"], + vuids: &["VUID-VkDeviceCreateInfo-pNext-04748"], ..Default::default() }); } - - if enabled_extensions.ext_shader_viewport_index_layer { - if !enabled_features.shader_output_viewport_index { - return Err(ValidationError { - problem: "the physical device API version is at least 1.2, and \ - `enabled_extensions` contains `ext_shader_viewport_index_layer`, but \ - `enabled_features` does not contain `shader_output_viewport_index`" - .into(), - vuids: &[" - - VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02835"], - ..Default::default() - }); - } - - if !enabled_features.shader_output_layer { - return Err(ValidationError { - problem: "the physical device API version is at least 1.2, and \ - `enabled_extensions` contains `ext_shader_viewport_index_layer`, but \ - `enabled_features` does not contain `shader_output_layer`" - .into(), - vuids: &["VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02835"], - ..Default::default() - }); - } - } - } - - let supported_extensions = physical_device.supported_extensions(); - - if supported_extensions.khr_portability_subset && !enabled_extensions.khr_portability_subset - { - return Err(ValidationError { - problem: "the physical device supports the `khr_portability_subset` extension, \ - but `enabled_extensions` does not contain `khr_portability_subset`" - .into(), - vuids: &["VUID-VkDeviceCreateInfo-pProperties-04451"], - ..Default::default() - }); } if enabled_features.shading_rate_image { @@ -1528,11 +1476,10 @@ impl DeviceCreateInfo { return Err(ValidationError { context: "physical_devices".into(), problem: "the length is greater than 1".into(), - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - instance_extensions: &["khr_device_group_creation"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::InstanceExtension("khr_device_group_creation")]), + ]), ..Default::default() }); } @@ -1671,9 +1618,10 @@ vulkan_bitflags! { /// Flags specifying additional properties of a queue. QueueCreateFlags = DeviceQueueCreateFlags(u32); - PROTECTED = PROTECTED { - api_version: V1_1, - }, + PROTECTED = PROTECTED + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + ]), } /// Implemented on objects that belong to a Vulkan device. diff --git a/vulkano/src/device/physical.rs b/vulkano/src/device/physical.rs index c063d936ac..9853cbc1d5 100644 --- a/vulkano/src/device/physical.rs +++ b/vulkano/src/device/physical.rs @@ -28,8 +28,8 @@ use crate::{ fence::{ExternalFenceInfo, ExternalFenceProperties}, semaphore::{ExternalSemaphoreInfo, ExternalSemaphoreProperties}, }, - ExtensionProperties, RequiresOneOf, RuntimeError, ValidationError, Version, VulkanError, - VulkanObject, + ExtensionProperties, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, + Version, VulkanError, VulkanObject, }; use bytemuck::cast_slice; use std::{ @@ -442,10 +442,9 @@ impl PhysicalDevice { ) -> Result<(), ValidationError> { if !self.instance.enabled_extensions().ext_directfb_surface { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_directfb_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ext_directfb_surface", + )])]), ..Default::default() }); } @@ -514,11 +513,12 @@ impl PhysicalDevice { .khr_external_memory_capabilities) { return Err(ValidationError { - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - instance_extensions: &["khr_external_memory_capabilities"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::InstanceExtension( + "khr_external_memory_capabilities", + )]), + ]), ..Default::default() }); } @@ -613,11 +613,12 @@ impl PhysicalDevice { .khr_external_fence_capabilities) { return Err(ValidationError { - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - instance_extensions: &["khr_external_fence_capabilities"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::InstanceExtension( + "khr_external_fence_capabilities", + )]), + ]), ..Default::default() }); } @@ -715,11 +716,12 @@ impl PhysicalDevice { .khr_external_semaphore_capabilities) { return Err(ValidationError { - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - instance_extensions: &["khr_external_semaphore_capabilities"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::InstanceExtension( + "khr_external_semaphore_capabilities", + )]), + ]), ..Default::default() }); } @@ -1109,10 +1111,9 @@ impl PhysicalDevice { ) -> Result<(), ValidationError> { if !self.instance.enabled_extensions().qnx_screen_surface { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["qnx_screen_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "qnx_screen_surface", + )])]), ..Default::default() }); } @@ -1358,10 +1359,10 @@ impl PhysicalDevice { || self.instance.enabled_extensions().khr_surface) { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_get_surface_capabilities2", "khr_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::InstanceExtension("khr_get_surface_capabilities2")]), + RequiresAllOf(&[Requires::InstanceExtension("khr_surface")]), + ]), ..Default::default() }); } @@ -1606,10 +1607,10 @@ impl PhysicalDevice { || self.instance.enabled_extensions().khr_surface) { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_get_surface_capabilities2", "khr_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::InstanceExtension("khr_get_surface_capabilities2")]), + RequiresAllOf(&[Requires::InstanceExtension("khr_surface")]), + ]), ..Default::default() }); } @@ -1644,10 +1645,9 @@ impl PhysicalDevice { return Err(ValidationError { context: "surface_info.full_screen_exclusive".into(), problem: "is not `FullScreenExclusive::Default`".into(), - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_get_surface_capabilities2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::InstanceExtension("khr_get_surface_capabilities2"), + ])]), ..Default::default() }); } @@ -1656,10 +1656,9 @@ impl PhysicalDevice { return Err(ValidationError { context: "surface_info.win32_monitor".into(), problem: "is `Some`".into(), - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_get_surface_capabilities2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::InstanceExtension("khr_get_surface_capabilities2"), + ])]), ..Default::default() }); } @@ -1858,10 +1857,9 @@ impl PhysicalDevice { fn validate_surface_present_modes(&self, surface: &Surface) -> Result<(), ValidationError> { if !self.instance.enabled_extensions().khr_surface { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_surface", + )])]), ..Default::default() }); } @@ -1956,10 +1954,9 @@ impl PhysicalDevice { ) -> Result<(), ValidationError> { if !self.instance.enabled_extensions().khr_surface { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_surface", + )])]), ..Default::default() }); } @@ -2020,11 +2017,10 @@ impl PhysicalDevice { fn validate_tool_properties(&self) -> Result<(), ValidationError> { if !(self.api_version() >= Version::V1_3 || self.supported_extensions().ext_tooling_info) { return Err(ValidationError { - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - device_extensions: &["ext_tooling_info"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::DeviceExtension("ext_tooling_info")]), + ]), ..Default::default() }); } @@ -2131,10 +2127,9 @@ impl PhysicalDevice { ) -> Result<(), ValidationError> { if !self.instance.enabled_extensions().khr_wayland_surface { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_wayland_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_wayland_surface", + )])]), ..Default::default() }); } @@ -2190,10 +2185,9 @@ impl PhysicalDevice { ) -> Result<(), ValidationError> { if !self.instance.enabled_extensions().khr_win32_surface { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_win32_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_win32_surface", + )])]), ..Default::default() }); } @@ -2248,10 +2242,9 @@ impl PhysicalDevice { ) -> Result<(), ValidationError> { if !self.instance.enabled_extensions().khr_xcb_surface { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_xcb_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_xcb_surface", + )])]), ..Default::default() }); } @@ -2316,10 +2309,9 @@ impl PhysicalDevice { ) -> Result<(), ValidationError> { if !self.instance.enabled_extensions().khr_xlib_surface { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_xlib_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_xlib_surface", + )])]), ..Default::default() }); } @@ -2578,16 +2570,19 @@ vulkan_bitflags! { /// The tool reports information to the user via a /// [`DebugUtilsMessenger`](crate::instance::debug::DebugUtilsMessenger). - DEBUG_REPORTING = DEBUG_REPORTING_EXT { - instance_extensions: [ext_debug_utils, ext_debug_report], - }, + DEBUG_REPORTING = DEBUG_REPORTING_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_debug_utils)]), + RequiresAllOf([InstanceExtension(ext_debug_report)]), + ]), /// The tool consumes debug markers or object debug annotation, queue labels or command buffer /// labels. - DEBUG_MARKERS = DEBUG_MARKERS_EXT { - device_extensions: [ext_debug_marker], - instance_extensions: [ext_debug_utils], - }, + DEBUG_MARKERS = DEBUG_MARKERS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_debug_marker)]), + RequiresAllOf([InstanceExtension(ext_debug_utils)]), + ]), } vulkan_bitflags! { @@ -2621,9 +2616,10 @@ vulkan_bitflags! { QUAD = QUAD, // TODO: document - PARTITIONED = PARTITIONED_NV { - device_extensions: [nv_shader_subgroup_partitioned], - }, + PARTITIONED = PARTITIONED_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_shader_subgroup_partitioned)]), + ]), } vulkan_enum! { diff --git a/vulkano/src/device/queue.rs b/vulkano/src/device/queue.rs index d1375eed9a..c879c7040b 100644 --- a/vulkano/src/device/queue.rs +++ b/vulkano/src/device/queue.rs @@ -26,7 +26,8 @@ use crate::{ future::{AccessCheckError, FlushError, GpuFuture}, semaphore::SemaphoreState, }, - OomError, RequiresOneOf, RuntimeError, ValidationError, Version, VulkanObject, + OomError, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, Version, + VulkanObject, }; use ahash::HashMap; use parking_lot::{Mutex, MutexGuard}; @@ -1155,10 +1156,9 @@ impl<'a> QueueGuard<'a> { .ext_debug_utils { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_debug_utils"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ext_debug_utils", + )])]), ..Default::default() }); } @@ -1212,10 +1212,9 @@ impl<'a> QueueGuard<'a> { .ext_debug_utils { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_debug_utils"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ext_debug_utils", + )])]), ..Default::default() }); } @@ -1262,10 +1261,9 @@ impl<'a> QueueGuard<'a> { .ext_debug_utils { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_debug_utils"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ext_debug_utils", + )])]), ..Default::default() }); } @@ -1655,24 +1653,28 @@ vulkan_bitflags! { SPARSE_BINDING = SPARSE_BINDING, /// Queues of this family can be created using the `protected` flag. - PROTECTED = PROTECTED { - api_version: V1_1, - }, + PROTECTED = PROTECTED + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + ]), /// Queues of this family can execute video decode operations. - VIDEO_DECODE = VIDEO_DECODE_KHR { - device_extensions: [khr_video_decode_queue], - }, + VIDEO_DECODE = VIDEO_DECODE_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]), /// Queues of this family can execute video encode operations. - VIDEO_ENCODE = VIDEO_ENCODE_KHR { - device_extensions: [khr_video_encode_queue], - }, + VIDEO_ENCODE = VIDEO_ENCODE_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]), /// Queues of this family can execute optical flow operations. - OPTICAL_FLOW = OPTICAL_FLOW_NV { - device_extensions: [nv_optical_flow], - }, + OPTICAL_FLOW = OPTICAL_FLOW_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_optical_flow)]), + ]), } #[cfg(test)] diff --git a/vulkano/src/format.rs b/vulkano/src/format.rs index 62cd7a14e3..9b4c63acdb 100644 --- a/vulkano/src/format.rs +++ b/vulkano/src/format.rs @@ -761,17 +761,19 @@ vulkan_bitflags! { /// Can be used with a storage image descriptor for reading, without specifying a format on the /// image view. - STORAGE_READ_WITHOUT_FORMAT = STORAGE_READ_WITHOUT_FORMAT { - api_version: V1_3, - device_extensions: [khr_format_feature_flags2], - }, + STORAGE_READ_WITHOUT_FORMAT = STORAGE_READ_WITHOUT_FORMAT + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_format_feature_flags2)]), + ]), /// Can be used with a storage image descriptor for writing, without specifying a format on the /// image view. - STORAGE_WRITE_WITHOUT_FORMAT = STORAGE_WRITE_WITHOUT_FORMAT { - api_version: V1_3, - device_extensions: [khr_format_feature_flags2], - }, + STORAGE_WRITE_WITHOUT_FORMAT = STORAGE_WRITE_WITHOUT_FORMAT + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_format_feature_flags2)]), + ]), /// Can be used with a color attachment in a framebuffer, or with an input attachment /// descriptor. @@ -786,26 +788,30 @@ vulkan_bitflags! { DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL_ATTACHMENT, /// Can be used with a fragment density map attachment in a framebuffer. - FRAGMENT_DENSITY_MAP = FRAGMENT_DENSITY_MAP_EXT { - device_extensions: [ext_fragment_density_map], - }, + FRAGMENT_DENSITY_MAP = FRAGMENT_DENSITY_MAP_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_fragment_density_map)]), + ]), /// Can be used with a fragment shading rate attachment in a framebuffer. - FRAGMENT_SHADING_RATE_ATTACHMENT = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR { - device_extensions: [khr_fragment_shading_rate], - }, + FRAGMENT_SHADING_RATE_ATTACHMENT = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_fragment_shading_rate)]), + ]), /// Can be used with the source image in a transfer (copy) operation. - TRANSFER_SRC = TRANSFER_SRC { - api_version: V1_1, - device_extensions: [khr_maintenance1], - }, + TRANSFER_SRC = TRANSFER_SRC + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_maintenance1)]), + ]), /// Can be used with the destination image in a transfer (copy) operation. - TRANSFER_DST = TRANSFER_DST { - api_version: V1_1, - device_extensions: [khr_maintenance1], - }, + TRANSFER_DST = TRANSFER_DST + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_maintenance1)]), + ]), /// Can be used with the source image in a blit operation. BLIT_SRC = BLIT_SRC, @@ -821,136 +827,215 @@ vulkan_bitflags! { /// Can be used with samplers or as a blit source, using the /// [`Cubic`](crate::sampler::Filter::Cubic) filter. - SAMPLED_IMAGE_FILTER_CUBIC = SAMPLED_IMAGE_FILTER_CUBIC_EXT { - device_extensions: [ext_filter_cubic, img_filter_cubic], - }, + SAMPLED_IMAGE_FILTER_CUBIC = SAMPLED_IMAGE_FILTER_CUBIC_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_filter_cubic)]), + RequiresAllOf([DeviceExtension(img_filter_cubic)]), + ]), /// Can be used with samplers using a reduction mode of /// [`Min`](crate::sampler::SamplerReductionMode::Min) or /// [`Max`](crate::sampler::SamplerReductionMode::Max). - SAMPLED_IMAGE_FILTER_MINMAX = SAMPLED_IMAGE_FILTER_MINMAX { - api_version: V1_2, - device_extensions: [ext_sampler_filter_minmax], - }, + SAMPLED_IMAGE_FILTER_MINMAX = SAMPLED_IMAGE_FILTER_MINMAX + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(ext_sampler_filter_minmax)]), + ]), /// Can be used with sampler YCbCr conversions using a chroma offset of /// [`Midpoint`](crate::sampler::ycbcr::ChromaLocation::Midpoint). - MIDPOINT_CHROMA_SAMPLES = MIDPOINT_CHROMA_SAMPLES { - api_version: V1_1, - device_extensions: [khr_sampler_ycbcr_conversion], - }, + MIDPOINT_CHROMA_SAMPLES = MIDPOINT_CHROMA_SAMPLES + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_sampler_ycbcr_conversion)]), + ]), /// Can be used with sampler YCbCr conversions using a chroma offset of /// [`CositedEven`](crate::sampler::ycbcr::ChromaLocation::CositedEven). - COSITED_CHROMA_SAMPLES = COSITED_CHROMA_SAMPLES { - api_version: V1_1, - device_extensions: [khr_sampler_ycbcr_conversion], - }, + COSITED_CHROMA_SAMPLES = COSITED_CHROMA_SAMPLES + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_sampler_ycbcr_conversion)]), + ]), /// Can be used with sampler YCbCr conversions using the /// [`Linear`](crate::sampler::Filter::Linear) chroma filter. - SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER = SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER { - api_version: V1_1, - device_extensions: [khr_sampler_ycbcr_conversion], - }, + SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER = SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_sampler_ycbcr_conversion)]), + ]), /// Can be used with sampler YCbCr conversions whose chroma filter differs from the filters of /// the base sampler. - SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER = SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER { - api_version: V1_1, - device_extensions: [khr_sampler_ycbcr_conversion], - }, + SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER = SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_sampler_ycbcr_conversion)]), + ]), /// When used with a sampler YCbCr conversion, the implementation will always perform /// explicit chroma reconstruction. - SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT = SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT { - api_version: V1_1, - device_extensions: [khr_sampler_ycbcr_conversion], - }, + SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT = SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_sampler_ycbcr_conversion)]), + ]), /// Can be used with sampler YCbCr conversions with forced explicit reconstruction. - SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE = SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE { - api_version: V1_1, - device_extensions: [khr_sampler_ycbcr_conversion], - }, + SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE = SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_sampler_ycbcr_conversion)]), + ]), /// Can be used with samplers using depth comparison. - SAMPLED_IMAGE_DEPTH_COMPARISON = SAMPLED_IMAGE_DEPTH_COMPARISON { - api_version: V1_3, - device_extensions: [khr_format_feature_flags2], - }, + SAMPLED_IMAGE_DEPTH_COMPARISON = SAMPLED_IMAGE_DEPTH_COMPARISON + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_format_feature_flags2)]), + ]), /* Video */ /// Can be used with the output image of a video decode operation. - VIDEO_DECODE_OUTPUT = VIDEO_DECODE_OUTPUT_KHR { - device_extensions: [khr_video_decode_queue], - }, + VIDEO_DECODE_OUTPUT = VIDEO_DECODE_OUTPUT_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]), /// Can be used with the DPB image of a video decode operation. - VIDEO_DECODE_DPB = VIDEO_DECODE_DPB_KHR { - device_extensions: [khr_video_decode_queue], - }, + VIDEO_DECODE_DPB = VIDEO_DECODE_DPB_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]), /// Can be used with the input image of a video encode operation. - VIDEO_ENCODE_INPUT = VIDEO_ENCODE_INPUT_KHR { - device_extensions: [khr_video_encode_queue], - }, + VIDEO_ENCODE_INPUT = VIDEO_ENCODE_INPUT_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]), /// Can be used with the DPB image of a video encode operation. - VIDEO_ENCODE_DPB = VIDEO_ENCODE_DPB_KHR { - device_extensions: [khr_video_encode_queue], - }, + VIDEO_ENCODE_DPB = VIDEO_ENCODE_DPB_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]), /* Misc image features */ /// For multi-planar formats, can be used with images created with the [`DISJOINT`] flag. /// /// [`DISJOINT`]: crate::image::ImageCreateFlags::DISJOINT - DISJOINT = DISJOINT { - api_version: V1_1, - device_extensions: [khr_sampler_ycbcr_conversion], - }, + DISJOINT = DISJOINT + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_sampler_ycbcr_conversion)]), + ]), // TODO: document - LINEAR_COLOR_ATTACHMENT = LINEAR_COLOR_ATTACHMENT_NV { - device_extensions: [nv_linear_color_attachment], - }, + LINEAR_COLOR_ATTACHMENT = LINEAR_COLOR_ATTACHMENT_NV + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(nv_linear_color_attachment), + ]), + RequiresAllOf([ + DeviceExtension(khr_format_feature_flags2), + DeviceExtension(nv_linear_color_attachment), + ]), + ]), // TODO: document - WEIGHT_IMAGE = WEIGHT_IMAGE_QCOM { - device_extensions: [qcom_image_processing], - }, + WEIGHT_IMAGE = WEIGHT_IMAGE_QCOM + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(qcom_image_processing), + ]), + RequiresAllOf([ + DeviceExtension(khr_format_feature_flags2), + DeviceExtension(qcom_image_processing), + ]), + ]), // TODO: document - WEIGHT_SAMPLED_IMAGE = WEIGHT_SAMPLED_IMAGE_QCOM { - device_extensions: [qcom_image_processing], - }, + WEIGHT_SAMPLED_IMAGE = WEIGHT_SAMPLED_IMAGE_QCOM + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(qcom_image_processing), + ]), + RequiresAllOf([ + DeviceExtension(khr_format_feature_flags2), + DeviceExtension(qcom_image_processing), + ]), + ]), // TODO: document - BLOCK_MATCHING = BLOCK_MATCHING_QCOM { - device_extensions: [qcom_image_processing], - }, + BLOCK_MATCHING = BLOCK_MATCHING_QCOM + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(qcom_image_processing), + ]), + RequiresAllOf([ + DeviceExtension(khr_format_feature_flags2), + DeviceExtension(qcom_image_processing), + ]), + ]), // TODO: document - BOX_FILTER_SAMPLED = BOX_FILTER_SAMPLED_QCOM { - device_extensions: [qcom_image_processing], - }, + BOX_FILTER_SAMPLED = BOX_FILTER_SAMPLED_QCOM + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(qcom_image_processing), + ]), + RequiresAllOf([ + DeviceExtension(khr_format_feature_flags2), + DeviceExtension(qcom_image_processing), + ]), + ]), // TODO: document - OPTICAL_FLOW_IMAGE = OPTICAL_FLOW_IMAGE_NV { - device_extensions: [nv_optical_flow], - }, + OPTICAL_FLOW_IMAGE = OPTICAL_FLOW_IMAGE_NV + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(nv_optical_flow), + ]), + RequiresAllOf([ + DeviceExtension(khr_format_feature_flags2), + DeviceExtension(nv_optical_flow), + ]), + ]), // TODO: document - OPTICAL_FLOW_VECTOR = OPTICAL_FLOW_VECTOR_NV { - device_extensions: [nv_optical_flow], - }, + OPTICAL_FLOW_VECTOR = OPTICAL_FLOW_VECTOR_NV + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(nv_optical_flow), + ]), + RequiresAllOf([ + DeviceExtension(khr_format_feature_flags2), + DeviceExtension(nv_optical_flow), + ]), + ]), // TODO: document - OPTICAL_FLOW_COST = OPTICAL_FLOW_COST_NV { - device_extensions: [nv_optical_flow], - }, + OPTICAL_FLOW_COST = OPTICAL_FLOW_COST_NV + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(nv_optical_flow), + ]), + RequiresAllOf([ + DeviceExtension(khr_format_feature_flags2), + DeviceExtension(nv_optical_flow), + ]), + ]), /* Buffer usage */ @@ -968,9 +1053,10 @@ vulkan_bitflags! { VERTEX_BUFFER = VERTEX_BUFFER, /// Can be used as the vertex format when building an acceleration structure. - ACCELERATION_STRUCTURE_VERTEX_BUFFER = ACCELERATION_STRUCTURE_VERTEX_BUFFER_KHR { - device_extensions: [khr_acceleration_structure], - }, + ACCELERATION_STRUCTURE_VERTEX_BUFFER = ACCELERATION_STRUCTURE_VERTEX_BUFFER_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_acceleration_structure)]), + ]), } impl From for FormatFeatures { diff --git a/vulkano/src/image/aspect.rs b/vulkano/src/image/aspect.rs index 849d8d3652..e8e913beaf 100644 --- a/vulkano/src/image/aspect.rs +++ b/vulkano/src/image/aspect.rs @@ -49,48 +49,54 @@ vulkan_bitflags_enum! { /// The first plane of an image with a multi-planar [format], holding the green color component. /// /// [format]: crate::format::Format - PLANE_0, Plane0 = PLANE_0 { - api_version: V1_1, - device_extensions: [khr_sampler_ycbcr_conversion], - }, + PLANE_0, Plane0 = PLANE_0 + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_sampler_ycbcr_conversion)]), + ]), /// The second plane of an image with a multi-planar [format], holding the blue color component /// if the format has three planes, and a combination of blue and red if the format has two /// planes. /// /// [format]: crate::format::Format - PLANE_1, Plane1 = PLANE_1 { - api_version: V1_1, - device_extensions: [khr_sampler_ycbcr_conversion], - }, + PLANE_1, Plane1 = PLANE_1 + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_sampler_ycbcr_conversion)]), + ]), /// The third plane of an image with a multi-planar [format], holding the red color component. - PLANE_2, Plane2 = PLANE_2 { - api_version: V1_1, - device_extensions: [khr_sampler_ycbcr_conversion], - }, + PLANE_2, Plane2 = PLANE_2 + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_sampler_ycbcr_conversion)]), + ]), /// The first memory plane of images created through the [`ext_image_drm_format_modifier`] /// extension. /// /// [`ext_image_drm_format_modifier`]: crate::device::DeviceExtensions::ext_image_drm_format_modifier - MEMORY_PLANE_0, MemoryPlane0 = MEMORY_PLANE_0_EXT { - device_extensions: [ext_image_drm_format_modifier], - }, + MEMORY_PLANE_0, MemoryPlane0 = MEMORY_PLANE_0_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_image_drm_format_modifier)]), + ]), /// The second memory plane of images created through the [`ext_image_drm_format_modifier`] /// extension. /// /// [`ext_image_drm_format_modifier`]: crate::device::DeviceExtensions::ext_image_drm_format_modifier - MEMORY_PLANE_1, MemoryPlane1 = MEMORY_PLANE_1_EXT { - device_extensions: [ext_image_drm_format_modifier], - }, + MEMORY_PLANE_1, MemoryPlane1 = MEMORY_PLANE_1_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_image_drm_format_modifier)]), + ]), /// The third memory plane of images created through the [`ext_image_drm_format_modifier`] /// extension. /// /// [`ext_image_drm_format_modifier`]: crate::device::DeviceExtensions::ext_image_drm_format_modifier - MEMORY_PLANE_2, MemoryPlane2 = MEMORY_PLANE_2_EXT { - device_extensions: [ext_image_drm_format_modifier], - }, + MEMORY_PLANE_2, MemoryPlane2 = MEMORY_PLANE_2_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_image_drm_format_modifier)]), + ]), } diff --git a/vulkano/src/image/layout.rs b/vulkano/src/image/layout.rs index 9c0f30638e..fc9401065e 100644 --- a/vulkano/src/image/layout.rs +++ b/vulkano/src/image/layout.rs @@ -79,124 +79,143 @@ vulkan_enum! { /// A combination of `DepthReadOnlyOptimal` for the depth aspect of the image, /// and `StencilAttachmentOptimal` for the stencil aspect of the image. - DepthReadOnlyStencilAttachmentOptimal = DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL { - api_version: V1_1, - device_extensions: [khr_maintenance2], - }, + DepthReadOnlyStencilAttachmentOptimal = DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_maintenance2)]), + ]), /// A combination of `DepthAttachmentOptimal` for the depth aspect of the image, /// and `StencilReadOnlyOptimal` for the stencil aspect of the image. - DepthAttachmentStencilReadOnlyOptimal = DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL { - api_version: V1_1, - device_extensions: [khr_maintenance2], - }, + DepthAttachmentStencilReadOnlyOptimal = DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_maintenance2)]), + ]), /// For a depth image used as a depth attachment in a framebuffer. - DepthAttachmentOptimal = DEPTH_ATTACHMENT_OPTIMAL { - api_version: V1_2, - device_extensions: [khr_separate_depth_stencil_layouts], - }, + DepthAttachmentOptimal = DEPTH_ATTACHMENT_OPTIMAL + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(khr_separate_depth_stencil_layouts)]), + ]), /// For a depth image used as a read-only depth attachment in a framebuffer, or /// as a (combined) sampled image or input attachment in a shader. - DepthReadOnlyOptimal = DEPTH_READ_ONLY_OPTIMAL { - api_version: V1_2, - device_extensions: [khr_separate_depth_stencil_layouts], - }, + DepthReadOnlyOptimal = DEPTH_READ_ONLY_OPTIMAL + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(khr_separate_depth_stencil_layouts)]), + ]), /// For a stencil image used as a stencil attachment in a framebuffer. - StencilAttachmentOptimal = STENCIL_ATTACHMENT_OPTIMAL { - api_version: V1_2, - device_extensions: [khr_separate_depth_stencil_layouts], - }, + StencilAttachmentOptimal = STENCIL_ATTACHMENT_OPTIMAL + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(khr_separate_depth_stencil_layouts)]), + ]), /// For a stencil image used as a read-only stencil attachment in a framebuffer, or /// as a (combined) sampled image or input attachment in a shader. - StencilReadOnlyOptimal = STENCIL_READ_ONLY_OPTIMAL { - api_version: V1_2, - device_extensions: [khr_separate_depth_stencil_layouts], - }, + StencilReadOnlyOptimal = STENCIL_READ_ONLY_OPTIMAL + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(khr_separate_depth_stencil_layouts)]), + ]), /* TODO: enable // TODO: document - ReadOnlyOptimal = READ_ONLY_OPTIMAL { - api_version: V1_3, - device_extensions: [khr_synchronization2], - },*/ + ReadOnlyOptimal = READ_ONLY_OPTIMAL + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]),*/ /* TODO: enable // TODO: document - AttachmentOptimal = ATTACHMENT_OPTIMAL { - api_version: V1_3, - device_extensions: [khr_synchronization2], - },*/ + AttachmentOptimal = ATTACHMENT_OPTIMAL + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]),*/ /// The layout of images that are held in a swapchain. Images are in this layout when they are /// acquired from the swapchain, and must be transitioned back into this layout before /// presenting them. - PresentSrc = PRESENT_SRC_KHR { - device_extensions: [khr_swapchain], - }, + PresentSrc = PRESENT_SRC_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_swapchain)]), + ]), /* TODO: enable // TODO: document - VideoDecodeDst = VIDEO_DECODE_DST_KHR { - device_extensions: [khr_video_decode_queue], - },*/ + VideoDecodeDst = VIDEO_DECODE_DST_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]),*/ /* TODO: enable // TODO: document - VideoDecodeSrc = VIDEO_DECODE_SRC_KHR { - device_extensions: [khr_video_decode_queue], - },*/ + VideoDecodeSrc = VIDEO_DECODE_SRC_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]),*/ /* TODO: enable // TODO: document - VideoDecodeDpb = VIDEO_DECODE_DPB_KHR { - device_extensions: [khr_video_decode_queue], - },*/ + VideoDecodeDpb = VIDEO_DECODE_DPB_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]),*/ /* TODO: enable // TODO: document - SharedPresent = SHARED_PRESENT_KHR { - device_extensions: [khr_shared_presentable_image], - },*/ + SharedPresent = SHARED_PRESENT_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_shared_presentable_image)]), + ]),*/ /* TODO: enable // TODO: document - FragmentDensityMapOptimal = FRAGMENT_DENSITY_MAP_OPTIMAL_EXT { - device_extensions: [ext_fragment_density_map], - },*/ + FragmentDensityMapOptimal = FRAGMENT_DENSITY_MAP_OPTIMAL_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_fragment_density_map)]), + ]),*/ /* TODO: enable // TODO: document - FragmentShadingRateAttachmentOptimal = FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR { - device_extensions: [khr_fragment_shading_rate], - },*/ + FragmentShadingRateAttachmentOptimal = FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_fragment_shading_rate)]), + ]),*/ /* TODO: enable // TODO: document - VideoEncodeDst = VIDEO_ENCODE_DST_KHR { - device_extensions: [khr_video_encode_queue], - },*/ + VideoEncodeDst = VIDEO_ENCODE_DST_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]),*/ /* TODO: enable // TODO: document - VideoEncodeSrc = VIDEO_ENCODE_SRC_KHR { - device_extensions: [khr_video_encode_queue], - },*/ + VideoEncodeSrc = VIDEO_ENCODE_SRC_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]),*/ /* TODO: enable // TODO: document - VideoEncodeDpb = VIDEO_ENCODE_DPB_KHR { - device_extensions: [khr_video_encode_queue], - },*/ + VideoEncodeDpb = VIDEO_ENCODE_DPB_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]),*/ /* TODO: enable // TODO: document - AttachmentFeedbackLoopOptimal = ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT { - device_extensions: [ext_attachment_feedback_loop_layout], - },*/ + AttachmentFeedbackLoopOptimal = ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_attachment_feedback_loop_layout)]), + ]),*/ } impl Default for ImageLayout { diff --git a/vulkano/src/image/mod.rs b/vulkano/src/image/mod.rs index 5ae5d079e0..9c8041c5a8 100644 --- a/vulkano/src/image/mod.rs +++ b/vulkano/src/image/mod.rs @@ -67,7 +67,7 @@ use crate::{ format::Format, macros::{vulkan_bitflags, vulkan_bitflags_enum, vulkan_enum}, memory::{ExternalMemoryHandleType, ExternalMemoryProperties}, - DeviceSize, RequiresOneOf, ValidationError, Version, + DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError, Version, }; use std::{cmp, ops::Range}; @@ -145,17 +145,19 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - ALIAS = ALIAS { - api_version: V1_1, - device_extensions: [khr_bind_memory2], - },*/ + ALIAS = ALIAS + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_bind_memory2)]), + ]),*/ /* TODO: enable // TODO: document - SPLIT_INSTANCE_BIND_REGIONS = SPLIT_INSTANCE_BIND_REGIONS { - api_version: V1_1, - device_extensions: [khr_device_group], - },*/ + SPLIT_INSTANCE_BIND_REGIONS = SPLIT_INSTANCE_BIND_REGIONS + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_device_group)]), + ]),*/ /// For 3D images, whether an image view of type [`ImageViewType::Dim2d`] or /// [`ImageViewType::Dim2dArray`] can be created from the image. @@ -167,76 +169,87 @@ vulkan_bitflags! { /// [`ImageViewType::Dim2dArray`]: crate::image::view::ImageViewType::Dim2dArray /// [portability subset]: crate::instance#portability-subset-devices-and-the-enumerate_portability-flag /// [`image_view2_d_on3_d_image`]: crate::device::Features::image_view2_d_on3_d_image - ARRAY_2D_COMPATIBLE = TYPE_2D_ARRAY_COMPATIBLE { - api_version: V1_1, - device_extensions: [khr_maintenance1], - }, + ARRAY_2D_COMPATIBLE = TYPE_2D_ARRAY_COMPATIBLE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_maintenance1)]), + ]), /// For images with a compressed format, whether an image view with an uncompressed /// format can be created from the image, where each texel in the view will correspond to a /// compressed texel block in the image. /// /// Requires `mutable_format`. - BLOCK_TEXEL_VIEW_COMPATIBLE = BLOCK_TEXEL_VIEW_COMPATIBLE { - api_version: V1_1, - device_extensions: [khr_maintenance2], - }, + BLOCK_TEXEL_VIEW_COMPATIBLE = BLOCK_TEXEL_VIEW_COMPATIBLE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_maintenance2)]), + ]), /* TODO: enable // TODO: document - EXTENDED_USAGE = EXTENDED_USAGE { - api_version: V1_1, - device_extensions: [khr_maintenance2], - },*/ + EXTENDED_USAGE = EXTENDED_USAGE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_maintenance2)]), + ]),*/ /* TODO: enable // TODO: document - PROTECTED = PROTECTED { - api_version: V1_1, - },*/ + PROTECTED = PROTECTED + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + ]),*/ /// For images with a multi-planar format, whether each plane will have its memory bound /// separately, rather than having a single memory binding for the whole image. - DISJOINT = DISJOINT { - api_version: V1_1, - device_extensions: [khr_sampler_ycbcr_conversion], - }, + DISJOINT = DISJOINT + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_sampler_ycbcr_conversion)]), + ]), /* TODO: enable // TODO: document - CORNER_SAMPLED = CORNER_SAMPLED_NV { - device_extensions: [nv_corner_sampled_image], - },*/ + CORNER_SAMPLED = CORNER_SAMPLED_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_corner_sampled_image)]), + ]),*/ /* TODO: enable // TODO: document - SAMPLE_LOCATIONS_COMPATIBLE_DEPTH = SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_EXT { - device_extensions: [ext_sample_locations], - },*/ + SAMPLE_LOCATIONS_COMPATIBLE_DEPTH = SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_sample_locations)]), + ]),*/ /* TODO: enable // TODO: document - SUBSAMPLED = SUBSAMPLED_EXT { - device_extensions: [ext_fragment_density_map], - },*/ + SUBSAMPLED = SUBSAMPLED_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_fragment_density_map)]), + ]),*/ /* TODO: enable // TODO: document - MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED = MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXT { - device_extensions: [ext_multisampled_render_to_single_sampled], - },*/ + MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED = MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_multisampled_render_to_single_sampled)]), + ]),*/ /* TODO: enable // TODO: document - TYPE_2D_VIEW_COMPATIBLE = TYPE_2D_VIEW_COMPATIBLE_EXT { - device_extensions: [ext_image_2d_view_of_3d], - },*/ + TYPE_2D_VIEW_COMPATIBLE = TYPE_2D_VIEW_COMPATIBLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_image_2d_view_of_3d)]), + ]),*/ /* TODO: enable // TODO: document - FRAGMENT_DENSITY_MAP_OFFSET = FRAGMENT_DENSITY_MAP_OFFSET_QCOM { - device_extensions: [qcom_fragment_density_map_offset], - },*/ + FRAGMENT_DENSITY_MAP_OFFSET = FRAGMENT_DENSITY_MAP_OFFSET_QCOM + RequiresOneOf([ + RequiresAllOf([DeviceExtension(qcom_fragment_density_map_offset)]), + ]),*/ } vulkan_bitflags_enum! { @@ -373,9 +386,10 @@ vulkan_enum! { Linear = LINEAR, // TODO: document - DrmFormatModifier = DRM_FORMAT_MODIFIER_EXT { - device_extensions: [ext_image_drm_format_modifier], - }, + DrmFormatModifier = DRM_FORMAT_MODIFIER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_image_drm_format_modifier)]), + ]), } /// The dimensions of an image. @@ -909,11 +923,10 @@ impl ImageFormatInfo { problem: "`stencil_usage` is `Some`, and `format` has both a depth and a \ stencil aspect" .into(), - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_2), - device_extensions: &["ext_separate_stencil_usage"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]), + RequiresAllOf(&[Requires::DeviceExtension("ext_separate_stencil_usage")]), + ]), ..Default::default() }); } @@ -945,11 +958,12 @@ impl ImageFormatInfo { { return Err(ValidationError { problem: "`external_memory_handle_type` is `Some`".into(), - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - instance_extensions: &["khr_external_memory_capabilities"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::InstanceExtension( + "khr_external_memory_capabilities", + )]), + ]), ..Default::default() }); } @@ -967,10 +981,9 @@ impl ImageFormatInfo { if !physical_device.supported_extensions().ext_filter_cubic { return Err(ValidationError { problem: "`image_view_type` is `Some`".into(), - requires_one_of: RequiresOneOf { - device_extensions: &["ext_filter_cubic"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_filter_cubic", + )])]), ..Default::default() }); } diff --git a/vulkano/src/image/sys.rs b/vulkano/src/image/sys.rs index fcc394af31..a258e25297 100644 --- a/vulkano/src/image/sys.rs +++ b/vulkano/src/image/sys.rs @@ -36,7 +36,8 @@ use crate::{ range_map::RangeMap, swapchain::Swapchain, sync::{future::AccessError, CurrentAccess, Sharing}, - DeviceSize, RequirementNotMet, RequiresOneOf, RuntimeError, Version, VulkanObject, + DeviceSize, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, Version, + VulkanObject, }; use ash::vk::ImageDrmFormatModifierExplicitCreateInfoEXT; use parking_lot::{Mutex, MutexGuard}; @@ -178,11 +179,10 @@ impl RawImage { return Err(ImageError::RequirementNotMet { required_for: "`create_info.stencil_usage` is `Some` and `create_info.format` \ has both a depth and a stencil aspect", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_2), - device_extensions: &["ext_separate_stencil_usage"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]), + RequiresAllOf(&[Requires::DeviceExtension("ext_separate_stencil_usage")]), + ]), }); } @@ -308,10 +308,9 @@ impl RawImage { required_for: "this device is a portability subset device, \ `create_info.samples` is not `SampleCount::Sample1` and \ `create_info.dimensions.array_layers()` is greater than `1`", - requires_one_of: RequiresOneOf { - features: &["multisample_array_image"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multisample_array_image", + )])]), }); } } @@ -338,10 +337,9 @@ impl RawImage { return Err(ImageError::RequirementNotMet { required_for: "`create_info.format.ycbcr_chroma_sampling()` is `Some` and \ `create_info.dimensions.array_layers()` is greater than `1`", - requires_one_of: RequiresOneOf { - features: &["ycbcr_image_arrays"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "ycbcr_image_arrays", + )])]), }); } @@ -436,10 +434,9 @@ impl RawImage { required_for: "`create_info.usage` or `create_info.stencil_usage` contains \ `ImageUsage::STORAGE`, and `create_info.samples` is not \ `SampleCount::Sample1`", - requires_one_of: RequiresOneOf { - features: &["shader_storage_image_multisample"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "shader_storage_image_multisample", + )])]), }); } } @@ -545,10 +542,9 @@ impl RawImage { return Err(ImageError::RequirementNotMet { required_for: "this device is a portability subset device, and \ `create_info.flags` contains `ImageCreateFlags::ARRAY_2D_COMPATIBLE`", - requires_one_of: RequiresOneOf { - features: &["image_view2_d_on3_d_image"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "image_view2_d_on3_d_image", + )])]), }); } } @@ -605,11 +601,10 @@ impl RawImage { { return Err(ImageError::RequirementNotMet { required_for: "`create_info.external_memory_handle_types` is not empty", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_external_memory"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_external_memory")]), + ]), }); } @@ -3293,7 +3288,7 @@ mod tests { sys::SubresourceRangeIterator, ImageAspect, ImageAspects, ImageCreateFlags, ImageDimensions, ImageSubresourceRange, SampleCount, }, - DeviceSize, RequiresOneOf, + DeviceSize, Requires, RequiresAllOf, RequiresOneOf, }; use smallvec::SmallVec; @@ -3405,9 +3400,12 @@ mod tests { match res { Err(ImageError::RequirementNotMet { - requires_one_of: RequiresOneOf { features, .. }, + requires_one_of: + RequiresOneOf( + [RequiresAllOf([Requires::Feature("shader_storage_image_multisample")])], + ), .. - }) if features.contains(&"shader_storage_image_multisample") => (), + }) => (), Err(ImageError::SampleCountNotSupported { .. }) => (), // unlikely but possible _ => panic!(), }; diff --git a/vulkano/src/image/usage.rs b/vulkano/src/image/usage.rs index b6b223de89..e62ea0dced 100644 --- a/vulkano/src/image/usage.rs +++ b/vulkano/src/image/usage.rs @@ -51,73 +51,85 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - VIDEO_DECODE_DST = VIDEO_DECODE_DST_KHR { - device_extensions: [khr_video_decode_queue], - },*/ + VIDEO_DECODE_DST = VIDEO_DECODE_DST_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]),*/ /* TODO: enable // TODO: document - VIDEO_DECODE_SRC = VIDEO_DECODE_SRC_KHR { - device_extensions: [khr_video_decode_queue], - },*/ + VIDEO_DECODE_SRC = VIDEO_DECODE_SRC_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]),*/ /* TODO: enable // TODO: document - VIDEO_DECODE_DPB = VIDEO_DECODE_DPB_KHR { - device_extensions: [khr_video_decode_queue], - },*/ + VIDEO_DECODE_DPB = VIDEO_DECODE_DPB_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]),*/ /* TODO: enable // TODO: document - FRAGMENT_DENSITY_MAP = FRAGMENT_DENSITY_MAP_EXT { - device_extensions: [ext_fragment_density_map], - },*/ + FRAGMENT_DENSITY_MAP = FRAGMENT_DENSITY_MAP_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_fragment_density_map)]), + ]),*/ /* TODO: enable // TODO: document - FRAGMENT_SHADING_RATE_ATTACHMENT = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR { - device_extensions: [khr_fragment_shading_rate], - },*/ + FRAGMENT_SHADING_RATE_ATTACHMENT = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_fragment_shading_rate)]), + ]),*/ /* TODO: enable // TODO: document - VIDEO_ENCODE_DST = VIDEO_ENCODE_DST_KHR { - device_extensions: [khr_video_encode_queue], - },*/ + VIDEO_ENCODE_DST = VIDEO_ENCODE_DST_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]),*/ /* TODO: enable // TODO: document - VIDEO_ENCODE_SRC = VIDEO_ENCODE_SRC_KHR { - device_extensions: [khr_video_encode_queue], - },*/ + VIDEO_ENCODE_SRC = VIDEO_ENCODE_SRC_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]),*/ /* TODO: enable // TODO: document - VIDEO_ENCODE_DPB = VIDEO_ENCODE_DPB_KHR { - device_extensions: [khr_video_encode_queue], - },*/ + VIDEO_ENCODE_DPB = VIDEO_ENCODE_DPB_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]),*/ /* TODO: enable // TODO: document - ATTACHMENT_FEEDBACK_LOOP = ATTACHMENT_FEEDBACK_LOOP_EXT { - device_extensions: [ext_attachment_feedback_loop_layout], - },*/ + ATTACHMENT_FEEDBACK_LOOP = ATTACHMENT_FEEDBACK_LOOP_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_attachment_feedback_loop_layout)]), + ]),*/ /* TODO: enable // TODO: document - INVOCATION_MASK = INVOCATION_MASK_HUAWEI { - device_extensions: [huawei_invocation_mask], - },*/ + INVOCATION_MASK = INVOCATION_MASK_HUAWEI + RequiresOneOf([ + RequiresAllOf([DeviceExtension(huawei_invocation_mask)]), + ]),*/ /* TODO: enable // TODO: document - SAMPLE_WEIGHT = SAMPLE_WEIGHT_QCOM { - device_extensions: [qcom_image_processing], - },*/ + SAMPLE_WEIGHT = SAMPLE_WEIGHT_QCOM + RequiresOneOf([ + RequiresAllOf([DeviceExtension(qcom_image_processing)]), + ]),*/ /* TODO: enable // TODO: document - SAMPLE_BLOCK_MATCH = SAMPLE_BLOCK_MATCH_QCOM { - device_extensions: [qcom_image_processing], - },*/ + SAMPLE_BLOCK_MATCH = SAMPLE_BLOCK_MATCH_QCOM + RequiresOneOf([ + RequiresAllOf([DeviceExtension(qcom_image_processing)]), + ]),*/ } diff --git a/vulkano/src/image/view.rs b/vulkano/src/image/view.rs index 45552e6a7d..ac17568129 100644 --- a/vulkano/src/image/view.rs +++ b/vulkano/src/image/view.rs @@ -22,7 +22,8 @@ use crate::{ image::{ImageAspects, ImageCreateFlags, ImageTiling, ImageType, SampleCount}, macros::{impl_id_counter, vulkan_enum}, sampler::{ycbcr::SamplerYcbcrConversion, ComponentMapping}, - OomError, RequirementNotMet, RequiresOneOf, RuntimeError, Version, VulkanObject, + OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, Version, + VulkanObject, }; use std::{ error::Error, @@ -206,10 +207,9 @@ where if view_type == ImageViewType::CubeArray && !device.enabled_features().image_cube_array { return Err(ImageViewCreationError::RequirementNotMet { required_for: "`create_info.viewtype` is `ImageViewType::CubeArray`", - requires_one_of: RequiresOneOf { - features: &["image_cube_array"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "image_cube_array", + )])]), }); } @@ -279,11 +279,10 @@ where { return Err(ImageViewCreationError::RequirementNotMet { required_for: "`create_info.usage` is not the default value", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_maintenance2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_maintenance2")]), + ]), }); } @@ -383,10 +382,9 @@ where required_for: "this device is a portability subset device, and the format of \ the image view does not have the same components and number of bits per \ component as the parent image", - requires_one_of: RequiresOneOf { - features: &["image_view_format_reinterpretation"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "image_view_format_reinterpretation", + )])]), }); } @@ -467,10 +465,9 @@ where return Err(ImageViewCreationError::RequirementNotMet { required_for: "this device is a portability subset device, and \ `create_info.component_mapping` is not the identity mapping", - requires_one_of: RequiresOneOf { - features: &["image_view_format_swizzle"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "image_view_format_swizzle", + )])]), }); } diff --git a/vulkano/src/instance/debug.rs b/vulkano/src/instance/debug.rs index 5f16543ede..df3edf092e 100644 --- a/vulkano/src/instance/debug.rs +++ b/vulkano/src/instance/debug.rs @@ -44,7 +44,8 @@ use super::{Instance, InstanceExtensions}; use crate::{ macros::{vulkan_bitflags, vulkan_enum}, - RequiresOneOf, RuntimeError, ValidationError, Version, VulkanError, VulkanObject, + Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, Version, VulkanError, + VulkanObject, }; use std::{ ffi::{c_void, CStr}, @@ -92,10 +93,9 @@ impl DebugUtilsMessenger { ) -> Result<(), ValidationError> { if !instance.enabled_extensions().ext_debug_utils { return Err(ValidationError { - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_debug_utils"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ext_debug_utils", + )])]), ..Default::default() }); } diff --git a/vulkano/src/instance/mod.rs b/vulkano/src/instance/mod.rs index 473aa0e211..589308d88f 100644 --- a/vulkano/src/instance/mod.rs +++ b/vulkano/src/instance/mod.rs @@ -90,7 +90,8 @@ use crate::{ }, instance::debug::trampoline, macros::{impl_id_counter, vulkan_bitflags}, - RequiresOneOf, RuntimeError, ValidationError, VulkanError, VulkanLibrary, VulkanObject, + Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, VulkanError, + VulkanLibrary, VulkanObject, }; pub use crate::{fns::InstanceFunctions, version::Version}; use parking_lot::RwLock; @@ -284,6 +285,7 @@ impl RefUnwindSafe for Instance {} impl Instance { /// Creates a new `Instance`. + #[inline] pub fn new( library: Arc, create_info: InstanceCreateInfo, @@ -372,10 +374,9 @@ impl Instance { return Err(ValidationError { context: "debug_utils_messengers".into(), problem: "is not empty".into(), - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_debug_utils"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::InstanceExtension("ext_debug_utils"), + ])]), vuids: &["VUID-VkInstanceCreateInfo-pNext-04926"], }); } @@ -412,6 +413,17 @@ impl Instance { Version::HEADER_VERSION } }); + create_info.enabled_extensions.enable_dependencies( + std::cmp::min( + create_info.max_api_version.unwrap_or_default(), + library.api_version(), + ), + &library + .supported_extensions_with_layers( + create_info.enabled_layers.iter().map(String::as_str), + ) + .unwrap(), + ); let &InstanceCreateInfo { mut flags, @@ -665,6 +677,9 @@ impl Instance { } /// Returns the extensions that have been enabled on the instance. + /// + /// This includes both the extensions specified in [`InstanceCreateInfo::enabled_extensions`], + /// and any extensions that are required by those extensions. #[inline] pub fn enabled_extensions(&self) -> &InstanceExtensions { &self.enabled_extensions @@ -763,11 +778,10 @@ impl Instance { || self.enabled_extensions().khr_device_group_creation) { return Err(ValidationError { - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - instance_extensions: &["khr_device_group_creation"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::InstanceExtension("khr_device_group_creation")]), + ]), ..Default::default() }); } @@ -988,6 +1002,9 @@ pub struct InstanceCreateInfo { /// The extensions to enable on the instance. /// + /// You only need to enable the extensions that you need. If the extensions you specified + /// require additional extensions to be enabled, they will be automatically enabled as well. + /// /// The default value is [`InstanceExtensions::empty()`]. pub enabled_extensions: InstanceExtensions, @@ -1088,10 +1105,9 @@ impl InstanceCreateInfo { return Err(ValidationError { context: "enabled_validation_features".into(), problem: "is not empty".into(), - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_validation_features"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::InstanceExtension("ext_validation_features"), + ])]), ..Default::default() }); } @@ -1142,10 +1158,9 @@ impl InstanceCreateInfo { return Err(ValidationError { context: "disabled_validation_features".into(), problem: "is not empty".into(), - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_validation_features"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::InstanceExtension("ext_validation_features"), + ])]), ..Default::default() }); } diff --git a/vulkano/src/lib.rs b/vulkano/src/lib.rs index cf0174f609..2af801f1b5 100644 --- a/vulkano/src/lib.rs +++ b/vulkano/src/lib.rs @@ -425,9 +425,9 @@ impl Display for ValidationError { if !self.requires_one_of.is_empty() { if self.problem.is_empty() { - write!(f, "{}", self.requires_one_of)?; + write!(f, "requires one of: {}", self.requires_one_of)?; } else { - write!(f, " -- {}", self.requires_one_of)?; + write!(f, " -- requires one of: {}", self.requires_one_of)?; } } @@ -449,115 +449,85 @@ impl Error for ValidationError {} /// Used in errors to indicate a set of alternatives that needs to be available/enabled to allow /// a given operation. -#[derive(Clone, Copy, Default, PartialEq, Eq)] -pub struct RequiresOneOf { - /// A minimum Vulkan API version that would allow the operation. - pub api_version: Option, - - /// Enabled features that would allow the operation. - pub features: &'static [&'static str], - - /// Available/enabled device extensions that would allow the operation. - pub device_extensions: &'static [&'static str], - - /// Available/enabled instance extensions that would allow the operation. - pub instance_extensions: &'static [&'static str], -} +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct RequiresOneOf(pub &'static [RequiresAllOf]); impl RequiresOneOf { - /// Returns whether there is more than one possible requirement. + /// Returns the number of alternatives. pub fn len(&self) -> usize { - self.api_version.map_or(0, |_| 1) - + self.features.len() - + self.device_extensions.len() - + self.instance_extensions.len() + self.0.len() } - /// Returns whether there are any requirements. + /// Returns whether there are any alternatives. pub fn is_empty(&self) -> bool { - self.api_version.is_none() - && self.features.is_empty() - && self.device_extensions.is_empty() - && self.instance_extensions.is_empty() + self.0.is_empty() } } -impl Debug for RequiresOneOf { +impl Display for RequiresOneOf { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "Requires one of:")?; - - if let Some(Version { major, minor, .. }) = self.api_version { - write!(f, "\n Vulkan API version {}.{}", major, minor)?; - } - - for feature in self.features { - write!(f, "\n The `{}` feature", feature)?; - } - - for extension in self.device_extensions { - write!(f, "\n The `{}` device extension", extension)?; - } + if let Some((first, rest)) = self.0.split_first() { + if first.0.len() > 1 { + write!(f, "({})", first)?; + } else { + write!(f, "{}", first)?; + } - for extension in self.instance_extensions { - write!(f, "\n The `{}` instance extension", extension)?; + for rest in rest { + if first.0.len() > 1 { + write!(f, "or ({})", rest)?; + } else { + write!(f, " or {}", rest)?; + } + } } Ok(()) } } -impl Display for RequiresOneOf { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "requires one of: ")?; - - let mut written = false; - - if let Some(Version { major, minor, .. }) = self.api_version { - write!(f, "Vulkan API version {}.{}", major, minor)?; - written = true; - } - - if let Some((first, rest)) = self.features.split_first() { - if written { - write!(f, ", ")?; - } +/// Used in errors to indicate a set of requirements that all need to be available/enabled to allow +/// a given operation. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct RequiresAllOf(pub &'static [Requires]); - write!(f, "feature `{}`", first)?; +impl Display for RequiresAllOf { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + if let Some((first, rest)) = self.0.split_first() { + write!(f, "{}", first)?; - for feature in rest { - write!(f, ", feature `{}`", feature)?; + for rest in rest { + write!(f, " + {}", rest)?; } - - written = true; } - if let Some((first, rest)) = self.device_extensions.split_first() { - if written { - write!(f, ", ")?; - } + Ok(()) + } +} - write!(f, "device extension `{}`", first)?; +/// Something that needs to be supported or enabled to allow a particular operation. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Requires { + APIVersion(Version), + Feature(&'static str), + DeviceExtension(&'static str), + InstanceExtension(&'static str), +} - for extension in rest { - write!(f, ", device extension `{}`", extension)?; +impl Display for Requires { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Requires::APIVersion(Version { major, minor, .. }) => { + write!(f, "Vulkan API version {}.{}", major, minor) } - - written = true; - } - - if let Some((first, rest)) = self.instance_extensions.split_first() { - if written { - write!(f, ", ")?; + Requires::Feature(feature) => write!(f, "feature `{}`", feature), + Requires::DeviceExtension(device_extension) => { + write!(f, "device extension `{}`", device_extension) } - - write!(f, "instance extension `{}`", first)?; - - for extension in rest { - write!(f, ", instance extension `{}`", extension)?; + Requires::InstanceExtension(instance_extension) => { + write!(f, "instance extension `{}`", instance_extension) } } - - Ok(()) } } diff --git a/vulkano/src/macros.rs b/vulkano/src/macros.rs index e889315fe4..dccb9ad9c9 100644 --- a/vulkano/src/macros.rs +++ b/vulkano/src/macros.rs @@ -236,12 +236,14 @@ macro_rules! vulkan_bitflags { $( $(#[doc = $flag_doc:literal])* $flag_name:ident = $flag_name_ffi:ident - $({ - $(api_version: $api_version:ident,)? - $(features: [$($feature:ident),+ $(,)?],)? - $(device_extensions: [$($device_extension:ident),+ $(,)?],)? - $(instance_extensions: [$($instance_extension:ident),+ $(,)?],)? - })? + $(RequiresOneOf([ + $(RequiresAllOf([ + $(APIVersion($api_version:ident) $(,)?)? + $($(Feature($feature:ident)),+ $(,)?)? + $($(DeviceExtension($device_extension:ident)),+ $(,)?)? + $($(InstanceExtension($instance_extension:ident)),+ $(,)?)? + ])),+ $(,)? + ]))? , )* } => { @@ -362,28 +364,39 @@ macro_rules! vulkan_bitflags { $( $( if self.intersects(Self::$flag_name) && ![ - $( - device_api_version >= crate::Version::$api_version, - )? - $($( - device_features.$feature, - )+)? - $($( - device_extensions.$device_extension, - )+)? - $($( - instance_extensions.$instance_extension, - )+)? + $([ + $( + device_api_version >= crate::Version::$api_version, + )? + $($( + device_features.$feature, + )+)? + $($( + device_extensions.$device_extension, + )+)? + $($( + instance_extensions.$instance_extension, + )+)? + ].into_iter().all(|x| x)),* ].into_iter().any(|x| x) { return Err(crate::RequirementNotMet { required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"), - requires_one_of: crate::RequiresOneOf { - $(api_version: Some(crate::Version::$api_version),)? - $(features: &[$(stringify!($feature)),+],)? - $(device_extensions: &[$(stringify!($device_extension)),+],)? - $(instance_extensions: &[$(stringify!($instance_extension)),+],)? - ..Default::default() - }, + requires_one_of: crate::RequiresOneOf(&[ + $(crate::RequiresAllOf(&[ + $( + crate::Requires::APIVersion(crate::Version::$api_version), + )? + $($( + crate::Requires::Feature(stringify!($feature)), + )+)? + $($( + crate::Requires::DeviceExtension(stringify!($device_extension)), + )+)? + $($( + crate::Requires::InstanceExtension(stringify!($instance_extension)), + )+)? + ])),* + ]), }); } )? @@ -413,20 +426,27 @@ macro_rules! vulkan_bitflags { $( $( if self.intersects(Self::$flag_name) && ![ - $( - instance_api_version >= crate::Version::$api_version, - )? - $($( - instance_extensions.$instance_extension, - )+)? + $([ + $( + instance_api_version >= crate::Version::$api_version, + )? + $($( + instance_extensions.$instance_extension, + )+)? + ].into_iter().all(|x| x)),* ].into_iter().any(|x| x) { return Err(crate::RequirementNotMet { required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"), - requires_one_of: crate::RequiresOneOf { - $(api_version: Some(crate::Version::$api_version),)? - $(instance_extensions: &[$(stringify!($instance_extension)),+],)? - ..Default::default() - }, + requires_one_of: crate::RequiresOneOf(&[ + $(crate::RequiresAllOf(&[ + $( + crate::Requires::APIVersion(crate::Version::$api_version), + )? + $($( + crate::Requires::InstanceExtension(stringify!($instance_extension)), + )+)? + ])),* + ]), }); } )? @@ -610,12 +630,14 @@ macro_rules! vulkan_enum { $( $(#[doc = $flag_doc:literal])* $flag_name:ident = $flag_name_ffi:ident - $({ - $(api_version: $api_version:ident,)? - $(features: [$($feature:ident),+ $(,)?],)? - $(device_extensions: [$($device_extension:ident),+ $(,)?],)? - $(instance_extensions: [$($instance_extension:ident),+ $(,)?],)? - })? + $(RequiresOneOf([ + $(RequiresAllOf([ + $(APIVersion($api_version:ident) $(,)?)? + $($(Feature($feature:ident)),+ $(,)?)? + $($(DeviceExtension($device_extension:ident)),+ $(,)?)? + $($(InstanceExtension($instance_extension:ident)),+ $(,)?)? + ])),+ $(,)? + ]))? , )+ } => { @@ -639,8 +661,8 @@ macro_rules! vulkan_enum { ) -> Result<(), crate::RequirementNotMet> { self.validate_device_raw( device.api_version(), - device.enabled_extensions(), device.enabled_features(), + device.enabled_extensions(), device.instance().enabled_extensions(), ) } @@ -653,8 +675,8 @@ macro_rules! vulkan_enum { ) -> Result<(), crate::RequirementNotMet> { self.validate_device_raw( physical_device.api_version(), - physical_device.supported_extensions(), physical_device.supported_features(), + physical_device.supported_extensions(), physical_device.instance().enabled_extensions(), ) } @@ -663,8 +685,8 @@ macro_rules! vulkan_enum { pub(crate) fn validate_device_raw( self, #[allow(unused_variables)] device_api_version: crate::Version, - #[allow(unused_variables)] device_extensions: &crate::device::DeviceExtensions, #[allow(unused_variables)] device_features: &crate::device::Features, + #[allow(unused_variables)] device_extensions: &crate::device::DeviceExtensions, #[allow(unused_variables)] instance_extensions: &crate::instance::InstanceExtensions, ) -> Result<(), crate::RequirementNotMet> { match self { @@ -672,28 +694,39 @@ macro_rules! vulkan_enum { $( Self::$flag_name => { if ![ - $( - device_api_version >= crate::Version::$api_version, - )? - $($( - device_features.$feature, - )+)? - $($( - device_extensions.$device_extension, - )+)? - $($( - instance_extensions.$instance_extension, - )+)? + $([ + $( + device_api_version >= crate::Version::$api_version, + )? + $($( + device_features.$feature, + )+)? + $($( + device_extensions.$device_extension, + )+)? + $($( + instance_extensions.$instance_extension, + )+)? + ].into_iter().all(|x| x)),* ].into_iter().any(|x| x) { return Err(crate::RequirementNotMet { required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"), - requires_one_of: crate::RequiresOneOf { - $(api_version: Some(crate::Version::$api_version),)? - $(features: &[$(stringify!($feature)),+],)? - $(device_extensions: &[$(stringify!($device_extension)),+],)? - $(instance_extensions: &[$(stringify!($instance_extension)),+],)? - ..Default::default() - }, + requires_one_of: crate::RequiresOneOf(&[ + $(crate::RequiresAllOf(&[ + $( + crate::Requires::APIVersion(crate::Version::$api_version), + )? + $($( + crate::Requires::Feature(stringify!($feature)), + )+)? + $($( + crate::Requires::DeviceExtension(stringify!($device_extension)), + )+)? + $($( + crate::Requires::InstanceExtension(stringify!($instance_extension)), + )+)? + ])),* + ]), }); } }, @@ -728,20 +761,27 @@ macro_rules! vulkan_enum { $( Self::$flag_name => { if ![ - $( - instance_api_version >= crate::Version::$api_version, - )? - $($( - instance_extensions.$instance_extension, - )+)? + $([ + $( + instance_api_version >= crate::Version::$api_version, + )? + $($( + instance_extensions.$instance_extension, + )+)? + ].into_iter().all(|x| x)),* ].into_iter().any(|x| x) { return Err(crate::RequirementNotMet { required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"), - requires_one_of: crate::RequiresOneOf { - $(api_version: Some(crate::Version::$api_version),)? - $(instance_extensions: &[$(stringify!($instance_extension)),+],)? - ..Default::default() - }, + requires_one_of: crate::RequiresOneOf(&[ + $(crate::RequiresAllOf(&[ + $( + crate::Requires::APIVersion(crate::Version::$api_version), + )? + $($( + crate::Requires::InstanceExtension(stringify!($instance_extension)), + )+)? + ])),* + ]), }); } }, @@ -800,12 +840,14 @@ macro_rules! vulkan_bitflags_enum { $( $(#[doc = $flag_doc:literal])* $flag_name_bitflags:ident, $flag_name_enum:ident = $flag_name_ffi:ident - $({ - $(api_version: $api_version:ident,)? - $(features: [$($feature:ident),+ $(,)?],)? - $(device_extensions: [$($device_extension:ident),+ $(,)?],)? - $(instance_extensions: [$($instance_extension:ident),+ $(,)?],)? - })? + $(RequiresOneOf([ + $(RequiresAllOf([ + $(APIVersion($api_version:ident) $(,)?)? + $($(Feature($feature:ident)),+ $(,)?)? + $($(DeviceExtension($device_extension:ident)),+ $(,)?)? + $($(InstanceExtension($instance_extension:ident)),+ $(,)?)? + ])),+ $(,)? + ]))? , )* } => { @@ -828,12 +870,14 @@ macro_rules! vulkan_bitflags_enum { $( $(#[doc = $flag_doc])* $flag_name_bitflags = $flag_name_ffi - $({ - $(api_version: $api_version,)? - $(features: [$($feature),+],)? - $(device_extensions: [$($device_extension),+],)? - $(instance_extensions: [$($instance_extension),+],)? - })? + $(RequiresOneOf([ + $(RequiresAllOf([ + $(APIVersion($api_version) ,)? + $($(Feature($feature)),+ ,)? + $($(DeviceExtension($device_extension)),+ ,)? + $($(InstanceExtension($instance_extension)),+ ,)? + ])),+ , + ]))? , )* } @@ -849,12 +893,14 @@ macro_rules! vulkan_bitflags_enum { $( $(#[doc = $flag_doc])* $flag_name_enum = $flag_name_ffi - $({ - $(api_version: $api_version,)? - $(features: [$($feature),+],)? - $(device_extensions: [$($device_extension),+],)? - $(instance_extensions: [$($instance_extension),+],)? - })? + $(RequiresOneOf([ + $(RequiresAllOf([ + $(APIVersion($api_version) ,)? + $($(Feature($feature)),+ ,)? + $($(DeviceExtension($device_extension)),+ ,)? + $($(InstanceExtension($instance_extension)),+ ,)? + ])),+ , + ]))? , )* } diff --git a/vulkano/src/memory/allocator/mod.rs b/vulkano/src/memory/allocator/mod.rs index b9619d5b2c..b65e04a2b1 100644 --- a/vulkano/src/memory/allocator/mod.rs +++ b/vulkano/src/memory/allocator/mod.rs @@ -234,7 +234,7 @@ use super::{ }; use crate::{ device::{Device, DeviceOwned}, - DeviceSize, RequirementNotMet, RequiresOneOf, RuntimeError, Version, + DeviceSize, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, Version, }; use ash::vk::{MAX_MEMORY_HEAPS, MAX_MEMORY_TYPES}; use parking_lot::RwLock; @@ -728,11 +728,10 @@ impl GenericMemoryAllocator { { return Err(GenericMemoryAllocatorCreationError::RequirementNotMet { required_for: "`create_info.export_handle_types` is not empty", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_external_memory"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_external_memory")]), + ]), }); } diff --git a/vulkano/src/memory/device_memory.rs b/vulkano/src/memory/device_memory.rs index 4c1c9bd96c..62c46a6e1f 100644 --- a/vulkano/src/memory/device_memory.rs +++ b/vulkano/src/memory/device_memory.rs @@ -12,7 +12,8 @@ use crate::{ device::{Device, DeviceOwned}, macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum}, memory::{is_aligned, MemoryPropertyFlags}, - DeviceSize, OomError, RequirementNotMet, RequiresOneOf, RuntimeError, Version, VulkanObject, + DeviceSize, OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, + Version, VulkanObject, }; use std::{ error::Error, @@ -182,10 +183,9 @@ impl DeviceMemory { return Err(DeviceMemoryError::RequirementNotMet { required_for: "`allocate_info.memory_type_index` refers to a memory type where \ `property_flags` contains `MemoryPropertyFlags::PROTECTED`", - requires_one_of: RequiresOneOf { - features: &["protected_memory"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "protected_memory", + )])]), }); } @@ -210,10 +210,9 @@ impl DeviceMemory { return Err(DeviceMemoryError::RequirementNotMet { required_for: "`allocate_info.memory_type_index` refers to a memory type where \ `property_flags` contains `MemoryPropertyFlags::DEVICE_COHERENT`", - requires_one_of: RequiresOneOf { - features: &["device_coherent_memory"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "device_coherent_memory", + )])]), }); } @@ -256,11 +255,10 @@ impl DeviceMemory { { return Err(DeviceMemoryError::RequirementNotMet { required_for: "`allocate_info.export_handle_types` is not empty", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_external_memory"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_external_memory")]), + ]), }); } @@ -287,10 +285,9 @@ impl DeviceMemory { return Err(DeviceMemoryError::RequirementNotMet { required_for: "`allocate_info.import_info` is \ `Some(MemoryImportInfo::Fd)`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_external_memory_fd"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::DeviceExtension("khr_external_memory_fd"), + ])]), }); } @@ -339,10 +336,9 @@ impl DeviceMemory { return Err(DeviceMemoryError::RequirementNotMet { required_for: "`allocate_info.import_info` is \ `Some(MemoryImportInfo::Win32)`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_external_memory_win32"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::DeviceExtension("khr_external_memory_win32"), + ])]), }); } @@ -389,11 +385,10 @@ impl DeviceMemory { { return Err(DeviceMemoryError::RequirementNotMet { required_for: "`allocate_info.flags` is not empty", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_device_group"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_device_group")]), + ]), }); } @@ -403,10 +398,9 @@ impl DeviceMemory { return Err(DeviceMemoryError::RequirementNotMet { required_for: "`allocate_info.flags` contains \ `MemoryAllocateFlags::DEVICE_ADDRESS`", - requires_one_of: RequiresOneOf { - features: &["buffer_device_address"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "buffer_device_address", + )])]), }); } @@ -414,11 +408,10 @@ impl DeviceMemory { return Err(DeviceMemoryError::RequirementNotMet { required_for: "`allocate_info.flags` contains \ `MemoryAllocateFlags::DEVICE_ADDRESS`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_2), - device_extensions: &["khr_buffer_device_address"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_buffer_device_address")]), + ]), }); } } @@ -902,34 +895,40 @@ vulkan_bitflags_enum! { D3D12_RESOURCE, D3D12Resource = D3D12_RESOURCE, /// A POSIX file descriptor handle that refers to a Linux dma-buf. - DMA_BUF, DmaBuf = DMA_BUF_EXT { - device_extensions: [ext_external_memory_dma_buf], - }, + DMA_BUF, DmaBuf = DMA_BUF_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_external_memory_dma_buf)]), + ]), /// A handle for an Android `AHardwareBuffer` object. - ANDROID_HARDWARE_BUFFER, AndroidHardwareBuffer = ANDROID_HARDWARE_BUFFER_ANDROID { - device_extensions: [android_external_memory_android_hardware_buffer], - }, + ANDROID_HARDWARE_BUFFER, AndroidHardwareBuffer = ANDROID_HARDWARE_BUFFER_ANDROID + RequiresOneOf([ + RequiresAllOf([DeviceExtension(android_external_memory_android_hardware_buffer)]), + ]), /// A pointer to memory that was allocated by the host. - HOST_ALLOCATION, HostAllocation = HOST_ALLOCATION_EXT { - device_extensions: [ext_external_memory_host], - }, + HOST_ALLOCATION, HostAllocation = HOST_ALLOCATION_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_external_memory_host)]), + ]), /// A pointer to a memory mapping on the host that maps non-host memory. - HOST_MAPPED_FOREIGN_MEMORY, HostMappedForeignMemory = HOST_MAPPED_FOREIGN_MEMORY_EXT { - device_extensions: [ext_external_memory_host], - }, + HOST_MAPPED_FOREIGN_MEMORY, HostMappedForeignMemory = HOST_MAPPED_FOREIGN_MEMORY_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_external_memory_host)]), + ]), /// A Zircon handle to a virtual memory object. - ZIRCON_VMO, ZirconVmo = ZIRCON_VMO_FUCHSIA { - device_extensions: [fuchsia_external_memory], - }, + ZIRCON_VMO, ZirconVmo = ZIRCON_VMO_FUCHSIA + RequiresOneOf([ + RequiresAllOf([DeviceExtension(fuchsia_external_memory)]), + ]), /// A Remote Direct Memory Address handle to an allocation that is accessible by remote devices. - RDMA_ADDRESS, RdmaAddress = RDMA_ADDRESS_NV { - device_extensions: [nv_external_memory_rdma], - }, + RDMA_ADDRESS, RdmaAddress = RDMA_ADDRESS_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_external_memory_rdma)]), + ]), } vulkan_bitflags! { diff --git a/vulkano/src/memory/mod.rs b/vulkano/src/memory/mod.rs index 94b6a1ae3e..d3a2eae7a7 100644 --- a/vulkano/src/memory/mod.rs +++ b/vulkano/src/memory/mod.rs @@ -246,32 +246,36 @@ vulkan_bitflags! { /// [`HOST_VISIBLE`]: MemoryPropertyFlags::HOST_VISIBLE /// [`HOST_COHERENT`]: MemoryPropertyFlags::HOST_COHERENT /// [`HOST_CACHED`]: MemoryPropertyFlags::HOST_CACHED - PROTECTED = PROTECTED { - api_version: V1_1, - }, + PROTECTED = PROTECTED + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + ]), /// Device accesses to the memory are automatically made available and visible to other device /// accesses. /// /// Memory of this type is slower to access by the device, so it is best avoided for general /// purpose use. Because of its coherence properties, however, it may be useful for debugging. - DEVICE_COHERENT = DEVICE_COHERENT_AMD { - device_extensions: [amd_device_coherent_memory], - }, + DEVICE_COHERENT = DEVICE_COHERENT_AMD + RequiresOneOf([ + RequiresAllOf([DeviceExtension(amd_device_coherent_memory)]), + ]), /// The memory is not cached on the device. /// /// `DEVICE_UNCACHED` memory is always also [`DEVICE_COHERENT`]. /// /// [`DEVICE_COHERENT`]: MemoryPropertyFlags::DEVICE_COHERENT - DEVICE_UNCACHED = DEVICE_UNCACHED_AMD { - device_extensions: [amd_device_coherent_memory], - }, + DEVICE_UNCACHED = DEVICE_UNCACHED_AMD + RequiresOneOf([ + RequiresAllOf([DeviceExtension(amd_device_coherent_memory)]), + ]), /// Other devices can access the memory via remote direct memory access (RDMA). - RDMA_CAPABLE = RDMA_CAPABLE_NV { - device_extensions: [nv_external_memory_rdma], - }, + RDMA_CAPABLE = RDMA_CAPABLE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_external_memory_rdma)]), + ]), } /// A memory heap in a physical device. @@ -296,10 +300,11 @@ vulkan_bitflags! { /// If used on a logical device that represents more than one physical device, allocations are /// replicated across each physical device's instance of this heap. - MULTI_INSTANCE = MULTI_INSTANCE { - api_version: V1_1, - instance_extensions: [khr_device_group_creation], - }, + MULTI_INSTANCE = MULTI_INSTANCE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([InstanceExtension(khr_device_group_creation)]), + ]), } /// Represents requirements expressed by the Vulkan implementation when it comes to binding memory diff --git a/vulkano/src/pipeline/graphics/color_blend.rs b/vulkano/src/pipeline/graphics/color_blend.rs index bb2761f070..a5814a08b0 100644 --- a/vulkano/src/pipeline/graphics/color_blend.rs +++ b/vulkano/src/pipeline/graphics/color_blend.rs @@ -424,279 +424,325 @@ vulkan_enum! { /* TODO: enable // TODO: document - Zero = ZERO_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Zero = ZERO_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Src = SRC_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Src = SRC_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Dst = DST_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Dst = DST_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - SrcOver = SRC_OVER_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + SrcOver = SRC_OVER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - DstOver = DST_OVER_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + DstOver = DST_OVER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - SrcIn = SRC_IN_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + SrcIn = SRC_IN_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - DstIn = DST_IN_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + DstIn = DST_IN_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - SrcOut = SRC_OUT_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + SrcOut = SRC_OUT_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - DstOut = DST_OUT_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + DstOut = DST_OUT_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - SrcAtop = SRC_ATOP_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + SrcAtop = SRC_ATOP_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - DstAtop = DST_ATOP_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + DstAtop = DST_ATOP_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Xor = XOR_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Xor = XOR_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Multiply = MULTIPLY_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Multiply = MULTIPLY_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Screen = SCREEN_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Screen = SCREEN_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Overlay = OVERLAY_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Overlay = OVERLAY_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Darken = DARKEN_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Darken = DARKEN_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Lighten = LIGHTEN_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Lighten = LIGHTEN_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Colordodge = COLORDODGE_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Colordodge = COLORDODGE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Colorburn = COLORBURN_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Colorburn = COLORBURN_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Hardlight = HARDLIGHT_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Hardlight = HARDLIGHT_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Softlight = SOFTLIGHT_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Softlight = SOFTLIGHT_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Difference = DIFFERENCE_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Difference = DIFFERENCE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Exclusion = EXCLUSION_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Exclusion = EXCLUSION_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Invert = INVERT_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Invert = INVERT_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - InvertRgb = INVERT_RGB_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + InvertRgb = INVERT_RGB_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Lineardodge = LINEARDODGE_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Lineardodge = LINEARDODGE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Linearburn = LINEARBURN_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Linearburn = LINEARBURN_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Vividlight = VIVIDLIGHT_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Vividlight = VIVIDLIGHT_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Linearlight = LINEARLIGHT_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Linearlight = LINEARLIGHT_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Pinlight = PINLIGHT_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Pinlight = PINLIGHT_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Hardmix = HARDMIX_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Hardmix = HARDMIX_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - HslHue = HSL_HUE_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + HslHue = HSL_HUE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - HslSaturation = HSL_SATURATION_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + HslSaturation = HSL_SATURATION_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - HslColor = HSL_COLOR_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + HslColor = HSL_COLOR_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - HslLuminosity = HSL_LUMINOSITY_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + HslLuminosity = HSL_LUMINOSITY_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Plus = PLUS_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Plus = PLUS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - PlusClamped = PLUS_CLAMPED_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + PlusClamped = PLUS_CLAMPED_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - PlusClampedAlpha = PLUS_CLAMPED_ALPHA_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + PlusClampedAlpha = PLUS_CLAMPED_ALPHA_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - PlusDarker = PLUS_DARKER_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + PlusDarker = PLUS_DARKER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Minus = MINUS_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Minus = MINUS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - MinusClamped = MINUS_CLAMPED_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + MinusClamped = MINUS_CLAMPED_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Contrast = CONTRAST_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Contrast = CONTRAST_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - InvertOvg = INVERT_OVG_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + InvertOvg = INVERT_OVG_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Red = RED_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Red = RED_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Green = GREEN_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Green = GREEN_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ /* TODO: enable // TODO: document - Blue = BLUE_EXT { - device_extensions: [ext_blend_operation_advanced], - },*/ + Blue = BLUE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]),*/ } vulkan_bitflags! { diff --git a/vulkano/src/pipeline/graphics/mod.rs b/vulkano/src/pipeline/graphics/mod.rs index d1c8c9cd16..2029cb7dc7 100644 --- a/vulkano/src/pipeline/graphics/mod.rs +++ b/vulkano/src/pipeline/graphics/mod.rs @@ -95,7 +95,8 @@ use crate::{ PipelineShaderStageCreateInfo, ShaderExecution, ShaderInterfaceMismatchError, ShaderScalarType, ShaderStage, ShaderStages, SpecializationConstant, }, - DeviceSize, OomError, RequirementNotMet, RequiresOneOf, RuntimeError, Version, VulkanObject, + DeviceSize, OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, + Version, VulkanObject, }; use ahash::HashMap; use smallvec::SmallVec; @@ -579,10 +580,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`stages` contains a `TessellationControl` or \ `TessellationEvaluation` shader stage", - requires_one_of: RequiresOneOf { - features: &["tessellation_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "tessellation_shader", + )])]), }); } @@ -594,10 +594,9 @@ impl GraphicsPipeline { if !device.enabled_features().geometry_shader { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`stages` contains a `Geometry` shader stage", - requires_one_of: RequiresOneOf { - features: &["geometry_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "geometry_shader", + )])]), }); } @@ -754,10 +753,9 @@ impl GraphicsPipeline { required_for: "`vertex_input_state.bindings` has an element \ where `input_rate` is `VertexInputRate::Instance`, where \ `divisor` is not `1`", - requires_one_of: RequiresOneOf { - features: &["vertex_attribute_instance_rate_divisor"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("vertex_attribute_instance_rate_divisor"), + ])]), }); } @@ -771,10 +769,11 @@ impl GraphicsPipeline { required_for: "`vertex_input_state.bindings` has an element \ where `input_rate` is `VertexInputRate::Instance`, where \ `divisor` is `0`", - requires_one_of: RequiresOneOf { - features: &["vertex_attribute_instance_rate_zero_divisor"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature( + "vertex_attribute_instance_rate_zero_divisor", + ), + ])]), }); } @@ -881,10 +880,9 @@ impl GraphicsPipeline { `vertex_input_state.attributes` has an element where \ `offset + format.block_size()` is greater than the `stride` of \ `binding`", - requires_one_of: RequiresOneOf { - features: &["vertex_attribute_access_beyond_stride"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "vertex_attribute_access_beyond_stride", + )])]), }); } } @@ -911,10 +909,9 @@ impl GraphicsPipeline { required_for: "this device is a portability subset \ device, and `input_assembly_state.topology` is \ `StateMode::Fixed(PrimitiveTopology::TriangleFan)`", - requires_one_of: RequiresOneOf { - features: &["triangle_fans"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("triangle_fans"), + ])]), }); } } @@ -927,10 +924,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`input_assembly_state.topology` is \ `StateMode::Fixed(PrimitiveTopology::*WithAdjacency)`", - requires_one_of: RequiresOneOf { - features: &["geometry_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("geometry_shader"), + ])]), }); } } @@ -940,10 +936,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`input_assembly_state.topology` is \ `StateMode::Fixed(PrimitiveTopology::PatchList)`", - requires_one_of: RequiresOneOf { - features: &["tessellation_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("tessellation_shader"), + ])]), }); } @@ -964,11 +959,10 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`input_assembly_state.topology` is \ `PartialStateMode::Dynamic`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } } @@ -993,10 +987,9 @@ impl GraphicsPipeline { is `StateMode::Fixed(true)` and \ `input_assembly_state.topology` is \ `StateMode::Fixed(PrimitiveTopology::*List)`", - requires_one_of: RequiresOneOf { - features: &["primitive_topology_list_restart"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("primitive_topology_list_restart"), + ])]), }); } } @@ -1012,10 +1005,11 @@ impl GraphicsPipeline { is `StateMode::Fixed(true)` and \ `input_assembly_state.topology` is \ `StateMode::Fixed(PrimitiveTopology::PatchList)`", - requires_one_of: RequiresOneOf { - features: &["primitive_topology_patch_list_restart"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature( + "primitive_topology_patch_list_restart", + ), + ])]), }); } } @@ -1031,11 +1025,10 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`input_assembly_state.primitive_restart_enable` is \ `StateMode::Dynamic`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state2")]), + ]), }); } } @@ -1066,10 +1059,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`tessellation_state.patch_control_points` is \ `StateMode::Dynamic`", - requires_one_of: RequiresOneOf { - features: &["extended_dynamic_state2_patch_control_points"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "extended_dynamic_state2_patch_control_points", + )])]), }); } } @@ -1085,11 +1077,10 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`tessellation_state.domain_origin` is not \ `TessellationDomainOrigin::UpperLeft`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_maintenance2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_maintenance2")]), + ]), }); } } @@ -1160,11 +1151,10 @@ impl GraphicsPipeline { required_for: "`viewport_state` is \ `ViewportState::FixedViewport`, where `scissor_count_dynamic` \ is set", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -1194,11 +1184,10 @@ impl GraphicsPipeline { required_for: "`viewport_state` is \ `ViewportState::FixedScissor`, where `viewport_count_dynamic` \ is set", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -1234,11 +1223,10 @@ impl GraphicsPipeline { required_for: "`viewport_state` is \ `ViewportState::Dynamic`, where `viewport_count_dynamic` \ is set", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -1257,11 +1245,10 @@ impl GraphicsPipeline { required_for: "`viewport_state` is \ `ViewportState::Dynamic`, where `scissor_count_dynamic` \ is set", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -1286,10 +1273,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`viewport_state` has a fixed viewport/scissor count that is \ greater than `1`", - requires_one_of: RequiresOneOf { - features: &["multi_viewport"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multi_viewport", + )])]), }); } @@ -1327,10 +1313,9 @@ impl GraphicsPipeline { if depth_clamp_enable && !device.enabled_features().depth_clamp { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`rasterization_state.depth_clamp_enable` is set", - requires_one_of: RequiresOneOf { - features: &["depth_clamp"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "depth_clamp", + )])]), }); } @@ -1343,11 +1328,10 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`rasterization_state.rasterizer_discard_enable` is \ `StateMode::Dynamic`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } } @@ -1362,10 +1346,9 @@ impl GraphicsPipeline { `rasterization_state.rasterizer_discard_enable` is \ `StateMode::Fixed(false)` and \ `rasterization_state.polygon_mode` is `PolygonMode::Point`", - requires_one_of: RequiresOneOf { - features: &["point_polygons"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "point_polygons", + )])]), }); } } @@ -1377,10 +1360,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`rasterization_state.polygon_mode` is not \ `PolygonMode::Fill`", - requires_one_of: RequiresOneOf { - features: &["fill_mode_non_solid"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "fill_mode_non_solid", + )])]), }); } @@ -1397,11 +1379,10 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`rasterization_state.cull_mode` is \ `StateMode::Dynamic`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } } @@ -1420,11 +1401,10 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`rasterization_state.front_face` is \ `StateMode::Dynamic`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } } @@ -1445,11 +1425,10 @@ impl GraphicsPipeline { required_for: "`rasterization_state.depth_bias` is \ `Some(depth_bias_state)`, where `depth_bias_state.enable_dynamic` \ is set", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state2")]), + ]), }); } @@ -1461,10 +1440,9 @@ impl GraphicsPipeline { required_for: "`rasterization_state.depth_bias` is \ `Some(depth_bias_state)`, where `depth_bias_state.bias` is \ `StateMode::Fixed(bias)`, where `bias.clamp` is not `0.0`", - requires_one_of: RequiresOneOf { - features: &["depth_bias_clamp"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "depth_bias_clamp", + )])]), }); } } @@ -1476,10 +1454,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`rasterization_state.line_width` is \ `StateMode::Fixed(line_width)`, where `line_width` is not `1.0`", - requires_one_of: RequiresOneOf { - features: &["wide_lines"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "wide_lines", + )])]), }); } @@ -1495,10 +1472,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`rasterization_state.line_rasterization_mode` \ is `LineRasterizationMode::Rectangular`", - requires_one_of: RequiresOneOf { - features: &["rectangular_lines"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("rectangular_lines"), + ])]), }); } } @@ -1508,10 +1484,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`rasterization_state.line_rasterization_mode` \ is `LineRasterizationMode::Bresenham`", - requires_one_of: RequiresOneOf { - features: &["bresenham_lines"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("bresenham_lines"), + ])]), }); } } @@ -1521,10 +1496,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`rasterization_state.line_rasterization_mode` \ is `LineRasterizationMode::RectangularSmooth`", - requires_one_of: RequiresOneOf { - features: &["smooth_lines"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("smooth_lines"), + ])]), }); } } @@ -1540,10 +1514,9 @@ impl GraphicsPipeline { `Some` and \ `rasterization_state.line_rasterization_mode` \ is `LineRasterizationMode::Default`", - requires_one_of: RequiresOneOf { - features: &["stippled_rectangular_lines"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("stippled_rectangular_lines"), + ])]), }); } @@ -1560,10 +1533,9 @@ impl GraphicsPipeline { `Some` and \ `rasterization_state.line_rasterization_mode` \ is `LineRasterizationMode::Rectangular`", - requires_one_of: RequiresOneOf { - features: &["stippled_rectangular_lines"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("stippled_rectangular_lines"), + ])]), }); } } @@ -1575,10 +1547,9 @@ impl GraphicsPipeline { `Some` and \ `rasterization_state.line_rasterization_mode` \ is `LineRasterizationMode::Bresenham`", - requires_one_of: RequiresOneOf { - features: &["stippled_bresenham_lines"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("stippled_bresenham_lines"), + ])]), }); } } @@ -1590,10 +1561,9 @@ impl GraphicsPipeline { `Some` and \ `rasterization_state.line_rasterization_mode` \ is `LineRasterizationMode::RectangularSmooth`", - requires_one_of: RequiresOneOf { - features: &["stippled_smooth_lines"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("stippled_smooth_lines"), + ])]), }); } } @@ -1610,20 +1580,18 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`rasterization_state.line_rasterization_mode` is not \ `LineRasterizationMode::Default`", - requires_one_of: RequiresOneOf { - device_extensions: &["ext_line_rasterization"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::DeviceExtension("ext_line_rasterization"), + ])]), }); } if line_stipple.is_some() { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`rasterization_state.line_stipple` is `Some`", - requires_one_of: RequiresOneOf { - device_extensions: &["ext_line_rasterization"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::DeviceExtension("ext_line_rasterization"), + ])]), }); } } @@ -1652,10 +1620,9 @@ impl GraphicsPipeline { if !device.enabled_features().sample_rate_shading { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`multisample_state.sample_shading` is `Some`", - requires_one_of: RequiresOneOf { - features: &["sample_rate_shading"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "sample_rate_shading", + )])]), }); } @@ -1668,10 +1635,9 @@ impl GraphicsPipeline { if alpha_to_one_enable && !device.enabled_features().alpha_to_one { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`multisample_state.alpha_to_one_enable` is set", - requires_one_of: RequiresOneOf { - features: &["alpha_to_one"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "alpha_to_one", + )])]), }); } @@ -1701,11 +1667,10 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`depth_stencil_state.depth` is `Some(depth_state)`, where \ `depth_state.enable_dynamic` is set", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -1720,11 +1685,10 @@ impl GraphicsPipeline { required_for: "`depth_stencil_state.depth` is \ `Some(depth_state)`, where `depth_state.write_enable` is \ `StateMode::Dynamic`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } } @@ -1744,11 +1708,10 @@ impl GraphicsPipeline { required_for: "`depth_stencil_state.depth` is \ `Some(depth_state)`, where `depth_state.compare_op` is \ `StateMode::Dynamic`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } } @@ -1765,10 +1728,9 @@ impl GraphicsPipeline { if !device.enabled_features().depth_bounds { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`depth_stencil_state.depth_bounds` is `Some`", - requires_one_of: RequiresOneOf { - features: &["depth_bounds"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "depth_bounds", + )])]), }); } @@ -1781,11 +1743,10 @@ impl GraphicsPipeline { required_for: "`depth_stencil_state.depth_bounds` is \ `Some(depth_bounds_state)`, where `depth_bounds_state.enable_dynamic` \ is set", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -1799,10 +1760,9 @@ impl GraphicsPipeline { required_for: "`depth_stencil_state.depth_bounds` is \ `Some(depth_bounds_state)`, where `depth_bounds_state.bounds` is \ not between `0.0` and `1.0` inclusive", - requires_one_of: RequiresOneOf { - device_extensions: &["ext_depth_range_unrestricted"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::DeviceExtension("ext_depth_range_unrestricted"), + ])]), }); } } @@ -1823,11 +1783,10 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`depth_stencil_state.stencil` is `Some(stencil_state)`, \ where `stencil_state.enable_dynamic` is set", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } @@ -1863,11 +1822,10 @@ impl GraphicsPipeline { required_for: "`depth_stencil_state.stencil` is \ `Some(stencil_state)`, where `stencil_state.front.ops` and \ `stencil_state.back.ops` are `StateMode::Dynamic`", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_3), - features: &["extended_dynamic_state"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), }); } } @@ -1915,10 +1873,9 @@ impl GraphicsPipeline { if !device.enabled_features().logic_op { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`color_blend_state.logic_op` is `Some`", - requires_one_of: RequiresOneOf { - features: &["logic_op"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "logic_op", + )])]), }); } @@ -1933,10 +1890,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`color_blend_state.logic_op` is \ `Some(StateMode::Dynamic)`", - requires_one_of: RequiresOneOf { - features: &["extended_dynamic_state2_logic_op"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("extended_dynamic_state2_logic_op"), + ])]), }); } } @@ -1955,10 +1911,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`color_blend_state.attachments` has elements where \ `blend` and `color_write_mask` do not match the other elements", - requires_one_of: RequiresOneOf { - features: &["independent_blend"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "independent_blend", + )])]), }); } } @@ -2022,10 +1977,9 @@ impl GraphicsPipeline { `blend` is `Some(blend)`, where `blend.color_source`, \ `blend.color_destination`, `blend.alpha_source` or \ `blend.alpha_destination` is `BlendFactor::Src1*`", - requires_one_of: RequiresOneOf { - features: &["dual_src_blend"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "dual_src_blend", + )])]), }); } @@ -2048,10 +2002,9 @@ impl GraphicsPipeline { `blend.color_source` or `blend.color_destination` is \ `BlendFactor::ConstantAlpha` or \ `BlendFactor::OneMinusConstantAlpha`", - requires_one_of: RequiresOneOf { - features: &["constant_alpha_color_blend_factors"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "constant_alpha_color_blend_factors", + )])]), }); } } @@ -2063,10 +2016,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`color_blend_state.attachments` has an element \ where `color_write_enable` is `StateMode::Fixed(false)`", - requires_one_of: RequiresOneOf { - features: &["color_write_enable"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("color_write_enable"), + ])]), }); } } @@ -2076,10 +2028,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`color_blend_state.attachments` has an element \ where `color_write_enable` is `StateMode::Dynamic`", - requires_one_of: RequiresOneOf { - features: &["color_write_enable"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("color_write_enable"), + ])]), }); } } @@ -2104,10 +2055,9 @@ impl GraphicsPipeline { required_for: "`tessellation_shaders` are provided and `render_pass` has a \ subpass where `view_mask` is not `0`", - requires_one_of: RequiresOneOf { - features: &["multiview_tessellation_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("multiview_tessellation_shader"), + ])]), }); } @@ -2119,10 +2069,9 @@ impl GraphicsPipeline { required_for: "`geometry_shader` is provided and `render_pass` has a \ subpass where `view_mask` is not `0`", - requires_one_of: RequiresOneOf { - features: &["multiview_geometry_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("multiview_geometry_shader"), + ])]), }); } } @@ -2141,10 +2090,9 @@ impl GraphicsPipeline { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`render_pass` is `PipelineRenderPassType::BeginRendering`", - requires_one_of: RequiresOneOf { - features: &["dynamic_rendering"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "dynamic_rendering", + )])]), }); } @@ -2154,10 +2102,9 @@ impl GraphicsPipeline { required_for: "`render_pass` is `PipelineRenderPassType::BeginRendering` \ where `view_mask` is not `0`", - requires_one_of: RequiresOneOf { - features: &["multiview"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multiview", + )])]), }); } @@ -2267,10 +2214,9 @@ impl GraphicsPipeline { required_for: "`tessellation_shaders` are provided and `render_pass` has a \ subpass where `view_mask` is not `0`", - requires_one_of: RequiresOneOf { - features: &["multiview_tessellation_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("multiview_tessellation_shader"), + ])]), }); } @@ -2282,10 +2228,9 @@ impl GraphicsPipeline { required_for: "`geometry_shader` is provided and `render_pass` has a \ subpass where `view_mask` is not `0`", - requires_one_of: RequiresOneOf { - features: &["multiview_geometry_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("multiview_geometry_shader"), + ])]), }); } } @@ -2297,10 +2242,9 @@ impl GraphicsPipeline { if !device.enabled_extensions().ext_discard_rectangles { return Err(GraphicsPipelineCreationError::RequirementNotMet { required_for: "`discard_rectangle_state` is `Some`", - requires_one_of: RequiresOneOf { - device_extensions: &["ext_discard_rectangles"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_discard_rectangles", + )])]), }); } @@ -2473,10 +2417,9 @@ impl GraphicsPipeline { `depth_stencil_state.stencil` is `Some(stencil_state)`, \ where `stencil_state.front.reference` does not equal \ `stencil_state.back.reference`", - requires_one_of: RequiresOneOf { - features: &["separate_stencil_mask_ref"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "separate_stencil_mask_ref", + )])]), }); } } diff --git a/vulkano/src/pipeline/graphics/rasterization.rs b/vulkano/src/pipeline/graphics/rasterization.rs index 185110adff..7ab586698e 100644 --- a/vulkano/src/pipeline/graphics/rasterization.rs +++ b/vulkano/src/pipeline/graphics/rasterization.rs @@ -250,9 +250,10 @@ vulkan_enum! { /* TODO: enable // TODO: document - FillRectangle = FILL_RECTANGLE_NV { - device_extensions: [nv_fill_rectangle], - },*/ + FillRectangle = FILL_RECTANGLE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_fill_rectangle)]), + ]),*/ } impl Default for PolygonMode { diff --git a/vulkano/src/pipeline/layout.rs b/vulkano/src/pipeline/layout.rs index 0e1d72b7fe..cbe092516e 100644 --- a/vulkano/src/pipeline/layout.rs +++ b/vulkano/src/pipeline/layout.rs @@ -757,9 +757,10 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - INDEPENDENT_SETS = INDEPENDENT_SETS_EXT { - device_extensions: [ext_graphics_pipeline_library], - }, */ + INDEPENDENT_SETS = INDEPENDENT_SETS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_graphics_pipeline_library)]), + ]), */ } /// Description of a range of the push constants of a pipeline layout. diff --git a/vulkano/src/pipeline/mod.rs b/vulkano/src/pipeline/mod.rs index e0c89ffba3..8f3fcad093 100644 --- a/vulkano/src/pipeline/mod.rs +++ b/vulkano/src/pipeline/mod.rs @@ -68,15 +68,18 @@ vulkan_enum! { /* TODO: enable // TODO: document - RayTracing = RAY_TRACING_KHR { - device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing], - },*/ + RayTracing = RAY_TRACING_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]),*/ /* TODO: enable // TODO: document - SubpassShading = SUBPASS_SHADING_HUAWEI { - device_extensions: [huawei_subpass_shading], - },*/ + SubpassShading = SUBPASS_SHADING_HUAWEI + RequiresOneOf([ + RequiresAllOf([DeviceExtension(huawei_subpass_shading)]), + ]),*/ } vulkan_bitflags! { @@ -98,31 +101,35 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - VIEW_INDEX_FROM_DEVICE_INDEX = VIEW_INDEX_FROM_DEVICE_INDEX { - api_version: V1_1, - device_extensions: [khr_device_group], - },*/ + VIEW_INDEX_FROM_DEVICE_INDEX = VIEW_INDEX_FROM_DEVICE_INDEX + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_device_group)]), + ]),*/ /* TODO: enable // TODO: document - DISPATCH_BASE = DISPATCH_BASE { - api_version: V1_1, - device_extensions: [khr_device_group], - },*/ + DISPATCH_BASE = DISPATCH_BASE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_device_group)]), + ]),*/ /* TODO: enable // TODO: document - FAIL_ON_PIPELINE_COMPILE_REQUIRED = FAIL_ON_PIPELINE_COMPILE_REQUIRED { - api_version: V1_3, - device_extensions: [ext_pipeline_creation_cache_control], - },*/ + FAIL_ON_PIPELINE_COMPILE_REQUIRED = FAIL_ON_PIPELINE_COMPILE_REQUIRED + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_pipeline_creation_cache_control)]), + ]),*/ /* TODO: enable // TODO: document - EARLY_RETURN_ON_FAILURE = EARLY_RETURN_ON_FAILURE { - api_version: V1_3, - device_extensions: [ext_pipeline_creation_cache_control], - }, + EARLY_RETURN_ON_FAILURE = EARLY_RETURN_ON_FAILURE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_pipeline_creation_cache_control)]), + ]), */ /* TODO: enable @@ -139,57 +146,66 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - RAY_TRACING_NO_NULL_ANY_HIT_SHADERS = RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_KHR { - device_extensions: [khr_ray_tracing_pipeline], - },*/ + RAY_TRACING_NO_NULL_ANY_HIT_SHADERS = RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + ]),*/ /* TODO: enable // TODO: document - RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS = RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_KHR { - device_extensions: [khr_ray_tracing_pipeline], - },*/ + RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS = RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + ]),*/ /* TODO: enable // TODO: document - RAY_TRACING_NO_NULL_MISS_SHADERS = RAY_TRACING_NO_NULL_MISS_SHADERS_KHR { - device_extensions: [khr_ray_tracing_pipeline], - },*/ + RAY_TRACING_NO_NULL_MISS_SHADERS = RAY_TRACING_NO_NULL_MISS_SHADERS_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + ]),*/ /* TODO: enable // TODO: document - RAY_TRACING_NO_NULL_INTERSECTION_SHADERS = RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_KHR { - device_extensions: [khr_ray_tracing_pipeline], - },*/ + RAY_TRACING_NO_NULL_INTERSECTION_SHADERS = RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + ]),*/ /* TODO: enable // TODO: document - RAY_TRACING_SKIP_TRIANGLES = RAY_TRACING_SKIP_TRIANGLES_KHR { - device_extensions: [khr_ray_tracing_pipeline], - },*/ + RAY_TRACING_SKIP_TRIANGLES = RAY_TRACING_SKIP_TRIANGLES_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + ]),*/ /* TODO: enable // TODO: document - RAY_TRACING_SKIP_AABBS = RAY_TRACING_SKIP_AABBS_KHR { - device_extensions: [khr_ray_tracing_pipeline], - },*/ + RAY_TRACING_SKIP_AABBS = RAY_TRACING_SKIP_AABBS_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + ]),*/ /* TODO: enable // TODO: document - RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY = RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_KHR { - device_extensions: [khr_ray_tracing_pipeline], - },*/ + RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY = RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + ]),*/ /* TODO: enable // TODO: document - DEFER_COMPILE = DEFER_COMPILE_NV { - device_extensions: [nv_ray_tracing], - },*/ + DEFER_COMPILE = DEFER_COMPILE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]),*/ /* TODO: enable // TODO: document - CAPTURE_STATISTICS = CAPTURE_STATISTICS_KHR { - device_extensions: [khr_pipeline_executable_properties], - },*/ + CAPTURE_STATISTICS = CAPTURE_STATISTICS_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_pipeline_executable_properties)]), + ]),*/ /* TODO: enable // TODO: document @@ -205,69 +221,80 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - LIBRARY = LIBRARY_KHR { - device_extensions: [khr_pipeline_library], - },*/ + LIBRARY = LIBRARY_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_pipeline_library)]), + ]),*/ /* TODO: enable // TODO: document - DESCRIPTOR_BUFFER = DESCRIPTOR_BUFFER_EXT { - device_extensions: [ext_descriptor_buffer], - },*/ + DESCRIPTOR_BUFFER = DESCRIPTOR_BUFFER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_descriptor_buffer)]), + ]),*/ /* TODO: enable // TODO: document - RETAIN_LINK_TIME_OPTIMIZATION_INFO = RETAIN_LINK_TIME_OPTIMIZATION_INFO_EXT { - device_extensions: [ext_graphics_pipeline_library], - },*/ + RETAIN_LINK_TIME_OPTIMIZATION_INFO = RETAIN_LINK_TIME_OPTIMIZATION_INFO_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_graphics_pipeline_library)]), + ]),*/ /* TODO: enable // TODO: document - LINK_TIME_OPTIMIZATION = LINK_TIME_OPTIMIZATION_EXT { - device_extensions: [ext_graphics_pipeline_library], - },*/ + LINK_TIME_OPTIMIZATION = LINK_TIME_OPTIMIZATION_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_graphics_pipeline_library)]), + ]),*/ /* TODO: enable // TODO: document - RAY_TRACING_ALLOW_MOTION = RAY_TRACING_ALLOW_MOTION_NV { - device_extensions: [nv_ray_tracing_motion_blur], - },*/ + RAY_TRACING_ALLOW_MOTION = RAY_TRACING_ALLOW_MOTION_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_ray_tracing_motion_blur)]), + ]),*/ /* TODO: enable // TODO: document - COLOR_ATTACHMENT_FEEDBACK_LOOP = COLOR_ATTACHMENT_FEEDBACK_LOOP_EXT { - device_extensions: [ext_attachment_feedback_loop_layout], - },*/ + COLOR_ATTACHMENT_FEEDBACK_LOOP = COLOR_ATTACHMENT_FEEDBACK_LOOP_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_attachment_feedback_loop_layout)]), + ]),*/ /* TODO: enable // TODO: document - DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP = DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_EXT { - device_extensions: [ext_attachment_feedback_loop_layout], - },*/ + DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP = DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_attachment_feedback_loop_layout)]), + ]),*/ /* TODO: enable // TODO: document - RAY_TRACING_OPACITY_MICROMAP = RAY_TRACING_OPACITY_MICROMAP_EXT { - device_extensions: [ext_opacity_micromap], - },*/ + RAY_TRACING_OPACITY_MICROMAP = RAY_TRACING_OPACITY_MICROMAP_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_opacity_micromap)]), + ]),*/ /* TODO: enable // TODO: document - RAY_TRACING_DISPLACEMENT_MICROMAP = RAY_TRACING_DISPLACEMENT_MICROMAP_NV { - device_extensions: [nv_displacement_micromap], - },*/ + RAY_TRACING_DISPLACEMENT_MICROMAP = RAY_TRACING_DISPLACEMENT_MICROMAP_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_displacement_micromap)]), + ]),*/ /* TODO: enable // TODO: document - NO_PROTECTED_ACCESS = NO_PROTECTED_ACCESS_EXT { - device_extensions: [ext_pipeline_protected_access], - },*/ + NO_PROTECTED_ACCESS = NO_PROTECTED_ACCESS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_pipeline_protected_access)]), + ]),*/ /* TODO: enable // TODO: document - PROTECTED_ACCESS_ONLY = PROTECTED_ACCESS_ONLY_EXT { - device_extensions: [ext_pipeline_protected_access], - },*/ + PROTECTED_ACCESS_ONLY = PROTECTED_ACCESS_ONLY_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_pipeline_protected_access)]), + ]),*/ } vulkan_enum! { @@ -305,314 +332,373 @@ vulkan_enum! { StencilReference = STENCIL_REFERENCE, // TODO: document - CullMode = CULL_MODE { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + CullMode = CULL_MODE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - FrontFace = FRONT_FACE { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + FrontFace = FRONT_FACE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - PrimitiveTopology = PRIMITIVE_TOPOLOGY { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + PrimitiveTopology = PRIMITIVE_TOPOLOGY + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - ViewportWithCount = VIEWPORT_WITH_COUNT { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + ViewportWithCount = VIEWPORT_WITH_COUNT + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - ScissorWithCount = SCISSOR_WITH_COUNT { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + ScissorWithCount = SCISSOR_WITH_COUNT + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - VertexInputBindingStride = VERTEX_INPUT_BINDING_STRIDE { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + VertexInputBindingStride = VERTEX_INPUT_BINDING_STRIDE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - DepthTestEnable = DEPTH_TEST_ENABLE { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + DepthTestEnable = DEPTH_TEST_ENABLE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - DepthWriteEnable = DEPTH_WRITE_ENABLE { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + DepthWriteEnable = DEPTH_WRITE_ENABLE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - DepthCompareOp = DEPTH_COMPARE_OP { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + DepthCompareOp = DEPTH_COMPARE_OP + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - DepthBoundsTestEnable = DEPTH_BOUNDS_TEST_ENABLE { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + DepthBoundsTestEnable = DEPTH_BOUNDS_TEST_ENABLE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - StencilTestEnable = STENCIL_TEST_ENABLE { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + StencilTestEnable = STENCIL_TEST_ENABLE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - StencilOp = STENCIL_OP { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state], - }, + StencilOp = STENCIL_OP + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state)]), + ]), // TODO: document - RasterizerDiscardEnable = RASTERIZER_DISCARD_ENABLE { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state2], - }, + RasterizerDiscardEnable = RASTERIZER_DISCARD_ENABLE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state2)]), + ]), // TODO: document - DepthBiasEnable = DEPTH_BIAS_ENABLE { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state2], - }, + DepthBiasEnable = DEPTH_BIAS_ENABLE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state2)]), + ]), // TODO: document - PrimitiveRestartEnable = PRIMITIVE_RESTART_ENABLE { - api_version: V1_3, - device_extensions: [ext_extended_dynamic_state2], - }, + PrimitiveRestartEnable = PRIMITIVE_RESTART_ENABLE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state2)]), + ]), // TODO: document - ViewportWScaling = VIEWPORT_W_SCALING_NV { - device_extensions: [nv_clip_space_w_scaling], - }, + ViewportWScaling = VIEWPORT_W_SCALING_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_clip_space_w_scaling)]), + ]), // TODO: document - DiscardRectangle = DISCARD_RECTANGLE_EXT { - device_extensions: [ext_discard_rectangles], - }, + DiscardRectangle = DISCARD_RECTANGLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_discard_rectangles)]), + ]), // TODO: document - SampleLocations = SAMPLE_LOCATIONS_EXT { - device_extensions: [ext_sample_locations], - }, + SampleLocations = SAMPLE_LOCATIONS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_sample_locations)]), + ]), // TODO: document - RayTracingPipelineStackSize = RAY_TRACING_PIPELINE_STACK_SIZE_KHR { - device_extensions: [khr_ray_tracing_pipeline], - }, + RayTracingPipelineStackSize = RAY_TRACING_PIPELINE_STACK_SIZE_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + ]), // TODO: document - ViewportShadingRatePalette = VIEWPORT_SHADING_RATE_PALETTE_NV { - device_extensions: [nv_shading_rate_image], - }, + ViewportShadingRatePalette = VIEWPORT_SHADING_RATE_PALETTE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_shading_rate_image)]), + ]), // TODO: document - ViewportCoarseSampleOrder = VIEWPORT_COARSE_SAMPLE_ORDER_NV { - device_extensions: [nv_shading_rate_image], - }, + ViewportCoarseSampleOrder = VIEWPORT_COARSE_SAMPLE_ORDER_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_shading_rate_image)]), + ]), // TODO: document - ExclusiveScissor = EXCLUSIVE_SCISSOR_NV { - device_extensions: [nv_scissor_exclusive], - }, + ExclusiveScissor = EXCLUSIVE_SCISSOR_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_scissor_exclusive)]), + ]), // TODO: document - FragmentShadingRate = FRAGMENT_SHADING_RATE_KHR { - device_extensions: [khr_fragment_shading_rate], - }, + FragmentShadingRate = FRAGMENT_SHADING_RATE_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_fragment_shading_rate)]), + ]), // TODO: document - LineStipple = LINE_STIPPLE_EXT { - device_extensions: [ext_line_rasterization], - }, + LineStipple = LINE_STIPPLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_line_rasterization)]), + ]), // TODO: document - VertexInput = VERTEX_INPUT_EXT { - device_extensions: [ext_vertex_input_dynamic_state], - }, + VertexInput = VERTEX_INPUT_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_vertex_input_dynamic_state)]), + ]), // TODO: document - PatchControlPoints = PATCH_CONTROL_POINTS_EXT { - device_extensions: [ext_extended_dynamic_state2], - }, + PatchControlPoints = PATCH_CONTROL_POINTS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state2)]), + ]), // TODO: document - LogicOp = LOGIC_OP_EXT { - device_extensions: [ext_extended_dynamic_state2], - }, + LogicOp = LOGIC_OP_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state2)]), + ]), // TODO: document - ColorWriteEnable = COLOR_WRITE_ENABLE_EXT { - device_extensions: [ext_color_write_enable], - }, + ColorWriteEnable = COLOR_WRITE_ENABLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_color_write_enable)]), + ]), // TODO: document - TessellationDomainOrigin = TESSELLATION_DOMAIN_ORIGIN_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + TessellationDomainOrigin = TESSELLATION_DOMAIN_ORIGIN_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - DepthClampEnable = DEPTH_CLAMP_ENABLE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + DepthClampEnable = DEPTH_CLAMP_ENABLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - PolygonMode = POLYGON_MODE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + PolygonMode = POLYGON_MODE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - RasterizationSamples = RASTERIZATION_SAMPLES_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + RasterizationSamples = RASTERIZATION_SAMPLES_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - SampleMask = SAMPLE_MASK_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + SampleMask = SAMPLE_MASK_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - AlphaToCoverageEnable = ALPHA_TO_COVERAGE_ENABLE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + AlphaToCoverageEnable = ALPHA_TO_COVERAGE_ENABLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - AlphaToOneEnable = ALPHA_TO_ONE_ENABLE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + AlphaToOneEnable = ALPHA_TO_ONE_ENABLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - LogicOpEnable = LOGIC_OP_ENABLE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + LogicOpEnable = LOGIC_OP_ENABLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - ColorBlendEnable = COLOR_BLEND_ENABLE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + ColorBlendEnable = COLOR_BLEND_ENABLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - ColorBlendEquation = COLOR_BLEND_EQUATION_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + ColorBlendEquation = COLOR_BLEND_EQUATION_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - ColorWriteMask = COLOR_WRITE_MASK_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + ColorWriteMask = COLOR_WRITE_MASK_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - RasterizationStream = RASTERIZATION_STREAM_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + RasterizationStream = RASTERIZATION_STREAM_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - ConservativeRasterizationMode = CONSERVATIVE_RASTERIZATION_MODE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + ConservativeRasterizationMode = CONSERVATIVE_RASTERIZATION_MODE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - ExtraPrimitiveOverestimationSize = EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + ExtraPrimitiveOverestimationSize = EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - DepthClipEnable = DEPTH_CLIP_ENABLE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + DepthClipEnable = DEPTH_CLIP_ENABLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - SampleLocationsEnable = SAMPLE_LOCATIONS_ENABLE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + SampleLocationsEnable = SAMPLE_LOCATIONS_ENABLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - ColorBlendAdvanced = COLOR_BLEND_ADVANCED_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + ColorBlendAdvanced = COLOR_BLEND_ADVANCED_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - ProvokingVertexMode = PROVOKING_VERTEX_MODE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + ProvokingVertexMode = PROVOKING_VERTEX_MODE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - LineRasterizationMode = LINE_RASTERIZATION_MODE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + LineRasterizationMode = LINE_RASTERIZATION_MODE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - LineStippleEnable = LINE_STIPPLE_ENABLE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + LineStippleEnable = LINE_STIPPLE_ENABLE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - DepthClipNegativeOneToOne = DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT { - device_extensions: [ext_extended_dynamic_state3], - }, + DepthClipNegativeOneToOne = DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - ViewportWScalingEnable = VIEWPORT_W_SCALING_ENABLE_NV { - device_extensions: [ext_extended_dynamic_state3], - }, + ViewportWScalingEnable = VIEWPORT_W_SCALING_ENABLE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - ViewportSwizzle = VIEWPORT_SWIZZLE_NV { - device_extensions: [ext_extended_dynamic_state3], - }, + ViewportSwizzle = VIEWPORT_SWIZZLE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - CoverageToColorEnable = COVERAGE_TO_COLOR_ENABLE_NV { - device_extensions: [ext_extended_dynamic_state3], - }, + CoverageToColorEnable = COVERAGE_TO_COLOR_ENABLE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - CoverageToColorLocation = COVERAGE_TO_COLOR_LOCATION_NV { - device_extensions: [ext_extended_dynamic_state3], - }, + CoverageToColorLocation = COVERAGE_TO_COLOR_LOCATION_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - CoverageModulationMode = COVERAGE_MODULATION_MODE_NV { - device_extensions: [ext_extended_dynamic_state3], - }, + CoverageModulationMode = COVERAGE_MODULATION_MODE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - CoverageModulationTableEnable = COVERAGE_MODULATION_TABLE_ENABLE_NV { - device_extensions: [ext_extended_dynamic_state3], - }, + CoverageModulationTableEnable = COVERAGE_MODULATION_TABLE_ENABLE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - CoverageModulationTable = COVERAGE_MODULATION_TABLE_NV { - device_extensions: [ext_extended_dynamic_state3], - }, + CoverageModulationTable = COVERAGE_MODULATION_TABLE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - ShadingRateImageEnable = SHADING_RATE_IMAGE_ENABLE_NV { - device_extensions: [ext_extended_dynamic_state3], - }, + ShadingRateImageEnable = SHADING_RATE_IMAGE_ENABLE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - RepresentativeFragmentTestEnable = REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV { - device_extensions: [ext_extended_dynamic_state3], - }, + RepresentativeFragmentTestEnable = REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), // TODO: document - CoverageReductionMode = COVERAGE_REDUCTION_MODE_NV { - device_extensions: [ext_extended_dynamic_state3], - }, + CoverageReductionMode = COVERAGE_REDUCTION_MODE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_extended_dynamic_state3)]), + ]), } /// Specifies how a dynamic state is handled by a graphics pipeline. diff --git a/vulkano/src/query.rs b/vulkano/src/query.rs index 2cd8f24bf8..21cb86add5 100644 --- a/vulkano/src/query.rs +++ b/vulkano/src/query.rs @@ -17,7 +17,8 @@ use crate::{ buffer::BufferContents, device::{Device, DeviceOwned}, macros::{impl_id_counter, vulkan_bitflags}, - DeviceSize, OomError, RequirementNotMet, RequiresOneOf, RuntimeError, VulkanObject, + DeviceSize, OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, + VulkanObject, }; use std::{ error::Error, @@ -632,10 +633,9 @@ impl QueryType { if !device.enabled_extensions().khr_acceleration_structure { return Err(crate::RequirementNotMet { required_for: "QueryType::AccelerationStructureCompactedSize", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_acceleration_structure"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::DeviceExtension("khr_acceleration_structure"), + ])]), }); } } @@ -643,10 +643,9 @@ impl QueryType { if !device.enabled_extensions().khr_acceleration_structure { return Err(crate::RequirementNotMet { required_for: "QueryType::AccelerationStructureSerializationSize", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_acceleration_structure"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::DeviceExtension("khr_acceleration_structure"), + ])]), }); } } @@ -655,10 +654,9 @@ impl QueryType { return Err(crate::RequirementNotMet { required_for: "QueryType::AccelerationStructureSerializationBottomLevelPointers", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_ray_tracing_maintenance1"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::DeviceExtension("khr_ray_tracing_maintenance1"), + ])]), }); } } @@ -666,10 +664,9 @@ impl QueryType { if !device.enabled_extensions().khr_ray_tracing_maintenance1 { return Err(crate::RequirementNotMet { required_for: "QueryType::AccelerationStructureSize", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_ray_tracing_maintenance1"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::DeviceExtension("khr_ray_tracing_maintenance1"), + ])]), }); } } @@ -779,15 +776,17 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - TASK_SHADER_INVOCATIONS = TASK_SHADER_INVOCATIONS_NV { - device_extensions: [nv_mesh_shader], - },*/ + TASK_SHADER_INVOCATIONS = TASK_SHADER_INVOCATIONS_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_mesh_shader)]), + ]),*/ /* TODO: enable // TODO: document - MESH_SHADER_INVOCATIONS = MESH_SHADER_INVOCATIONS_NV { - device_extensions: [nv_mesh_shader], - },*/ + MESH_SHADER_INVOCATIONS = MESH_SHADER_INVOCATIONS_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_mesh_shader)]), + ]),*/ } vulkan_bitflags! { @@ -814,9 +813,10 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - WITH_STATUS = WITH_STATUS_KHR { - device_extensions: [khr_video_queue], - },*/ + WITH_STATUS = WITH_STATUS_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_queue)]), + ]),*/ } #[cfg(test)] diff --git a/vulkano/src/render_pass/mod.rs b/vulkano/src/render_pass/mod.rs index 1edd5f2415..cbf112bdcb 100644 --- a/vulkano/src/render_pass/mod.rs +++ b/vulkano/src/render_pass/mod.rs @@ -33,7 +33,8 @@ use crate::{ macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum, vulkan_enum}, shader::ShaderInterface, sync::{AccessFlags, DependencyFlags, MemoryBarrier, PipelineStages}, - RequiresOneOf, RuntimeError, ValidationError, Version, VulkanError, VulkanObject, + Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, Version, VulkanError, + VulkanObject, }; use ahash::HashMap; use std::{ @@ -1450,11 +1451,13 @@ impl RenderPassCreateInfo { subpass_index, ref_index, ) .into(), - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_create_renderpass2", "khr_maintenance2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension( + "khr_create_renderpass2", + )]), + RequiresAllOf(&[Requires::DeviceExtension("khr_maintenance2")]), + ]), // vuids? ..Default::default() }); @@ -1840,10 +1843,9 @@ impl AttachmentDescription { problem: "specifies a layout for only the depth aspect or only the \ stencil aspect" .into(), - requires_one_of: RequiresOneOf { - features: &["separate_depth_stencil_layouts"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "separate_depth_stencil_layouts", + )])]), vuids: &["VUID-VkAttachmentDescription2-separateDepthStencilLayouts-03284"], }); } @@ -1860,10 +1862,9 @@ impl AttachmentDescription { problem: "specifies a layout for only the depth aspect or only the \ stencil aspect" .into(), - requires_one_of: RequiresOneOf { - features: &["separate_depth_stencil_layouts"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "separate_depth_stencil_layouts", + )])]), vuids: &["VUID-VkAttachmentDescription2-separateDepthStencilLayouts-03285"], }); } @@ -1903,10 +1904,9 @@ impl AttachmentDescription { return Err(ValidationError { context: "stencil_initial_layout".into(), problem: "is `Some`".into(), - requires_one_of: RequiresOneOf { - features: &["separate_depth_stencil_layouts"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "separate_depth_stencil_layouts", + )])]), ..Default::default() }); } @@ -1947,10 +1947,9 @@ impl AttachmentDescription { return Err(ValidationError { context: "stencil_final_layout".into(), problem: "is `Some`".into(), - requires_one_of: RequiresOneOf { - features: &["separate_depth_stencil_layouts"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "separate_depth_stencil_layouts", + )])]), ..Default::default() }); } @@ -2706,11 +2705,12 @@ impl SubpassDescription { return Err(ValidationError { context: "depth_stencil_resolve_attachment".into(), problem: "is `Some`".into(), - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_2), - device_extensions: &["khr_depth_stencil_resolve"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]), + RequiresAllOf(&[Requires::DeviceExtension( + "khr_depth_stencil_resolve", + )]), + ]), // vuids? ..Default::default() }); @@ -2998,10 +2998,7 @@ impl SubpassDescription { return Err(ValidationError { context: "view_mask".into(), problem: "is not 0".into(), - requires_one_of: RequiresOneOf { - features: &["multiview"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("multiview")])]), vuids: &["VUID-VkSubpassDescription2-multiview-06558"], }); } @@ -3184,10 +3181,9 @@ impl AttachmentReference { context: "layout".into(), problem: "specifies a layout for only the depth aspect or only the stencil aspect" .into(), - requires_one_of: RequiresOneOf { - features: &["separate_depth_stencil_layouts"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "separate_depth_stencil_layouts", + )])]), vuids: &["VUID-VkAttachmentReference2-separateDepthStencilLayouts-03313"], }); } @@ -3197,10 +3193,9 @@ impl AttachmentReference { return Err(ValidationError { context: "stencil_layout".into(), problem: "is `Some`".into(), - requires_one_of: RequiresOneOf { - features: &["separate_depth_stencil_layouts"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "separate_depth_stencil_layouts", + )])]), ..Default::default() }); } @@ -3410,11 +3405,10 @@ impl SubpassDependency { return Err(ValidationError { context: "src_stages".into(), problem: "contains flags from `VkPipelineStageFlagBits2`".into(), - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_2), - device_extensions: &["khr_create_renderpass2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_create_renderpass2")]), + ]), ..Default::default() }); } @@ -3423,11 +3417,10 @@ impl SubpassDependency { return Err(ValidationError { context: "dst_stages".into(), problem: "contains flags from `VkPipelineStageFlagBits2`".into(), - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_2), - device_extensions: &["khr_create_renderpass2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_create_renderpass2")]), + ]), ..Default::default() }); } @@ -3436,11 +3429,10 @@ impl SubpassDependency { return Err(ValidationError { context: "src_access".into(), problem: "contains flags from `VkAccessFlagBits2`".into(), - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_2), - device_extensions: &["khr_create_renderpass2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_create_renderpass2")]), + ]), ..Default::default() }); } @@ -3449,11 +3441,10 @@ impl SubpassDependency { return Err(ValidationError { context: "dst_access".into(), problem: "contains flags from `VkAccessFlagBits2`".into(), - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_2), - device_extensions: &["khr_create_renderpass2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_create_renderpass2")]), + ]), ..Default::default() }); } @@ -3464,10 +3455,9 @@ impl SubpassDependency { return Err(ValidationError { context: "src_stages".into(), problem: "is empty".into(), - requires_one_of: RequiresOneOf { - features: &["synchronization2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "synchronization2", + )])]), vuids: &["VUID-VkSubpassDependency2-srcStageMask-03937"], }); } @@ -3476,10 +3466,9 @@ impl SubpassDependency { return Err(ValidationError { context: "dst_stages".into(), problem: "is empty".into(), - requires_one_of: RequiresOneOf { - features: &["synchronization2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "synchronization2", + )])]), vuids: &["VUID-VkSubpassDependency2-dstStageMask-03937"], }); } @@ -3612,9 +3601,10 @@ vulkan_enum! { /* TODO: enable // TODO: document - None = NONE_EXT { - device_extensions: [ext_load_store_op_none], - },*/ + None = NONE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_load_store_op_none)]), + ]),*/ } vulkan_enum! { diff --git a/vulkano/src/sampler/mod.rs b/vulkano/src/sampler/mod.rs index a385e9bd93..45f5961b80 100644 --- a/vulkano/src/sampler/mod.rs +++ b/vulkano/src/sampler/mod.rs @@ -54,7 +54,8 @@ use crate::{ macros::{impl_id_counter, vulkan_enum}, pipeline::graphics::depth_stencil::CompareOp, shader::ShaderScalarType, - OomError, RequirementNotMet, RequiresOneOf, RuntimeError, ValidationError, VulkanObject, + OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, + ValidationError, VulkanObject, }; use std::{ error::Error, @@ -164,17 +165,18 @@ impl Sampler { } if address_mode.contains(&SamplerAddressMode::MirrorClampToEdge) { - if !device.enabled_features().sampler_mirror_clamp_to_edge - && !device.enabled_extensions().khr_sampler_mirror_clamp_to_edge + if !(device.enabled_features().sampler_mirror_clamp_to_edge + || device.enabled_extensions().khr_sampler_mirror_clamp_to_edge) { return Err(SamplerCreationError::RequirementNotMet { required_for: "`create_info.address_mode` contains \ `SamplerAddressMode::MirrorClampToEdge`", - requires_one_of: RequiresOneOf { - features: &["sampler_mirror_clamp_to_edge"], - device_extensions: &["khr_sampler_mirror_clamp_to_edge"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::Feature("sampler_mirror_clamp_to_edge")]), + RequiresAllOf(&[Requires::DeviceExtension( + "khr_sampler_mirror_clamp_to_edge", + )]), + ]), }); } } @@ -198,10 +200,9 @@ impl Sampler { return Err(SamplerCreationError::RequirementNotMet { required_for: "this device is a portability subset device, and \ `create_info.mip_lod_bias` is not zero", - requires_one_of: RequiresOneOf { - features: &["sampler_mip_lod_bias"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "sampler_mip_lod_bias", + )])]), }); } @@ -211,10 +212,9 @@ impl Sampler { if !device.enabled_features().sampler_anisotropy { return Err(SamplerCreationError::RequirementNotMet { required_for: "`create_info.anisotropy` is `Some`", - requires_one_of: RequiresOneOf { - features: &["sampler_anisotropy"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "sampler_anisotropy", + )])]), }); } @@ -296,32 +296,32 @@ impl Sampler { } } - let mut sampler_reduction_mode_create_info = - if reduction_mode != SamplerReductionMode::WeightedAverage { - if !(device.enabled_features().sampler_filter_minmax - || device.enabled_extensions().ext_sampler_filter_minmax) - { - return Err(SamplerCreationError::RequirementNotMet { - required_for: "`create_info.reduction_mode` is not \ + let mut sampler_reduction_mode_create_info = if reduction_mode + != SamplerReductionMode::WeightedAverage + { + if !(device.enabled_features().sampler_filter_minmax + || device.enabled_extensions().ext_sampler_filter_minmax) + { + return Err(SamplerCreationError::RequirementNotMet { + required_for: "`create_info.reduction_mode` is not \ `SamplerReductionMode::WeightedAverage`", - requires_one_of: RequiresOneOf { - features: &["sampler_filter_minmax"], - device_extensions: &["ext_sampler_filter_minmax"], - ..Default::default() - }, - }); - } + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::Feature("sampler_filter_minmax")]), + RequiresAllOf(&[Requires::DeviceExtension("ext_sampler_filter_minmax")]), + ]), + }); + } - // VUID-VkSamplerReductionModeCreateInfo-reductionMode-parameter - reduction_mode.validate_device(&device)?; + // VUID-VkSamplerReductionModeCreateInfo-reductionMode-parameter + reduction_mode.validate_device(&device)?; - Some(ash::vk::SamplerReductionModeCreateInfo { - reduction_mode: reduction_mode.into(), - ..Default::default() - }) - } else { - None - }; + Some(ash::vk::SamplerReductionModeCreateInfo { + reduction_mode: reduction_mode.into(), + ..Default::default() + }) + } else { + None + }; // Don't need to check features because you can't create a conversion object without the // feature anyway. @@ -1410,9 +1410,11 @@ vulkan_enum! { /// The [`ext_filter_cubic`](crate::device::DeviceExtensions::ext_filter_cubic) extension must /// be enabled on the device, and anisotropy must be disabled. Sampled image views must have /// a type of [`Dim2d`](crate::image::view::ImageViewType::Dim2d). - Cubic = CUBIC_EXT { - device_extensions: [ext_filter_cubic, img_filter_cubic], - }, + Cubic = CUBIC_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_filter_cubic)]), + RequiresAllOf([DeviceExtension(img_filter_cubic)]), + ]), } vulkan_enum! { @@ -1465,10 +1467,11 @@ vulkan_enum! { /// feature or the /// [`khr_sampler_mirror_clamp_to_edge`](crate::device::DeviceExtensions::khr_sampler_mirror_clamp_to_edge) /// extension must be enabled on the device. - MirrorClampToEdge = MIRROR_CLAMP_TO_EDGE { - api_version: V1_2, - device_extensions: [khr_sampler_mirror_clamp_to_edge], - }, + MirrorClampToEdge = MIRROR_CLAMP_TO_EDGE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_2)]), + RequiresAllOf([DeviceExtension(khr_sampler_mirror_clamp_to_edge)]), + ]), } vulkan_enum! { @@ -1502,15 +1505,17 @@ vulkan_enum! { /* TODO: enable // TODO: document - FloatCustom = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT { - device_extensions: [ext_custom_border_color], - },*/ + FloatCustom = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_custom_border_color)]), + ]),*/ /* TODO: enable // TODO: document - IntCustom = INT_CUSTOM_EXT { - device_extensions: [ext_custom_border_color], - },*/ + IntCustom = INT_CUSTOM_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_custom_border_color)]), + ]),*/ } vulkan_enum! { @@ -1549,7 +1554,7 @@ mod tests { Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerCreationError, SamplerReductionMode, }, - RequiresOneOf, + Requires, RequiresAllOf, RequiresOneOf, }; #[test] @@ -1681,9 +1686,10 @@ mod tests { match r { Err(SamplerCreationError::RequirementNotMet { - requires_one_of: RequiresOneOf { features, .. }, + requires_one_of: + RequiresOneOf([RequiresAllOf([Requires::Feature("sampler_anisotropy")])]), .. - }) if features.contains(&"sampler_anisotropy") => (), + }) => (), _ => panic!(), } } @@ -1752,14 +1758,13 @@ mod tests { match r { Err(SamplerCreationError::RequirementNotMet { requires_one_of: - RequiresOneOf { - features, - device_extensions, - .. - }, + RequiresOneOf( + [RequiresAllOf([Requires::Feature("sampler_mirror_clamp_to_edge")]), RequiresAllOf( + [Requires::DeviceExtension("khr_sampler_mirror_clamp_to_edge")], + )], + ), .. - }) if features.contains(&"sampler_mirror_clamp_to_edge") - && device_extensions.contains(&"khr_sampler_mirror_clamp_to_edge") => {} + }) => {} _ => panic!(), } } @@ -1781,14 +1786,11 @@ mod tests { match r { Err(SamplerCreationError::RequirementNotMet { requires_one_of: - RequiresOneOf { - features, - device_extensions, - .. - }, + RequiresOneOf( + [RequiresAllOf([Requires::Feature("sampler_filter_minmax")]), RequiresAllOf([Requires::DeviceExtension("ext_sampler_filter_minmax")])], + ), .. - }) if features.contains(&"sampler_filter_minmax") - && device_extensions.contains(&"ext_sampler_filter_minmax") => {} + }) => {} _ => panic!(), } } diff --git a/vulkano/src/sampler/ycbcr.rs b/vulkano/src/sampler/ycbcr.rs index db97b6c76f..8c6cda5d95 100644 --- a/vulkano/src/sampler/ycbcr.rs +++ b/vulkano/src/sampler/ycbcr.rs @@ -95,7 +95,8 @@ use crate::{ format::{ChromaSampling, Format, FormatFeatures, NumericType}, macros::{impl_id_counter, vulkan_enum}, sampler::{ComponentMapping, ComponentSwizzle, Filter}, - OomError, RequirementNotMet, RequiresOneOf, RuntimeError, Version, VulkanObject, + OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, Version, + VulkanObject, }; use std::{ error::Error, @@ -145,10 +146,9 @@ impl SamplerYcbcrConversion { if !device.enabled_features().sampler_ycbcr_conversion { return Err(SamplerYcbcrConversionCreationError::RequirementNotMet { required_for: "`SamplerYcbcrConversion::new`", - requires_one_of: RequiresOneOf { - features: &["sampler_ycbcr_conversion"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "sampler_ycbcr_conversion", + )])]), }); } @@ -791,7 +791,7 @@ vulkan_enum! { #[cfg(test)] mod tests { use super::{SamplerYcbcrConversion, SamplerYcbcrConversionCreationError}; - use crate::RequiresOneOf; + use crate::{Requires, RequiresAllOf, RequiresOneOf}; #[test] fn feature_not_enabled() { @@ -801,9 +801,10 @@ mod tests { match r { Err(SamplerYcbcrConversionCreationError::RequirementNotMet { - requires_one_of: RequiresOneOf { features, .. }, + requires_one_of: + RequiresOneOf([RequiresAllOf([Requires::Feature("sampler_ycbcr_conversion")])]), .. - }) if features.contains(&"sampler_ycbcr_conversion") => (), + }) => (), _ => panic!(), } } diff --git a/vulkano/src/shader/mod.rs b/vulkano/src/shader/mod.rs index 7bd5c5ad05..2a8161ec54 100644 --- a/vulkano/src/shader/mod.rs +++ b/vulkano/src/shader/mod.rs @@ -774,18 +774,20 @@ vulkan_bitflags! { /* TODO: enable // TODO: document - ALLOW_VARYING_SUBGROUP_SIZE = ALLOW_VARYING_SUBGROUP_SIZE { - api_version: V1_3, - device_extensions: [ext_subgroup_size_control], - }, + ALLOW_VARYING_SUBGROUP_SIZE = ALLOW_VARYING_SUBGROUP_SIZE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_subgroup_size_control)]), + ]), */ /* TODO: enable // TODO: document - REQUIRE_FULL_SUBGROUPS = REQUIRE_FULL_SUBGROUPS { - api_version: V1_3, - device_extensions: [ext_subgroup_size_control], - }, + REQUIRE_FULL_SUBGROUPS = REQUIRE_FULL_SUBGROUPS + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_subgroup_size_control)]), + ]), */ } @@ -1108,49 +1110,66 @@ vulkan_bitflags_enum! { COMPUTE, Compute = COMPUTE, // TODO: document - RAYGEN, Raygen = RAYGEN_KHR { - device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing], - }, + RAYGEN, Raygen = RAYGEN_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]), // TODO: document - ANY_HIT, AnyHit = ANY_HIT_KHR { - device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing], - }, + ANY_HIT, AnyHit = ANY_HIT_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]), // TODO: document - CLOSEST_HIT, ClosestHit = CLOSEST_HIT_KHR { - device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing], - }, + CLOSEST_HIT, ClosestHit = CLOSEST_HIT_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]), // TODO: document - MISS, Miss = MISS_KHR { - device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing], - }, + MISS, Miss = MISS_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]), // TODO: document - INTERSECTION, Intersection = INTERSECTION_KHR { - device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing], - }, + INTERSECTION, Intersection = INTERSECTION_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]), // TODO: document - CALLABLE, Callable = CALLABLE_KHR { - device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing], - }, + CALLABLE, Callable = CALLABLE_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]), // TODO: document - TASK, Task = TASK_EXT { - device_extensions: [ext_mesh_shader, nv_mesh_shader], - }, + TASK, Task = TASK_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_mesh_shader)]), + RequiresAllOf([DeviceExtension(nv_mesh_shader)]), + ]), // TODO: document - MESH, Mesh = MESH_EXT { - device_extensions: [ext_mesh_shader, nv_mesh_shader], - }, + MESH, Mesh = MESH_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_mesh_shader)]), + RequiresAllOf([DeviceExtension(nv_mesh_shader)]), + ]), // TODO: document - SUBPASS_SHADING, SubpassShading = SUBPASS_SHADING_HUAWEI { - device_extensions: [huawei_subpass_shading], - }, + SUBPASS_SHADING, SubpassShading = SUBPASS_SHADING_HUAWEI + RequiresOneOf([ + RequiresAllOf([DeviceExtension(huawei_subpass_shading)]), + ]), } impl From<&ShaderExecution> for ShaderStage { diff --git a/vulkano/src/swapchain/surface.rs b/vulkano/src/swapchain/surface.rs index e36c776100..e0c578768f 100644 --- a/vulkano/src/swapchain/surface.rs +++ b/vulkano/src/swapchain/surface.rs @@ -19,7 +19,7 @@ use crate::{ display::{DisplayMode, DisplayPlane}, SurfaceSwapchainLock, }, - OomError, RequiresOneOf, RuntimeError, ValidationError, VulkanObject, + OomError, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, VulkanObject, }; #[cfg(any(target_os = "macos", target_os = "ios"))] use objc::{class, msg_send, runtime::Object, sel, sel_impl}; @@ -185,10 +185,9 @@ impl Surface { if !instance.enabled_extensions().ext_headless_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::headless`", - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_headless_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ext_headless_surface", + )])]), }); } @@ -255,10 +254,9 @@ impl Surface { { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_display_plane`", - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_display"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_display", + )])]), }); } @@ -340,10 +338,9 @@ impl Surface { if !instance.enabled_extensions().khr_android_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_android`", - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_android_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_android_surface", + )])]), }); } @@ -416,10 +413,9 @@ impl Surface { if !instance.enabled_extensions().ext_directfb_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_directfb`", - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_directfb_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ext_directfb_surface", + )])]), }); } @@ -496,10 +492,9 @@ impl Surface { if !instance.enabled_extensions().fuchsia_imagepipe_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_fuchsia_image_pipe`", - requires_one_of: RequiresOneOf { - instance_extensions: &["fuchsia_imagepipe_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "fuchsia_imagepipe_surface", + )])]), }); } @@ -572,10 +567,9 @@ impl Surface { if !instance.enabled_extensions().ggp_stream_descriptor_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_ggp_stream_descriptor`", - requires_one_of: RequiresOneOf { - instance_extensions: &["ggp_stream_descriptor_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ggp_stream_descriptor_surface", + )])]), }); } @@ -647,10 +641,9 @@ impl Surface { if !instance.enabled_extensions().mvk_ios_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_ios`", - requires_one_of: RequiresOneOf { - instance_extensions: &["mvk_ios_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "mvk_ios_surface", + )])]), }); } @@ -725,10 +718,9 @@ impl Surface { if !instance.enabled_extensions().mvk_macos_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_mac_os`", - requires_one_of: RequiresOneOf { - instance_extensions: &["mvk_macos_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "mvk_macos_surface", + )])]), }); } @@ -800,10 +792,9 @@ impl Surface { if !instance.enabled_extensions().ext_metal_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_metal`", - requires_one_of: RequiresOneOf { - instance_extensions: &["ext_metal_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "ext_metal_surface", + )])]), }); } @@ -873,10 +864,9 @@ impl Surface { if !instance.enabled_extensions().qnx_screen_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_qnx_screen`", - requires_one_of: RequiresOneOf { - instance_extensions: &["qnx_screen_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "qnx_screen_surface", + )])]), }); } @@ -949,10 +939,9 @@ impl Surface { if !instance.enabled_extensions().nn_vi_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_vi`", - requires_one_of: RequiresOneOf { - instance_extensions: &["nn_vi_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "nn_vi_surface", + )])]), }); } @@ -1027,10 +1016,9 @@ impl Surface { if !instance.enabled_extensions().khr_wayland_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_wayland`", - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_wayland_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_wayland_surface", + )])]), }); } @@ -1110,10 +1098,9 @@ impl Surface { if !instance.enabled_extensions().khr_win32_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_win32`", - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_win32_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_win32_surface", + )])]), }); } @@ -1193,10 +1180,9 @@ impl Surface { if !instance.enabled_extensions().khr_xcb_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_xcb`", - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_xcb_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_xcb_surface", + )])]), }); } @@ -1276,10 +1262,9 @@ impl Surface { if !instance.enabled_extensions().khr_xlib_surface { return Err(SurfaceCreationError::RequirementNotMet { required_for: "`Surface::from_xlib`", - requires_one_of: RequiresOneOf { - instance_extensions: &["khr_xlib_surface"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension( + "khr_xlib_surface", + )])]), }); } @@ -1619,15 +1604,17 @@ vulkan_enum! { /* TODO: enable // TODO: document - SharedDemandRefresh = SHARED_DEMAND_REFRESH_KHR { - device_extensions: [khr_shared_presentable_image], - },*/ + SharedDemandRefresh = SHARED_DEMAND_REFRESH_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_shared_presentable_image)]), + ]),*/ /* TODO: enable // TODO: document - SharedContinuousRefresh = SHARED_CONTINUOUS_REFRESH_KHR { - device_extensions: [khr_shared_presentable_image], - },*/ + SharedContinuousRefresh = SHARED_CONTINUOUS_REFRESH_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_shared_presentable_image)]), + ]),*/ } vulkan_bitflags_enum! { @@ -1799,79 +1786,94 @@ vulkan_enum! { SrgbNonLinear = SRGB_NONLINEAR, // TODO: document - DisplayP3NonLinear = DISPLAY_P3_NONLINEAR_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + DisplayP3NonLinear = DISPLAY_P3_NONLINEAR_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - ExtendedSrgbLinear = EXTENDED_SRGB_LINEAR_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + ExtendedSrgbLinear = EXTENDED_SRGB_LINEAR_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - ExtendedSrgbNonLinear = EXTENDED_SRGB_NONLINEAR_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + ExtendedSrgbNonLinear = EXTENDED_SRGB_NONLINEAR_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - DisplayP3Linear = DISPLAY_P3_LINEAR_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + DisplayP3Linear = DISPLAY_P3_LINEAR_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - DciP3NonLinear = DCI_P3_NONLINEAR_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + DciP3NonLinear = DCI_P3_NONLINEAR_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - Bt709Linear = BT709_LINEAR_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + Bt709Linear = BT709_LINEAR_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - Bt709NonLinear = BT709_NONLINEAR_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + Bt709NonLinear = BT709_NONLINEAR_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - Bt2020Linear = BT2020_LINEAR_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + Bt2020Linear = BT2020_LINEAR_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - Hdr10St2084 = HDR10_ST2084_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + Hdr10St2084 = HDR10_ST2084_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - DolbyVision = DOLBYVISION_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + DolbyVision = DOLBYVISION_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - Hdr10Hlg = HDR10_HLG_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + Hdr10Hlg = HDR10_HLG_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - AdobeRgbLinear = ADOBERGB_LINEAR_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + AdobeRgbLinear = ADOBERGB_LINEAR_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - AdobeRgbNonLinear = ADOBERGB_NONLINEAR_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + AdobeRgbNonLinear = ADOBERGB_NONLINEAR_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - PassThrough = PASS_THROUGH_EXT { - instance_extensions: [ext_swapchain_colorspace], - }, + PassThrough = PASS_THROUGH_EXT + RequiresOneOf([ + RequiresAllOf([InstanceExtension(ext_swapchain_colorspace)]), + ]), // TODO: document - DisplayNative = DISPLAY_NATIVE_AMD { - device_extensions: [amd_display_native_hdr], - }, + DisplayNative = DISPLAY_NATIVE_AMD + RequiresOneOf([ + RequiresAllOf([DeviceExtension(amd_display_native_hdr)]), + ]), } /// Parameters for [`PhysicalDevice::surface_capabilities`] and [`PhysicalDevice::surface_formats`]. @@ -1912,10 +1914,9 @@ impl SurfaceInfo { return Err(ValidationError { context: "full_screen_exclusive".into(), problem: "is not `FullScreenExclusive::Default`".into(), - requires_one_of: RequiresOneOf { - device_extensions: &["ext_full_screen_exclusive"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_full_screen_exclusive", + )])]), ..Default::default() }); } @@ -2008,7 +2009,7 @@ pub struct SurfaceCapabilities { mod tests { use crate::{ swapchain::{Surface, SurfaceCreationError}, - RequiresOneOf, + Requires, RequiresAllOf, RequiresOneOf, }; use std::ptr; @@ -2018,12 +2019,9 @@ mod tests { match unsafe { Surface::from_win32(instance, ptr::null::(), ptr::null::(), None) } { Err(SurfaceCreationError::RequirementNotMet { requires_one_of: - RequiresOneOf { - instance_extensions, - .. - }, + RequiresOneOf([RequiresAllOf([Requires::InstanceExtension("khr_win32_surface")])]), .. - }) if instance_extensions.contains(&"khr_win32_surface") => (), + }) => (), _ => panic!(), } } @@ -2034,12 +2032,9 @@ mod tests { match unsafe { Surface::from_xcb(instance, ptr::null::(), 0, None) } { Err(SurfaceCreationError::RequirementNotMet { requires_one_of: - RequiresOneOf { - instance_extensions, - .. - }, + RequiresOneOf([RequiresAllOf([Requires::InstanceExtension("khr_xcb_surface")])]), .. - }) if instance_extensions.contains(&"khr_xcb_surface") => (), + }) => (), _ => panic!(), } } @@ -2050,12 +2045,9 @@ mod tests { match unsafe { Surface::from_xlib(instance, ptr::null::(), 0, None) } { Err(SurfaceCreationError::RequirementNotMet { requires_one_of: - RequiresOneOf { - instance_extensions, - .. - }, + RequiresOneOf([RequiresAllOf([Requires::InstanceExtension("khr_xlib_surface")])]), .. - }) if instance_extensions.contains(&"khr_xlib_surface") => (), + }) => (), _ => panic!(), } } @@ -2067,12 +2059,9 @@ mod tests { { Err(SurfaceCreationError::RequirementNotMet { requires_one_of: - RequiresOneOf { - instance_extensions, - .. - }, + RequiresOneOf([RequiresAllOf([Requires::InstanceExtension("khr_wayland_surface")])]), .. - }) if instance_extensions.contains(&"khr_wayland_surface") => (), + }) => (), _ => panic!(), } } @@ -2083,12 +2072,9 @@ mod tests { match unsafe { Surface::from_android(instance, ptr::null::(), None) } { Err(SurfaceCreationError::RequirementNotMet { requires_one_of: - RequiresOneOf { - instance_extensions, - .. - }, + RequiresOneOf([RequiresAllOf([Requires::InstanceExtension("khr_android_surface")])]), .. - }) if instance_extensions.contains(&"khr_android_surface") => (), + }) => (), _ => panic!(), } } diff --git a/vulkano/src/swapchain/swapchain.rs b/vulkano/src/swapchain/swapchain.rs index 6cd76a0db9..b2d4f8f530 100644 --- a/vulkano/src/swapchain/swapchain.rs +++ b/vulkano/src/swapchain/swapchain.rs @@ -27,7 +27,8 @@ use crate::{ semaphore::{Semaphore, SemaphoreError}, Sharing, }, - DeviceSize, OomError, RequirementNotMet, RequiresOneOf, RuntimeError, VulkanObject, + DeviceSize, OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, + VulkanObject, }; use parking_lot::Mutex; use smallvec::{smallvec, SmallVec}; @@ -299,10 +300,9 @@ impl Swapchain { if !device.enabled_extensions().khr_swapchain { return Err(SwapchainCreationError::RequirementNotMet { required_for: "`Swapchain::new`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_swapchain"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_swapchain", + )])]), }); } @@ -331,10 +331,9 @@ impl Swapchain { return Err(SwapchainCreationError::RequirementNotMet { required_for: "`create_info.full_screen_exclusive` is not \ `FullScreenExclusive::Default`", - requires_one_of: RequiresOneOf { - device_extensions: &["ext_full_screen_exclusive"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_full_screen_exclusive", + )])]), }); } @@ -1577,10 +1576,7 @@ pub fn wait_for_present( if !swapchain.device.enabled_features().present_wait { return Err(PresentWaitError::RequirementNotMet { required_for: "`wait_for_present`", - requires_one_of: RequiresOneOf { - features: &["present_wait"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("present_wait")])]), }); } diff --git a/vulkano/src/sync/event.rs b/vulkano/src/sync/event.rs index bf7ff1b8c9..8b70311e48 100644 --- a/vulkano/src/sync/event.rs +++ b/vulkano/src/sync/event.rs @@ -27,7 +27,7 @@ use crate::{ device::{Device, DeviceOwned}, macros::impl_id_counter, - OomError, RequiresOneOf, RuntimeError, VulkanObject, + OomError, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, VulkanObject, }; use std::{ error::Error, @@ -66,10 +66,7 @@ impl Event { return Err(EventError::RequirementNotMet { required_for: "this device is a portability subset device, and `Event::new` was \ called", - requires_one_of: RequiresOneOf { - features: &["events"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("events")])]), }); } diff --git a/vulkano/src/sync/fence.rs b/vulkano/src/sync/fence.rs index 67cda15962..215149a72e 100644 --- a/vulkano/src/sync/fence.rs +++ b/vulkano/src/sync/fence.rs @@ -13,8 +13,8 @@ use crate::{ device::{physical::PhysicalDevice, Device, DeviceOwned, Queue}, macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum}, - OomError, RequirementNotMet, RequiresOneOf, RuntimeError, ValidationError, Version, - VulkanObject, + OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, + ValidationError, Version, VulkanObject, }; use parking_lot::{Mutex, MutexGuard}; use smallvec::SmallVec; @@ -90,11 +90,10 @@ impl Fence { { return Err(FenceError::RequirementNotMet { required_for: "`create_info.export_handle_types` is not empty", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_external_fence"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_external_fence")]), + ]), }); } @@ -589,10 +588,9 @@ impl Fence { if !self.device.enabled_extensions().khr_external_fence_fd { return Err(FenceError::RequirementNotMet { required_for: "`Fence::export_fd`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_external_fence_fd"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_external_fence_fd", + )])]), }); } @@ -714,10 +712,9 @@ impl Fence { if !self.device.enabled_extensions().khr_external_fence_win32 { return Err(FenceError::RequirementNotMet { required_for: "`Fence::export_win32_handle`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_external_fence_win32"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_external_fence_win32", + )])]), }); } @@ -850,10 +847,9 @@ impl Fence { if !self.device.enabled_extensions().khr_external_fence_fd { return Err(FenceError::RequirementNotMet { required_for: "`Fence::import_fd`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_external_fence_fd"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_external_fence_fd", + )])]), }); } @@ -969,10 +965,9 @@ impl Fence { if !self.device.enabled_extensions().khr_external_fence_win32 { return Err(FenceError::RequirementNotMet { required_for: "`Fence::import_win32_handle`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_external_fence_win32"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_external_fence_win32", + )])]), }); } diff --git a/vulkano/src/sync/pipeline.rs b/vulkano/src/sync/pipeline.rs index a211929200..5b0f12317b 100644 --- a/vulkano/src/sync/pipeline.rs +++ b/vulkano/src/sync/pipeline.rs @@ -14,7 +14,7 @@ use crate::{ image::{sys::Image, ImageAspects, ImageLayout, ImageSubresourceRange}, macros::{vulkan_bitflags, vulkan_bitflags_enum}, shader::ShaderStages, - DeviceSize, RequiresOneOf, ValidationError, + DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError, }; use ahash::HashMap; use once_cell::sync::Lazy; @@ -256,41 +256,47 @@ vulkan_bitflags_enum! { /// The `copy_buffer`, `copy_image`, `copy_buffer_to_image`, `copy_image_to_buffer` and /// `copy_query_pool_results` commands are executed. - COPY, Copy = COPY { - api_version: V1_3, - device_extensions: [khr_synchronization2], - }, + COPY, Copy = COPY + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]), /// The `resolve_image` command is executed. - RESOLVE, Resolve = RESOLVE { - api_version: V1_3, - device_extensions: [khr_synchronization2], - }, + RESOLVE, Resolve = RESOLVE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]), /// The `blit_image` command is executed. - BLIT, Blit = BLIT { - api_version: V1_3, - device_extensions: [khr_synchronization2], - }, + BLIT, Blit = BLIT + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]), /// The `clear_color_image`, `clear_depth_stencil_image`, `fill_buffer` and `update_buffer` /// commands are executed. - CLEAR, Clear = CLEAR { - api_version: V1_3, - device_extensions: [khr_synchronization2], - }, + CLEAR, Clear = CLEAR + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]), /// Index buffers are read. - INDEX_INPUT, IndexInput = INDEX_INPUT { - api_version: V1_3, - device_extensions: [khr_synchronization2], - }, + INDEX_INPUT, IndexInput = INDEX_INPUT + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]), /// Vertex buffers are read. - VERTEX_ATTRIBUTE_INPUT, VertexAttributeInput = VERTEX_ATTRIBUTE_INPUT { - api_version: V1_3, - device_extensions: [khr_synchronization2], - }, + VERTEX_ATTRIBUTE_INPUT, VertexAttributeInput = VERTEX_ATTRIBUTE_INPUT + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]), /// The various pre-rasterization shader types are executed. /// @@ -303,92 +309,127 @@ vulkan_bitflags_enum! { /// - `geometry_shader` /// - `task_shader` /// - `mesh_shader` - PRE_RASTERIZATION_SHADERS, PreRasterizationShaders = PRE_RASTERIZATION_SHADERS { - api_version: V1_3, - device_extensions: [khr_synchronization2], - }, + PRE_RASTERIZATION_SHADERS, PreRasterizationShaders = PRE_RASTERIZATION_SHADERS + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]), /// Video decode operations are performed. - VIDEO_DECODE, VideoDecode = VIDEO_DECODE_KHR { - device_extensions: [khr_video_decode_queue], - }, + VIDEO_DECODE, VideoDecode = VIDEO_DECODE_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_decode_queue)]), + ]), /// Video encode operations are performed. - VIDEO_ENCODE, VideoEncode = VIDEO_ENCODE_KHR { - device_extensions: [khr_video_encode_queue], - }, + VIDEO_ENCODE, VideoEncode = VIDEO_ENCODE_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_video_encode_queue)]), + ]), /// Vertex attribute output values are written to the transform feedback buffers. - TRANSFORM_FEEDBACK, TransformFeedback = TRANSFORM_FEEDBACK_EXT { - device_extensions: [ext_transform_feedback], - }, + TRANSFORM_FEEDBACK, TransformFeedback = TRANSFORM_FEEDBACK_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_transform_feedback)]), + ]), /// The predicate of conditional rendering is read. - CONDITIONAL_RENDERING, ConditionalRendering = CONDITIONAL_RENDERING_EXT { - device_extensions: [ext_conditional_rendering], - }, + CONDITIONAL_RENDERING, ConditionalRendering = CONDITIONAL_RENDERING_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_conditional_rendering)]), + ]), /// Acceleration_structure commands are executed. - ACCELERATION_STRUCTURE_BUILD, AccelerationStructureBuild = ACCELERATION_STRUCTURE_BUILD_KHR { - device_extensions: [khr_acceleration_structure, nv_ray_tracing], - }, + ACCELERATION_STRUCTURE_BUILD, AccelerationStructureBuild = ACCELERATION_STRUCTURE_BUILD_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_acceleration_structure)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]), /// The various ray tracing shader types are executed. - RAY_TRACING_SHADER, RayTracingShader = RAY_TRACING_SHADER_KHR { - device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing], - }, + RAY_TRACING_SHADER, RayTracingShader = RAY_TRACING_SHADER_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_pipeline)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]), /// The fragment density map is read to generate the fragment areas. - FRAGMENT_DENSITY_PROCESS, FragmentDensityProcess = FRAGMENT_DENSITY_PROCESS_EXT { - device_extensions: [ext_fragment_density_map], - }, + FRAGMENT_DENSITY_PROCESS, FragmentDensityProcess = FRAGMENT_DENSITY_PROCESS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_fragment_density_map)]), + ]), /// The fragment shading rate attachment or shading rate image is read to determine the /// fragment shading rate for portions of a rasterized primitive. - FRAGMENT_SHADING_RATE_ATTACHMENT, FragmentShadingRateAttachment = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR { - device_extensions: [khr_fragment_shading_rate], - }, + FRAGMENT_SHADING_RATE_ATTACHMENT, FragmentShadingRateAttachment = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_fragment_shading_rate)]), + ]), /// Device-side preprocessing for generated commands via the `preprocess_generated_commands` /// command is handled. - COMMAND_PREPROCESS, CommandPreprocess = COMMAND_PREPROCESS_NV { - device_extensions: [nv_device_generated_commands], - }, + COMMAND_PREPROCESS, CommandPreprocess = COMMAND_PREPROCESS_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_device_generated_commands)]), + ]), /// Task shaders are executed. - TASK_SHADER, TaskShader = TASK_SHADER_EXT { - device_extensions: [ext_mesh_shader, nv_mesh_shader], - }, + TASK_SHADER, TaskShader = TASK_SHADER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_mesh_shader)]), + RequiresAllOf([DeviceExtension(nv_mesh_shader)]), + ]), /// Mesh shaders are executed. - MESH_SHADER, MeshShader = MESH_SHADER_EXT { - device_extensions: [ext_mesh_shader, nv_mesh_shader], - }, + MESH_SHADER, MeshShader = MESH_SHADER_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_mesh_shader)]), + RequiresAllOf([DeviceExtension(nv_mesh_shader)]), + ]), /// Subpass shading shaders are executed. - SUBPASS_SHADING, SubpassShading = SUBPASS_SHADING_HUAWEI { - device_extensions: [huawei_subpass_shading], - }, + SUBPASS_SHADING, SubpassShading = SUBPASS_SHADING_HUAWEI + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(huawei_subpass_shading), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(huawei_subpass_shading), + ]), + ]), /// The invocation mask image is read to optimize ray dispatch. - INVOCATION_MASK, InvocationMask = INVOCATION_MASK_HUAWEI { - device_extensions: [huawei_invocation_mask], - }, + INVOCATION_MASK, InvocationMask = INVOCATION_MASK_HUAWEI + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(huawei_invocation_mask), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(huawei_invocation_mask), + ]), + ]), /// The `copy_acceleration_structure` command is executed. - ACCELERATION_STRUCTURE_COPY, AccelerationStructureCopy = ACCELERATION_STRUCTURE_COPY_KHR { - device_extensions: [khr_ray_tracing_maintenance1], - }, + ACCELERATION_STRUCTURE_COPY, AccelerationStructureCopy = ACCELERATION_STRUCTURE_COPY_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_ray_tracing_maintenance1)]), + ]), /// Micromap commands are executed. - MICROMAP_BUILD, MicromapBuild = MICROMAP_BUILD_EXT { - device_extensions: [ext_opacity_micromap], - }, + MICROMAP_BUILD, MicromapBuild = MICROMAP_BUILD_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_opacity_micromap)]), + ]), /// Optical flow operations are performed. - OPTICAL_FLOW, OpticalFlow = OPTICAL_FLOW_NV { - device_extensions: [nv_optical_flow], - }, + OPTICAL_FLOW, OpticalFlow = OPTICAL_FLOW_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_optical_flow)]), + ]), } impl From for ash::vk::PipelineStageFlags { @@ -685,130 +726,228 @@ vulkan_bitflags! { MEMORY_WRITE = MEMORY_WRITE, /// Read access to a uniform texel buffer or sampled image in a shader. - SHADER_SAMPLED_READ = SHADER_SAMPLED_READ { - api_version: V1_3, - device_extensions: [khr_synchronization2], - }, + SHADER_SAMPLED_READ = SHADER_SAMPLED_READ + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]), /// Read access to a storage buffer, storage texel buffer or storage image in a shader. - SHADER_STORAGE_READ = SHADER_STORAGE_READ { - api_version: V1_3, - device_extensions: [khr_synchronization2], - }, + SHADER_STORAGE_READ = SHADER_STORAGE_READ + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]), /// Write access to a storage buffer, storage texel buffer or storage image in a shader. - SHADER_STORAGE_WRITE = SHADER_STORAGE_WRITE { - api_version: V1_3, - device_extensions: [khr_synchronization2], - }, + SHADER_STORAGE_WRITE = SHADER_STORAGE_WRITE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]), /// Read access to an image or buffer as part of a video decode operation. - VIDEO_DECODE_READ = VIDEO_DECODE_READ_KHR { - device_extensions: [khr_video_decode_queue], - }, + VIDEO_DECODE_READ = VIDEO_DECODE_READ_KHR + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(khr_video_decode_queue), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(khr_video_decode_queue), + ]), + ]), /// Write access to an image or buffer as part of a video decode operation. - VIDEO_DECODE_WRITE = VIDEO_DECODE_WRITE_KHR { - device_extensions: [khr_video_decode_queue], - }, + VIDEO_DECODE_WRITE = VIDEO_DECODE_WRITE_KHR + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(khr_video_decode_queue), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(khr_video_decode_queue), + ]), + ]), /// Read access to an image or buffer as part of a video encode operation. - VIDEO_ENCODE_READ = VIDEO_ENCODE_READ_KHR { - device_extensions: [khr_video_encode_queue], - }, + VIDEO_ENCODE_READ = VIDEO_ENCODE_READ_KHR + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(khr_video_encode_queue), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(khr_video_encode_queue), + ]), + ]), /// Write access to an image or buffer as part of a video encode operation. - VIDEO_ENCODE_WRITE = VIDEO_ENCODE_WRITE_KHR { - device_extensions: [khr_video_encode_queue], - }, + VIDEO_ENCODE_WRITE = VIDEO_ENCODE_WRITE_KHR + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(khr_video_encode_queue), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(khr_video_encode_queue), + ]), + ]), /// Write access to a transform feedback buffer during transform feedback operations. - TRANSFORM_FEEDBACK_WRITE = TRANSFORM_FEEDBACK_WRITE_EXT { - device_extensions: [ext_transform_feedback], - }, + TRANSFORM_FEEDBACK_WRITE = TRANSFORM_FEEDBACK_WRITE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_transform_feedback)]), + ]), /// Read access to a transform feedback counter buffer during transform feedback operations. - TRANSFORM_FEEDBACK_COUNTER_READ = TRANSFORM_FEEDBACK_COUNTER_READ_EXT { - device_extensions: [ext_transform_feedback], - }, + TRANSFORM_FEEDBACK_COUNTER_READ = TRANSFORM_FEEDBACK_COUNTER_READ_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_transform_feedback)]), + ]), /// Write access to a transform feedback counter buffer during transform feedback operations. - TRANSFORM_FEEDBACK_COUNTER_WRITE = TRANSFORM_FEEDBACK_COUNTER_WRITE_EXT { - device_extensions: [ext_transform_feedback], - }, + TRANSFORM_FEEDBACK_COUNTER_WRITE = TRANSFORM_FEEDBACK_COUNTER_WRITE_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_transform_feedback)]), + ]), /// Read access to a predicate during conditional rendering. - CONDITIONAL_RENDERING_READ = CONDITIONAL_RENDERING_READ_EXT { - device_extensions: [ext_conditional_rendering], - }, + CONDITIONAL_RENDERING_READ = CONDITIONAL_RENDERING_READ_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_conditional_rendering)]), + ]), /// Read access to preprocess buffers input to `preprocess_generated_commands`. - COMMAND_PREPROCESS_READ = COMMAND_PREPROCESS_READ_NV { - device_extensions: [nv_device_generated_commands], - }, + COMMAND_PREPROCESS_READ = COMMAND_PREPROCESS_READ_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_device_generated_commands)]), + ]), /// Read access to sequences buffers output by `preprocess_generated_commands`. - COMMAND_PREPROCESS_WRITE = COMMAND_PREPROCESS_WRITE_NV { - device_extensions: [nv_device_generated_commands], - }, + COMMAND_PREPROCESS_WRITE = COMMAND_PREPROCESS_WRITE_NV + RequiresOneOf([ + RequiresAllOf([DeviceExtension(nv_device_generated_commands)]), + ]), /// Read access to a fragment shading rate attachment during rasterization. - FRAGMENT_SHADING_RATE_ATTACHMENT_READ = FRAGMENT_SHADING_RATE_ATTACHMENT_READ_KHR { - device_extensions: [khr_fragment_shading_rate], - }, + FRAGMENT_SHADING_RATE_ATTACHMENT_READ = FRAGMENT_SHADING_RATE_ATTACHMENT_READ_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_fragment_shading_rate)]), + ]), /// Read access to an acceleration structure or acceleration structure scratch buffer during /// trace, build or copy commands. - ACCELERATION_STRUCTURE_READ = ACCELERATION_STRUCTURE_READ_KHR { - device_extensions: [khr_acceleration_structure, nv_ray_tracing], - }, + ACCELERATION_STRUCTURE_READ = ACCELERATION_STRUCTURE_READ_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_acceleration_structure)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]), /// Write access to an acceleration structure or acceleration structure scratch buffer during /// trace, build or copy commands. - ACCELERATION_STRUCTURE_WRITE = ACCELERATION_STRUCTURE_WRITE_KHR { - device_extensions: [khr_acceleration_structure, nv_ray_tracing], - }, + ACCELERATION_STRUCTURE_WRITE = ACCELERATION_STRUCTURE_WRITE_KHR + RequiresOneOf([ + RequiresAllOf([DeviceExtension(khr_acceleration_structure)]), + RequiresAllOf([DeviceExtension(nv_ray_tracing)]), + ]), /// Read access to a fragment density map attachment during dynamic fragment density map /// operations. - FRAGMENT_DENSITY_MAP_READ = FRAGMENT_DENSITY_MAP_READ_EXT { - device_extensions: [ext_fragment_density_map], - }, + FRAGMENT_DENSITY_MAP_READ = FRAGMENT_DENSITY_MAP_READ_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_fragment_density_map)]), + ]), /// Read access to color attachments when performing advanced blend operations. - COLOR_ATTACHMENT_READ_NONCOHERENT = COLOR_ATTACHMENT_READ_NONCOHERENT_EXT { - device_extensions: [ext_blend_operation_advanced], - }, + COLOR_ATTACHMENT_READ_NONCOHERENT = COLOR_ATTACHMENT_READ_NONCOHERENT_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_blend_operation_advanced)]), + ]), /// Read access to an invocation mask image. - INVOCATION_MASK_READ = INVOCATION_MASK_READ_HUAWEI { - device_extensions: [huawei_invocation_mask], - }, + INVOCATION_MASK_READ = INVOCATION_MASK_READ_HUAWEI + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(huawei_invocation_mask), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(huawei_invocation_mask), + ]), + ]), /// Read access to a shader binding table. - SHADER_BINDING_TABLE_READ = SHADER_BINDING_TABLE_READ_KHR { - device_extensions: [khr_ray_tracing_maintenance1], - }, + SHADER_BINDING_TABLE_READ = SHADER_BINDING_TABLE_READ_KHR + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(khr_ray_tracing_pipeline), + DeviceExtension(khr_ray_tracing_maintenance1), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(khr_ray_tracing_pipeline), + DeviceExtension(khr_ray_tracing_maintenance1), + ]), + ]), /// Read access to a micromap object. - MICROMAP_READ = MICROMAP_READ_EXT { - device_extensions: [ext_opacity_micromap], - }, + MICROMAP_READ = MICROMAP_READ_EXT + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(ext_opacity_micromap), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(ext_opacity_micromap), + ]), + ]), /// Write access to a micromap object. - MICROMAP_WRITE = MICROMAP_WRITE_EXT { - device_extensions: [ext_opacity_micromap], - }, + MICROMAP_WRITE = MICROMAP_WRITE_EXT + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(ext_opacity_micromap), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(ext_opacity_micromap), + ]), + ]), /// Read access to a buffer or image during optical flow operations. - OPTICAL_FLOW_READ = OPTICAL_FLOW_READ_NV { - device_extensions: [nv_optical_flow], - }, + OPTICAL_FLOW_READ = OPTICAL_FLOW_READ_NV + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(nv_optical_flow), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(nv_optical_flow), + ]), + ]), /// Write access to a buffer or image during optical flow operations. - OPTICAL_FLOW_WRITE = OPTICAL_FLOW_WRITE_NV { - device_extensions: [nv_optical_flow], - }, + OPTICAL_FLOW_WRITE = OPTICAL_FLOW_WRITE_NV + RequiresOneOf([ + RequiresAllOf([ + APIVersion(V1_3), + DeviceExtension(nv_optical_flow), + ]), + RequiresAllOf([ + DeviceExtension(khr_synchronization2), + DeviceExtension(nv_optical_flow), + ]), + ]), } impl From for ash::vk::AccessFlags { @@ -1661,10 +1800,11 @@ vulkan_bitflags! { /// enabled on the device. /// /// [`khr_device_group`]: crate::device::DeviceExtensions::khr_device_group - DEVICE_GROUP = DEVICE_GROUP { - api_version: V1_1, - device_extensions: [khr_device_group], - }, + DEVICE_GROUP = DEVICE_GROUP + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_device_group)]), + ]), /// For subpass dependencies, and pipeline barriers executing within a render pass instance, @@ -1676,10 +1816,11 @@ vulkan_bitflags! { /// enabled on the device. /// /// [`khr_multiview`]: crate::device::DeviceExtensions::khr_multiview - VIEW_LOCAL = VIEW_LOCAL { - api_version: V1_1, - device_extensions: [khr_multiview], - }, + VIEW_LOCAL = VIEW_LOCAL + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_1)]), + RequiresAllOf([DeviceExtension(khr_multiview)]), + ]), } /// A memory barrier that is applied globally. @@ -1767,10 +1908,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_stages".into(), problem: "contains flags from `VkPipelineStageFlagBits2`".into(), - requires_one_of: RequiresOneOf { - features: &["synchronization2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "synchronization2", + )])]), ..Default::default() }); } @@ -1779,10 +1919,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_stages".into(), problem: "contains flags from `VkPipelineStageFlagBits2`".into(), - requires_one_of: RequiresOneOf { - features: &["synchronization2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "synchronization2", + )])]), ..Default::default() }); } @@ -1791,10 +1930,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_access".into(), problem: "contains flags from `VkAccessFlagBits2`".into(), - requires_one_of: RequiresOneOf { - features: &["synchronization2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "synchronization2", + )])]), ..Default::default() }); } @@ -1803,10 +1941,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_access".into(), problem: "contains flags from `VkAccessFlagBits2`".into(), - requires_one_of: RequiresOneOf { - features: &["synchronization2"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "synchronization2", + )])]), ..Default::default() }); } @@ -1817,10 +1954,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_stages".into(), problem: "contains `PipelineStages::GEOMETRY_SHADER`".into(), - requires_one_of: RequiresOneOf { - features: &["geometry_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "geometry_shader", + )])]), vuids: &["VUID-VkMemoryBarrier2-srcStageMask-03929"], }); } @@ -1829,10 +1965,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_stages".into(), problem: "contains `PipelineStages::GEOMETRY_SHADER`".into(), - requires_one_of: RequiresOneOf { - features: &["geometry_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "geometry_shader", + )])]), vuids: &["VUID-VkMemoryBarrier2-dstStageMask-03929"], }); } @@ -1848,10 +1983,9 @@ impl MemoryBarrier { problem: "contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \ `PipelineStages::TESSELLATION_EVALUATION_SHADER`" .into(), - requires_one_of: RequiresOneOf { - features: &["tessellation_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "tessellation_shader", + )])]), vuids: &["VUID-VkMemoryBarrier2-srcStageMask-03930"], }); } @@ -1865,10 +1999,9 @@ impl MemoryBarrier { problem: "contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \ `PipelineStages::TESSELLATION_EVALUATION_SHADER`" .into(), - requires_one_of: RequiresOneOf { - features: &["tessellation_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "tessellation_shader", + )])]), vuids: &["VUID-VkMemoryBarrier2-dstStageMask-03930"], }); } @@ -1879,10 +2012,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_stages".into(), problem: "contains `PipelineStages::CONDITIONAL_RENDERING`".into(), - requires_one_of: RequiresOneOf { - features: &["conditional_rendering"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "conditional_rendering", + )])]), vuids: &["VUID-VkMemoryBarrier2-srcStageMask-03931"], }); } @@ -1891,10 +2023,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_stages".into(), problem: "contains `PipelineStages::CONDITIONAL_RENDERING`".into(), - requires_one_of: RequiresOneOf { - features: &["conditional_rendering"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "conditional_rendering", + )])]), vuids: &["VUID-VkMemoryBarrier2-dstStageMask-03931"], }); } @@ -1905,10 +2036,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_stages".into(), problem: "contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`".into(), - requires_one_of: RequiresOneOf { - features: &["fragment_density_map"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "fragment_density_map", + )])]), vuids: &["VUID-VkMemoryBarrier2-srcStageMask-03932"], }); } @@ -1917,10 +2047,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_stages".into(), problem: "contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`".into(), - requires_one_of: RequiresOneOf { - features: &["fragment_density_map"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "fragment_density_map", + )])]), vuids: &["VUID-VkMemoryBarrier2-dstStageMask-03932"], }); } @@ -1931,10 +2060,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_stages".into(), problem: "contains `PipelineStages::TRANSFORM_FEEDBACK`".into(), - requires_one_of: RequiresOneOf { - features: &["transform_feedback"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "transform_feedback", + )])]), vuids: &["VUID-VkMemoryBarrier2-srcStageMask-03933"], }); } @@ -1943,10 +2071,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_stages".into(), problem: "contains `PipelineStages::TRANSFORM_FEEDBACK`".into(), - requires_one_of: RequiresOneOf { - features: &["transform_feedback"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "transform_feedback", + )])]), vuids: &["VUID-VkMemoryBarrier2-dstStageMask-03933"], }); } @@ -1957,10 +2084,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_stages".into(), problem: "contains `PipelineStages::MESH_SHADER`".into(), - requires_one_of: RequiresOneOf { - features: &["mesh_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "mesh_shader", + )])]), vuids: &["VUID-VkMemoryBarrier2-srcStageMask-03934"], }); } @@ -1969,10 +2095,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_stages".into(), problem: "contains `PipelineStages::MESH_SHADER`".into(), - requires_one_of: RequiresOneOf { - features: &["mesh_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "mesh_shader", + )])]), vuids: &["VUID-VkMemoryBarrier2-dstStageMask-03934"], }); } @@ -1983,10 +2108,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_stages".into(), problem: "contains `PipelineStages::TASK_SHADER`".into(), - requires_one_of: RequiresOneOf { - features: &["task_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "task_shader", + )])]), vuids: &["VUID-VkMemoryBarrier2-srcStageMask-03935"], }); } @@ -1995,10 +2119,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_stages".into(), problem: "contains `PipelineStages::TASK_SHADER`".into(), - requires_one_of: RequiresOneOf { - features: &["task_shader"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "task_shader", + )])]), vuids: &["VUID-VkMemoryBarrier2-dstStageMask-03935"], }); } @@ -2011,10 +2134,10 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_stages".into(), problem: "contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`".into(), - requires_one_of: RequiresOneOf { - features: &["attachment_fragment_shading_rate", "shading_rate_image"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::Feature("attachment_fragment_shading_rate")]), + RequiresAllOf(&[Requires::Feature("shading_rate_image")]), + ]), vuids: &["VUID-VkMemoryBarrier2-shadingRateImage-07316"], }); } @@ -2023,10 +2146,10 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_stages".into(), problem: "contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`".into(), - requires_one_of: RequiresOneOf { - features: &["attachment_fragment_shading_rate", "shading_rate_image"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::Feature("attachment_fragment_shading_rate")]), + RequiresAllOf(&[Requires::Feature("shading_rate_image")]), + ]), vuids: &["VUID-VkMemoryBarrier2-shadingRateImage-07316"], }); } @@ -2037,10 +2160,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_stages".into(), problem: "contains `PipelineStages::SUBPASS_SHADING`".into(), - requires_one_of: RequiresOneOf { - features: &["subpass_shading"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "subpass_shading", + )])]), vuids: &["VUID-VkMemoryBarrier2-srcStageMask-04957"], }); } @@ -2049,10 +2171,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_stages".into(), problem: "contains `PipelineStages::SUBPASS_SHADING`".into(), - requires_one_of: RequiresOneOf { - features: &["subpass_shading"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "subpass_shading", + )])]), vuids: &["VUID-VkMemoryBarrier2-dstStageMask-04957"], }); } @@ -2063,10 +2184,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_stages".into(), problem: "contains `PipelineStages::INVOCATION_MASK`".into(), - requires_one_of: RequiresOneOf { - features: &["invocation_mask"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "invocation_mask", + )])]), vuids: &["VUID-VkMemoryBarrier2-srcStageMask-04995"], }); } @@ -2075,10 +2195,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_stages".into(), problem: "contains `PipelineStages::INVOCATION_MASK`".into(), - requires_one_of: RequiresOneOf { - features: &["invocation_mask"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "invocation_mask", + )])]), vuids: &["VUID-VkMemoryBarrier2-dstStageMask-04995"], }); } @@ -2091,10 +2210,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "src_stages".into(), problem: "contains `PipelineStages::RAY_TRACING_SHADER`".into(), - requires_one_of: RequiresOneOf { - features: &["ray_tracing_pipeline"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "ray_tracing_pipeline", + )])]), vuids: &["VUID-VkMemoryBarrier2-srcStageMask-07946"], }); } @@ -2103,10 +2221,9 @@ impl MemoryBarrier { return Err(ValidationError { context: "dst_stages".into(), problem: "contains `PipelineStages::RAY_TRACING_SHADER`".into(), - requires_one_of: RequiresOneOf { - features: &["ray_tracing_pipeline"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "ray_tracing_pipeline", + )])]), vuids: &["VUID-VkMemoryBarrier2-dstStageMask-07946"], }); } diff --git a/vulkano/src/sync/semaphore.rs b/vulkano/src/sync/semaphore.rs index 31fe9c5731..58202e47d1 100644 --- a/vulkano/src/sync/semaphore.rs +++ b/vulkano/src/sync/semaphore.rs @@ -13,8 +13,8 @@ use crate::{ device::{physical::PhysicalDevice, Device, DeviceOwned, Queue}, macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum}, - OomError, RequirementNotMet, RequiresOneOf, RuntimeError, ValidationError, Version, - VulkanObject, + OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, + ValidationError, Version, VulkanObject, }; use parking_lot::{Mutex, MutexGuard}; #[cfg(unix)] @@ -71,11 +71,10 @@ impl Semaphore { { return Err(SemaphoreError::RequirementNotMet { required_for: "`create_info.export_handle_types` is not empty", - requires_one_of: RequiresOneOf { - api_version: Some(Version::V1_1), - device_extensions: &["khr_external_semaphore"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_external_semaphore")]), + ]), }); } @@ -239,10 +238,9 @@ impl Semaphore { if !self.device.enabled_extensions().khr_external_semaphore_fd { return Err(SemaphoreError::RequirementNotMet { required_for: "`Semaphore::export_fd`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_external_semaphore_fd"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_external_semaphore_fd", + )])]), }); } @@ -374,10 +372,9 @@ impl Semaphore { { return Err(SemaphoreError::RequirementNotMet { required_for: "`Semaphore::export_win32_handle`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_external_semaphore_win32"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_external_semaphore_win32", + )])]), }); } @@ -509,10 +506,9 @@ impl Semaphore { if !self.device.enabled_extensions().fuchsia_external_semaphore { return Err(SemaphoreError::RequirementNotMet { required_for: "`Semaphore::export_zircon_handle`", - requires_one_of: RequiresOneOf { - device_extensions: &["fuchsia_external_semaphore"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "fuchsia_external_semaphore", + )])]), }); } @@ -640,10 +636,9 @@ impl Semaphore { if !self.device.enabled_extensions().khr_external_semaphore_fd { return Err(SemaphoreError::RequirementNotMet { required_for: "`Semaphore::import_fd`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_external_semaphore_fd"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_external_semaphore_fd", + )])]), }); } @@ -769,10 +764,9 @@ impl Semaphore { { return Err(SemaphoreError::RequirementNotMet { required_for: "`Semaphore::import_win32_handle`", - requires_one_of: RequiresOneOf { - device_extensions: &["khr_external_semaphore_win32"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "khr_external_semaphore_win32", + )])]), }); } @@ -896,10 +890,9 @@ impl Semaphore { if !self.device.enabled_extensions().fuchsia_external_semaphore { return Err(SemaphoreError::RequirementNotMet { required_for: "`Semaphore::import_zircon_handle`", - requires_one_of: RequiresOneOf { - device_extensions: &["fuchsia_external_semaphore"], - ..Default::default() - }, + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "fuchsia_external_semaphore", + )])]), }); } @@ -1231,9 +1224,10 @@ vulkan_bitflags_enum! { /// The [`fuchsia_external_semaphore`] extension must be enabled on the device. /// /// [`fuchsia_external_semaphore`]: crate::device::DeviceExtensions::fuchsia_external_semaphore - ZIRCON_EVENT, ZirconEvent = ZIRCON_EVENT_FUCHSIA { - device_extensions: [fuchsia_external_semaphore], - }, + ZIRCON_EVENT, ZirconEvent = ZIRCON_EVENT_FUCHSIA + RequiresOneOf([ + RequiresAllOf([DeviceExtension(fuchsia_external_semaphore)]), + ]), } vulkan_bitflags! { From 3c06bd98f8be452ad2a10f80a2c0fa971533c61d Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 18 Jun 2023 11:57:31 +0200 Subject: [PATCH 2/6] Add more missing backticks and backslashes to error messages --- vulkano/src/acceleration_structure.rs | 28 +- vulkano/src/command_buffer/auto/builder.rs | 2 +- .../commands/acceleration_structure.rs | 242 +++++++++--------- vulkano/src/descriptor_set/layout.rs | 4 +- vulkano/src/device/mod.rs | 8 +- vulkano/src/sampler/mod.rs | 33 +-- 6 files changed, 166 insertions(+), 151 deletions(-) diff --git a/vulkano/src/acceleration_structure.rs b/vulkano/src/acceleration_structure.rs index 52286c576a..40d10bc237 100644 --- a/vulkano/src/acceleration_structure.rs +++ b/vulkano/src/acceleration_structure.rs @@ -412,7 +412,7 @@ impl AccelerationStructureCreateInfo { if buffer.offset() % 256 != 0 { return Err(ValidationError { context: "buffer".into(), - problem: "the offset of the buffer was not a multiple of 256".into(), + problem: "the offset of the buffer is not a multiple of 256".into(), vuids: &["VUID-VkAccelerationStructureCreateInfoKHR-offset-03734"], ..Default::default() }); @@ -538,7 +538,7 @@ impl AccelerationStructureBuildGeometryInfo { if geometries.len() as u64 > max_geometry_count { return Err(ValidationError { context: "geometries".into(), - problem: "the max_geometry_count limit has been exceeded".into(), + problem: "the length exceeds the `max_geometry_count` limit".into(), vuids: &["VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03793"], ..Default::default() }); @@ -559,7 +559,7 @@ impl AccelerationStructureBuildGeometryInfo { if geometries.len() as u64 > max_geometry_count { return Err(ValidationError { context: "geometries".into(), - problem: "the max_geometry_count limit has been exceeded".into(), + problem: "the length exceeds the `max_geometry_count` limit".into(), vuids: &["VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03793"], ..Default::default() }); @@ -590,8 +590,8 @@ impl AccelerationStructureBuildGeometryInfo { ) { return Err(ValidationError { context: "flags".into(), - problem: "contains both BuildAccelerationStructureFlags::PREFER_FAST_TRACE and \ - BuildAccelerationStructureFlags::PREFER_FAST_BUILD" + problem: "contains both `BuildAccelerationStructureFlags::PREFER_FAST_TRACE` and \ + `BuildAccelerationStructureFlags::PREFER_FAST_BUILD`" .into(), vuids: &["VUID-VkAccelerationStructureBuildGeometryInfoKHR-flags-03796"], ..Default::default() @@ -1036,7 +1036,7 @@ impl AccelerationStructureGeometryTrianglesData { return Err(ValidationError { context: "vertex_format".into(), problem: "format features do not contain \ - FormatFeature::ACCELERATION_STRUCTURE_VERTEX_BUFFER" + `FormatFeature::ACCELERATION_STRUCTURE_VERTEX_BUFFER`" .into(), vuids: &["VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexFormat-03797"], ..Default::default() @@ -1053,8 +1053,8 @@ impl AccelerationStructureGeometryTrianglesData { if vertex_stride % smallest_component_bytes != 0 { return Err(ValidationError { - problem: "vertex_stride is not a multiple of the byte size of the \ - smallest component of vertex_format" + problem: "`vertex_stride` is not a multiple of the byte size of the \ + smallest component of `vertex_format`" .into(), vuids: &["VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexStride-03735"], ..Default::default() @@ -1065,7 +1065,7 @@ impl AccelerationStructureGeometryTrianglesData { if !matches!(index_data, IndexBuffer::U16(_) | IndexBuffer::U32(_)) { return Err(ValidationError { context: "index_data".into(), - problem: "is not IndexBuffer::U16 or IndexBuffer::U32".into(), + problem: "is not `IndexBuffer::U16` or `IndexBuffer::U32`".into(), vuids: &[ "VUID-VkAccelerationStructureGeometryTrianglesDataKHR-indexType-03798", ], @@ -1414,8 +1414,8 @@ impl CopyAccelerationStructureInfo { ) { return Err(ValidationError { context: "mode".into(), - problem: "is not CopyAccelerationStructureMode::Compact or \ - CopyAccelerationStructureMode::Clone" + problem: "is not `CopyAccelerationStructureMode::Compact` or \ + `CopyAccelerationStructureMode::Clone`" .into(), vuids: &["VUID-VkCopyAccelerationStructureInfoKHR-mode-03410"], ..Default::default() @@ -1424,7 +1424,7 @@ impl CopyAccelerationStructureInfo { if src.buffer() == dst.buffer() { return Err(ValidationError { - problem: "src and dst share the same buffer".into(), + problem: "`src` and `dst` share the same buffer".into(), vuids: &["VUID-VkCopyAccelerationStructureInfoKHR-dst-07791"], ..Default::default() }); @@ -1494,7 +1494,7 @@ impl CopyAccelerationStructureToMemoryInfo { if !matches!(mode, CopyAccelerationStructureMode::Serialize) { return Err(ValidationError { context: "mode".into(), - problem: "is not CopyAccelerationStructureMode::Serialize".into(), + problem: "is not `CopyAccelerationStructureMode::Serialize`".into(), vuids: &["VUID-VkCopyAccelerationStructureToMemoryInfoKHR-mode-03412"], ..Default::default() }); @@ -1564,7 +1564,7 @@ impl CopyMemoryToAccelerationStructureInfo { if !matches!(mode, CopyAccelerationStructureMode::Deserialize) { return Err(ValidationError { context: "mode".into(), - problem: "is not CopyAccelerationStructureMode::Deserialize".into(), + problem: "is not `CopyAccelerationStructureMode::Deserialize`".into(), vuids: &["VUID-VkCopyMemoryToAccelerationStructureInfoKHR-mode-03413"], ..Default::default() }); diff --git a/vulkano/src/command_buffer/auto/builder.rs b/vulkano/src/command_buffer/auto/builder.rs index bfe35935c8..30f972eb0b 100644 --- a/vulkano/src/command_buffer/auto/builder.rs +++ b/vulkano/src/command_buffer/auto/builder.rs @@ -1491,7 +1491,7 @@ impl AutoSyncState { if !self.device.enabled_features().synchronization2 { panic!( "The command requires the `Preinitialized` layout, \ - but this is not allowed in pipeline barriers without + but this is not allowed in pipeline barriers without \ the `synchronization2` feature enabled" ); } diff --git a/vulkano/src/command_buffer/commands/acceleration_structure.rs b/vulkano/src/command_buffer/commands/acceleration_structure.rs index c7f751c6c0..097859e633 100644 --- a/vulkano/src/command_buffer/commands/acceleration_structure.rs +++ b/vulkano/src/command_buffer/commands/acceleration_structure.rs @@ -167,7 +167,8 @@ where { return Err(ValidationError { context: "info.scratch_data".into(), - problem: "the buffer was not created with the `STORAGE_BUFFER` usage".into(), + problem: "the buffer was not created with the `BufferUsage::STORAGE_BUFFER` usage" + .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03674"], ..Default::default() }); @@ -186,8 +187,8 @@ where { return Err(ValidationError { context: "info.scratch_data".into(), - problem: "the device address of the buffer was not a multiple of the \ - min_acceleration_structure_scratch_offset_alignment device property" + problem: "the device address of the buffer is not a multiple of the \ + `min_acceleration_structure_scratch_offset_alignment` device property" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03710"], ..Default::default() @@ -199,9 +200,9 @@ where if !matches!(geometries, AccelerationStructureGeometries::Instances(_)) { return Err(ValidationError { context: "info".into(), - problem: "dst_acceleration_structure is a top-level \ - acceleration structure, but geometries is not \ - AccelerationStructureGeometries::Instances" + problem: "`dst_acceleration_structure` is a top-level \ + acceleration structure, but `geometries` is not \ + `AccelerationStructureGeometries::Instances`" .into(), vuids: &[ "VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03789", @@ -215,9 +216,9 @@ where if matches!(geometries, AccelerationStructureGeometries::Instances(_)) { return Err(ValidationError { context: "info".into(), - problem: "dst_acceleration_structure is a bottom-level \ - acceleration structure, but geometries is \ - AccelerationStructureGeometries::Instances" + problem: "`dst_acceleration_structure` is a bottom-level \ + acceleration structure, but `geometries` is \ + `AccelerationStructureGeometries::Instances`" .into(), vuids: &[ "VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03791", @@ -232,7 +233,8 @@ where if geometries.len() != build_range_infos.len() { return Err(ValidationError { - problem: "info.geometries and build_range_infos do not have the same length".into(), + problem: "`info.geometries` and `build_range_infos` do not have the same length" + .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-ppBuildRangeInfos-03676"], ..Default::default() }); @@ -281,7 +283,7 @@ where geometry_index ) .into(), - problem: "the max_primitive_count limit has been exceeded".into(), + problem: "exceeds the `max_primitive_count` limit".into(), vuids: &["VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03795"], ..Default::default() }); @@ -296,7 +298,7 @@ where context: format!("info.geometries[{}].vertex_data", geometry_index) .into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673"], ..Default::default() @@ -318,7 +320,7 @@ where context: format!("info.geometries[{}].vertex_data", geometry_index) .into(), problem: "the buffer's device address is not a multiple of the byte \ - size of the smallest component of vertex_format" + size of the smallest component of `vertex_format`" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03711"], ..Default::default() @@ -336,7 +338,8 @@ where context: format!("info.geometries[{}].index_data", geometry_index) .into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` \ + usage" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673"], ..Default::default() @@ -361,10 +364,11 @@ where if primitive_offset as u64 % index_data.index_type().size() != 0 { return Err(ValidationError { problem: format!( - "info.geometries is \ - AccelerationStructureGeometries::Triangles, and - build_range_infos[{}].primitive_offset is not a multiple of \ - the size of the index type of info.geometries[{0}].index_data", + "`info.geometries` is \ + `AccelerationStructureGeometries::Triangles`, and \ + `build_range_infos[{}].primitive_offset` is not a multiple of \ + the size of the index type of \ + `info.geometries[{0}].index_data`", geometry_index, ) .into(), @@ -380,13 +384,13 @@ where { return Err(ValidationError { problem: format!( - "infos.geometries is \ - AccelerationStructureGeometries::Triangles, \ - info.geometries[{0}].index_data is Some, \ - and build_range_infos[{0}].primitive_offset + \ - 3 * build_range_infos[{0}].primitive_count * \ - info.geometries[{0}].index_data.index_type().size is greater \ - than the size of infos.geometries[{0}].index_data", + "`infos.geometries` is \ + `AccelerationStructureGeometries::Triangles`, \ + `info.geometries[{0}].index_data` is `Some`, and \ + `build_range_infos[{0}].primitive_offset` + \ + 3 * `build_range_infos[{0}].primitive_count` * \ + `info.geometries[{0}].index_data.index_type().size` is \ + greater than the size of `infos.geometries[{0}].index_data`", geometry_index, ) .into(), @@ -397,11 +401,11 @@ where if primitive_offset % smallest_component_bytes != 0 { return Err(ValidationError { problem: format!( - "info.geometries is \ - AccelerationStructureGeometries::Triangles, and - build_range_infos[{}].primitive_offset is not a multiple of \ + "`info.geometries` is \ + `AccelerationStructureGeometries::Triangles`, and + `build_range_infos[{}].primitive_offset` is not a multiple of \ the byte size of the smallest component of \ - info.geometries[{0}].vertex_format", + `info.geometries[{0}].vertex_format`", geometry_index, ) .into(), @@ -417,14 +421,14 @@ where { return Err(ValidationError { problem: format!( - "infos.geometries is \ - AccelerationStructureGeometries::Triangles, \ - info.geometries[{0}].index_data is None, \ - and build_range_infos[{0}].primitive_offset + \ - (build_range_infos[{0}].first_vertex + 3 * \ - build_range_infos[{0}].primitive_count) * \ - info.geometries[{0}].vertex_stride is greater than the size \ - of infos.geometries[{0}].vertex_data", + "`infos.geometries` is \ + `AccelerationStructureGeometries::Triangles`, \ + `info.geometries[{0}].index_data` is `None`, \ + and `build_range_infos[{0}].primitive_offset` + \ + (`build_range_infos[{0}].first_vertex` + 3 * \ + `build_range_infos[{0}].primitive_count`) * \ + `info.geometries[{0}].vertex_stride` is greater than the size \ + of `infos.geometries[{0}].vertex_data`", geometry_index, ) .into(), @@ -446,7 +450,8 @@ where ) .into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` \ + usage" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673"], ..Default::default() @@ -470,9 +475,10 @@ where if transform_offset % 16 != 0 { return Err(ValidationError { problem: format!( - "info.geometries is \ - AccelerationStructureGeometries::Triangles, and - build_range_infos[{}].transform_offset is not a multiple of 16", + "`info.geometries` is \ + `AccelerationStructureGeometries::Triangles`, and \ + `build_range_infos[{}].transform_offset` is not a multiple of \ + 16", geometry_index, ) .into(), @@ -487,11 +493,11 @@ where { return Err(ValidationError { problem: format!( - "infos.geometries is \ - AccelerationStructureGeometries::Triangles, and \ - build_range_infos[{0}].transform_offset + \ - size_of:: is greater than the size of \ - infos.geometries[{0}].transform_data", + "`infos.geometries` is \ + `AccelerationStructureGeometries::Triangles`, and \ + `build_range_infos[{0}].transform_offset` + \ + `size_of::` is greater than the size of \ + `infos.geometries[{0}].transform_data`", geometry_index, ) .into(), @@ -522,7 +528,7 @@ where if primitive_count as u64 > max_primitive_count { return Err(ValidationError { context: format!("build_range_infos[{}]", geometry_index).into(), - problem: "the max_primitive_count limit has been exceeded".into(), + problem: "exceeds the `max_primitive_count` limit".into(), vuids: &["VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03794"], ..Default::default() }); @@ -536,7 +542,8 @@ where return Err(ValidationError { context: format!("info.geometries[{}].data", geometry_index).into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` \ + usage" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673"], ..Default::default() @@ -555,9 +562,9 @@ where if primitive_offset % 8 != 0 { return Err(ValidationError { problem: format!( - "info.geometries is \ - AccelerationStructureGeometries::Aabbs, and - build_range_infos[{}].primitive_offset is not a multiple of 8", + "`info.geometries` is \ + `AccelerationStructureGeometries::Aabbs`, and \ + `build_range_infos[{}].primitive_offset` is not a multiple of 8", geometry_index, ) .into(), @@ -572,11 +579,11 @@ where { return Err(ValidationError { problem: format!( - "infos.geometries is AccelerationStructureGeometries::Aabbs, - and build_range_infos[{0}].primitive_offset + \ - build_range_infos[{0}].primitive_count * \ - info.geometries[{0}].stride is greater than the size of - infos.geometries[{0}].data", + "`infos.geometries` is `AccelerationStructureGeometries::Aabbs`, + and `build_range_infos[{0}].primitive_offset` + \ + `build_range_infos[{0}].primitive_count` * \ + `info.geometries[{0}].stride` is greater than the size of \ + `infos.geometries[{0}].data`", geometry_index, ) .into(), @@ -602,7 +609,7 @@ where if primitive_count as u64 > max_instance_count { return Err(ValidationError { context: "build_range_infos[0]".into(), - problem: "the max_instance_count limit has been exceeded".into(), + problem: "exceeds the the `max_instance_count` limit".into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03801"], ..Default::default() }); @@ -610,9 +617,9 @@ where if primitive_offset % 16 != 0 { return Err(ValidationError { - problem: "info.geometries is \ - AccelerationStructureGeometries::Instances, and - build_range_infos[0].primitive_offset is not a multiple of 16" + problem: "`info.geometries is` \ + `AccelerationStructureGeometries::Instances`, and \ + `build_range_infos[0].primitive_offset` is not a multiple of 16" .into(), vuids: &[ "VUID-VkAccelerationStructureBuildRangeInfoKHR-primitiveOffset-03660", @@ -626,8 +633,8 @@ where if data.device_address().unwrap().get() % 16 != 0 { return Err(ValidationError { context: "info.geometries.data".into(), - problem: "is AccelerationStructureGeometryInstancesDataType::\ - Values, and the buffer's device address is not a multiple of \ + problem: "is `AccelerationStructureGeometryInstancesDataType::\ + Values`, and the buffer's device address is not a multiple of \ 16" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03715"], @@ -641,14 +648,14 @@ where > data.size() { return Err(ValidationError { - problem: "infos.geometries is - AccelerationStructureGeometries::Instances, \ - infos.geometries.data is \ - AccelerationStructureGeometryInstancesDataType::Values, and \ - build_range_infos[0].primitive_offset + \ - build_range_infos[0].primitive_count * \ - size_of::() is greater than the \ - size of infos.geometries.data" + problem: "`infos.geometries` is \ + `AccelerationStructureGeometries::Instances`, \ + `infos.geometries.data` is \ + `AccelerationStructureGeometryInstancesDataType::Values`, and \ + `build_range_infos[0].primitive_offset` + \ + `build_range_infos[0].primitive_count` * \ + `size_of::()` is greater than \ + the size of `infos.geometries.data`" .into(), ..Default::default() }); @@ -665,7 +672,8 @@ where return Err(ValidationError { context: "info.geometries.data".into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` \ + usage" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673"], ..Default::default() @@ -675,10 +683,10 @@ where if data.device_address().unwrap().get() % 8 != 0 { return Err(ValidationError { context: "info.geometries.data".into(), - problem: - "is AccelerationStructureGeometryInstancesDataType::\ - Pointers and the buffer's device address is not a multiple of 8" - .into(), + problem: "is `AccelerationStructureGeometryInstancesDataType::\ + Pointers` and the buffer's device address is not a multiple \ + of 8" + .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03716"], ..Default::default() }); @@ -689,14 +697,14 @@ where > data.size() { return Err(ValidationError { - problem: "infos.geometries is - AccelerationStructureGeometries::Instances, \ - infos.geometries.data is \ - AccelerationStructureGeometryInstancesDataType::Pointers, and \ - build_range_infos[0].primitive_offset + \ - build_range_infos[0].primitive_count * \ - size_of::() is greater than the \ - size of infos.geometries.data" + problem: "`infos.geometries` is \ + `AccelerationStructureGeometries::Instances`, \ + `infos.geometries.data` is \ + `AccelerationStructureGeometryInstancesDataType::Pointers`, \ + and `build_range_infos[0].primitive_offset` + \ + `build_range_infos[0].primitive_count` * \ + `size_of::()` is greater than the \ + size of `infos.geometries.data`" .into(), ..Default::default() }); @@ -716,7 +724,7 @@ where return Err(ValidationError { context: "info.geometries.data".into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673"], ..Default::default() @@ -962,7 +970,8 @@ where { return Err(ValidationError { context: "info.scratch_data".into(), - problem: "the buffer was not created with the `STORAGE_BUFFER` usage".into(), + problem: "the buffer was not created with the `BufferUsage::STORAGE_BUFFER` usage" + .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03674"], ..Default::default() }); @@ -981,8 +990,8 @@ where { return Err(ValidationError { context: "info.scratch_data".into(), - problem: "the device address of the buffer was not a multiple of the \ - min_acceleration_structure_scratch_offset_alignment device property" + problem: "the device address of the buffer is not a multiple of the \ + `min_acceleration_structure_scratch_offset_alignment` device property" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03710"], ..Default::default() @@ -994,9 +1003,9 @@ where if !matches!(geometries, AccelerationStructureGeometries::Instances(_)) { return Err(ValidationError { context: "info".into(), - problem: "dst_acceleration_structure is a top-level \ - acceleration structure, but geometries is not \ - AccelerationStructureGeometries::Instances" + problem: "`dst_acceleration_structure` is a top-level \ + acceleration structure, but `geometries` is not \ + `AccelerationStructureGeometries::Instances`" .into(), vuids: &[ "VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03789", @@ -1010,9 +1019,9 @@ where if matches!(geometries, AccelerationStructureGeometries::Instances(_)) { return Err(ValidationError { context: "info".into(), - problem: "dst_acceleration_structure is a bottom-level \ - acceleration structure, but geometries is \ - AccelerationStructureGeometries::Instances" + problem: "`dst_acceleration_structure` is a bottom-level \ + acceleration structure, but `geometries` is \ + `AccelerationStructureGeometries::Instances`" .into(), vuids: &[ "VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03791", @@ -1027,7 +1036,7 @@ where if geometries.len() != max_primitive_counts.len() { return Err(ValidationError { - problem: "info.geometries and max_primitive_counts do not have the same length" + problem: "`info.geometries` and `max_primitive_counts` do not have the same length" .into(), vuids: &[ "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-ppMaxPrimitiveCounts-parameter", @@ -1062,7 +1071,7 @@ where context: format!("info.geometries[{}].vertex_data", geometry_index) .into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" .into(), vuids: &[ "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-geometry-03673", @@ -1086,7 +1095,7 @@ where context: format!("info.geometries[{}].vertex_data", geometry_index) .into(), problem: "the buffer's device address is not a multiple of the byte \ - size of the smallest component of vertex_format" + size of the smallest component of `vertex_format`" .into(), vuids: &[ "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03711", @@ -1106,7 +1115,8 @@ where context: format!("info.geometries[{}].index_data", geometry_index) .into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` \ + usage" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresIndirectKHR-geometry-03673"], ..Default::default() @@ -1150,7 +1160,8 @@ where ) .into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` \ + usage" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresIndirectKHR-geometry-03673"], ..Default::default() @@ -1198,7 +1209,7 @@ where return Err(ValidationError { context: format!("info.geometries[{}].data", geometry_index).into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" .into(), vuids: &[ "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-geometry-03673", @@ -1237,9 +1248,10 @@ where if data.device_address().unwrap().get() % 16 != 0 { return Err(ValidationError { context: "info.geometries.data".into(), - problem: "is AccelerationStructureGeometryInstancesDataType::\ - Values and the buffer's device address is not a multiple of 16" - .into(), + problem: "is `AccelerationStructureGeometryInstancesDataType::\ + Values` and the buffer's device address is not a multiple of \ + 16" + .into(), vuids: &[ "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03715", ], @@ -1258,7 +1270,8 @@ where return Err(ValidationError { context: "info.geometries.data".into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` \ + usage" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresIndirectKHR-geometry-03673"], ..Default::default() @@ -1268,10 +1281,10 @@ where if data.device_address().unwrap().get() % 8 != 0 { return Err(ValidationError { context: "info.geometries.data".into(), - problem: - "is AccelerationStructureGeometryInstancesDataType::\ - Pointers and the buffer's device address is not a multiple of 8" - .into(), + problem: "is `AccelerationStructureGeometryInstancesDataType::\ + Pointers` and the buffer's device address is not a multiple \ + of 8" + .into(), vuids: &[ "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03716", ], @@ -1293,7 +1306,7 @@ where return Err(ValidationError { context: "info.geometries.data".into(), problem: "the buffer was not created with the \ - `ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" + `BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY` usage" .into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresIndirectKHR-geometry-03673"], ..Default::default() @@ -1354,7 +1367,8 @@ where if geometries.len() as DeviceSize * stride as DeviceSize > indirect_buffer.size() { return Err(ValidationError { - problem: "info.geometries.len() * stride is greater than the size of indirect_buffer".into(), + problem: "`info.geometries.len()` * `stride` is greater than the size of \ + `indirect_buffer`".into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pIndirectDeviceAddresses-03646"], ..Default::default() }); @@ -1367,7 +1381,7 @@ where { return Err(ValidationError { context: "indirect_buffer".into(), - problem: "the buffer was not created with the `INDIRECT_BUFFER` usage".into(), + problem: "the buffer was not created with the `BufferUsage::INDIRECT_BUFFER` usage".into(), vuids: &["VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pIndirectDeviceAddresses-03647"], ..Default::default() }); @@ -1576,7 +1590,7 @@ where if info.dst.device_address().unwrap().get() % 256 != 0 { return Err(ValidationError { context: "info.dst".into(), - problem: "the device address of the buffer was not a multiple of 256".into(), + problem: "the device address of the buffer is not a multiple of 256".into(), vuids: &["VUID-vkCmdCopyAccelerationStructureToMemoryKHR-pInfo-03740"], ..Default::default() }); @@ -1686,7 +1700,7 @@ where if info.src.device_address().unwrap().get() % 256 != 0 { return Err(ValidationError { context: "info.src".into(), - problem: "the device address of the buffer was not a multiple of 256".into(), + problem: "the device address of the buffer is not a multiple of 256".into(), vuids: &["VUID-vkCmdCopyMemoryToAccelerationStructureKHR-pInfo-03743"], ..Default::default() }); @@ -1834,8 +1848,8 @@ where if first_query as usize + acceleration_structures.len() > query_pool.query_count() as usize { return Err(ValidationError { - problem: "first_query + acceleration_structures.len() is greater than \ - query_pool.query_count" + problem: "`first_query` + `acceleration_structures.len()` is greater than \ + `query_pool.query_count`" .into(), vuids: &["VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-query-04880"], ..Default::default() diff --git a/vulkano/src/descriptor_set/layout.rs b/vulkano/src/descriptor_set/layout.rs index 613e2f269b..587c8ef5b1 100644 --- a/vulkano/src/descriptor_set/layout.rs +++ b/vulkano/src/descriptor_set/layout.rs @@ -441,7 +441,7 @@ impl DescriptorSetLayoutCreateInfo { { return Err(ValidationError { problem: "`flags` contains `DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR`, and \ - the total number of descriptors in `bindings` exceeds the + the total number of descriptors in `bindings` exceeds the \ `max_push_descriptors` limit" .into(), vuids: &["VUID-VkDescriptorSetLayoutCreateInfo-flags-00281"], @@ -648,7 +648,7 @@ impl DescriptorSetLayoutBinding { if !device.enabled_features().inline_uniform_block { return Err(ValidationError { context: "descriptor_type".into(), - problem: "DescriptorType::InlineUniformBlock".into(), + problem: "`DescriptorType::InlineUniformBlock`".into(), requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( "inline_uniform_block", )])]), diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index c1138cd582..e5355a8a5b 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -664,7 +664,7 @@ impl Device { if primitive_count as u64 > max_primitive_count { return Err(ValidationError { context: format!("max_primitive_counts[{}]", index).into(), - problem: "the max_primitive_count limit has been exceeded".into(), + problem: "exceeds the `max_primitive_count` limit".into(), vuids: &["VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03795"], ..Default::default() }); @@ -678,7 +678,7 @@ impl Device { if primitive_count as u64 > max_primitive_count { return Err(ValidationError { context: format!("max_primitive_counts[{}]", index).into(), - problem: "the max_primitive_count limit has been exceeded".into(), + problem: "exceeds the `max_primitive_count` limit".into(), vuids: &["VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03794"], ..Default::default() }); @@ -692,7 +692,7 @@ impl Device { if instance_count as u64 > max_instance_count { return Err(ValidationError { context: format!("max_primitive_counts[{}]", index).into(), - problem: "the max_instance_count limit has been exceeded".into(), + problem: "exceeds the `max_instance_count` limit".into(), vuids: &[ "VUID-vkGetAccelerationStructureBuildSizesKHR-pBuildInfo-03785", ], @@ -707,7 +707,7 @@ impl Device { if max_primitive_counts.len() != geometry_count { return Err(ValidationError { - problem: "build_info.geometries and max_primitive_counts \ + problem: "`build_info.geometries` and `max_primitive_counts` \ do not have the same length" .into(), vuids: &["VUID-vkGetAccelerationStructureBuildSizesKHR-pBuildInfo-03619"], diff --git a/vulkano/src/sampler/mod.rs b/vulkano/src/sampler/mod.rs index 45f5961b80..d8048b3acf 100644 --- a/vulkano/src/sampler/mod.rs +++ b/vulkano/src/sampler/mod.rs @@ -530,7 +530,7 @@ impl Sampler { return Err(ValidationError { problem: "the sampler has depth comparison enabled, and \ the image view's format features do not include \ - FormatFeatures::SAMPLED_IMAGE_DEPTH_COMPARISON" + `FormatFeatures::SAMPLED_IMAGE_DEPTH_COMPARISON`" .into(), ..Default::default() }); @@ -546,7 +546,7 @@ impl Sampler { { return Err(ValidationError { problem: "the sampler has depth comparison enabled, and \ - the image view's aspects do not include ImageAspects::DEPTH" + the image view's aspects do not include `ImageAspects::DEPTH`" .into(), ..Default::default() }); @@ -559,9 +559,9 @@ impl Sampler { // VUID-vkCmdDispatch-magFilter-04553 if self.mag_filter == Filter::Linear || self.min_filter == Filter::Linear { return Err(ValidationError { - problem: "the sampler's mag_filter or min_filter is Filter::Linear, and \ - the image view's format features do not include \ - FormatFeatures::SAMPLED_IMAGE_FILTER_LINEAR" + problem: "the sampler's `mag_filter` or `min_filter` is `Filter::Linear`, \ + and the image view's format features do not include \ + `FormatFeatures::SAMPLED_IMAGE_FILTER_LINEAR`" .into(), ..Default::default() }); @@ -570,9 +570,9 @@ impl Sampler { // VUID-vkCmdDispatch-mipmapMode-04770 if self.mipmap_mode == SamplerMipmapMode::Linear { return Err(ValidationError { - problem: "the sampler's mipmap_mode is SamplerMipmapMpde::Linear, and \ + problem: "the sampler's `mipmap_mode` is `SamplerMipmapMpde::Linear`, and \ the image view's format features do not include \ - FormatFeatures::SAMPLED_IMAGE_FILTER_LINEAR" + `FormatFeatures::SAMPLED_IMAGE_FILTER_LINEAR`" .into(), ..Default::default() }); @@ -587,9 +587,9 @@ impl Sampler { .intersects(FormatFeatures::SAMPLED_IMAGE_FILTER_CUBIC) { return Err(ValidationError { - problem: "the sampler's mag_filter or min_filter is Filter::Cubic, and \ + problem: "the sampler's `mag_filter` or `min_filter` is `Filter::Cubic`, and \ the image view's format features do not include \ - FormatFeatures::SAMPLED_IMAGE_FILTER_CUBIC" + `FormatFeatures::SAMPLED_IMAGE_FILTER_CUBIC`" .into(), ..Default::default() }); @@ -598,9 +598,9 @@ impl Sampler { // VUID-vkCmdDispatch-filterCubic-02694 if !image_view.filter_cubic() { return Err(ValidationError { - problem: "the sampler's mag_filter or min_filter is Filter::Cubic, and \ + problem: "the sampler's `mag_filter` or `min_filter` is Filter::Cubic, and \ the image view does not support this, as returned by \ - PhysicalDevice::image_format_properties" + `PhysicalDevice::image_format_properties`" .into(), ..Default::default() }); @@ -613,11 +613,11 @@ impl Sampler { ) && !image_view.filter_cubic_minmax() { return Err(ValidationError { - problem: "the sampler's mag_filter or min_filter is Filter::Cubic, and \ - the its reduction_mode is SamplerReductionMode::Min or \ - SamplerReductionMode::Max, and + problem: "the sampler's `mag_filter` or `min_filter` is `Filter::Cubic`, and \ + the its `reduction_mode` is `SamplerReductionMode::Min` or \ + `SamplerReductionMode::Max`, and \ the image view does not support this, as returned by \ - PhysicalDevice::image_format_properties" + `PhysicalDevice::image_format_properties`" .into(), ..Default::default() }); @@ -715,7 +715,8 @@ impl Sampler { ) { return Err(ValidationError { problem: "the sampler uses unnormalized coordinates, and \ - the image view's type is not ImageViewtype::Dim1d or ImageViewType::Dim2d" + the image view's type is not `ImageViewtype::Dim1d` or \ + `ImageViewType::Dim2d`" .into(), ..Default::default() }); From 7c14786cb78008b1037a9464be7ff039ccacefe7 Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 18 Jun 2023 12:02:27 +0200 Subject: [PATCH 3/6] Use updated VUIDs that require `acceleration_structure` --- vulkano/src/device/mod.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index e5355a8a5b..6ac1048f3f 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -623,13 +623,14 @@ impl Device { }); } - if !(self.enabled_features().ray_tracing_pipeline || self.enabled_features().ray_query) { + if !self.enabled_features().acceleration_structure { return Err(ValidationError { - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::Feature("ray_tracing_pipeline")]), - RequiresAllOf(&[Requires::Feature("ray_query")]), - ]), - vuids: &["VUID-vkGetAccelerationStructureBuildSizesKHR-rayTracingPipeline-03617"], + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "acceleration_structure", + )])]), + vuids: &[ + "VUID-vkGetAccelerationStructureBuildSizesKHR-accelerationStructure-08933", + ], ..Default::default() }); } @@ -777,13 +778,12 @@ impl Device { }); } - if !(self.enabled_features().ray_tracing_pipeline || self.enabled_features().ray_query) { + if !self.enabled_features().acceleration_structure { return Err(ValidationError { requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::Feature("ray_tracing_pipeline")]), - RequiresAllOf(&[Requires::Feature("ray_query")]), + RequiresAllOf(&[Requires::Feature("acceleration_structure")]), ]), - vuids: &["VUID-vkGetDeviceAccelerationStructureCompatibilityKHR-rayTracingPipeline-03661"], + vuids: &["VUID-vkGetDeviceAccelerationStructureCompatibilityKHR-accelerationStructure-08928"], ..Default::default() }); } From ffe1d1b26fc14f472b50673c77637461cb1e0b65 Mon Sep 17 00:00:00 2001 From: Rua Date: Fri, 23 Jun 2023 17:38:12 +0200 Subject: [PATCH 4/6] ValidationError-ify `GraphicsPipeline` --- examples/src/bin/async-update.rs | 14 +- examples/src/bin/basic-compute-shader.rs | 4 +- examples/src/bin/buffer-allocator.rs | 15 +- .../deferred/frame/ambient_lighting_system.rs | 24 +- .../frame/directional_lighting_system.rs | 24 +- .../deferred/frame/point_lighting_system.rs | 24 +- .../src/bin/deferred/triangle_draw_system.rs | 13 +- examples/src/bin/dynamic-buffers.rs | 4 +- examples/src/bin/dynamic-local-size.rs | 4 +- examples/src/bin/gl-interop.rs | 21 +- examples/src/bin/image-self-copy-blit/main.rs | 14 +- examples/src/bin/image/main.rs | 14 +- examples/src/bin/immutable-sampler/main.rs | 14 +- examples/src/bin/indirect.rs | 16 +- examples/src/bin/instancing.rs | 15 +- .../fractal_compute_pipeline.rs | 4 +- .../pixels_draw_pipeline.rs | 12 +- examples/src/bin/msaa-renderpass.rs | 13 +- examples/src/bin/multi-window.rs | 15 +- .../multi_window_game_of_life/game_of_life.rs | 4 +- .../multi_window_game_of_life/pixels_draw.rs | 12 +- examples/src/bin/multiview.rs | 13 +- examples/src/bin/occlusion-query.rs | 15 +- examples/src/bin/pipeline-caching.rs | 34 +- examples/src/bin/push-constants.rs | 4 +- examples/src/bin/push-descriptors/main.rs | 14 +- examples/src/bin/runtime-shader/main.rs | 16 +- examples/src/bin/runtime_array/main.rs | 14 +- examples/src/bin/self-copy-buffer.rs | 4 +- examples/src/bin/shader-include/main.rs | 4 +- examples/src/bin/shader-types-sharing.rs | 6 +- examples/src/bin/simple-particles.rs | 14 +- examples/src/bin/specialization-constants.rs | 4 +- examples/src/bin/teapot/main.rs | 13 +- examples/src/bin/tessellation.rs | 19 +- examples/src/bin/texture_array/main.rs | 14 +- examples/src/bin/triangle-v1_3.rs | 15 +- examples/src/bin/triangle.rs | 15 +- .../command_buffer/commands/dynamic_state.rs | 5 - vulkano/src/descriptor_set/layout.rs | 78 +- vulkano/src/pipeline/cache.rs | 338 +- vulkano/src/pipeline/compute.rs | 168 +- vulkano/src/pipeline/graphics/color_blend.rs | 392 +- .../src/pipeline/graphics/depth_stencil.rs | 365 +- .../pipeline/graphics/discard_rectangle.rs | 35 + .../src/pipeline/graphics/input_assembly.rs | 162 + vulkano/src/pipeline/graphics/mod.rs | 6689 ++++++----------- vulkano/src/pipeline/graphics/multisample.rs | 59 +- .../src/pipeline/graphics/rasterization.rs | 353 +- vulkano/src/pipeline/graphics/subpass.rs | 150 +- vulkano/src/pipeline/graphics/tessellation.rs | 82 +- .../pipeline/graphics/vertex_input/buffers.rs | 10 +- .../graphics/vertex_input/definition.rs | 96 +- .../src/pipeline/graphics/vertex_input/mod.rs | 271 +- vulkano/src/pipeline/graphics/viewport.rs | 520 +- vulkano/src/pipeline/layout.rs | 124 +- vulkano/src/pipeline/mod.rs | 213 +- vulkano/src/shader/mod.rs | 66 +- 58 files changed, 5523 insertions(+), 5151 deletions(-) diff --git a/examples/src/bin/async-update.rs b/examples/src/bin/async-update.rs index a774876945..ae08083920 100644 --- a/examples/src/bin/async-update.rs +++ b/examples/src/bin/async-update.rs @@ -79,10 +79,10 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Sampler, SamplerCreateInfo}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -438,8 +438,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -471,9 +471,9 @@ fn main() { }; let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); @@ -850,7 +850,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/basic-compute-shader.rs b/examples/src/bin/basic-compute-shader.rs index 934ee27dc9..e7dc821a24 100644 --- a/examples/src/bin/basic-compute-shader.rs +++ b/examples/src/bin/basic-compute-shader.rs @@ -30,8 +30,8 @@ use vulkano::{ pipeline::{ compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::PipelineShaderStageCreateInfo, sync::{self, GpuFuture}, VulkanLibrary, }; @@ -142,7 +142,7 @@ fn main() { .unwrap() .entry_point("main") .unwrap(); - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) diff --git a/examples/src/bin/buffer-allocator.rs b/examples/src/bin/buffer-allocator.rs index cbf8ae70ec..da3352d12c 100644 --- a/examples/src/bin/buffer-allocator.rs +++ b/examples/src/bin/buffer-allocator.rs @@ -40,10 +40,9 @@ use vulkano::{ GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, - GraphicsPipeline, PipelineLayout, + GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -237,8 +236,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -267,9 +266,9 @@ fn main() { }; let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); let mut recreate_swapchain = false; @@ -435,7 +434,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/deferred/frame/ambient_lighting_system.rs b/examples/src/bin/deferred/frame/ambient_lighting_system.rs index 7f64b089b0..245f380bdc 100644 --- a/examples/src/bin/deferred/frame/ambient_lighting_system.rs +++ b/examples/src/bin/deferred/frame/ambient_lighting_system.rs @@ -32,9 +32,9 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::Subpass, - shader::PipelineShaderStageCreateInfo, }; use super::LightingVertex; @@ -99,8 +99,8 @@ impl AmbientLightingSystem { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -122,12 +122,12 @@ impl AmbientLightingSystem { color_blend_state: Some( ColorBlendState::new(subpass.num_color_attachments()).blend( AttachmentBlend { - color_op: BlendOp::Add, - color_source: BlendFactor::One, - color_destination: BlendFactor::One, - alpha_op: BlendOp::Max, - alpha_source: BlendFactor::One, - alpha_destination: BlendFactor::One, + color_blend_op: BlendOp::Add, + src_color_blend_factor: BlendFactor::One, + dst_color_blend_factor: BlendFactor::One, + alpha_blend_op: BlendOp::Max, + src_alpha_blend_factor: BlendFactor::One, + dst_alpha_blend_factor: BlendFactor::One, }, ), ), @@ -179,9 +179,9 @@ impl AmbientLightingSystem { .unwrap(); let viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], + depth_range: 0.0..=1.0, }; let mut builder = AutoCommandBufferBuilder::secondary( diff --git a/examples/src/bin/deferred/frame/directional_lighting_system.rs b/examples/src/bin/deferred/frame/directional_lighting_system.rs index 5f145ba146..27d22752bd 100644 --- a/examples/src/bin/deferred/frame/directional_lighting_system.rs +++ b/examples/src/bin/deferred/frame/directional_lighting_system.rs @@ -33,9 +33,9 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::Subpass, - shader::PipelineShaderStageCreateInfo, }; use super::LightingVertex; @@ -102,8 +102,8 @@ impl DirectionalLightingSystem { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -125,12 +125,12 @@ impl DirectionalLightingSystem { color_blend_state: Some( ColorBlendState::new(subpass.num_color_attachments()).blend( AttachmentBlend { - color_op: BlendOp::Add, - color_source: BlendFactor::One, - color_destination: BlendFactor::One, - alpha_op: BlendOp::Max, - alpha_source: BlendFactor::One, - alpha_destination: BlendFactor::One, + color_blend_op: BlendOp::Add, + src_color_blend_factor: BlendFactor::One, + dst_color_blend_factor: BlendFactor::One, + alpha_blend_op: BlendOp::Max, + src_alpha_blend_factor: BlendFactor::One, + dst_alpha_blend_factor: BlendFactor::One, }, ), ), @@ -195,9 +195,9 @@ impl DirectionalLightingSystem { .unwrap(); let viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], + depth_range: 0.0..=1.0, }; let mut builder = AutoCommandBufferBuilder::secondary( diff --git a/examples/src/bin/deferred/frame/point_lighting_system.rs b/examples/src/bin/deferred/frame/point_lighting_system.rs index 4c742e9298..eda6ee64db 100644 --- a/examples/src/bin/deferred/frame/point_lighting_system.rs +++ b/examples/src/bin/deferred/frame/point_lighting_system.rs @@ -33,9 +33,9 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::Subpass, - shader::PipelineShaderStageCreateInfo, }; use super::LightingVertex; @@ -99,8 +99,8 @@ impl PointLightingSystem { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -122,12 +122,12 @@ impl PointLightingSystem { color_blend_state: Some( ColorBlendState::new(subpass.num_color_attachments()).blend( AttachmentBlend { - color_op: BlendOp::Add, - color_source: BlendFactor::One, - color_destination: BlendFactor::One, - alpha_op: BlendOp::Max, - alpha_source: BlendFactor::One, - alpha_destination: BlendFactor::One, + color_blend_op: BlendOp::Add, + src_color_blend_factor: BlendFactor::One, + dst_color_blend_factor: BlendFactor::One, + alpha_blend_op: BlendOp::Max, + src_alpha_blend_factor: BlendFactor::One, + dst_alpha_blend_factor: BlendFactor::One, }, ), ), @@ -206,9 +206,9 @@ impl PointLightingSystem { .unwrap(); let viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], + depth_range: 0.0..=1.0, }; let mut builder = AutoCommandBufferBuilder::secondary( diff --git a/examples/src/bin/deferred/triangle_draw_system.rs b/examples/src/bin/deferred/triangle_draw_system.rs index 06ecc9ade2..a1e74390f9 100644 --- a/examples/src/bin/deferred/triangle_draw_system.rs +++ b/examples/src/bin/deferred/triangle_draw_system.rs @@ -28,10 +28,9 @@ use vulkano::{ GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, - GraphicsPipeline, PipelineLayout, + GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, render_pass::Subpass, - shader::PipelineShaderStageCreateInfo, }; pub struct TriangleDrawSystem { @@ -89,8 +88,8 @@ impl TriangleDrawSystem { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -143,9 +142,9 @@ impl TriangleDrawSystem { .set_viewport( 0, [Viewport { - origin: [0.0, 0.0], - dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], + depth_range: 0.0..=1.0, }] .into_iter() .collect(), diff --git a/examples/src/bin/dynamic-buffers.rs b/examples/src/bin/dynamic-buffers.rs index 58bb7990b3..418d2e043c 100644 --- a/examples/src/bin/dynamic-buffers.rs +++ b/examples/src/bin/dynamic-buffers.rs @@ -32,8 +32,8 @@ use vulkano::{ pipeline::{ compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::PipelineShaderStageCreateInfo, sync::{self, GpuFuture}, DeviceSize, VulkanLibrary, }; @@ -127,7 +127,7 @@ fn main() { .unwrap() .entry_point("main") .unwrap(); - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = { let mut layout_create_info = PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]); diff --git a/examples/src/bin/dynamic-local-size.rs b/examples/src/bin/dynamic-local-size.rs index 169c6719d3..1d284756fc 100644 --- a/examples/src/bin/dynamic-local-size.rs +++ b/examples/src/bin/dynamic-local-size.rs @@ -34,8 +34,8 @@ use vulkano::{ pipeline::{ compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::PipelineShaderStageCreateInfo, sync::{self, GpuFuture}, VulkanLibrary, }; @@ -192,7 +192,7 @@ fn main() { ] .into_iter() .collect(), - ..PipelineShaderStageCreateInfo::entry_point(cs) + ..PipelineShaderStageCreateInfo::new(cs) }; let layout = PipelineLayout::new( device.clone(), diff --git a/examples/src/bin/gl-interop.rs b/examples/src/bin/gl-interop.rs index f516162861..c06ea0cb75 100644 --- a/examples/src/bin/gl-interop.rs +++ b/examples/src/bin/gl-interop.rs @@ -41,15 +41,15 @@ mod linux { multisample::MultisampleState, rasterization::RasterizationState, vertex_input::{Vertex, VertexDefinition}, - viewport::{Scissor, Viewport, ViewportState}, + viewport::{Viewport, ViewportState}, GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, - shader::PipelineShaderStageCreateInfo, swapchain::{ AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -621,8 +621,8 @@ mod linux { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -641,10 +641,7 @@ mod linux { input_assembly_state: Some( InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip), ), - viewport_state: Some(ViewportState::FixedScissor { - scissors: (0..1).map(|_| Scissor::irrelevant()).collect(), - viewport_count_dynamic: false, - }), + viewport_state: Some(ViewportState::viewport_dynamic_scissor_irrelevant()), rasterization_state: Some(RasterizationState::default()), multisample_state: Some(MultisampleState::default()), color_blend_state: Some( @@ -658,9 +655,9 @@ mod linux { }; let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); @@ -705,7 +702,7 @@ mod linux { ) -> Vec> { use vulkano::{image::ImageAccess, render_pass::FramebufferCreateInfo}; let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/image-self-copy-blit/main.rs b/examples/src/bin/image-self-copy-blit/main.rs index 8897e26f44..16e5f498c3 100644 --- a/examples/src/bin/image-self-copy-blit/main.rs +++ b/examples/src/bin/image-self-copy-blit/main.rs @@ -42,10 +42,10 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -348,8 +348,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -391,9 +391,9 @@ fn main() { .unwrap(); let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); @@ -527,7 +527,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/image/main.rs b/examples/src/bin/image/main.rs index 3d838e5a6f..7d3ed079ef 100644 --- a/examples/src/bin/image/main.rs +++ b/examples/src/bin/image/main.rs @@ -40,10 +40,10 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -274,8 +274,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -317,9 +317,9 @@ fn main() { .unwrap(); let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); @@ -453,7 +453,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/immutable-sampler/main.rs b/examples/src/bin/immutable-sampler/main.rs index 54209ba442..96b658c16e 100644 --- a/examples/src/bin/immutable-sampler/main.rs +++ b/examples/src/bin/immutable-sampler/main.rs @@ -49,10 +49,10 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -280,8 +280,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = { let mut layout_create_info = @@ -338,9 +338,9 @@ fn main() { .unwrap(); let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); @@ -474,7 +474,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/indirect.rs b/examples/src/bin/indirect.rs index 6ba1545109..01b0cd7f5a 100644 --- a/examples/src/bin/indirect.rs +++ b/examples/src/bin/indirect.rs @@ -56,9 +56,9 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, - shader::PipelineShaderStageCreateInfo, single_pass_renderpass, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, @@ -272,7 +272,7 @@ fn main() { .unwrap() .entry_point("main") .unwrap(); - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) @@ -327,8 +327,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -357,9 +357,9 @@ fn main() { }; let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); let mut recreate_swapchain = false; @@ -541,7 +541,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/instancing.rs b/examples/src/bin/instancing.rs index 646696dd54..024181eb2e 100644 --- a/examples/src/bin/instancing.rs +++ b/examples/src/bin/instancing.rs @@ -37,10 +37,9 @@ use vulkano::{ GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, - GraphicsPipeline, PipelineLayout, + GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, - shader::PipelineShaderStageCreateInfo, single_pass_renderpass, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, @@ -307,8 +306,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -339,9 +338,9 @@ fn main() { }; let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); let mut recreate_swapchain = false; @@ -476,7 +475,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/interactive_fractal/fractal_compute_pipeline.rs b/examples/src/bin/interactive_fractal/fractal_compute_pipeline.rs index 6281cb4679..982b0d090c 100644 --- a/examples/src/bin/interactive_fractal/fractal_compute_pipeline.rs +++ b/examples/src/bin/interactive_fractal/fractal_compute_pipeline.rs @@ -25,8 +25,8 @@ use vulkano::{ pipeline::{ compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::PipelineShaderStageCreateInfo, sync::GpuFuture, }; use vulkano_util::renderer::DeviceImageView; @@ -80,7 +80,7 @@ impl FractalComputePipeline { .unwrap() .entry_point("main") .unwrap(); - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) diff --git a/examples/src/bin/interactive_fractal/pixels_draw_pipeline.rs b/examples/src/bin/interactive_fractal/pixels_draw_pipeline.rs index 44dc7b75f3..8a0dfb28b1 100644 --- a/examples/src/bin/interactive_fractal/pixels_draw_pipeline.rs +++ b/examples/src/bin/interactive_fractal/pixels_draw_pipeline.rs @@ -32,10 +32,10 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::Subpass, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode}, - shader::PipelineShaderStageCreateInfo, }; /// Vertex for textured quads. @@ -133,8 +133,8 @@ impl PixelsDrawPipeline { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -223,9 +223,9 @@ impl PixelsDrawPipeline { .set_viewport( 0, [Viewport { - origin: [0.0, 0.0], - dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], + depth_range: 0.0..=1.0, }] .into_iter() .collect(), diff --git a/examples/src/bin/msaa-renderpass.rs b/examples/src/bin/msaa-renderpass.rs index d11ea3c1f4..b5f80d59c1 100644 --- a/examples/src/bin/msaa-renderpass.rs +++ b/examples/src/bin/msaa-renderpass.rs @@ -88,10 +88,9 @@ use vulkano::{ GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, - GraphicsPipeline, PipelineLayout, + GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, Subpass}, - shader::PipelineShaderStageCreateInfo, sync::GpuFuture, VulkanLibrary, }; @@ -315,8 +314,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -348,9 +347,9 @@ fn main() { }; let viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [1024.0, 1024.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [1024.0, 1024.0], + depth_range: 0.0..=1.0, }; let command_buffer_allocator = StandardCommandBufferAllocator::new(device, Default::default()); diff --git a/examples/src/bin/multi-window.rs b/examples/src/bin/multi-window.rs index e754ba04f1..a7c5063d18 100644 --- a/examples/src/bin/multi-window.rs +++ b/examples/src/bin/multi-window.rs @@ -41,10 +41,9 @@ use vulkano::{ GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, - GraphicsPipeline, PipelineLayout, + GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -276,8 +275,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -306,9 +305,9 @@ fn main() { }; let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let command_buffer_allocator = @@ -516,7 +515,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/multi_window_game_of_life/game_of_life.rs b/examples/src/bin/multi_window_game_of_life/game_of_life.rs index cbc8561bdb..f8fb042e5d 100644 --- a/examples/src/bin/multi_window_game_of_life/game_of_life.rs +++ b/examples/src/bin/multi_window_game_of_life/game_of_life.rs @@ -27,8 +27,8 @@ use vulkano::{ pipeline::{ compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::PipelineShaderStageCreateInfo, sync::GpuFuture, }; use vulkano_util::renderer::DeviceImageView; @@ -77,7 +77,7 @@ impl GameOfLifeComputePipeline { .unwrap() .entry_point("main") .unwrap(); - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) diff --git a/examples/src/bin/multi_window_game_of_life/pixels_draw.rs b/examples/src/bin/multi_window_game_of_life/pixels_draw.rs index fcc2d460f7..77127c0f71 100644 --- a/examples/src/bin/multi_window_game_of_life/pixels_draw.rs +++ b/examples/src/bin/multi_window_game_of_life/pixels_draw.rs @@ -33,10 +33,10 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::Subpass, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode}, - shader::PipelineShaderStageCreateInfo, }; /// Vertex for textured quads. @@ -129,8 +129,8 @@ impl PixelsDrawPipeline { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -219,9 +219,9 @@ impl PixelsDrawPipeline { .set_viewport( 0, [Viewport { - origin: [0.0, 0.0], - dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], + depth_range: 0.0..=1.0, }] .into_iter() .collect(), diff --git a/examples/src/bin/multiview.rs b/examples/src/bin/multiview.rs index 5d92c3b395..747ec34af3 100644 --- a/examples/src/bin/multiview.rs +++ b/examples/src/bin/multiview.rs @@ -41,14 +41,13 @@ use vulkano::{ GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, - GraphicsPipeline, PipelineLayout, + GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, render_pass::{ AttachmentDescription, AttachmentLoadOp, AttachmentReference, AttachmentStoreOp, Framebuffer, FramebufferCreateInfo, RenderPass, RenderPassCreateInfo, Subpass, SubpassDescription, }, - shader::PipelineShaderStageCreateInfo, sync::{self, GpuFuture}, VulkanLibrary, }; @@ -272,8 +271,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -292,12 +291,12 @@ fn main() { input_assembly_state: Some(InputAssemblyState::default()), viewport_state: Some(ViewportState::viewport_fixed_scissor_irrelevant([ Viewport { - origin: [0.0, 0.0], - dimensions: [ + offset: [0.0, 0.0], + extent: [ image.dimensions().width() as f32, image.dimensions().height() as f32, ], - depth_range: 0.0..1.0, + depth_range: 0.0..=1.0, }, ])), rasterization_state: Some(RasterizationState::default()), diff --git a/examples/src/bin/occlusion-query.rs b/examples/src/bin/occlusion-query.rs index 8060ce5235..568fe72002 100644 --- a/examples/src/bin/occlusion-query.rs +++ b/examples/src/bin/occlusion-query.rs @@ -38,11 +38,10 @@ use vulkano::{ GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, - GraphicsPipeline, PipelineLayout, + GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, query::{QueryControlFlags, QueryPool, QueryPoolCreateInfo, QueryResultFlags, QueryType}, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -317,8 +316,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -351,9 +350,9 @@ fn main() { }; let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let command_buffer_allocator = @@ -569,7 +568,7 @@ fn window_size_dependent_setup( memory_allocator: &StandardMemoryAllocator, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; let depth_attachment = ImageView::new_default( AttachmentImage::with_usage( diff --git a/examples/src/bin/pipeline-caching.rs b/examples/src/bin/pipeline-caching.rs index 6ecdb159f8..105a2edbaa 100644 --- a/examples/src/bin/pipeline-caching.rs +++ b/examples/src/bin/pipeline-caching.rs @@ -35,10 +35,11 @@ use vulkano::{ }, instance::{Instance, InstanceCreateFlags, InstanceCreateInfo}, pipeline::{ - cache::PipelineCache, compute::ComputePipelineCreateInfo, - layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, PipelineLayout, + cache::{PipelineCache, PipelineCacheCreateInfo}, + compute::ComputePipelineCreateInfo, + layout::PipelineDescriptorSetLayoutCreateInfo, + ComputePipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, - shader::PipelineShaderStageCreateInfo, VulkanLibrary, }; @@ -100,7 +101,7 @@ fn main() { .unwrap(); // We are creating an empty PipelineCache to start somewhere. - let pipeline_cache = PipelineCache::empty(device.clone()).unwrap(); + let pipeline_cache = unsafe { PipelineCache::new(device.clone(), Default::default()).unwrap() }; // We need to create the compute pipeline that describes our operation. We are using the shader // from the basic-compute-shader example. @@ -135,7 +136,7 @@ fn main() { .unwrap() .entry_point("main") .unwrap(); - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) @@ -175,24 +176,29 @@ fn main() { // To load the cache from the file, we just need to load the data into a Vec and build the // `PipelineCache` from that. Note that this function is currently unsafe as there are no // checks, as it was mentioned at the start of this example. - let data = { + let initial_data = { if let Ok(mut file) = File::open("pipeline_cache.bin") { let mut data = Vec::new(); if file.read_to_end(&mut data).is_ok() { - Some(data) + data } else { - None + Vec::new() } } else { - None + Vec::new() } }; - let second_cache = if let Some(data) = data { - // This is unsafe because there is no way to be sure that the file contains valid data. - unsafe { PipelineCache::with_data(device, &data).unwrap() } - } else { - PipelineCache::empty(device).unwrap() + // This is unsafe because there is no way to be sure that the file contains valid data. + let second_cache = unsafe { + PipelineCache::new( + device, + PipelineCacheCreateInfo { + initial_data, + ..Default::default() + }, + ) + .unwrap() }; // As the `PipelineCache` of the Vulkan implementation saves an opaque blob of data, there is diff --git a/examples/src/bin/push-constants.rs b/examples/src/bin/push-constants.rs index 33bd74df47..acaa9929f0 100644 --- a/examples/src/bin/push-constants.rs +++ b/examples/src/bin/push-constants.rs @@ -29,8 +29,8 @@ use vulkano::{ pipeline::{ compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::PipelineShaderStageCreateInfo, sync::{self, GpuFuture}, VulkanLibrary, }; @@ -124,7 +124,7 @@ fn main() { .unwrap() .entry_point("main") .unwrap(); - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) diff --git a/examples/src/bin/push-descriptors/main.rs b/examples/src/bin/push-descriptors/main.rs index f57a8481da..8825752818 100644 --- a/examples/src/bin/push-descriptors/main.rs +++ b/examples/src/bin/push-descriptors/main.rs @@ -38,10 +38,10 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -269,8 +269,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = { let mut layout_create_info = @@ -311,9 +311,9 @@ fn main() { }; let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); @@ -449,7 +449,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/runtime-shader/main.rs b/examples/src/bin/runtime-shader/main.rs index 2afddbc8e6..fed4efa5d1 100644 --- a/examples/src/bin/runtime-shader/main.rs +++ b/examples/src/bin/runtime-shader/main.rs @@ -46,10 +46,10 @@ use vulkano::{ GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, - GraphicsPipeline, PipelineLayout, + GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, - shader::{PipelineShaderStageCreateInfo, ShaderModule}, + shader::ShaderModule, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -208,8 +208,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -288,9 +288,9 @@ fn main() { // TODO: Outdated ^ let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); let mut previous_frame_end = Some(sync::now(device.clone()).boxed()); @@ -412,7 +412,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/runtime_array/main.rs b/examples/src/bin/runtime_array/main.rs index f979b92ad6..7ff6be86de 100644 --- a/examples/src/bin/runtime_array/main.rs +++ b/examples/src/bin/runtime_array/main.rs @@ -41,10 +41,10 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -363,8 +363,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = { let mut layout_create_info = @@ -425,9 +425,9 @@ fn main() { .unwrap(); let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); @@ -561,7 +561,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/self-copy-buffer.rs b/examples/src/bin/self-copy-buffer.rs index 85f197fc87..87d8130ce6 100644 --- a/examples/src/bin/self-copy-buffer.rs +++ b/examples/src/bin/self-copy-buffer.rs @@ -29,8 +29,8 @@ use vulkano::{ pipeline::{ compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::PipelineShaderStageCreateInfo, sync::{self, GpuFuture}, VulkanLibrary, }; @@ -116,7 +116,7 @@ fn main() { .unwrap() .entry_point("main") .unwrap(); - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) diff --git a/examples/src/bin/shader-include/main.rs b/examples/src/bin/shader-include/main.rs index 63f6285bf9..3a3ab2572b 100644 --- a/examples/src/bin/shader-include/main.rs +++ b/examples/src/bin/shader-include/main.rs @@ -28,8 +28,8 @@ use vulkano::{ pipeline::{ compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::PipelineShaderStageCreateInfo, sync::{self, GpuFuture}, VulkanLibrary, }; @@ -124,7 +124,7 @@ fn main() { .unwrap() .entry_point("main") .unwrap(); - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) diff --git a/examples/src/bin/shader-types-sharing.rs b/examples/src/bin/shader-types-sharing.rs index 17f3c9e4b0..65d0838ae1 100644 --- a/examples/src/bin/shader-types-sharing.rs +++ b/examples/src/bin/shader-types-sharing.rs @@ -43,8 +43,8 @@ use vulkano::{ pipeline::{ compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::PipelineShaderStageCreateInfo, sync::{self, GpuFuture}, VulkanLibrary, }; @@ -257,7 +257,7 @@ fn main() { .unwrap(); let stage = PipelineShaderStageCreateInfo { specialization_info: [(0, true.into())].into_iter().collect(), - ..PipelineShaderStageCreateInfo::entry_point(cs) + ..PipelineShaderStageCreateInfo::new(cs) }; let layout = PipelineLayout::new( device.clone(), @@ -282,7 +282,7 @@ fn main() { .unwrap(); let stage = PipelineShaderStageCreateInfo { specialization_info: [(0, true.into())].into_iter().collect(), - ..PipelineShaderStageCreateInfo::entry_point(cs) + ..PipelineShaderStageCreateInfo::new(cs) }; let layout = PipelineLayout::new( device.clone(), diff --git a/examples/src/bin/simple-particles.rs b/examples/src/bin/simple-particles.rs index a8935dba07..864bee3f61 100644 --- a/examples/src/bin/simple-particles.rs +++ b/examples/src/bin/simple-particles.rs @@ -42,9 +42,9 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, GraphicsPipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, Subpass}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, PresentMode, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, @@ -422,7 +422,7 @@ fn main() { .unwrap() .entry_point("main") .unwrap(); - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) @@ -459,9 +459,9 @@ fn main() { // Fixed viewport dimensions. let viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [WINDOW_WIDTH as f32, WINDOW_HEIGHT as f32], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [WINDOW_WIDTH as f32, WINDOW_HEIGHT as f32], + depth_range: 0.0..=1.0, }; // Create a basic graphics pipeline for rendering particles. @@ -478,8 +478,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), diff --git a/examples/src/bin/specialization-constants.rs b/examples/src/bin/specialization-constants.rs index d4c47644f0..82808e855c 100644 --- a/examples/src/bin/specialization-constants.rs +++ b/examples/src/bin/specialization-constants.rs @@ -26,8 +26,8 @@ use vulkano::{ pipeline::{ compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::PipelineShaderStageCreateInfo, sync::{self, GpuFuture}, VulkanLibrary, }; @@ -123,7 +123,7 @@ fn main() { specialization_info: [(0, 1i32.into()), (1, 1.0f32.into()), (2, true.into())] .into_iter() .collect(), - ..PipelineShaderStageCreateInfo::entry_point(cs) + ..PipelineShaderStageCreateInfo::new(cs) }; let layout = PipelineLayout::new( device.clone(), diff --git a/examples/src/bin/teapot/main.rs b/examples/src/bin/teapot/main.rs index 4208805231..c10e8f0993 100644 --- a/examples/src/bin/teapot/main.rs +++ b/examples/src/bin/teapot/main.rs @@ -43,9 +43,10 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, - shader::{EntryPoint, PipelineShaderStageCreateInfo}, + shader::EntryPoint, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -470,8 +471,8 @@ fn window_size_dependent_setup( .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -490,9 +491,9 @@ fn window_size_dependent_setup( input_assembly_state: Some(InputAssemblyState::default()), viewport_state: Some(ViewportState::viewport_fixed_scissor_irrelevant([ Viewport { - origin: [0.0, 0.0], - dimensions: [dimensions[0] as f32, dimensions[1] as f32], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [dimensions[0] as f32, dimensions[1] as f32], + depth_range: 0.0..=1.0, }, ])), rasterization_state: Some(RasterizationState::default()), diff --git a/examples/src/bin/tessellation.rs b/examples/src/bin/tessellation.rs index 77918241fd..1abb321f73 100644 --- a/examples/src/bin/tessellation.rs +++ b/examples/src/bin/tessellation.rs @@ -47,10 +47,9 @@ use vulkano::{ GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, - GraphicsPipeline, PipelineLayout, + GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -357,10 +356,10 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(tcs), - PipelineShaderStageCreateInfo::entry_point(tes), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(tcs), + PipelineShaderStageCreateInfo::new(tes), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -402,9 +401,9 @@ fn main() { let mut recreate_swapchain = false; let mut previous_frame_end = Some(sync::now(device.clone()).boxed()); let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); @@ -525,7 +524,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/texture_array/main.rs b/examples/src/bin/texture_array/main.rs index 57928ce196..338a378cb4 100644 --- a/examples/src/bin/texture_array/main.rs +++ b/examples/src/bin/texture_array/main.rs @@ -40,10 +40,10 @@ use vulkano::{ }, layout::PipelineDescriptorSetLayoutCreateInfo, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Sampler, SamplerCreateInfo}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -279,8 +279,8 @@ fn main() { .definition(&vs.info().input_interface) .unwrap(); let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), @@ -322,9 +322,9 @@ fn main() { .unwrap(); let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); @@ -458,7 +458,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/triangle-v1_3.rs b/examples/src/bin/triangle-v1_3.rs index 78bc762630..e2d4dd4cab 100644 --- a/examples/src/bin/triangle-v1_3.rs +++ b/examples/src/bin/triangle-v1_3.rs @@ -47,10 +47,9 @@ use vulkano::{ GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, - GraphicsPipeline, PipelineLayout, + GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, render_pass::{AttachmentLoadOp, AttachmentStoreOp}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -401,8 +400,8 @@ fn main() { // Make a list of the shader stages that the pipeline will have. let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; // We must now create a **pipeline layout** object, which describes the locations and types of @@ -472,9 +471,9 @@ fn main() { // Dynamic viewports allow us to recreate just the viewport when the window is resized. // Otherwise we would have to recreate the whole pipeline. let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; // When creating the swapchain, we only created plain images. To use them as an attachment for @@ -697,7 +696,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec>> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/examples/src/bin/triangle.rs b/examples/src/bin/triangle.rs index 46e14e17df..34d443665b 100644 --- a/examples/src/bin/triangle.rs +++ b/examples/src/bin/triangle.rs @@ -41,10 +41,9 @@ use vulkano::{ GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, - GraphicsPipeline, PipelineLayout, + GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, - shader::PipelineShaderStageCreateInfo, swapchain::{ acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, @@ -405,8 +404,8 @@ fn main() { // Make a list of the shader stages that the pipeline will have. let stages = [ - PipelineShaderStageCreateInfo::entry_point(vs), - PipelineShaderStageCreateInfo::entry_point(fs), + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), ]; // We must now create a **pipeline layout** object, which describes the locations and types of @@ -467,9 +466,9 @@ fn main() { // Dynamic viewports allow us to recreate just the viewport when the window is resized. // Otherwise we would have to recreate the whole pipeline. let mut viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [0.0, 0.0], - depth_range: 0.0..1.0, + offset: [0.0, 0.0], + extent: [0.0, 0.0], + depth_range: 0.0..=1.0, }; // The render pass we created above only describes the layout of our framebuffers. Before we @@ -692,7 +691,7 @@ fn window_size_dependent_setup( viewport: &mut Viewport, ) -> Vec> { let dimensions = images[0].dimensions().width_height(); - viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + viewport.extent = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() diff --git a/vulkano/src/command_buffer/commands/dynamic_state.rs b/vulkano/src/command_buffer/commands/dynamic_state.rs index 5e3b306ed6..dac4e77f6a 100644 --- a/vulkano/src/command_buffer/commands/dynamic_state.rs +++ b/vulkano/src/command_buffer/commands/dynamic_state.rs @@ -2341,7 +2341,6 @@ where ) -> &mut Self { let rectangles = rectangles .iter() - .copied() .map(|v| v.into()) .collect::>(); if rectangles.is_empty() { @@ -2550,7 +2549,6 @@ where pub unsafe fn set_scissor(&mut self, first_scissor: u32, scissors: &[Scissor]) -> &mut Self { let scissors = scissors .iter() - .copied() .map(ash::vk::Rect2D::from) .collect::>(); if scissors.is_empty() { @@ -2574,7 +2572,6 @@ where pub unsafe fn set_scissor_with_count(&mut self, scissors: &[Scissor]) -> &mut Self { let scissors = scissors .iter() - .copied() .map(ash::vk::Rect2D::from) .collect::>(); if scissors.is_empty() { @@ -2611,7 +2608,6 @@ where ) -> &mut Self { let viewports = viewports .iter() - .cloned() .map(|v| v.into()) .collect::>(); if viewports.is_empty() { @@ -2635,7 +2631,6 @@ where pub unsafe fn set_viewport_with_count(&mut self, viewports: &[Viewport]) -> &mut Self { let viewports = viewports .iter() - .cloned() .map(|v| v.into()) .collect::>(); if viewports.is_empty() { diff --git a/vulkano/src/descriptor_set/layout.rs b/vulkano/src/descriptor_set/layout.rs index 587c8ef5b1..7ea36d6d80 100644 --- a/vulkano/src/descriptor_set/layout.rs +++ b/vulkano/src/descriptor_set/layout.rs @@ -21,15 +21,7 @@ use crate::{ VulkanObject, }; use ahash::HashMap; -use std::{ - collections::BTreeMap, - error::Error, - fmt::{Display, Error as FmtError, Formatter}, - mem::MaybeUninit, - num::NonZeroU64, - ptr, - sync::Arc, -}; +use std::{collections::BTreeMap, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc}; /// Describes to the Vulkan implementation the layout of all descriptors within a descriptor set. #[derive(Debug)] @@ -578,7 +570,7 @@ impl DescriptorSetLayoutBinding { pub fn ensure_compatible_with_shader( &self, binding_requirements: &DescriptorBindingRequirements, - ) -> Result<(), DescriptorRequirementsNotMet> { + ) -> Result<(), ValidationError> { let &DescriptorBindingRequirements { ref descriptor_types, descriptor_count, @@ -591,25 +583,31 @@ impl DescriptorSetLayoutBinding { } = binding_requirements; if !descriptor_types.contains(&self.descriptor_type) { - return Err(DescriptorRequirementsNotMet::DescriptorType { - required: descriptor_types.clone(), - obtained: self.descriptor_type, + return Err(ValidationError { + problem: "the descriptor type is not one of the types allowed by the \ + descriptor binding requirements" + .into(), + ..Default::default() }); } if let Some(required) = descriptor_count { if self.descriptor_count < required { - return Err(DescriptorRequirementsNotMet::DescriptorCount { - required, - obtained: self.descriptor_count, + return Err(ValidationError { + problem: "the descriptor count is less than the count required by the \ + descriptor binding requirements" + .into(), + ..Default::default() }); } } if !self.stages.contains(stages) { - return Err(DescriptorRequirementsNotMet::ShaderStages { - required: stages, - obtained: self.stages, + return Err(ValidationError { + problem: "the stages are not a superset of the stages required by the \ + descriptor binding requirements" + .into(), + ..Default::default() }); } @@ -1001,48 +999,6 @@ pub struct DescriptorSetLayoutSupport { pub max_variable_descriptor_count: u32, } -/// Error when checking whether the requirements for a binding have been met. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum DescriptorRequirementsNotMet { - /// The binding's `descriptor_type` is not one of those required. - DescriptorType { - required: Vec, - obtained: DescriptorType, - }, - - /// The binding's `descriptor_count` is less than what is required. - DescriptorCount { required: u32, obtained: u32 }, - - /// The binding's `stages` does not contain the stages that are required. - ShaderStages { - required: ShaderStages, - obtained: ShaderStages, - }, -} - -impl Error for DescriptorRequirementsNotMet {} - -impl Display for DescriptorRequirementsNotMet { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - Self::DescriptorType { required, obtained } => write!( - f, - "the descriptor's type ({:?}) is not one of those required ({:?})", - obtained, required, - ), - Self::DescriptorCount { required, obtained } => write!( - f, - "the descriptor count ({}) is less than what is required ({})", - obtained, required, - ), - Self::ShaderStages { .. } => write!( - f, - "the descriptor's shader stages do not contain the stages that are required", - ), - } - } -} - #[cfg(test)] mod tests { use crate::{ diff --git a/vulkano/src/pipeline/cache.rs b/vulkano/src/pipeline/cache.rs index f26f78245d..a7675340cb 100644 --- a/vulkano/src/pipeline/cache.rs +++ b/vulkano/src/pipeline/cache.rs @@ -23,9 +23,11 @@ use crate::{ device::{Device, DeviceOwned}, - OomError, RuntimeError, VulkanObject, + macros::{impl_id_counter, vulkan_bitflags}, + RuntimeError, ValidationError, VulkanError, VulkanObject, }; -use std::{mem::MaybeUninit, ptr, sync::Arc}; +use smallvec::SmallVec; +use std::{mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc}; /// Opaque cache that contains pipeline objects. /// @@ -34,92 +36,102 @@ use std::{mem::MaybeUninit, ptr, sync::Arc}; pub struct PipelineCache { device: Arc, handle: ash::vk::PipelineCache, + id: NonZeroU64, + + flags: PipelineCacheCreateFlags, } impl PipelineCache { - /// Builds a new pipeline cache from existing data. The data must have been previously obtained - /// with [`get_data`](#method.get_data). + /// Builds a new pipeline cache. /// - /// The data passed to this function will most likely be blindly trusted by the Vulkan - /// implementation. Therefore you can easily crash your application or the system by passing - /// wrong data. Hence why this function is unsafe. + /// # Safety + /// + /// - The data in `create_info.initial_data` must be valid data that was previously retrieved + /// using [`get_data`](PipelineCache::get_data). /// /// # Examples /// /// This example loads a cache from a file, if it exists. /// See [`get_data`](#method.get_data) for how to store the data in a file. - /// TODO: there's a header in the cached data that must be checked ; talk about this /// /// ``` /// # use std::sync::Arc; /// # use vulkano::device::Device; /// use std::fs::File; /// use std::io::Read; - /// use vulkano::pipeline::cache::PipelineCache; + /// use vulkano::pipeline::cache::{PipelineCache, PipelineCacheCreateInfo}; /// # let device: Arc = return; /// - /// let data = { + /// let initial_data = { /// let file = File::open("pipeline_cache.bin"); /// if let Ok(mut file) = file { /// let mut data = Vec::new(); /// if let Ok(_) = file.read_to_end(&mut data) { - /// Some(data) + /// data /// } else { - /// None + /// Vec::new() /// } /// } else { - /// None + /// Vec::new() /// } /// }; /// - /// let cache = if let Some(data) = data { - /// // This is unsafe because there is no way to be sure that the file contains valid data. - /// unsafe { PipelineCache::with_data(device.clone(), &data).unwrap() } - /// } else { - /// PipelineCache::empty(device.clone()).unwrap() + /// // This is unsafe because there is no way to be sure that the file contains valid data. + /// let cache = unsafe { + /// PipelineCache::new( + /// device.clone(), + /// PipelineCacheCreateInfo { + /// initial_data, + /// ..Default::default() + /// } + /// ).unwrap() /// }; /// ``` #[inline] - pub unsafe fn with_data( + pub unsafe fn new( device: Arc, - initial_data: &[u8], - ) -> Result, OomError> { - PipelineCache::new_impl(device, Some(initial_data)) + create_info: PipelineCacheCreateInfo, + ) -> Result, VulkanError> { + Self::validate_new(&device, &create_info)?; + + Ok(Self::new_unchecked(device, create_info)?) } - /// Builds a new empty pipeline cache. - /// - /// # Examples - /// - /// ``` - /// # use std::sync::Arc; - /// # use vulkano::device::Device; - /// use vulkano::pipeline::cache::PipelineCache; - /// # let device: Arc = return; - /// let cache = PipelineCache::empty(device.clone()).unwrap(); - /// ``` - #[inline] - pub fn empty(device: Arc) -> Result, OomError> { - unsafe { PipelineCache::new_impl(device, None) } + fn validate_new( + device: &Device, + create_info: &PipelineCacheCreateInfo, + ) -> Result<(), ValidationError> { + create_info + .validate(device) + .map_err(|err| err.add_context("create_info"))?; + + Ok(()) } - // Actual implementation of the constructor. - unsafe fn new_impl( + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] + pub unsafe fn new_unchecked( device: Arc, - initial_data: Option<&[u8]>, - ) -> Result, OomError> { - let fns = device.fns(); - - let cache = { - let infos = ash::vk::PipelineCacheCreateInfo { - flags: ash::vk::PipelineCacheCreateFlags::empty(), - initial_data_size: initial_data.map(|d| d.len()).unwrap_or(0), - p_initial_data: initial_data - .map(|d| d.as_ptr() as *const _) - .unwrap_or(ptr::null()), - ..Default::default() - }; + create_info: PipelineCacheCreateInfo, + ) -> Result, RuntimeError> { + let &PipelineCacheCreateInfo { + flags, + ref initial_data, + _ne: _, + } = &create_info; + + let infos = ash::vk::PipelineCacheCreateInfo { + flags: flags.into(), + initial_data_size: initial_data.len(), + p_initial_data: if initial_data.is_empty() { + ptr::null() + } else { + initial_data.as_ptr() as _ + }, + ..Default::default() + }; + let handle = { + let fns = device.fns(); let mut output = MaybeUninit::uninit(); (fns.v1_0.create_pipeline_cache)( device.handle(), @@ -132,59 +144,46 @@ impl PipelineCache { output.assume_init() }; - Ok(Arc::new(PipelineCache { - device: device.clone(), - handle: cache, - })) + Ok(Self::from_handle(device, handle, create_info)) } - /// Merges other pipeline caches into this one. - /// - /// It is `self` that is modified here. The pipeline caches passed as parameter are untouched. + /// Creates a new `PipelineCache` from a raw object handle. /// - /// # Panics + /// # Safety /// - /// - Panics if `self` is included in the list of other pipelines. - /// - // FIXME: vkMergePipelineCaches is not thread safe for the destination cache - // TODO: write example - pub fn merge<'a>( - &self, - pipelines: impl IntoIterator>, - ) -> Result<(), OomError> { - unsafe { - let fns = self.device.fns(); - - let pipelines = pipelines - .into_iter() - .map(|pipeline| { - assert!(&***pipeline as *const _ != self as *const _); - pipeline.handle - }) - .collect::>(); - - (fns.v1_0.merge_pipeline_caches)( - self.device.handle(), - self.handle, - pipelines.len() as u32, - pipelines.as_ptr(), - ) - .result() - .map_err(RuntimeError::from)?; + /// - `handle` must be a valid Vulkan object handle created from `device`. + /// - `create_info` must match the info used to create the object. + pub unsafe fn from_handle( + device: Arc, + handle: ash::vk::PipelineCache, + create_info: PipelineCacheCreateInfo, + ) -> Arc { + let PipelineCacheCreateInfo { + flags, + initial_data: _, + _ne: _, + } = create_info; + + Arc::new(PipelineCache { + device, + handle, + id: Self::next_id(), + + flags, + }) + } - Ok(()) - } + /// Returns the flags that the pipeline cache was created with. + pub fn flags(&self) -> PipelineCacheCreateFlags { + self.flags } /// Obtains the data from the cache. /// - /// This data can be stored and then reloaded and passed to `PipelineCache::with_data`. + /// This data can be stored and then reloaded and passed to `PipelineCache::new`. /// /// # Examples /// - /// This example stores the data of a pipeline cache on the disk. - /// See [`with_data`](#method.with_data) for how to reload it. - /// /// ``` /// use std::fs; /// use std::fs::File; @@ -205,7 +204,7 @@ impl PipelineCache { /// } /// ``` #[inline] - pub fn get_data(&self) -> Result, OomError> { + pub fn get_data(&self) -> Result, RuntimeError> { let fns = self.device.fns(); let data = unsafe { @@ -234,13 +233,65 @@ impl PipelineCache { break data; } ash::vk::Result::INCOMPLETE => (), - err => return Err(RuntimeError::from(err).into()), + err => return Err(RuntimeError::from(err)), } } }; Ok(data) } + + /// Merges other pipeline caches into this one. + /// + /// It is `self` that is modified here. The pipeline caches passed as parameter are untouched. + /// + // FIXME: vkMergePipelineCaches is not thread safe for the destination cache + // TODO: write example + pub fn merge<'a>( + &self, + src_caches: impl IntoIterator, + ) -> Result<(), VulkanError> { + let src_caches: SmallVec<[_; 8]> = src_caches.into_iter().collect(); + self.validate_merge(&src_caches)?; + + unsafe { Ok(self.merge_unchecked(src_caches)?) } + } + + fn validate_merge(&self, src_caches: &[&PipelineCache]) -> Result<(), ValidationError> { + for (index, &src_cache) in src_caches.iter().enumerate() { + if src_cache == self { + return Err(ValidationError { + context: format!("src_caches[{}]", index).into(), + problem: "equals `self`".into(), + vuids: &["VUID-vkMergePipelineCaches-dstCache-00770"], + ..Default::default() + }); + } + } + + Ok(()) + } + + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] + pub unsafe fn merge_unchecked<'a>( + &self, + src_caches: impl IntoIterator, + ) -> Result<(), RuntimeError> { + let src_caches_vk: SmallVec<[_; 8]> = + src_caches.into_iter().map(VulkanObject::handle).collect(); + + let fns = self.device.fns(); + (fns.v1_0.merge_pipeline_caches)( + self.device.handle(), + self.handle, + src_caches_vk.len() as u32, + src_caches_vk.as_ptr(), + ) + .result() + .map_err(RuntimeError::from)?; + + Ok(()) + } } impl Drop for PipelineCache { @@ -269,30 +320,103 @@ unsafe impl DeviceOwned for PipelineCache { } } +impl_id_counter!(PipelineCache); + +/// Parameters to create a new `PipelineCache`. +#[derive(Clone, Debug)] +pub struct PipelineCacheCreateInfo { + /// Additional properties of the pipeline cache. + /// + /// The default value is empty. + pub flags: PipelineCacheCreateFlags, + + /// The initial data to provide to the cache. + /// + /// If this is not empty, then the data must have been previously retrieved by calling + /// [`PipelineCache::get_data`]. + /// + /// The data passed to this function will most likely be blindly trusted by the Vulkan + /// implementation. Therefore you can easily crash your application or the system by passing + /// wrong data. + /// + /// The default value is empty. + pub initial_data: Vec, + + pub _ne: crate::NonExhaustive, +} + +impl Default for PipelineCacheCreateInfo { + #[inline] + fn default() -> Self { + Self { + flags: PipelineCacheCreateFlags::empty(), + initial_data: Vec::new(), + _ne: crate::NonExhaustive(()), + } + } +} + +impl PipelineCacheCreateInfo { + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + flags, + initial_data: _, + _ne, + } = self; + + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkPipelineCacheCreateInfo-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; + + Ok(()) + } +} + +vulkan_bitflags! { + #[non_exhaustive] + + /// Flags specifying additional properties of a pipeline cache. + PipelineCacheCreateFlags = PipelineCacheCreateFlags(u32); + + /* TODO: enable + // TODO: document + EXTERNALLY_SYNCHRONIZED = EXTERNALLY_SYNCHRONIZED + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_pipeline_creation_cache_control)]), + ]), */ +} + #[cfg(test)] mod tests { use crate::{ pipeline::{ cache::PipelineCache, compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::{PipelineShaderStageCreateInfo, ShaderModule}, + shader::ShaderModule, }; #[test] fn merge_self_forbidden() { let (device, _queue) = gfx_dev_and_queue!(); - let pipeline = PipelineCache::empty(device).unwrap(); - assert_should_panic!({ - pipeline.merge(&[&pipeline]).unwrap(); - }); + let pipeline = unsafe { PipelineCache::new(device, Default::default()).unwrap() }; + match pipeline.merge([pipeline.as_ref()]) { + Err(_) => (), + Ok(_) => panic!(), + } } #[test] fn cache_returns_same_data() { let (device, _queue) = gfx_dev_and_queue!(); - let cache = PipelineCache::empty(device.clone()).unwrap(); + let cache = unsafe { PipelineCache::new(device.clone(), Default::default()).unwrap() }; let cs = unsafe { /* @@ -311,7 +435,7 @@ mod tests { }; let _pipeline = { - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) @@ -337,7 +461,7 @@ mod tests { fn cache_returns_different_data() { let (device, _queue) = gfx_dev_and_queue!(); - let cache = PipelineCache::empty(device.clone()).unwrap(); + let cache = unsafe { PipelineCache::new(device.clone(), Default::default()).unwrap() }; let _first_pipeline = { let cs = unsafe { @@ -356,7 +480,7 @@ mod tests { module.entry_point("main").unwrap() }; - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) @@ -397,7 +521,7 @@ mod tests { module.entry_point("main").unwrap() }; - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) @@ -426,7 +550,7 @@ mod tests { fn cache_data_does_not_change() { let (device, _queue) = gfx_dev_and_queue!(); - let cache = PipelineCache::empty(device.clone()).unwrap(); + let cache = unsafe { PipelineCache::new(device.clone(), Default::default()).unwrap() }; let cs = unsafe { /* @@ -445,7 +569,7 @@ mod tests { }; let _first_pipeline = { - let stage = PipelineShaderStageCreateInfo::entry_point(cs.clone()); + let stage = PipelineShaderStageCreateInfo::new(cs.clone()); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) @@ -464,7 +588,7 @@ mod tests { let cache_data = cache.get_data().unwrap(); let _second_pipeline = { - let stage = PipelineShaderStageCreateInfo::entry_point(cs); + let stage = PipelineShaderStageCreateInfo::new(cs); let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages([&stage]) diff --git a/vulkano/src/pipeline/compute.rs b/vulkano/src/pipeline/compute.rs index 6ce8e31891..193b57b999 100644 --- a/vulkano/src/pipeline/compute.rs +++ b/vulkano/src/pipeline/compute.rs @@ -22,14 +22,12 @@ //! any descriptor sets and/or push constants that the pipeline needs, and then issuing a `dispatch` //! command on the command buffer. -use super::PipelineCreateFlags; +use super::{PipelineCreateFlags, PipelineShaderStageCreateInfo}; use crate::{ device::{Device, DeviceOwned}, macros::impl_id_counter, pipeline::{cache::PipelineCache, layout::PipelineLayout, Pipeline, PipelineBindPoint}, - shader::{ - DescriptorBindingRequirements, PipelineShaderStageCreateInfo, ShaderExecution, ShaderStage, - }, + shader::{DescriptorBindingRequirements, ShaderExecution, ShaderStage}, RuntimeError, ValidationError, VulkanError, VulkanObject, }; use ahash::HashMap; @@ -82,93 +80,9 @@ impl ComputePipeline { assert_eq!(device, cache.device().as_ref()); } - let &ComputePipelineCreateInfo { - flags: _, - ref stage, - ref layout, - _ne: _, - } = create_info; - - { - let &PipelineShaderStageCreateInfo { - flags, - ref entry_point, - ref specialization_info, - _ne: _, - } = &stage; - - flags - .validate_device(device) - .map_err(|err| ValidationError { - context: "create_info.stage.flags".into(), - vuids: &["VUID-VkPipelineShaderStageCreateInfo-flags-parameter"], - ..ValidationError::from_requirement(err) - })?; - - let entry_point_info = entry_point.info(); - - if !matches!(entry_point_info.execution, ShaderExecution::Compute) { - return Err(ValidationError { - context: "create_info.stage.entry_point".into(), - problem: "is not a compute shader".into(), - vuids: &[ - "VUID-VkComputePipelineCreateInfo-stage-00701", - "VUID-VkPipelineShaderStageCreateInfo-stage-parameter", - ], - ..Default::default() - }); - } - - for (&constant_id, provided_value) in specialization_info { - // Per `VkSpecializationMapEntry` spec: - // "If a constantID value is not a specialization constant ID used in the shader, - // that map entry does not affect the behavior of the pipeline." - // We *may* want to be stricter than this for the sake of catching user errors? - if let Some(default_value) = - entry_point_info.specialization_constants.get(&constant_id) - { - // Check for equal types rather than only equal size. - if !provided_value.eq_type(default_value) { - return Err(ValidationError { - context: format!( - "create_info.stage.specialization_info[{}]", - constant_id - ) - .into(), - problem: "the provided value has a different type than the constant's \ - default value" - .into(), - vuids: &["VUID-VkSpecializationMapEntry-constantID-00776"], - ..Default::default() - }); - } - } - } - - // TODO: Make sure that all VUIDs are indeed checked. - layout - .ensure_compatible_with_shader( - entry_point_info - .descriptor_binding_requirements - .iter() - .map(|(k, v)| (*k, v)), - entry_point_info.push_constant_requirements.as_ref(), - ) - .map_err(|err| ValidationError { - context: "create_info.stage.entry_point".into(), - vuids: &[ - "VUID-VkComputePipelineCreateInfo-layout-07987", - "VUID-VkComputePipelineCreateInfo-layout-07988", - "VUID-VkComputePipelineCreateInfo-layout-07990", - "VUID-VkComputePipelineCreateInfo-layout-07991", - ], - ..ValidationError::from_error(err) - })?; - - // VUID-VkComputePipelineCreateInfo-stage-00702 - // VUID-VkComputePipelineCreateInfo-layout-01687 - // TODO: - } + create_info + .validate(device) + .map_err(|err| err.add_context("create_info"))?; Ok(()) } @@ -379,7 +293,7 @@ impl Drop for ComputePipeline { /// Parameters to create a new `ComputePipeline`. #[derive(Clone, Debug)] pub struct ComputePipelineCreateInfo { - /// Specifies how to create the pipeline. + /// Additional properties of the pipeline. /// /// The default value is empty. pub flags: PipelineCreateFlags, @@ -408,6 +322,71 @@ impl ComputePipelineCreateInfo { _ne: crate::NonExhaustive(()), } } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + flags, + ref stage, + ref layout, + _ne: _, + } = self; + + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkComputePipelineCreateInfo-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; + + stage + .validate(device) + .map_err(|err| err.add_context("stage"))?; + + let &PipelineShaderStageCreateInfo { + flags: _, + ref entry_point, + specialization_info: _, + _ne: _, + } = &stage; + + let entry_point_info = entry_point.info(); + + if !matches!(entry_point_info.execution, ShaderExecution::Compute) { + return Err(ValidationError { + context: "stage.entry_point".into(), + problem: "is not a `ShaderStage::Compute` entry point".into(), + vuids: &["VUID-VkComputePipelineCreateInfo-stage-00701"], + ..Default::default() + }); + } + + // TODO: Make sure that all VUIDs are indeed checked. + layout + .ensure_compatible_with_shader( + entry_point_info + .descriptor_binding_requirements + .iter() + .map(|(k, v)| (*k, v)), + entry_point_info.push_constant_requirements.as_ref(), + ) + .map_err(|err| ValidationError { + context: "stage.entry_point".into(), + vuids: &[ + "VUID-VkComputePipelineCreateInfo-layout-07987", + "VUID-VkComputePipelineCreateInfo-layout-07988", + "VUID-VkComputePipelineCreateInfo-layout-07990", + "VUID-VkComputePipelineCreateInfo-layout-07991", + ], + ..ValidationError::from_error(err) + })?; + + // TODO: + // VUID-VkComputePipelineCreateInfo-stage-00702 + // VUID-VkComputePipelineCreateInfo-layout-01687 + + Ok(()) + } } #[cfg(test)] @@ -424,8 +403,9 @@ mod tests { pipeline::{ compute::ComputePipelineCreateInfo, layout::PipelineDescriptorSetLayoutCreateInfo, ComputePipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, }, - shader::{PipelineShaderStageCreateInfo, ShaderModule}, + shader::ShaderModule, sync::{now, GpuFuture}, }; @@ -473,7 +453,7 @@ mod tests { let pipeline = { let stage = PipelineShaderStageCreateInfo { specialization_info: [(83, 0x12345678i32.into())].into_iter().collect(), - ..PipelineShaderStageCreateInfo::entry_point(cs) + ..PipelineShaderStageCreateInfo::new(cs) }; let layout = PipelineLayout::new( device.clone(), diff --git a/vulkano/src/pipeline/graphics/color_blend.rs b/vulkano/src/pipeline/graphics/color_blend.rs index a5814a08b0..c8cd8bcf33 100644 --- a/vulkano/src/pipeline/graphics/color_blend.rs +++ b/vulkano/src/pipeline/graphics/color_blend.rs @@ -22,14 +22,21 @@ //! will take precedence if it is activated, otherwise the blending operation is applied. use crate::{ + device::Device, macros::{vulkan_bitflags, vulkan_enum}, pipeline::StateMode, + Requires, RequiresAllOf, RequiresOneOf, ValidationError, }; /// Describes how the color output of the fragment shader is written to the attachment. See the /// documentation of the `blend` module for more info. #[derive(Clone, Debug)] pub struct ColorBlendState { + /// Additional properties of the color blend state. + /// + /// The default value is empty. + pub flags: ColorBlendStateFlags, + /// Sets the logical operation to perform between the incoming fragment color and the existing /// fragment in the framebuffer attachment. /// @@ -58,6 +65,7 @@ impl ColorBlendState { #[inline] pub fn new(num: u32) -> Self { Self { + flags: ColorBlendStateFlags::empty(), logic_op: None, attachments: (0..num) .map(|_| ColorBlendAttachmentState { @@ -133,6 +141,93 @@ impl ColorBlendState { self.blend_constants = StateMode::Dynamic; self } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + flags, + logic_op, + ref attachments, + blend_constants: _, + } = self; + + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkPipelineColorBlendStateCreateInfo-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if let Some(logic_op) = logic_op { + if !device.enabled_features().logic_op { + return Err(ValidationError { + context: "logic_op".into(), + problem: "is `Some`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "logic_op", + )])]), + vuids: &["VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00606"], + }); + } + + match logic_op { + StateMode::Fixed(logic_op) => { + logic_op + .validate_device(device) + .map_err(|err| ValidationError { + context: "logic_op".into(), + vuids: &[ + "VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00607", + ], + ..ValidationError::from_requirement(err) + })? + } + StateMode::Dynamic => { + if !device.enabled_features().extended_dynamic_state2_logic_op { + return Err(ValidationError { + context: "logic_op".into(), + problem: "is dynamic".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "extended_dynamic_state2_logic_op", + )])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04869"], + }); + } + } + } + } + + if device.enabled_features().independent_blend { + for (index, state) in attachments.iter().enumerate() { + state + .validate(device) + .map_err(|err| err.add_context(format!("attachments[{}]", index)))?; + } + } else if let Some(first) = attachments.first() { + first + .validate(device) + .map_err(|err| err.add_context("attachments[0]"))?; + + for (index, state) in attachments.iter().enumerate().skip(1) { + if state != first { + return Err(ValidationError { + problem: format!( + "`attachments[{}]` does not equal `attachments[0]`", + index + ) + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "independent_blend", + )])]), + vuids: &["VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605"], + ..Default::default() + }); + } + } + } + + Ok(()) + } } impl Default for ColorBlendState { @@ -143,6 +238,21 @@ impl Default for ColorBlendState { } } +vulkan_bitflags! { + #[non_exhaustive] + + /// Flags specifying additional properties of the color blend state. + ColorBlendStateFlags = PipelineColorBlendStateCreateFlags(u32); + + /* TODO: enable + // TODO: document + RASTERIZATION_ORDER_ATTACHMENT_ACCESS = RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_rasterization_order_attachment_access)]), + RequiresAllOf([DeviceExtension(arm_rasterization_order_attachment_access)]), + ]), */ +} + vulkan_enum! { #[non_exhaustive] /// Which logical operation to apply to the output values. @@ -213,7 +323,7 @@ impl Default for LogicOp { /// Describes how a framebuffer color attachment is handled in the pipeline during the color /// blend stage. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ColorBlendAttachmentState { /// The blend parameters for the attachment. /// @@ -233,28 +343,73 @@ pub struct ColorBlendAttachmentState { pub color_write_enable: StateMode, } +impl ColorBlendAttachmentState { + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + ref blend, + color_write_mask: _, + color_write_enable, + } = self; + + if let Some(blend) = blend { + blend + .validate(device) + .map_err(|err| err.add_context("blend"))?; + } + + match color_write_enable { + StateMode::Fixed(enable) => { + if !enable && !device.enabled_features().color_write_enable { + return Err(ValidationError { + context: "color_write_enable".into(), + problem: "is `false`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "color_write_enable", + )])]), + vuids: &["VUID-VkPipelineColorWriteCreateInfoEXT-pAttachments-04801"], + }); + } + } + StateMode::Dynamic => { + if !device.enabled_features().color_write_enable { + return Err(ValidationError { + context: "color_write_enable".into(), + problem: "is dynamic".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "color_write_enable", + )])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04800"], + }); + } + } + } + + Ok(()) + } +} + /// Describes how the blending system should behave for an attachment. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct AttachmentBlend { - /// The operation to apply between the color components of the source and destination pixels, - /// to produce the final pixel value. - pub color_op: BlendOp, - /// The operation to apply to the source color component before applying `color_op`. - pub color_source: BlendFactor, + pub src_color_blend_factor: BlendFactor, /// The operation to apply to the destination color component before applying `color_op`. - pub color_destination: BlendFactor, + pub dst_color_blend_factor: BlendFactor, - /// The operation to apply between the alpha component of the source and destination pixels, + /// The operation to apply between the color components of the source and destination pixels, /// to produce the final pixel value. - pub alpha_op: BlendOp, + pub color_blend_op: BlendOp, /// The operation to apply to the source alpha component before applying `alpha_op`. - pub alpha_source: BlendFactor, + pub src_alpha_blend_factor: BlendFactor, /// The operation to apply to the destination alpha component before applying `alpha_op`. - pub alpha_destination: BlendFactor, + pub dst_alpha_blend_factor: BlendFactor, + + /// The operation to apply between the alpha component of the source and destination pixels, + /// to produce the final pixel value. + pub alpha_blend_op: BlendOp, } impl AttachmentBlend { @@ -263,12 +418,12 @@ impl AttachmentBlend { #[inline] pub fn ignore_source() -> Self { Self { - color_op: BlendOp::Add, - color_source: BlendFactor::Zero, - color_destination: BlendFactor::DstColor, - alpha_op: BlendOp::Add, - alpha_source: BlendFactor::Zero, - alpha_destination: BlendFactor::DstColor, + src_color_blend_factor: BlendFactor::Zero, + dst_color_blend_factor: BlendFactor::DstColor, + color_blend_op: BlendOp::Add, + src_alpha_blend_factor: BlendFactor::Zero, + dst_alpha_blend_factor: BlendFactor::DstColor, + alpha_blend_op: BlendOp::Add, } } @@ -277,12 +432,12 @@ impl AttachmentBlend { #[inline] pub fn alpha() -> Self { Self { - color_op: BlendOp::Add, - color_source: BlendFactor::SrcAlpha, - color_destination: BlendFactor::OneMinusSrcAlpha, - alpha_op: BlendOp::Add, - alpha_source: BlendFactor::SrcAlpha, - alpha_destination: BlendFactor::OneMinusSrcAlpha, + src_color_blend_factor: BlendFactor::SrcAlpha, + dst_color_blend_factor: BlendFactor::OneMinusSrcAlpha, + color_blend_op: BlendOp::Add, + src_alpha_blend_factor: BlendFactor::SrcAlpha, + dst_alpha_blend_factor: BlendFactor::OneMinusSrcAlpha, + alpha_blend_op: BlendOp::Add, } } @@ -291,14 +446,181 @@ impl AttachmentBlend { #[inline] pub fn additive() -> Self { Self { - color_op: BlendOp::Add, - color_source: BlendFactor::One, - color_destination: BlendFactor::One, - alpha_op: BlendOp::Max, - alpha_source: BlendFactor::One, - alpha_destination: BlendFactor::One, + src_color_blend_factor: BlendFactor::One, + dst_color_blend_factor: BlendFactor::One, + color_blend_op: BlendOp::Add, + src_alpha_blend_factor: BlendFactor::One, + dst_alpha_blend_factor: BlendFactor::One, + alpha_blend_op: BlendOp::Max, } } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + src_color_blend_factor, + dst_color_blend_factor, + color_blend_op, + src_alpha_blend_factor, + dst_alpha_blend_factor, + alpha_blend_op, + } = self; + + src_color_blend_factor + .validate_device(device) + .map_err(|err| ValidationError { + context: "src_color_blend_factor".into(), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-srcColorBlendFactor-parameter"], + ..ValidationError::from_requirement(err) + })?; + + dst_color_blend_factor + .validate_device(device) + .map_err(|err| ValidationError { + context: "dst_color_blend_factor".into(), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-dstColorBlendFactor-parameter"], + ..ValidationError::from_requirement(err) + })?; + + color_blend_op + .validate_device(device) + .map_err(|err| ValidationError { + context: "color_blend_op".into(), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-colorBlendOp-parameter"], + ..ValidationError::from_requirement(err) + })?; + + src_alpha_blend_factor + .validate_device(device) + .map_err(|err| ValidationError { + context: "src_alpha_blend_factor".into(), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-srcAlphaBlendFactor-parameter"], + ..ValidationError::from_requirement(err) + })?; + + dst_alpha_blend_factor + .validate_device(device) + .map_err(|err| ValidationError { + context: "dst_alpha_blend_factor".into(), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-dstAlphaBlendFactor-parameter"], + ..ValidationError::from_requirement(err) + })?; + + alpha_blend_op + .validate_device(device) + .map_err(|err| ValidationError { + context: "alpha_blend_op".into(), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-alphaBlendOp-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if !device.enabled_features().dual_src_blend { + if matches!( + src_color_blend_factor, + BlendFactor::Src1Color + | BlendFactor::OneMinusSrc1Color + | BlendFactor::Src1Alpha + | BlendFactor::OneMinusSrc1Alpha + ) { + return Err(ValidationError { + context: "src_color_blend_factor".into(), + problem: "is `BlendFactor::Src1*`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "dual_src_blend", + )])]), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-srcColorBlendFactor-00608"], + }); + } + + if matches!( + dst_color_blend_factor, + BlendFactor::Src1Color + | BlendFactor::OneMinusSrc1Color + | BlendFactor::Src1Alpha + | BlendFactor::OneMinusSrc1Alpha + ) { + return Err(ValidationError { + context: "dst_color_blend_factor".into(), + problem: "is `BlendFactor::Src1*`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "dual_src_blend", + )])]), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-dstColorBlendFactor-00609"], + }); + } + + if matches!( + src_alpha_blend_factor, + BlendFactor::Src1Color + | BlendFactor::OneMinusSrc1Color + | BlendFactor::Src1Alpha + | BlendFactor::OneMinusSrc1Alpha + ) { + return Err(ValidationError { + context: "src_alpha_blend_factor".into(), + problem: "is `BlendFactor::Src1*`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "dual_src_blend", + )])]), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-srcAlphaBlendFactor-00610"], + }); + } + + if matches!( + dst_alpha_blend_factor, + BlendFactor::Src1Color + | BlendFactor::OneMinusSrc1Color + | BlendFactor::Src1Alpha + | BlendFactor::OneMinusSrc1Alpha + ) { + return Err(ValidationError { + context: "dst_alpha_blend_factor".into(), + problem: "is `BlendFactor::Src1*`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "dual_src_blend", + )])]), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-dstAlphaBlendFactor-00611"], + }); + } + } + + if device.enabled_extensions().khr_portability_subset + && !device.enabled_features().constant_alpha_color_blend_factors + { + if matches!( + src_color_blend_factor, + BlendFactor::ConstantAlpha | BlendFactor::OneMinusConstantAlpha + ) { + return Err(ValidationError { + problem: "this device is a portability subset device, and \ + `src_color_blend_factor` is `BlendFactor::ConstantAlpha` or \ + `BlendFactor::OneMinusConstantAlpha`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "constant_alpha_color_blend_factors", + )])]), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-constantAlphaColorBlendFactors-04454"], + ..Default::default() + }); + } + + if matches!( + dst_color_blend_factor, + BlendFactor::ConstantAlpha | BlendFactor::OneMinusConstantAlpha + ) { + return Err(ValidationError { + problem: "this device is a portability subset device, and \ + `dst_color_blend_factor` is `BlendFactor::ConstantAlpha` or \ + `BlendFactor::OneMinusConstantAlpha`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "constant_alpha_color_blend_factors", + )])]), + vuids: &["VUID-VkPipelineColorBlendAttachmentState-constantAlphaColorBlendFactors-04455"], + ..Default::default() + }); + } + } + + Ok(()) + } } impl From for ash::vk::PipelineColorBlendAttachmentState { @@ -306,12 +628,12 @@ impl From for ash::vk::PipelineColorBlendAttachmentState { fn from(val: AttachmentBlend) -> Self { ash::vk::PipelineColorBlendAttachmentState { blend_enable: ash::vk::TRUE, - src_color_blend_factor: val.color_source.into(), - dst_color_blend_factor: val.color_destination.into(), - color_blend_op: val.color_op.into(), - src_alpha_blend_factor: val.alpha_source.into(), - dst_alpha_blend_factor: val.alpha_destination.into(), - alpha_blend_op: val.alpha_op.into(), + src_color_blend_factor: val.src_color_blend_factor.into(), + dst_color_blend_factor: val.dst_color_blend_factor.into(), + color_blend_op: val.color_blend_op.into(), + src_alpha_blend_factor: val.src_alpha_blend_factor.into(), + dst_alpha_blend_factor: val.dst_alpha_blend_factor.into(), + alpha_blend_op: val.alpha_blend_op.into(), color_write_mask: ash::vk::ColorComponentFlags::empty(), } } diff --git a/vulkano/src/pipeline/graphics/depth_stencil.rs b/vulkano/src/pipeline/graphics/depth_stencil.rs index 650be60e03..456c18588b 100644 --- a/vulkano/src/pipeline/graphics/depth_stencil.rs +++ b/vulkano/src/pipeline/graphics/depth_stencil.rs @@ -20,13 +20,23 @@ //! value in the stencil buffer at each fragment's location. Depending on the outcome of the //! depth and stencil tests, the value of the stencil buffer at that location can be updated. -use crate::{macros::vulkan_enum, pipeline::StateMode}; +use crate::{ + device::Device, + macros::{vulkan_bitflags, vulkan_enum}, + pipeline::StateMode, + Requires, RequiresAllOf, RequiresOneOf, ValidationError, Version, +}; use std::ops::RangeInclusive; /// The state in a graphics pipeline describing how the depth, depth bounds and stencil tests /// should behave. #[derive(Clone, Debug)] pub struct DepthStencilState { + /// Additional properties of the depth/stencil state. + /// + /// The default value is empty. + pub flags: DepthStencilStateFlags, + /// The state of the depth test. /// /// If set to `None`, the depth test is disabled, all fragments will pass and no depth writes @@ -50,6 +60,7 @@ impl DepthStencilState { #[inline] pub fn disabled() -> Self { Self { + flags: DepthStencilStateFlags::empty(), depth: Default::default(), depth_bounds: Default::default(), stencil: Default::default(), @@ -61,6 +72,7 @@ impl DepthStencilState { #[inline] pub fn simple_depth_test() -> Self { Self { + flags: DepthStencilStateFlags::empty(), depth: Some(DepthState { enable_dynamic: false, compare_op: StateMode::Fixed(CompareOp::Less), @@ -70,6 +82,56 @@ impl DepthStencilState { stencil: Default::default(), } } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + flags, + ref depth, + ref depth_bounds, + ref stencil, + } = self; + + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkPipelineDepthStencilStateCreateInfo-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if let Some(depth_state) = depth { + depth_state + .validate(device) + .map_err(|err| err.add_context("depth"))?; + } + + if let Some(depth_bounds_state) = depth_bounds { + if !device.enabled_features().depth_bounds { + return Err(ValidationError { + context: "depth_bounds".into(), + problem: "is `Some`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "depth_bounds", + )])]), + vuids: &[ + "VUID-VkPipelineDepthStencilStateCreateInfo-depthBoundsTestEnable-00598", + ], + }); + } + + depth_bounds_state + .validate(device) + .map_err(|err| err.add_context("depth_bounds"))?; + } + + if let Some(stencil_state) = stencil { + stencil_state + .validate(device) + .map_err(|err| err.add_context("stencil"))?; + } + + Ok(()) + } } impl Default for DepthStencilState { @@ -80,6 +142,29 @@ impl Default for DepthStencilState { } } +vulkan_bitflags! { + #[non_exhaustive] + + /// Flags specifying additional properties of the depth/stencil state. + DepthStencilStateFlags = PipelineDepthStencilStateCreateFlags(u32); + + /* TODO: enable + // TODO: document + RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS = RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_rasterization_order_attachment_access)]), + RequiresAllOf([DeviceExtension(arm_rasterization_order_attachment_access)]), + ]), */ + + /* TODO: enable + // TODO: document + RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS = RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_EXT + RequiresOneOf([ + RequiresAllOf([DeviceExtension(ext_rasterization_order_attachment_access)]), + RequiresAllOf([DeviceExtension(arm_rasterization_order_attachment_access)]), + ]), */ +} + /// The state in a graphics pipeline describing how the depth test should behave when enabled. #[derive(Clone, Copy, Debug)] pub struct DepthState { @@ -107,6 +192,84 @@ pub struct DepthState { pub compare_op: StateMode, } +impl DepthState { + pub(crate) fn validate(self, device: &Device) -> Result<(), ValidationError> { + let Self { + enable_dynamic, + write_enable, + compare_op, + } = self; + + if enable_dynamic + && !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state) + { + return Err(ValidationError { + context: "enable_dynamic".into(), + problem: "is `true`".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), + // vuids? + ..Default::default() + }); + } + + match write_enable { + StateMode::Fixed(_) => (), + StateMode::Dynamic => { + if !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state) + { + return Err(ValidationError { + context: "write_enable".into(), + problem: "is dynamic".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), + // vuids? + ..Default::default() + }); + } + } + } + + match compare_op { + StateMode::Fixed(compare_op) => { + compare_op + .validate_device(device) + .map_err(|err| ValidationError { + context: "compare_op".into(), + vuids: &[ + "VUID-VkPipelineDepthStencilStateCreateInfo-depthCompareOp-parameter", + ], + ..ValidationError::from_requirement(err) + })?; + } + StateMode::Dynamic => { + if !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state) + { + return Err(ValidationError { + context: "compare_op".into(), + problem: "is dynamic".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), + // vuids? + ..Default::default() + }); + } + } + } + + Ok(()) + } +} + impl Default for DepthState { /// Creates a `DepthState` with no dynamic state, depth writes disabled and `compare_op` set /// to always pass. @@ -141,6 +304,59 @@ pub struct DepthBoundsState { pub bounds: StateMode>, } +impl DepthBoundsState { + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + enable_dynamic, + ref bounds, + } = self; + + if enable_dynamic + && !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state) + { + return Err(ValidationError { + context: "enable_dynamic".into(), + problem: "is `true`".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), + // vuids? + ..Default::default() + }); + } + + if let StateMode::Fixed(bounds) = bounds { + if !device.enabled_extensions().ext_depth_range_unrestricted { + if !(0.0..1.0).contains(bounds.start()) { + return Err(ValidationError { + context: "bounds.start".into(), + problem: "is not between 0.0 and 1.0 inclusive".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::DeviceExtension("ext_depth_range_unrestricted"), + ])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-02510"], + }); + } + + if !(0.0..1.0).contains(bounds.end()) { + return Err(ValidationError { + context: "bounds.end".into(), + problem: "is not between 0.0 and 1.0 inclusive".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::DeviceExtension("ext_depth_range_unrestricted"), + ])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-02510"], + }); + } + } + } + + Ok(()) + } +} + impl Default for DepthBoundsState { /// Creates a `DepthBoundsState` with no dynamic state and the bounds set to `0.0..=1.0`. #[inline] @@ -175,6 +391,108 @@ pub struct StencilState { pub back: StencilOpState, } +impl StencilState { + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &StencilState { + enable_dynamic, + ref front, + ref back, + } = self; + + if enable_dynamic + && !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state) + { + return Err(ValidationError { + context: "enable_dynamic".into(), + problem: "is `true`".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), + // vuids? + ..Default::default() + }); + } + + match (front.ops, back.ops) { + (StateMode::Fixed(front_ops), StateMode::Fixed(back_ops)) => { + front_ops + .validate(device) + .map_err(|err| err.add_context("front.ops"))?; + back_ops + .validate(device) + .map_err(|err| err.add_context("back.ops"))?; + } + (StateMode::Dynamic, StateMode::Dynamic) => { + if !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state) + { + return Err(ValidationError { + problem: "`front.ops` and `back.ops` are dynamic".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), + // vuids? + ..Default::default() + }); + } + } + _ => { + return Err(ValidationError { + problem: "`front.ops` and `back.ops` are \ + not both fixed or both dynamic" + .into(), + // vuids? + ..Default::default() + }); + } + } + + if !matches!( + (front.compare_mask, back.compare_mask), + (StateMode::Fixed(_), StateMode::Fixed(_)) | (StateMode::Dynamic, StateMode::Dynamic) + ) { + return Err(ValidationError { + problem: "`front.compare_mask` and `back.compare_mask` are \ + not both fixed or both dynamic" + .into(), + // vuids? + ..Default::default() + }); + } + + if !matches!( + (front.write_mask, back.write_mask), + (StateMode::Fixed(_), StateMode::Fixed(_)) | (StateMode::Dynamic, StateMode::Dynamic) + ) { + return Err(ValidationError { + problem: "`front.write_mask` and `back.write_mask` are \ + not both fixed or both dynamic" + .into(), + // vuids? + ..Default::default() + }); + } + + if !matches!( + (front.reference, back.reference), + (StateMode::Fixed(_), StateMode::Fixed(_)) | (StateMode::Dynamic, StateMode::Dynamic) + ) { + return Err(ValidationError { + problem: "`front.reference` and `back.reference` are \ + not both fixed or both dynamic" + .into(), + // vuids? + ..Default::default() + }); + } + + Ok(()) + } +} + /// Stencil test operations for a single face. #[derive(Clone, Copy, Debug)] pub struct StencilOpState { @@ -236,6 +554,51 @@ pub struct StencilOps { pub compare_op: CompareOp, } +impl StencilOps { + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + fail_op, + pass_op, + depth_fail_op, + compare_op, + } = self; + + fail_op + .validate_device(device) + .map_err(|err| ValidationError { + context: "fail_op".into(), + vuids: &["VUID-VkStencilOpState-failOp-parameter"], + ..ValidationError::from_requirement(err) + })?; + + pass_op + .validate_device(device) + .map_err(|err| ValidationError { + context: "pass_op".into(), + vuids: &["VUID-VkStencilOpState-passOp-parameter"], + ..ValidationError::from_requirement(err) + })?; + + depth_fail_op + .validate_device(device) + .map_err(|err| ValidationError { + context: "depth_fail_op".into(), + vuids: &["VUID-VkStencilOpState-depthFailOp-parameter"], + ..ValidationError::from_requirement(err) + })?; + + compare_op + .validate_device(device) + .map_err(|err| ValidationError { + context: "compare_op".into(), + vuids: &["VUID-VkStencilOpState-compareOp-parameter"], + ..ValidationError::from_requirement(err) + })?; + + Ok(()) + } +} + impl Default for StencilOps { /// Creates a `StencilOps` with no dynamic state, `compare_op` set to `Never` and the stencil /// operations set to `Keep`. diff --git a/vulkano/src/pipeline/graphics/discard_rectangle.rs b/vulkano/src/pipeline/graphics/discard_rectangle.rs index 3548870f9f..036c05facf 100644 --- a/vulkano/src/pipeline/graphics/discard_rectangle.rs +++ b/vulkano/src/pipeline/graphics/discard_rectangle.rs @@ -12,8 +12,10 @@ //! The discard rectangle test is similar to, but separate from the scissor test. use crate::{ + device::Device, macros::vulkan_enum, pipeline::{graphics::viewport::Scissor, PartialStateMode}, + ValidationError, }; /// The state in a graphics pipeline describing how the discard rectangle test should behave. @@ -40,6 +42,39 @@ impl DiscardRectangleState { rectangles: PartialStateMode::Fixed(Vec::new()), } } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + mode, + ref rectangles, + } = self; + + let properties = device.physical_device().properties(); + + mode.validate_device(device).map_err(|err| ValidationError { + context: "mode".into(), + vuids: &["VUID-VkPipelineDiscardRectangleStateCreateInfoEXT-discardRectangleMode-parameter"], + ..ValidationError::from_requirement(err) + })?; + + let discard_rectangle_count = match rectangles { + PartialStateMode::Dynamic(count) => *count, + PartialStateMode::Fixed(rectangles) => rectangles.len() as u32, + }; + + if discard_rectangle_count > properties.max_discard_rectangles.unwrap() { + return Err(ValidationError { + context: "rectangles".into(), + problem: "the length exceeds the `max_discard_rectangles` limit".into(), + vuids: &[ + "VUID-VkPipelineDiscardRectangleStateCreateInfoEXT-discardRectangleCount-00582", + ], + ..Default::default() + }); + } + + Ok(()) + } } impl Default for DiscardRectangleState { diff --git a/vulkano/src/pipeline/graphics/input_assembly.rs b/vulkano/src/pipeline/graphics/input_assembly.rs index edfd2ef7b7..99fb35d9e3 100644 --- a/vulkano/src/pipeline/graphics/input_assembly.rs +++ b/vulkano/src/pipeline/graphics/input_assembly.rs @@ -10,8 +10,10 @@ //! Configures how input vertices are assembled into primitives. use crate::{ + device::Device, macros::vulkan_enum, pipeline::{PartialStateMode, StateMode}, + Requires, RequiresAllOf, RequiresOneOf, ValidationError, Version, }; /// The state in a graphics pipeline describing how the input assembly stage should behave. @@ -78,6 +80,166 @@ impl InputAssemblyState { self.primitive_restart_enable = StateMode::Dynamic; self } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + topology, + primitive_restart_enable, + } = self; + + match topology { + PartialStateMode::Fixed(topology) => { + topology + .validate_device(device) + .map_err(|err| ValidationError { + context: "topology".into(), + vuids: &["VUID-VkPipelineInputAssemblyStateCreateInfo-topology-parameter"], + ..ValidationError::from_requirement(err) + })?; + + match topology { + PrimitiveTopology::TriangleFan => { + if device.enabled_extensions().khr_portability_subset + && !device.enabled_features().triangle_fans + { + return Err(ValidationError { + problem: "this device is a portability subset device, and \ + `topology` is `PrimitiveTopology::TriangleFan`" + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("triangle_fans"), + ])]), + vuids: &["VUID-VkPipelineInputAssemblyStateCreateInfo-triangleFans-04452"], + ..Default::default() + }); + } + } + PrimitiveTopology::LineListWithAdjacency + | PrimitiveTopology::LineStripWithAdjacency + | PrimitiveTopology::TriangleListWithAdjacency + | PrimitiveTopology::TriangleStripWithAdjacency => { + if !device.enabled_features().geometry_shader { + return Err(ValidationError { + context: "topology".into(), + problem: "is `PrimitiveTopology::*WithAdjacency`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("geometry_shader"), + ])]), + vuids: &[ + "VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00429", + ], + }); + } + } + PrimitiveTopology::PatchList => { + if !device.enabled_features().tessellation_shader { + return Err(ValidationError { + context: "topology".into(), + problem: "is `PrimitiveTopology::PatchList`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("tessellation_shader"), + ])]), + vuids: &[ + "VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00430", + ], + }); + } + } + _ => (), + } + } + PartialStateMode::Dynamic(topology_class) => { + topology_class + .example() + .validate_device(device) + .map_err(|err| ValidationError { + context: "topology".into(), + vuids: &["VUID-VkPipelineInputAssemblyStateCreateInfo-topology-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state) + { + return Err(ValidationError { + context: "topology".into(), + problem: "is dynamic".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), + // vuids? + ..Default::default() + }); + } + } + } + + match primitive_restart_enable { + StateMode::Fixed(primitive_restart_enable) => { + if primitive_restart_enable { + match topology { + PartialStateMode::Fixed( + PrimitiveTopology::PointList + | PrimitiveTopology::LineList + | PrimitiveTopology::TriangleList + | PrimitiveTopology::LineListWithAdjacency + | PrimitiveTopology::TriangleListWithAdjacency, + ) => { + if !device.enabled_features().primitive_topology_list_restart { + return Err(ValidationError { + problem: "`topology` is `PrimitiveTopology::*List`, and \ + `primitive_restart_enable` is `true`" + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("primitive_topology_list_restart"), + ])]), + vuids: &["VUID-VkPipelineInputAssemblyStateCreateInfo-topology-06252"], + ..Default::default() + }); + } + } + PartialStateMode::Fixed(PrimitiveTopology::PatchList) => { + if !device + .enabled_features() + .primitive_topology_patch_list_restart + { + return Err(ValidationError { + problem: "`topology` is `PrimitiveTopology::PatchList`, and \ + `primitive_restart_enable` is `true`" + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("primitive_topology_patch_list_restart"), + ])]), + vuids: &["VUID-VkPipelineInputAssemblyStateCreateInfo-topology-06253"], + ..Default::default() + }); + } + } + _ => (), + } + } + } + StateMode::Dynamic => { + if !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state2) + { + return Err(ValidationError { + context: "primitive_restart_enable".into(), + problem: "is dynamic".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), + // vuids? + ..Default::default() + }); + } + } + } + + Ok(()) + } } impl Default for InputAssemblyState { diff --git a/vulkano/src/pipeline/graphics/mod.rs b/vulkano/src/pipeline/graphics/mod.rs index 2029cb7dc7..ed1c6bab0d 100644 --- a/vulkano/src/pipeline/graphics/mod.rs +++ b/vulkano/src/pipeline/graphics/mod.rs @@ -57,26 +57,24 @@ //! command. use self::{ - color_blend::{AttachmentBlend, BlendFactor, ColorBlendState}, - depth_stencil::{DepthBoundsState, DepthState, DepthStencilState, StencilOps}, + color_blend::ColorBlendState, + depth_stencil::{DepthBoundsState, DepthState, DepthStencilState}, discard_rectangle::DiscardRectangleState, input_assembly::{InputAssemblyState, PrimitiveTopology, PrimitiveTopologyClass}, multisample::MultisampleState, - rasterization::{DepthBiasState, LineRasterizationMode, PolygonMode, RasterizationState}, + rasterization::RasterizationState, subpass::PipelineSubpassType, tessellation::TessellationState, - vertex_input::{ - VertexInputAttributeDescription, VertexInputBindingDescription, VertexInputState, - }, + vertex_input::VertexInputState, viewport::ViewportState, }; use super::{ - cache::PipelineCache, layout::PipelineLayoutSupersetError, DynamicState, Pipeline, - PipelineBindPoint, PipelineCreateFlags, PipelineLayout, StateMode, + cache::PipelineCache, DynamicState, Pipeline, PipelineBindPoint, PipelineCreateFlags, + PipelineLayout, PipelineShaderStageCreateInfo, StateMode, }; use crate::{ device::{Device, DeviceOwned}, - format::{Format, FormatFeatures, NumericType}, + format::{FormatFeatures, NumericType}, image::{ImageAspect, ImageAspects}, macros::impl_id_counter, pipeline::{ @@ -92,19 +90,17 @@ use crate::{ }, shader::{ DescriptorBindingRequirements, FragmentShaderExecution, FragmentTestsStages, - PipelineShaderStageCreateInfo, ShaderExecution, ShaderInterfaceMismatchError, - ShaderScalarType, ShaderStage, ShaderStages, SpecializationConstant, + ShaderExecution, ShaderScalarType, ShaderStage, ShaderStages, }, - DeviceSize, OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, - Version, VulkanObject, + Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, VulkanError, + VulkanObject, }; use ahash::HashMap; use smallvec::SmallVec; use std::{ collections::hash_map::Entry, - error::Error, ffi::CString, - fmt::{Debug, Display, Error as FmtError, Formatter}, + fmt::{Debug, Error as FmtError, Formatter}, mem::MaybeUninit, num::NonZeroU64, ptr, @@ -161,7 +157,7 @@ impl GraphicsPipeline { device: Arc, cache: Option>, create_info: GraphicsPipelineCreateInfo, - ) -> Result, GraphicsPipelineCreationError> { + ) -> Result, VulkanError> { Self::validate_new(&device, cache.as_ref().map(AsRef::as_ref), &create_info)?; unsafe { Ok(Self::new_unchecked(device, cache, create_info)?) } @@ -171,12 +167,22 @@ impl GraphicsPipeline { device: &Device, _cache: Option<&PipelineCache>, create_info: &GraphicsPipelineCreateInfo, - ) -> Result<(), GraphicsPipelineCreationError> { - let physical_device = device.physical_device(); - let properties = physical_device.properties(); + ) -> Result<(), ValidationError> { + create_info + .validate(device) + .map_err(|err| err.add_context("create_info"))?; + + Ok(()) + } + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] + pub unsafe fn new_unchecked( + device: Arc, + cache: Option>, + create_info: GraphicsPipelineCreateInfo, + ) -> Result, RuntimeError> { let &GraphicsPipelineCreateInfo { - flags: _, + flags, ref stages, ref vertex_input_state, @@ -193,4632 +199,2845 @@ impl GraphicsPipeline { ref discard_rectangle_state, _ne: _, - } = create_info; + } = &create_info; - /* - Gather shader stages - */ + let mut dynamic_state: HashMap = HashMap::default(); - let mut stages_present = ShaderStages::empty(); - let mut vertex_stage = None; - let mut tessellation_control_stage = None; - let mut tessellation_evaluation_stage = None; - let mut geometry_stage = None; - let mut fragment_stage = None; + struct PerPipelineShaderStageCreateInfo { + name_vk: CString, + specialization_info_vk: ash::vk::SpecializationInfo, + specialization_map_entries_vk: Vec, + specialization_data_vk: Vec, + } - for (stage_index, stage) in stages.iter().enumerate() { - let entry_point_info = stage.entry_point.info(); - let stage_enum = ShaderStage::from(&entry_point_info.execution); - let stage_flag = ShaderStages::from(stage_enum); + let (mut stages_vk, mut per_stage_vk): (SmallVec<[_; 5]>, SmallVec<[_; 5]>) = stages + .iter() + .map(|stage| { + let &PipelineShaderStageCreateInfo { + flags, + ref entry_point, + ref specialization_info, + _ne: _, + } = stage; - // VUID-VkGraphicsPipelineCreateInfo-stage-06897 - if stages_present.intersects(stage_flag) { - return Err(GraphicsPipelineCreationError::ShaderStageDuplicate { - stage_index, - stage: stage_enum, - }); - } + let entry_point_info = entry_point.info(); + let stage = ShaderStage::from(&entry_point_info.execution); - // VUID-VkGraphicsPipelineCreateInfo-pStages-02095 - // VUID-VkGraphicsPipelineCreateInfo-pStages-06896 - // VUID-VkPipelineShaderStageCreateInfo-stage-parameter - let stage_slot = match stage_enum { - ShaderStage::Vertex => &mut vertex_stage, - ShaderStage::TessellationControl => &mut tessellation_control_stage, - ShaderStage::TessellationEvaluation => &mut tessellation_evaluation_stage, - ShaderStage::Geometry => &mut geometry_stage, - ShaderStage::Fragment => &mut fragment_stage, - _ => { - return Err(GraphicsPipelineCreationError::ShaderStageInvalid { - stage_index, - stage: stage_enum, + let mut specialization_data_vk: Vec = Vec::new(); + let specialization_map_entries_vk: Vec<_> = specialization_info + .iter() + .map(|(&constant_id, value)| { + let data = value.as_bytes(); + let offset = specialization_data_vk.len() as u32; + let size = data.len(); + specialization_data_vk.extend(data); + + ash::vk::SpecializationMapEntry { + constant_id, + offset, + size, + } }) - } + .collect(); + + ( + ash::vk::PipelineShaderStageCreateInfo { + flags: flags.into(), + stage: stage.into(), + module: entry_point.module().handle(), + p_name: ptr::null(), + p_specialization_info: ptr::null(), + ..Default::default() + }, + PerPipelineShaderStageCreateInfo { + name_vk: CString::new(entry_point_info.name.as_str()).unwrap(), + specialization_info_vk: ash::vk::SpecializationInfo { + map_entry_count: specialization_map_entries_vk.len() as u32, + p_map_entries: ptr::null(), + data_size: specialization_data_vk.len(), + p_data: ptr::null(), + }, + specialization_map_entries_vk, + specialization_data_vk, + }, + ) + }) + .unzip(); + + for ( + stage_vk, + PerPipelineShaderStageCreateInfo { + name_vk, + specialization_info_vk, + specialization_map_entries_vk, + specialization_data_vk, + }, + ) in (stages_vk.iter_mut()).zip(per_stage_vk.iter_mut()) + { + *stage_vk = ash::vk::PipelineShaderStageCreateInfo { + p_name: name_vk.as_ptr(), + p_specialization_info: specialization_info_vk, + ..*stage_vk }; - *stage_slot = Some(stage); - stages_present |= stage_flag; + *specialization_info_vk = ash::vk::SpecializationInfo { + p_map_entries: specialization_map_entries_vk.as_ptr(), + p_data: specialization_data_vk.as_ptr() as _, + ..*specialization_info_vk + }; } - /* - Validate needed/unused state - */ - - let need_pre_rasterization_shader_state = true; + let mut vertex_input_state_vk = None; + let mut vertex_binding_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new(); + let mut vertex_attribute_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new(); + let mut vertex_binding_divisor_state_vk = None; + let mut vertex_binding_divisor_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new(); - // Check this first because everything else depends on it. - // VUID? - match ( - rasterization_state.is_some(), - need_pre_rasterization_shader_state, - ) { - (true, false) => { - return Err(GraphicsPipelineCreationError::StateUnused { - state: "rasterization_state", - }) - } - (false, true) => { - return Err(GraphicsPipelineCreationError::StateMissing { - state: "rasterization_state", - }) - } - _ => (), - } + if let Some(vertex_input_state) = vertex_input_state { + dynamic_state.insert(DynamicState::VertexInput, false); - let need_vertex_input_state = need_pre_rasterization_shader_state - && stages - .iter() - .any(|stage| matches!(stage.entry_point.info().execution, ShaderExecution::Vertex)); - let need_fragment_shader_state = need_pre_rasterization_shader_state - && rasterization_state - .as_ref() - .unwrap() - .rasterizer_discard_enable - != StateMode::Fixed(true); - let need_fragment_output_state = need_pre_rasterization_shader_state - && rasterization_state - .as_ref() - .unwrap() - .rasterizer_discard_enable - != StateMode::Fixed(true); + let VertexInputState { + bindings, + attributes, + } = vertex_input_state; - // VUID-VkGraphicsPipelineCreateInfo-stage-02096 - // VUID-VkGraphicsPipelineCreateInfo-pStages-06895 - match (vertex_stage.is_some(), need_pre_rasterization_shader_state) { - (true, false) => { - return Err(GraphicsPipelineCreationError::ShaderStageUnused { - stage: ShaderStage::Vertex, - }) - } - (false, true) => return Err(GraphicsPipelineCreationError::VertexShaderStageMissing), - _ => (), - } + vertex_binding_descriptions_vk.extend(bindings.iter().map( + |(&binding, binding_desc)| ash::vk::VertexInputBindingDescription { + binding, + stride: binding_desc.stride, + input_rate: binding_desc.input_rate.into(), + }, + )); - // VUID-VkGraphicsPipelineCreateInfo-pStages-06895 - match ( - tessellation_control_stage.is_some(), - need_pre_rasterization_shader_state, - ) { - (true, false) => { - return Err(GraphicsPipelineCreationError::ShaderStageUnused { - stage: ShaderStage::Vertex, - }) - } - (false, true) => (), - _ => (), - } + vertex_attribute_descriptions_vk.extend(attributes.iter().map( + |(&location, attribute_desc)| ash::vk::VertexInputAttributeDescription { + location, + binding: attribute_desc.binding, + format: attribute_desc.format.into(), + offset: attribute_desc.offset, + }, + )); - // VUID-VkGraphicsPipelineCreateInfo-pStages-06895 - match ( - tessellation_evaluation_stage.is_some(), - need_pre_rasterization_shader_state, - ) { - (true, false) => { - return Err(GraphicsPipelineCreationError::ShaderStageUnused { - stage: ShaderStage::Vertex, - }) - } - (false, true) => (), - _ => (), - } + let vertex_input_state = + vertex_input_state_vk.insert(ash::vk::PipelineVertexInputStateCreateInfo { + flags: ash::vk::PipelineVertexInputStateCreateFlags::empty(), + vertex_binding_description_count: vertex_binding_descriptions_vk.len() as u32, + p_vertex_binding_descriptions: vertex_binding_descriptions_vk.as_ptr(), + vertex_attribute_description_count: vertex_attribute_descriptions_vk.len() + as u32, + p_vertex_attribute_descriptions: vertex_attribute_descriptions_vk.as_ptr(), + ..Default::default() + }); - // VUID-VkGraphicsPipelineCreateInfo-pStages-00729 - // VUID-VkGraphicsPipelineCreateInfo-pStages-00730 - if stages_present - .intersects(ShaderStages::TESSELLATION_CONTROL | ShaderStages::TESSELLATION_EVALUATION) - && !stages_present.contains( - ShaderStages::TESSELLATION_CONTROL | ShaderStages::TESSELLATION_EVALUATION, - ) - { - return Err(GraphicsPipelineCreationError::OtherTessellationShaderStageMissing); - } + { + vertex_binding_divisor_descriptions_vk.extend( + bindings + .iter() + .filter_map(|(&binding, binding_desc)| match binding_desc.input_rate { + VertexInputRate::Instance { divisor } if divisor != 1 => { + Some((binding, divisor)) + } + _ => None, + }) + .map(|(binding, divisor)| { + ash::vk::VertexInputBindingDivisorDescriptionEXT { binding, divisor } + }), + ); - // VUID-VkGraphicsPipelineCreateInfo-pStages-06895 - match ( - geometry_stage.is_some(), - need_pre_rasterization_shader_state, - ) { - (true, false) => { - return Err(GraphicsPipelineCreationError::ShaderStageUnused { - stage: ShaderStage::Vertex, - }) + // VUID-VkPipelineVertexInputDivisorStateCreateInfoEXT-vertexBindingDivisorCount-arraylength + if !vertex_binding_divisor_descriptions_vk.is_empty() { + vertex_input_state.p_next = vertex_binding_divisor_state_vk.insert( + ash::vk::PipelineVertexInputDivisorStateCreateInfoEXT { + vertex_binding_divisor_count: vertex_binding_divisor_descriptions_vk + .len() + as u32, + p_vertex_binding_divisors: vertex_binding_divisor_descriptions_vk + .as_ptr(), + ..Default::default() + }, + ) as *const _ as *const _; + } } - (false, true) => (), - _ => (), } - // VUID-VkGraphicsPipelineCreateInfo-pStages-06894 - match (fragment_stage.is_some(), need_fragment_shader_state) { - (true, false) => { - return Err(GraphicsPipelineCreationError::ShaderStageUnused { - stage: ShaderStage::Vertex, - }) - } - (false, true) => (), - _ => (), - } + let mut input_assembly_state_vk = None; - // VUID-VkGraphicsPipelineCreateInfo-pVertexInputState-04910 - match (vertex_input_state.is_some(), need_vertex_input_state) { - (true, false) => { - return Err(GraphicsPipelineCreationError::StateUnused { - state: "vertex_input_state", - }) - } - (false, true) => { - return Err(GraphicsPipelineCreationError::StateMissing { - state: "vertex_input_state", - }) - } - _ => (), - } + if let Some(input_assembly_state) = input_assembly_state { + let &InputAssemblyState { + topology, + primitive_restart_enable, + } = input_assembly_state; - // VUID-VkGraphicsPipelineCreateInfo-pStages-02098 - match (input_assembly_state.is_some(), need_vertex_input_state) { - (true, false) => { - return Err(GraphicsPipelineCreationError::StateUnused { - state: "input_assembly_state", - }) - } - (false, true) => { - return Err(GraphicsPipelineCreationError::StateMissing { - state: "input_assembly_state", - }) - } - _ => (), - } + let topology = match topology { + PartialStateMode::Fixed(topology) => { + dynamic_state.insert(DynamicState::PrimitiveTopology, false); + topology.into() + } + PartialStateMode::Dynamic(topology_class) => { + dynamic_state.insert(DynamicState::PrimitiveTopology, true); + topology_class.example().into() + } + }; - // VUID-VkGraphicsPipelineCreateInfo-pStages-00731 - match ( - tessellation_state.is_some(), - need_pre_rasterization_shader_state - && stages_present.contains( - ShaderStages::TESSELLATION_CONTROL | ShaderStages::TESSELLATION_EVALUATION, - ), - ) { - (true, false) => { - return Err(GraphicsPipelineCreationError::StateUnused { - state: "tessellation_state", - }) - } - (false, true) => { - return Err(GraphicsPipelineCreationError::StateMissing { - state: "tessellation_state", - }) - } - _ => (), - } + let primitive_restart_enable = match primitive_restart_enable { + StateMode::Fixed(primitive_restart_enable) => { + dynamic_state.insert(DynamicState::PrimitiveRestartEnable, false); + primitive_restart_enable as ash::vk::Bool32 + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::PrimitiveRestartEnable, true); + Default::default() + } + }; - // VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00750 - // VUID-VkGraphicsPipelineCreateInfo-pViewportState-04892 - match ( - viewport_state.is_some(), - need_pre_rasterization_shader_state - && rasterization_state - .as_ref() - .unwrap() - .rasterizer_discard_enable - != StateMode::Fixed(true), - ) { - (true, false) => { - return Err(GraphicsPipelineCreationError::StateUnused { - state: "viewport_state", - }) - } - (false, true) => { - return Err(GraphicsPipelineCreationError::StateMissing { - state: "viewport_state", - }) - } - _ => (), + let _ = input_assembly_state_vk.insert(ash::vk::PipelineInputAssemblyStateCreateInfo { + flags: ash::vk::PipelineInputAssemblyStateCreateFlags::empty(), + topology, + primitive_restart_enable, + ..Default::default() + }); } - // VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00751 - match (multisample_state.is_some(), need_fragment_output_state) { - (true, false) => { - return Err(GraphicsPipelineCreationError::StateUnused { - state: "multisample_state", - }) - } - (false, true) => { - return Err(GraphicsPipelineCreationError::StateMissing { - state: "multisample_state", - }) - } - _ => (), - } + let mut tessellation_state_vk = None; + let mut tessellation_domain_origin_state_vk = None; - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06590 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06043 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06053 - match ( - depth_stencil_state.is_some(), - !need_fragment_output_state - || match render_pass { - Some(PipelineSubpassType::BeginRenderPass(subpass)) => { - subpass.subpass_desc().depth_stencil_attachment.is_some() - } - Some(PipelineSubpassType::BeginRendering(rendering_info)) => { - rendering_info.depth_attachment_format.is_some() - || rendering_info.stencil_attachment_format.is_some() - } - None => false, - }, - ) { - (true, false) => { - return Err(GraphicsPipelineCreationError::StateUnused { - state: "depth_stencil_state", - }) - } - (false, true) => { - return Err(GraphicsPipelineCreationError::StateMissing { - state: "depth_stencil_state", - }) - } - _ => (), - } + if let Some(tessellation_state) = tessellation_state { + let &TessellationState { + patch_control_points, + domain_origin, + } = tessellation_state; - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06044 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06054 - match ( - color_blend_state.is_some(), - need_fragment_output_state - && match render_pass { - Some(PipelineSubpassType::BeginRenderPass(subpass)) => { - !subpass.subpass_desc().color_attachments.is_empty() - } - Some(PipelineSubpassType::BeginRendering(rendering_info)) => { - !rendering_info.color_attachment_formats.is_empty() - } - None => false, - }, - ) { - (true, false) => { - return Err(GraphicsPipelineCreationError::StateUnused { - state: "color_blend_state", - }) - } - (false, true) => { - return Err(GraphicsPipelineCreationError::StateMissing { - state: "color_blend_state", - }) - } - _ => (), - } + let patch_control_points = match patch_control_points { + StateMode::Fixed(patch_control_points) => { + dynamic_state.insert(DynamicState::PatchControlPoints, false); + patch_control_points + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::PatchControlPoints, true); + Default::default() + } + }; - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06575 - match ( - render_pass.is_some(), - need_pre_rasterization_shader_state - || need_fragment_shader_state - || need_fragment_output_state, - ) { - (true, false) => { - return Err(GraphicsPipelineCreationError::StateUnused { - state: "render_pass", - }) - } - (false, true) => { - return Err(GraphicsPipelineCreationError::StateMissing { - state: "render_pass", - }) - } - _ => (), - } + let tessellation_state_vk = + tessellation_state_vk.insert(ash::vk::PipelineTessellationStateCreateInfo { + flags: ash::vk::PipelineTessellationStateCreateFlags::empty(), + patch_control_points, + ..Default::default() + }); - // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04058 (partly) - match ( - discard_rectangle_state.is_some(), - need_pre_rasterization_shader_state, - ) { - (true, false) => { - return Err(GraphicsPipelineCreationError::StateUnused { - state: "discard_rectangle_state", - }) + if domain_origin != TessellationDomainOrigin::default() { + let tessellation_domain_origin_state_vk = tessellation_domain_origin_state_vk + .insert(ash::vk::PipelineTessellationDomainOriginStateCreateInfo { + domain_origin: domain_origin.into(), + ..Default::default() + }); + + tessellation_domain_origin_state_vk.p_next = tessellation_state_vk.p_next; + tessellation_state_vk.p_next = + tessellation_domain_origin_state_vk as *const _ as *const _; } - (false, true) => (), - _ => (), } - /* - Validate shader stages individually - */ + let mut viewport_state_vk = None; + let mut viewports_vk: SmallVec<[_; 2]> = SmallVec::new(); + let mut scissors_vk: SmallVec<[_; 2]> = SmallVec::new(); - for (stage_index, stage) in stages.iter().enumerate() { - let &PipelineShaderStageCreateInfo { - flags, - ref entry_point, - ref specialization_info, + if let Some(viewport_state) = viewport_state { + let ViewportState { + viewports, + scissors, _ne: _, - } = stage; - - // VUID-VkPipelineShaderStageCreateInfo-flags-parameter - flags.validate_device(device)?; + } = viewport_state; - let entry_point_info = entry_point.info(); - let stage_enum = ShaderStage::from(&entry_point_info.execution); - - // VUID-VkPipelineShaderStageCreateInfo-pName-00707 - // Guaranteed by definition of `EntryPoint`. - - // TODO: - // VUID-VkPipelineShaderStageCreateInfo-maxClipDistances-00708 - // VUID-VkPipelineShaderStageCreateInfo-maxCullDistances-00709 - // VUID-VkPipelineShaderStageCreateInfo-maxCombinedClipAndCullDistances-00710 - // VUID-VkPipelineShaderStageCreateInfo-maxSampleMaskWords-00711 - - match stage_enum { - ShaderStage::Vertex => { - vertex_stage = Some(stage); - - // VUID-VkPipelineShaderStageCreateInfo-stage-00712 - // TODO: + let viewport_count = match viewports { + PartialStateMode::Fixed(viewports) => { + dynamic_state.insert(DynamicState::Viewport, false); + dynamic_state.insert(DynamicState::ViewportWithCount, false); + viewports_vk.extend(viewports.iter().map(Into::into)); + viewports.len() as u32 } - ShaderStage::TessellationControl | ShaderStage::TessellationEvaluation => { - // VUID-VkPipelineShaderStageCreateInfo-stage-00705 - if !device.enabled_features().tessellation_shader { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`stages` contains a `TessellationControl` or \ - `TessellationEvaluation` shader stage", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "tessellation_shader", - )])]), - }); - } - - // VUID-VkPipelineShaderStageCreateInfo-stage-00713 - // TODO: + PartialStateMode::Dynamic(StateMode::Fixed(count)) => { + dynamic_state.insert(DynamicState::Viewport, true); + dynamic_state.insert(DynamicState::ViewportWithCount, false); + *count } - ShaderStage::Geometry => { - // VUID-VkPipelineShaderStageCreateInfo-stage-00704 - if !device.enabled_features().geometry_shader { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`stages` contains a `Geometry` shader stage", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "geometry_shader", - )])]), - }); - } - - // VUID-VkPipelineShaderStageCreateInfo-stage-00714 - // VUID-VkPipelineShaderStageCreateInfo-stage-00715 - // TODO: + PartialStateMode::Dynamic(StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::Viewport, true); + dynamic_state.insert(DynamicState::ViewportWithCount, true); + 0 } - ShaderStage::Fragment => { - fragment_stage = Some(stage); + }; - // VUID-VkPipelineShaderStageCreateInfo-stage-00718 - // VUID-VkPipelineShaderStageCreateInfo-stage-06685 - // VUID-VkPipelineShaderStageCreateInfo-stage-06686 - // TODO: + let scissor_count = match scissors { + PartialStateMode::Fixed(scissors) => { + dynamic_state.insert(DynamicState::Scissor, false); + dynamic_state.insert(DynamicState::ScissorWithCount, false); + scissors_vk.extend(scissors.iter().map(Into::into)); + scissors.len() as u32 } - _ => unreachable!(), - } - - // TODO: - // VUID-VkPipelineShaderStageCreateInfo-stage-02596 - // VUID-VkPipelineShaderStageCreateInfo-stage-02597 - - for (&constant_id, provided_value) in specialization_info { - // Per `VkSpecializationMapEntry` spec: - // "If a constantID value is not a specialization constant ID used in the shader, - // that map entry does not affect the behavior of the pipeline." - // We *may* want to be stricter than this for the sake of catching user errors? - if let Some(default_value) = - entry_point_info.specialization_constants.get(&constant_id) - { - // VUID-VkSpecializationMapEntry-constantID-00776 - // Check for equal types rather than only equal size. - if !provided_value.eq_type(default_value) { - return Err( - GraphicsPipelineCreationError::ShaderSpecializationConstantTypeMismatch { - stage_index, - constant_id, - default_value: *default_value, - provided_value: *provided_value, - }, - ); - } + PartialStateMode::Dynamic(StateMode::Fixed(count)) => { + dynamic_state.insert(DynamicState::Scissor, true); + dynamic_state.insert(DynamicState::ScissorWithCount, false); + *count } - } + PartialStateMode::Dynamic(StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::Scissor, true); + dynamic_state.insert(DynamicState::ScissorWithCount, true); + 0 + } + }; - // VUID-VkGraphicsPipelineCreateInfo-layout-00756 - layout.ensure_compatible_with_shader( - entry_point_info - .descriptor_binding_requirements - .iter() - .map(|(k, v)| (*k, v)), - entry_point_info.push_constant_requirements.as_ref(), - )?; + let _ = viewport_state_vk.insert(ash::vk::PipelineViewportStateCreateInfo { + flags: ash::vk::PipelineViewportStateCreateFlags::empty(), + viewport_count, + p_viewports: if viewports_vk.is_empty() { + ptr::null() + } else { + viewports_vk.as_ptr() + }, + scissor_count, + p_scissors: if scissors_vk.is_empty() { + ptr::null() + } else { + scissors_vk.as_ptr() + }, + ..Default::default() + }); } - let ordered_stages: SmallVec<[_; 5]> = [ - vertex_stage, - tessellation_control_stage, - tessellation_evaluation_stage, - geometry_stage, - fragment_stage, - ] - .into_iter() - .flatten() - .collect(); + let mut rasterization_state_vk = None; + let mut rasterization_line_state_vk = None; - // VUID-VkGraphicsPipelineCreateInfo-pStages-00742 - // VUID-VkGraphicsPipelineCreateInfo-None-04889 + if let Some(rasterization_state) = rasterization_state { + let &RasterizationState { + depth_clamp_enable, + rasterizer_discard_enable, + polygon_mode, + cull_mode, + front_face, + depth_bias, + line_width, + line_rasterization_mode, + line_stipple, + } = rasterization_state; - // TODO: this check is too strict; the output only has to be a superset, any variables - // not used in the input of the next shader are just ignored. - for (output, input) in ordered_stages.iter().zip(ordered_stages.iter().skip(1)) { - if let Err(err) = (input.entry_point.info().input_interface) - .matches(&output.entry_point.info().output_interface) - { - return Err(GraphicsPipelineCreationError::ShaderStagesMismatch(err)); - } - } - - // VUID-VkGraphicsPipelineCreateInfo-layout-01688 - // Checked at pipeline layout creation time. - - /* - Validate states individually - */ - - if let Some(vertex_input_state) = vertex_input_state { - let VertexInputState { - bindings, - attributes, - } = vertex_input_state; - - // VUID-VkPipelineVertexInputStateCreateInfo-vertexBindingDescriptionCount-00613 - if bindings.len() > properties.max_vertex_input_bindings as usize { - return Err( - GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded { - max: properties.max_vertex_input_bindings, - obtained: bindings.len() as u32, - }, - ); - } - - // VUID-VkPipelineVertexInputStateCreateInfo-pVertexBindingDescriptions-00616 - // Ensured by HashMap. - - for (&binding, binding_desc) in bindings { - let &VertexInputBindingDescription { stride, input_rate } = binding_desc; - - // VUID-VkVertexInputBindingDescription-binding-00618 - if binding >= properties.max_vertex_input_bindings { - return Err( - GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded { - max: properties.max_vertex_input_bindings, - obtained: binding, - }, - ); - } - - // VUID-VkVertexInputBindingDescription-stride-00619 - if stride > properties.max_vertex_input_binding_stride { - return Err( - GraphicsPipelineCreationError::MaxVertexInputBindingStrideExceeded { - binding, - max: properties.max_vertex_input_binding_stride, - obtained: stride, - }, - ); - } - - // VUID-VkVertexInputBindingDescription-stride-04456 - if device.enabled_extensions().khr_portability_subset - && (stride == 0 - || stride - % properties - .min_vertex_input_binding_stride_alignment - .unwrap() - != 0) - { - return Err(GraphicsPipelineCreationError::MinVertexInputBindingStrideAlignmentExceeded { - binding, - max: properties.min_vertex_input_binding_stride_alignment.unwrap(), - obtained: binding, - }); - } - - match input_rate { - VertexInputRate::Instance { divisor } if divisor != 1 => { - // VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateDivisor-02229 - if !device - .enabled_features() - .vertex_attribute_instance_rate_divisor - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`vertex_input_state.bindings` has an element \ - where `input_rate` is `VertexInputRate::Instance`, where \ - `divisor` is not `1`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("vertex_attribute_instance_rate_divisor"), - ])]), - }); - } - - // VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateZeroDivisor-02228 - if divisor == 0 - && !device - .enabled_features() - .vertex_attribute_instance_rate_zero_divisor - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`vertex_input_state.bindings` has an element \ - where `input_rate` is `VertexInputRate::Instance`, where \ - `divisor` is `0`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature( - "vertex_attribute_instance_rate_zero_divisor", - ), - ])]), - }); - } - - // VUID-VkVertexInputBindingDivisorDescriptionEXT-divisor-01870 - if divisor > properties.max_vertex_attrib_divisor.unwrap() { - return Err( - GraphicsPipelineCreationError::MaxVertexAttribDivisorExceeded { - binding, - max: properties.max_vertex_attrib_divisor.unwrap(), - obtained: divisor, - }, - ); - } - } - _ => (), + let rasterizer_discard_enable = match rasterizer_discard_enable { + StateMode::Fixed(rasterizer_discard_enable) => { + dynamic_state.insert(DynamicState::RasterizerDiscardEnable, false); + rasterizer_discard_enable as ash::vk::Bool32 } - } - - // VUID-VkPipelineVertexInputStateCreateInfo-vertexAttributeDescriptionCount-00614 - if attributes.len() > properties.max_vertex_input_attributes as usize { - return Err( - GraphicsPipelineCreationError::MaxVertexInputAttributesExceeded { - max: properties.max_vertex_input_attributes, - obtained: attributes.len(), - }, - ); - } - - // VUID-VkPipelineVertexInputStateCreateInfo-pVertexAttributeDescriptions-00617 - // Ensured by HashMap with the exception of formats exceeding a single location. - // When a format exceeds a single location the location following it (e.g. - // R64B64G64_SFLOAT) needs to be unassigned. - let unassigned_locations = attributes - .iter() - .filter(|&(_, attribute_desc)| attribute_desc.format.block_size().unwrap() > 16) - .map(|(location, _)| location + 1); - for location in unassigned_locations { - if !attributes.get(&location).is_none() { - return Err(GraphicsPipelineCreationError::VertexInputAttributeInvalidAssignedLocation { - location, - }); + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::RasterizerDiscardEnable, true); + ash::vk::FALSE } - } - - for (&location, attribute_desc) in attributes { - let &VertexInputAttributeDescription { - binding, - format, - offset, - } = attribute_desc; - - // VUID-VkVertexInputAttributeDescription-format-parameter - format.validate_device(device)?; - - // TODO: - // VUID-VkVertexInputAttributeDescription-location-00620 + }; - // VUID-VkPipelineVertexInputStateCreateInfo-binding-00615 - let binding_desc = bindings.get(&binding).ok_or( - GraphicsPipelineCreationError::VertexInputAttributeInvalidBinding { - location, - binding, - }, - )?; - - // VUID-VkVertexInputAttributeDescription-offset-00622 - if offset > properties.max_vertex_input_attribute_offset { - return Err( - GraphicsPipelineCreationError::MaxVertexInputAttributeOffsetExceeded { - max: properties.max_vertex_input_attribute_offset, - obtained: offset, - }, - ); + let cull_mode = match cull_mode { + StateMode::Fixed(cull_mode) => { + dynamic_state.insert(DynamicState::CullMode, false); + cull_mode.into() } - - // Use unchecked, because all validation has been done above. - let format_features = unsafe { - device - .physical_device() - .format_properties_unchecked(format) - .buffer_features - }; - - // VUID-VkVertexInputAttributeDescription-format-00623 - if !format_features.intersects(FormatFeatures::VERTEX_BUFFER) { - return Err( - GraphicsPipelineCreationError::VertexInputAttributeUnsupportedFormat { - location, - format, - }, - ); + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::CullMode, true); + CullMode::default().into() } + }; - // VUID-VkVertexInputAttributeDescription-vertexAttributeAccessBeyondStride-04457 - if device.enabled_extensions().khr_portability_subset - && !device - .enabled_features() - .vertex_attribute_access_beyond_stride - && offset as DeviceSize + format.block_size().unwrap() - > binding_desc.stride as DeviceSize - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "this device is a portability subset device, and \ - `vertex_input_state.attributes` has an element where \ - `offset + format.block_size()` is greater than the `stride` of \ - `binding`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "vertex_attribute_access_beyond_stride", - )])]), - }); + let front_face = match front_face { + StateMode::Fixed(front_face) => { + dynamic_state.insert(DynamicState::FrontFace, false); + front_face.into() } - } - } - - if let Some(input_assembly_state) = input_assembly_state { - let &InputAssemblyState { - topology, - primitive_restart_enable, - } = input_assembly_state; - - match topology { - PartialStateMode::Fixed(topology) => { - // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-parameter - topology.validate_device(device)?; - - match topology { - PrimitiveTopology::TriangleFan => { - // VUID-VkPipelineInputAssemblyStateCreateInfo-triangleFans-04452 - if device.enabled_extensions().khr_portability_subset - && !device.enabled_features().triangle_fans - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "this device is a portability subset \ - device, and `input_assembly_state.topology` is \ - `StateMode::Fixed(PrimitiveTopology::TriangleFan)`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("triangle_fans"), - ])]), - }); - } - } - PrimitiveTopology::LineListWithAdjacency - | PrimitiveTopology::LineStripWithAdjacency - | PrimitiveTopology::TriangleListWithAdjacency - | PrimitiveTopology::TriangleStripWithAdjacency => { - // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00429 - if !device.enabled_features().geometry_shader { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`input_assembly_state.topology` is \ - `StateMode::Fixed(PrimitiveTopology::*WithAdjacency)`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("geometry_shader"), - ])]), - }); - } - } - PrimitiveTopology::PatchList => { - // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00430 - if !device.enabled_features().tessellation_shader { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`input_assembly_state.topology` is \ - `StateMode::Fixed(PrimitiveTopology::PatchList)`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("tessellation_shader"), - ])]), - }); - } - - // TODO: - // VUID-VkGraphicsPipelineCreateInfo-topology-00737 - } - _ => (), - } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::FrontFace, true); + FrontFace::default().into() } - PartialStateMode::Dynamic(topology_class) => { - // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-parameter - topology_class.example().validate_device(device)?; + }; - // VUID? - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`input_assembly_state.topology` is \ - `PartialStateMode::Dynamic`", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } + let ( + depth_bias_enable, + depth_bias_constant_factor, + depth_bias_clamp, + depth_bias_slope_factor, + ) = if let Some(depth_bias_state) = depth_bias { + if depth_bias_state.enable_dynamic { + dynamic_state.insert(DynamicState::DepthBiasEnable, true); + } else { + dynamic_state.insert(DynamicState::DepthBiasEnable, false); } - } - match primitive_restart_enable { - StateMode::Fixed(primitive_restart_enable) => { - if primitive_restart_enable { - match topology { - PartialStateMode::Fixed( - PrimitiveTopology::PointList - | PrimitiveTopology::LineList - | PrimitiveTopology::TriangleList - | PrimitiveTopology::LineListWithAdjacency - | PrimitiveTopology::TriangleListWithAdjacency, - ) => { - // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-06252 - if !device.enabled_features().primitive_topology_list_restart { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: - "`input_assembly_state.primitive_restart_enable` \ - is `StateMode::Fixed(true)` and \ - `input_assembly_state.topology` is \ - `StateMode::Fixed(PrimitiveTopology::*List)`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("primitive_topology_list_restart"), - ])]), - }); - } - } - PartialStateMode::Fixed(PrimitiveTopology::PatchList) => { - // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-06253 - if !device - .enabled_features() - .primitive_topology_patch_list_restart - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: - "`input_assembly_state.primitive_restart_enable` \ - is `StateMode::Fixed(true)` and \ - `input_assembly_state.topology` is \ - `StateMode::Fixed(PrimitiveTopology::PatchList)`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature( - "primitive_topology_patch_list_restart", - ), - ])]), - }); - } - } - _ => (), - } + let (constant_factor, clamp, slope_factor) = match depth_bias_state.bias { + StateMode::Fixed(bias) => { + dynamic_state.insert(DynamicState::DepthBias, false); + (bias.constant_factor, bias.clamp, bias.slope_factor) } - } - StateMode::Dynamic => { - // VUID? - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state2) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`input_assembly_state.primitive_restart_enable` is \ - `StateMode::Dynamic`", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state2")]), - ]), - }); + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::DepthBias, true); + (0.0, 0.0, 0.0) } - } - } - } + }; - if let Some(tessellation_state) = tessellation_state { - let &TessellationState { - patch_control_points, - domain_origin, - } = tessellation_state; + (ash::vk::TRUE, constant_factor, clamp, slope_factor) + } else { + (ash::vk::FALSE, 0.0, 0.0, 0.0) + }; - match patch_control_points { - StateMode::Fixed(patch_control_points) => { - // VUID-VkPipelineTessellationStateCreateInfo-patchControlPoints-01214 - if patch_control_points == 0 - || patch_control_points > properties.max_tessellation_patch_size - { - return Err(GraphicsPipelineCreationError::InvalidNumPatchControlPoints); - } + let line_width = match line_width { + StateMode::Fixed(line_width) => { + dynamic_state.insert(DynamicState::LineWidth, false); + line_width } StateMode::Dynamic => { - // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04870 - if !device - .enabled_features() - .extended_dynamic_state2_patch_control_points - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`tessellation_state.patch_control_points` is \ - `StateMode::Dynamic`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "extended_dynamic_state2_patch_control_points", - )])]), - }); - } + dynamic_state.insert(DynamicState::LineWidth, true); + 1.0 } }; - // VUID-VkPipelineTessellationDomainOriginStateCreateInfo-domainOrigin-parameter - domain_origin.validate_device(device)?; - - if domain_origin != TessellationDomainOrigin::default() - && !(device.api_version() >= Version::V1_1 - || device.enabled_extensions().khr_maintenance2) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`tessellation_state.domain_origin` is not \ - `TessellationDomainOrigin::UpperLeft`", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]), - RequiresAllOf(&[Requires::DeviceExtension("khr_maintenance2")]), - ]), + let rasterization_state = + rasterization_state_vk.insert(ash::vk::PipelineRasterizationStateCreateInfo { + flags: ash::vk::PipelineRasterizationStateCreateFlags::empty(), + depth_clamp_enable: depth_clamp_enable as ash::vk::Bool32, + rasterizer_discard_enable, + polygon_mode: polygon_mode.into(), + cull_mode, + front_face, + depth_bias_enable, + depth_bias_constant_factor, + depth_bias_clamp, + depth_bias_slope_factor, + line_width, + ..Default::default() }); - } - } - - if let Some(viewport_state) = viewport_state { - let (viewport_count, scissor_count) = match viewport_state { - ViewportState::Fixed { data } => { - let count = data.len() as u32; - assert!(count != 0); // TODO: return error? - - for (viewport, _) in data { - for i in 0..2 { - if viewport.dimensions[i] > properties.max_viewport_dimensions[i] as f32 - { - return Err( - GraphicsPipelineCreationError::MaxViewportDimensionsExceeded, - ); - } - - if viewport.origin[i] < properties.viewport_bounds_range[0] - || viewport.origin[i] + viewport.dimensions[i] - > properties.viewport_bounds_range[1] - { - return Err(GraphicsPipelineCreationError::ViewportBoundsExceeded); - } - } - } - - // TODO: - // VUID-VkPipelineViewportStateCreateInfo-offset-02822 - // VUID-VkPipelineViewportStateCreateInfo-offset-02823 - (count, count) - } - ViewportState::FixedViewport { - viewports, - scissor_count_dynamic, - } => { - let viewport_count = viewports.len() as u32; - - // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136 - assert!(viewport_count != 0); // TODO: return error? - - for viewport in viewports { - for i in 0..2 { - if viewport.dimensions[i] > properties.max_viewport_dimensions[i] as f32 - { - return Err( - GraphicsPipelineCreationError::MaxViewportDimensionsExceeded, - ); + if device.enabled_extensions().ext_line_rasterization { + let (stippled_line_enable, line_stipple_factor, line_stipple_pattern) = + if let Some(line_stipple) = line_stipple { + let (factor, pattern) = match line_stipple { + StateMode::Fixed(line_stipple) => { + dynamic_state.insert(DynamicState::LineStipple, false); + (line_stipple.factor, line_stipple.pattern) } - - if viewport.origin[i] < properties.viewport_bounds_range[0] - || viewport.origin[i] + viewport.dimensions[i] - > properties.viewport_bounds_range[1] - { - return Err(GraphicsPipelineCreationError::ViewportBoundsExceeded); + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::LineStipple, true); + (1, 0) } - } - } - - // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136 - let scissor_count = if *scissor_count_dynamic { - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`viewport_state` is \ - `ViewportState::FixedViewport`, where `scissor_count_dynamic` \ - is set", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } + }; - // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03380 - 0 + (ash::vk::TRUE, factor, pattern) } else { - viewport_count + (ash::vk::FALSE, 1, 0) }; - (viewport_count, scissor_count) - } - ViewportState::FixedScissor { - scissors, - viewport_count_dynamic, - } => { - let scissor_count = scissors.len() as u32; - - // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135 - assert!(scissor_count != 0); // TODO: return error? - - // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135 - let viewport_count = if *viewport_count_dynamic { - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`viewport_state` is \ - `ViewportState::FixedScissor`, where `viewport_count_dynamic` \ - is set", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } - - // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03379 - 0 - } else { - scissor_count - }; + rasterization_state.p_next = rasterization_line_state_vk.insert( + ash::vk::PipelineRasterizationLineStateCreateInfoEXT { + line_rasterization_mode: line_rasterization_mode.into(), + stippled_line_enable, + line_stipple_factor, + line_stipple_pattern, + ..Default::default() + }, + ) as *const _ as *const _; + } + } - // TODO: - // VUID-VkPipelineViewportStateCreateInfo-offset-02822 - // VUID-VkPipelineViewportStateCreateInfo-offset-02823 + let mut multisample_state_vk = None; - (viewport_count, scissor_count) - } - &ViewportState::Dynamic { - count, - viewport_count_dynamic, - scissor_count_dynamic, - } => { - // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135 - // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136 - if !(viewport_count_dynamic && scissor_count_dynamic) { - assert!(count != 0); // TODO: return error? - } - - // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135 - let viewport_count = if viewport_count_dynamic { - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`viewport_state` is \ - `ViewportState::Dynamic`, where `viewport_count_dynamic` \ - is set", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } - - // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03379 - 0 - } else { - count - }; - - // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136 - let scissor_count = if scissor_count_dynamic { - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`viewport_state` is \ - `ViewportState::Dynamic`, where `scissor_count_dynamic` \ - is set", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } + if let Some(multisample_state) = multisample_state { + let &MultisampleState { + rasterization_samples, + sample_shading, + ref sample_mask, + alpha_to_coverage_enable, + alpha_to_one_enable, + } = multisample_state; - // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03380 - 0 - } else { - count - }; + let (sample_shading_enable, min_sample_shading) = + if let Some(min_sample_shading) = sample_shading { + (ash::vk::TRUE, min_sample_shading) + } else { + (ash::vk::FALSE, 0.0) + }; - (viewport_count, scissor_count) - } - }; + let _ = multisample_state_vk.insert(ash::vk::PipelineMultisampleStateCreateInfo { + flags: ash::vk::PipelineMultisampleStateCreateFlags::empty(), + rasterization_samples: rasterization_samples.into(), + sample_shading_enable, + min_sample_shading, + p_sample_mask: sample_mask as _, + alpha_to_coverage_enable: alpha_to_coverage_enable as ash::vk::Bool32, + alpha_to_one_enable: alpha_to_one_enable as ash::vk::Bool32, + ..Default::default() + }); + } - // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04134 - // Ensured by the definition of `ViewportState`. + let mut depth_stencil_state_vk = None; - let viewport_scissor_count = u32::max(viewport_count, scissor_count); + if let Some(depth_stencil_state) = depth_stencil_state { + let &DepthStencilState { + flags, + ref depth, + ref depth_bounds, + ref stencil, + } = depth_stencil_state; - // VUID-VkPipelineViewportStateCreateInfo-viewportCount-01216 - // VUID-VkPipelineViewportStateCreateInfo-scissorCount-01217 - if viewport_scissor_count > 1 && !device.enabled_features().multi_viewport { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`viewport_state` has a fixed viewport/scissor count that is \ - greater than `1`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "multi_viewport", - )])]), - }); - } + let (depth_test_enable, depth_write_enable, depth_compare_op) = + if let Some(depth_state) = depth { + let &DepthState { + enable_dynamic, + write_enable, + compare_op, + } = depth_state; - // VUID-VkPipelineViewportStateCreateInfo-viewportCount-01218 - // VUID-VkPipelineViewportStateCreateInfo-scissorCount-01219 - if viewport_scissor_count > properties.max_viewports { - return Err(GraphicsPipelineCreationError::MaxViewportsExceeded { - obtained: viewport_scissor_count, - max: properties.max_viewports, - }); - } + if enable_dynamic { + dynamic_state.insert(DynamicState::DepthTestEnable, true); + } else { + dynamic_state.insert(DynamicState::DepthTestEnable, false); + } - // TODO: - // VUID-VkGraphicsPipelineCreateInfo-primitiveFragmentShadingRateWithMultipleViewports-04503 - // VUID-VkGraphicsPipelineCreateInfo-primitiveFragmentShadingRateWithMultipleViewports-04504 - } + let write_enable = match write_enable { + StateMode::Fixed(write_enable) => { + dynamic_state.insert(DynamicState::DepthWriteEnable, false); + write_enable as ash::vk::Bool32 + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::DepthWriteEnable, true); + ash::vk::TRUE + } + }; - if let Some(rasterization_state) = rasterization_state { - let &RasterizationState { - depth_clamp_enable, - rasterizer_discard_enable, - polygon_mode, - cull_mode, - front_face, - depth_bias, - line_width, - line_rasterization_mode, - line_stipple, - } = rasterization_state; + let compare_op = match compare_op { + StateMode::Fixed(compare_op) => { + dynamic_state.insert(DynamicState::DepthCompareOp, false); + compare_op.into() + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::DepthCompareOp, true); + ash::vk::CompareOp::ALWAYS + } + }; - // VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-parameter - polygon_mode.validate_device(device)?; + (ash::vk::TRUE, write_enable, compare_op) + } else { + (ash::vk::FALSE, ash::vk::FALSE, ash::vk::CompareOp::ALWAYS) + }; - // VUID-VkPipelineRasterizationStateCreateInfo-depthClampEnable-00782 - if depth_clamp_enable && !device.enabled_features().depth_clamp { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.depth_clamp_enable` is set", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "depth_clamp", - )])]), - }); - } + let (depth_bounds_test_enable, min_depth_bounds, max_depth_bounds) = + if let Some(depth_bounds_state) = depth_bounds { + let depth_stencil::DepthBoundsState { + enable_dynamic, + bounds, + } = depth_bounds_state; - match rasterizer_discard_enable { - StateMode::Dynamic => { - // VUID? - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state2) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.rasterizer_discard_enable` is \ - `StateMode::Dynamic`", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } - } - StateMode::Fixed(false) => { - // VUID-VkPipelineRasterizationStateCreateInfo-pointPolygons-04458 - if device.enabled_extensions().khr_portability_subset - && !device.enabled_features().point_polygons - && polygon_mode == PolygonMode::Point - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "this device is a portability subset device, \ - `rasterization_state.rasterizer_discard_enable` is \ - `StateMode::Fixed(false)` and \ - `rasterization_state.polygon_mode` is `PolygonMode::Point`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "point_polygons", - )])]), - }); + if *enable_dynamic { + dynamic_state.insert(DynamicState::DepthBoundsTestEnable, true); + } else { + dynamic_state.insert(DynamicState::DepthBoundsTestEnable, false); } - } - _ => (), - } - // VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-01507 - if polygon_mode != PolygonMode::Fill && !device.enabled_features().fill_mode_non_solid { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.polygon_mode` is not \ - `PolygonMode::Fill`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "fill_mode_non_solid", - )])]), - }); - } - - match cull_mode { - StateMode::Fixed(cull_mode) => { - // VUID-VkPipelineRasterizationStateCreateInfo-cullMode-parameter - cull_mode.validate_device(device)?; - } - StateMode::Dynamic => { - // VUID? - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.cull_mode` is \ - `StateMode::Dynamic`", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } - } - } + let (min_bounds, max_bounds) = match bounds.clone() { + StateMode::Fixed(bounds) => { + dynamic_state.insert(DynamicState::DepthBounds, false); + bounds.into_inner() + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::DepthBounds, true); + (0.0, 1.0) + } + }; - match front_face { - StateMode::Fixed(front_face) => { - // VUID-VkPipelineRasterizationStateCreateInfo-frontFace-parameter - front_face.validate_device(device)?; - } - StateMode::Dynamic => { - // VUID? - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.front_face` is \ - `StateMode::Dynamic`", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } - } - } + (ash::vk::TRUE, min_bounds, max_bounds) + } else { + (ash::vk::FALSE, 0.0, 1.0) + }; - if let Some(depth_bias_state) = depth_bias { - let DepthBiasState { + let (stencil_test_enable, front, back) = if let Some(stencil_state) = stencil { + let StencilState { enable_dynamic, - bias, - } = depth_bias_state; - - // VUID? - if enable_dynamic - && !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state2) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.depth_bias` is \ - `Some(depth_bias_state)`, where `depth_bias_state.enable_dynamic` \ - is set", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state2")]), - ]), - }); - } + front, + back, + } = stencil_state; - // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00754 - if matches!(bias, StateMode::Fixed(bias) if bias.clamp != 0.0) - && !device.enabled_features().depth_bias_clamp - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.depth_bias` is \ - `Some(depth_bias_state)`, where `depth_bias_state.bias` is \ - `StateMode::Fixed(bias)`, where `bias.clamp` is not `0.0`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "depth_bias_clamp", - )])]), - }); + if *enable_dynamic { + dynamic_state.insert(DynamicState::StencilTestEnable, true); + } else { + dynamic_state.insert(DynamicState::StencilTestEnable, false); } - } - - // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00749 - if matches!(line_width, StateMode::Fixed(line_width) if line_width != 1.0) - && !device.enabled_features().wide_lines - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.line_width` is \ - `StateMode::Fixed(line_width)`, where `line_width` is not `1.0`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "wide_lines", - )])]), - }); - } - if device.enabled_extensions().ext_line_rasterization { - // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-parameter - line_rasterization_mode.validate_device(device)?; - - match line_rasterization_mode { - LineRasterizationMode::Default => (), - LineRasterizationMode::Rectangular => { - // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02768 - if !device.enabled_features().rectangular_lines { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.line_rasterization_mode` \ - is `LineRasterizationMode::Rectangular`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("rectangular_lines"), - ])]), - }); - } - } - LineRasterizationMode::Bresenham => { - // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02769 - if !device.enabled_features().bresenham_lines { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.line_rasterization_mode` \ - is `LineRasterizationMode::Bresenham`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("bresenham_lines"), - ])]), - }); - } + match (front.ops, back.ops) { + (StateMode::Fixed(_), StateMode::Fixed(_)) => { + dynamic_state.insert(DynamicState::StencilOp, false); } - LineRasterizationMode::RectangularSmooth => { - // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02770 - if !device.enabled_features().smooth_lines { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.line_rasterization_mode` \ - is `LineRasterizationMode::RectangularSmooth`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("smooth_lines"), - ])]), - }); - } + (StateMode::Dynamic, StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::StencilOp, true); } - } + _ => unreachable!(), + }; - if let Some(line_stipple) = line_stipple { - match line_rasterization_mode { - LineRasterizationMode::Default => { - // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02774 - if !device.enabled_features().stippled_rectangular_lines { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.line_stipple` is \ - `Some` and \ - `rasterization_state.line_rasterization_mode` \ - is `LineRasterizationMode::Default`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("stippled_rectangular_lines"), - ])]), - }); - } + match (front.compare_mask, back.compare_mask) { + (StateMode::Fixed(_), StateMode::Fixed(_)) => { + dynamic_state.insert(DynamicState::StencilCompareMask, false); + } + (StateMode::Dynamic, StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::StencilCompareMask, true); + } + _ => unreachable!(), + }; - // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02774 - if !properties.strict_lines { - return Err(GraphicsPipelineCreationError::StrictLinesNotSupported); - } - } - LineRasterizationMode::Rectangular => { - // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02771 - if !device.enabled_features().stippled_rectangular_lines { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.line_stipple` is \ - `Some` and \ - `rasterization_state.line_rasterization_mode` \ - is `LineRasterizationMode::Rectangular`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("stippled_rectangular_lines"), - ])]), - }); - } - } - LineRasterizationMode::Bresenham => { - // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02772 - if !device.enabled_features().stippled_bresenham_lines { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.line_stipple` is \ - `Some` and \ - `rasterization_state.line_rasterization_mode` \ - is `LineRasterizationMode::Bresenham`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("stippled_bresenham_lines"), - ])]), - }); - } - } - LineRasterizationMode::RectangularSmooth => { - // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02773 - if !device.enabled_features().stippled_smooth_lines { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.line_stipple` is \ - `Some` and \ - `rasterization_state.line_rasterization_mode` \ - is `LineRasterizationMode::RectangularSmooth`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("stippled_smooth_lines"), - ])]), - }); - } - } + match (front.write_mask, back.write_mask) { + (StateMode::Fixed(_), StateMode::Fixed(_)) => { + dynamic_state.insert(DynamicState::StencilWriteMask, false); } + (StateMode::Dynamic, StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::StencilWriteMask, true); + } + _ => unreachable!(), + }; - if let StateMode::Fixed(line_stipple) = line_stipple { - // VUID-VkGraphicsPipelineCreateInfo-stippledLineEnable-02767 - assert!(line_stipple.factor >= 1 && line_stipple.factor <= 256); - // TODO: return error? + match (front.reference, back.reference) { + (StateMode::Fixed(_), StateMode::Fixed(_)) => { + dynamic_state.insert(DynamicState::StencilReference, false); } - } - } else { - if line_rasterization_mode != LineRasterizationMode::Default { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.line_rasterization_mode` is not \ - `LineRasterizationMode::Default`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::DeviceExtension("ext_line_rasterization"), - ])]), - }); - } + (StateMode::Dynamic, StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::StencilReference, true); + } + _ => unreachable!(), + }; - if line_stipple.is_some() { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`rasterization_state.line_stipple` is `Some`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::DeviceExtension("ext_line_rasterization"), - ])]), - }); - } - } - - // TODO: - // VUID-VkGraphicsPipelineCreateInfo-pStages-00740 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06049 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06050 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06059 - } - - if let Some(multisample_state) = multisample_state { - let &MultisampleState { - rasterization_samples, - sample_shading, - sample_mask: _, - alpha_to_coverage_enable: _, - alpha_to_one_enable, - } = multisample_state; - - // VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-parameter - rasterization_samples.validate_device(device)?; - - if let Some(min_sample_shading) = sample_shading { - // VUID-VkPipelineMultisampleStateCreateInfo-sampleShadingEnable-00784 - if !device.enabled_features().sample_rate_shading { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`multisample_state.sample_shading` is `Some`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "sample_rate_shading", - )])]), - }); - } + let [front, back] = [front, back].map(|stencil_op_state| { + let &StencilOpState { + ops, + compare_mask, + write_mask, + reference, + } = stencil_op_state; - // VUID-VkPipelineMultisampleStateCreateInfo-minSampleShading-00786 - // TODO: return error? - assert!((0.0..=1.0).contains(&min_sample_shading)); - } + let ops = match ops { + StateMode::Fixed(x) => x, + StateMode::Dynamic => Default::default(), + }; + let compare_mask = match compare_mask { + StateMode::Fixed(x) => x, + StateMode::Dynamic => Default::default(), + }; + let write_mask = match write_mask { + StateMode::Fixed(x) => x, + StateMode::Dynamic => Default::default(), + }; + let reference = match reference { + StateMode::Fixed(x) => x, + StateMode::Dynamic => Default::default(), + }; - // VUID-VkPipelineMultisampleStateCreateInfo-alphaToOneEnable-00785 - if alpha_to_one_enable && !device.enabled_features().alpha_to_one { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`multisample_state.alpha_to_one_enable` is set", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "alpha_to_one", - )])]), + ash::vk::StencilOpState { + fail_op: ops.fail_op.into(), + pass_op: ops.pass_op.into(), + depth_fail_op: ops.depth_fail_op.into(), + compare_op: ops.compare_op.into(), + compare_mask, + write_mask, + reference, + } }); - } - // TODO: - // VUID-VkGraphicsPipelineCreateInfo-lineRasterizationMode-02766 + (ash::vk::TRUE, front, back) + } else { + (ash::vk::FALSE, Default::default(), Default::default()) + }; + + let _ = depth_stencil_state_vk.insert(ash::vk::PipelineDepthStencilStateCreateInfo { + flags: flags.into(), + depth_test_enable, + depth_write_enable, + depth_compare_op, + depth_bounds_test_enable, + stencil_test_enable, + front, + back, + min_depth_bounds, + max_depth_bounds, + ..Default::default() + }); } - if let Some(depth_stencil_state) = depth_stencil_state { - let DepthStencilState { - depth, - depth_bounds, - stencil, - } = depth_stencil_state; + let mut color_blend_state_vk = None; + let mut color_blend_attachments_vk: SmallVec<[_; 4]> = SmallVec::new(); + let mut color_write_vk = None; + let mut color_write_enables_vk: SmallVec<[_; 4]> = SmallVec::new(); - if let Some(depth_state) = depth { - let &DepthState { - enable_dynamic, - write_enable, - compare_op, - } = depth_state; + if let Some(color_blend_state) = color_blend_state { + let &ColorBlendState { + flags, + logic_op, + ref attachments, + blend_constants, + } = color_blend_state; - // VUID? - if enable_dynamic - && !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`depth_stencil_state.depth` is `Some(depth_state)`, where \ - `depth_state.enable_dynamic` is set", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } + color_blend_attachments_vk.extend(attachments.iter().map( + |color_blend_attachment_state| { + let &ColorBlendAttachmentState { + blend, + color_write_mask, + color_write_enable: _, + } = color_blend_attachment_state; - match write_enable { - StateMode::Fixed(_) => (), - StateMode::Dynamic => { - // VUID? - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`depth_stencil_state.depth` is \ - `Some(depth_state)`, where `depth_state.write_enable` is \ - `StateMode::Dynamic`", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } + let blend = if let Some(blend) = blend { + blend.into() + } else { + Default::default() + }; + + ash::vk::PipelineColorBlendAttachmentState { + color_write_mask: color_write_mask.into(), + ..blend } - } + }, + )); - match compare_op { - StateMode::Fixed(compare_op) => { - // VUID-VkPipelineDepthStencilStateCreateInfo-depthCompareOp-parameter - compare_op.validate_device(device)?; + let (logic_op_enable, logic_op) = if let Some(logic_op) = logic_op { + let logic_op = match logic_op { + StateMode::Fixed(logic_op) => { + dynamic_state.insert(DynamicState::LogicOp, false); + logic_op.into() } StateMode::Dynamic => { - // VUID? - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`depth_stencil_state.depth` is \ - `Some(depth_state)`, where `depth_state.compare_op` is \ - `StateMode::Dynamic`", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } + dynamic_state.insert(DynamicState::LogicOp, true); + Default::default() } - } - } - - if let Some(depth_bounds_state) = depth_bounds { - let DepthBoundsState { - enable_dynamic, - bounds, - } = depth_bounds_state; + }; - // VUID-VkPipelineDepthStencilStateCreateInfo-depthBoundsTestEnable-00598 - if !device.enabled_features().depth_bounds { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`depth_stencil_state.depth_bounds` is `Some`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "depth_bounds", - )])]), - }); - } + (ash::vk::TRUE, logic_op) + } else { + (ash::vk::FALSE, Default::default()) + }; - // VUID? - if *enable_dynamic - && !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`depth_stencil_state.depth_bounds` is \ - `Some(depth_bounds_state)`, where `depth_bounds_state.enable_dynamic` \ - is set", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); + let blend_constants = match blend_constants { + StateMode::Fixed(blend_constants) => { + dynamic_state.insert(DynamicState::BlendConstants, false); + blend_constants } - - if let StateMode::Fixed(bounds) = bounds { - // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-02510 - if !device.enabled_extensions().ext_depth_range_unrestricted - && !(0.0..1.0).contains(bounds.start()) - && !(0.0..1.0).contains(bounds.end()) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`depth_stencil_state.depth_bounds` is \ - `Some(depth_bounds_state)`, where `depth_bounds_state.bounds` is \ - not between `0.0` and `1.0` inclusive", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::DeviceExtension("ext_depth_range_unrestricted"), - ])]), - }); - } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::BlendConstants, true); + Default::default() } - } + }; - if let Some(stencil_state) = stencil { - let StencilState { - enable_dynamic, - front, - back, - } = stencil_state; + let mut color_blend_state_vk = + color_blend_state_vk.insert(ash::vk::PipelineColorBlendStateCreateInfo { + flags: flags.into(), + logic_op_enable, + logic_op, + attachment_count: color_blend_attachments_vk.len() as u32, + p_attachments: color_blend_attachments_vk.as_ptr(), + blend_constants, + ..Default::default() + }); - // VUID? - if *enable_dynamic - && !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`depth_stencil_state.stencil` is `Some(stencil_state)`, \ - where `stencil_state.enable_dynamic` is set", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); - } + if device.enabled_extensions().ext_color_write_enable { + color_write_enables_vk.extend(attachments.iter().map( + |color_blend_attachment_state| { + let &ColorBlendAttachmentState { + blend: _, + color_write_mask: _, + color_write_enable, + } = color_blend_attachment_state; - match (front.ops, back.ops) { - (StateMode::Fixed(front_ops), StateMode::Fixed(back_ops)) => { - for ops in [front_ops, back_ops] { - let StencilOps { - fail_op, - pass_op, - depth_fail_op, - compare_op, - } = ops; - - // VUID-VkStencilOpState-failOp-parameter - fail_op.validate_device(device)?; - - // VUID-VkStencilOpState-passOp-parameter - pass_op.validate_device(device)?; - - // VUID-VkStencilOpState-depthFailOp-parameter - depth_fail_op.validate_device(device)?; - - // VUID-VkStencilOpState-compareOp-parameter - compare_op.validate_device(device)?; - } - } - (StateMode::Dynamic, StateMode::Dynamic) => { - // VUID? - if !(device.api_version() >= Version::V1_3 - || device.enabled_features().extended_dynamic_state) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`depth_stencil_state.stencil` is \ - `Some(stencil_state)`, where `stencil_state.front.ops` and \ - `stencil_state.back.ops` are `StateMode::Dynamic`", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), - RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), - ]), - }); + match color_write_enable { + StateMode::Fixed(enable) => { + dynamic_state.insert(DynamicState::ColorWriteEnable, false); + enable as ash::vk::Bool32 + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::ColorWriteEnable, true); + ash::vk::TRUE + } } - } - _ => return Err(GraphicsPipelineCreationError::WrongStencilState), - } - - if !matches!( - (front.compare_mask, back.compare_mask), - (StateMode::Fixed(_), StateMode::Fixed(_)) - | (StateMode::Dynamic, StateMode::Dynamic) - ) { - return Err(GraphicsPipelineCreationError::WrongStencilState); - } - - if !matches!( - (front.write_mask, back.write_mask), - (StateMode::Fixed(_), StateMode::Fixed(_)) - | (StateMode::Dynamic, StateMode::Dynamic) - ) { - return Err(GraphicsPipelineCreationError::WrongStencilState); - } - - if !matches!( - (front.reference, back.reference), - (StateMode::Fixed(_), StateMode::Fixed(_)) - | (StateMode::Dynamic, StateMode::Dynamic) - ) { - return Err(GraphicsPipelineCreationError::WrongStencilState); - } + }, + )); - // TODO: - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06040 + color_blend_state_vk.p_next = + color_write_vk.insert(ash::vk::PipelineColorWriteCreateInfoEXT { + attachment_count: color_write_enables_vk.len() as u32, + p_color_write_enables: color_write_enables_vk.as_ptr(), + ..Default::default() + }) as *const _ as *const _; } } - if let Some(color_blend_state) = color_blend_state { - let ColorBlendState { - logic_op, - attachments, - blend_constants: _, - } = color_blend_state; + let mut dynamic_state_list: SmallVec<[_; 4]> = SmallVec::new(); + let mut dynamic_state_vk = None; - if let Some(logic_op) = logic_op { - // VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00606 - if !device.enabled_features().logic_op { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`color_blend_state.logic_op` is `Some`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "logic_op", - )])]), - }); - } + { + dynamic_state_list.extend( + dynamic_state + .iter() + .filter(|(_, d)| **d) + .map(|(&state, _)| state.into()), + ); - match logic_op { - StateMode::Fixed(logic_op) => { - // VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00607 - logic_op.validate_device(device)? - } - StateMode::Dynamic => { - // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04869 - if !device.enabled_features().extended_dynamic_state2_logic_op { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`color_blend_state.logic_op` is \ - `Some(StateMode::Dynamic)`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("extended_dynamic_state2_logic_op"), - ])]), - }); - } - } - } + if !dynamic_state_list.is_empty() { + let _ = dynamic_state_vk.insert(ash::vk::PipelineDynamicStateCreateInfo { + flags: ash::vk::PipelineDynamicStateCreateFlags::empty(), + dynamic_state_count: dynamic_state_list.len() as u32, + p_dynamic_states: dynamic_state_list.as_ptr(), + ..Default::default() + }); } + } - if attachments.len() > 1 && !device.enabled_features().independent_blend { - // Ensure that all `blend` and `color_write_mask` are identical. - let mut iter = attachments - .iter() - .map(|state| (&state.blend, &state.color_write_mask)); - let first = iter.next().unwrap(); - - // VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 - if !iter.all(|state| state == first) { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`color_blend_state.attachments` has elements where \ - `blend` and `color_write_mask` do not match the other elements", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "independent_blend", - )])]), - }); - } - } - - for state in attachments { - let &ColorBlendAttachmentState { - blend, - color_write_mask: _, - color_write_enable, - } = state; - - if let Some(blend) = blend { - let AttachmentBlend { - color_op, - color_source, - color_destination, - alpha_op, - alpha_source, - alpha_destination, - } = blend; - - // VUID-VkPipelineColorBlendAttachmentState-colorBlendOp-parameter - color_op.validate_device(device)?; + let render_pass = render_pass.as_ref().unwrap(); + let mut render_pass_vk = ash::vk::RenderPass::null(); + let mut subpass_vk = 0; + let mut color_attachment_formats_vk: SmallVec<[_; 4]> = SmallVec::new(); + let mut rendering_create_info_vk = None; - // VUID-VkPipelineColorBlendAttachmentState-srcColorBlendFactor-parameter - color_source.validate_device(device)?; + match render_pass { + PipelineSubpassType::BeginRenderPass(subpass) => { + render_pass_vk = subpass.render_pass().handle(); + subpass_vk = subpass.index(); + } + PipelineSubpassType::BeginRendering(rendering_info) => { + let &PipelineRenderingCreateInfo { + view_mask, + ref color_attachment_formats, + depth_attachment_format, + stencil_attachment_format, + _ne: _, + } = rendering_info; - // VUID-VkPipelineColorBlendAttachmentState-dstColorBlendFactor-parameter - color_destination.validate_device(device)?; + color_attachment_formats_vk.extend( + color_attachment_formats + .iter() + .map(|format| format.map_or(ash::vk::Format::UNDEFINED, Into::into)), + ); - // VUID-VkPipelineColorBlendAttachmentState-alphaBlendOp-parameter - alpha_op.validate_device(device)?; + let _ = rendering_create_info_vk.insert(ash::vk::PipelineRenderingCreateInfo { + view_mask, + color_attachment_count: color_attachment_formats_vk.len() as u32, + p_color_attachment_formats: color_attachment_formats_vk.as_ptr(), + depth_attachment_format: depth_attachment_format + .map_or(ash::vk::Format::UNDEFINED, Into::into), + stencil_attachment_format: stencil_attachment_format + .map_or(ash::vk::Format::UNDEFINED, Into::into), + ..Default::default() + }); + } + } - // VUID-VkPipelineColorBlendAttachmentState-srcAlphaBlendFactor-parameter - alpha_source.validate_device(device)?; + let mut discard_rectangle_state_vk = None; + let mut discard_rectangles: SmallVec<[_; 2]> = SmallVec::new(); - // VUID-VkPipelineColorBlendAttachmentState-dstAlphaBlendFactor-parameter - alpha_destination.validate_device(device)?; + if let Some(discard_rectangle_state) = discard_rectangle_state { + let DiscardRectangleState { mode, rectangles } = discard_rectangle_state; - // VUID? - if !device.enabled_features().dual_src_blend - && [ - color_source, - color_destination, - alpha_source, - alpha_destination, - ] - .into_iter() - .any(|blend_factor| { - matches!( - blend_factor, - BlendFactor::Src1Color - | BlendFactor::OneMinusSrc1Color - | BlendFactor::Src1Alpha - | BlendFactor::OneMinusSrc1Alpha - ) - }) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`color_blend_state.attachments` has an element where \ - `blend` is `Some(blend)`, where `blend.color_source`, \ - `blend.color_destination`, `blend.alpha_source` or \ - `blend.alpha_destination` is `BlendFactor::Src1*`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "dual_src_blend", - )])]), - }); - } + let discard_rectangle_count = match rectangles { + PartialStateMode::Fixed(rectangles) => { + dynamic_state.insert(DynamicState::DiscardRectangle, false); + discard_rectangles.extend(rectangles.iter().map(|rect| rect.into())); - // VUID-VkPipelineColorBlendAttachmentState-constantAlphaColorBlendFactors-04454 - // VUID-VkPipelineColorBlendAttachmentState-constantAlphaColorBlendFactors-04455 - if device.enabled_extensions().khr_portability_subset - && !device.enabled_features().constant_alpha_color_blend_factors - && (matches!( - color_source, - BlendFactor::ConstantAlpha | BlendFactor::OneMinusConstantAlpha - ) || matches!( - color_destination, - BlendFactor::ConstantAlpha | BlendFactor::OneMinusConstantAlpha - )) - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "this device is a portability subset device, and \ - `color_blend_state.attachments` has an element where `blend` is \ - `Some(blend)`, where \ - `blend.color_source` or `blend.color_destination` is \ - `BlendFactor::ConstantAlpha` or \ - `BlendFactor::OneMinusConstantAlpha`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "constant_alpha_color_blend_factors", - )])]), - }); - } + discard_rectangles.len() as u32 } + PartialStateMode::Dynamic(count) => { + dynamic_state.insert(DynamicState::DiscardRectangle, true); - match color_write_enable { - StateMode::Fixed(enable) => { - // VUID-VkPipelineColorWriteCreateInfoEXT-pAttachments-04801 - if !enable && !device.enabled_features().color_write_enable { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`color_blend_state.attachments` has an element \ - where `color_write_enable` is `StateMode::Fixed(false)`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("color_write_enable"), - ])]), - }); - } - } - StateMode::Dynamic => { - // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04800 - if !device.enabled_features().color_write_enable { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`color_blend_state.attachments` has an element \ - where `color_write_enable` is `StateMode::Dynamic`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("color_write_enable"), - ])]), - }); - } - } + *count } - } + }; + + let _ = discard_rectangle_state_vk.insert( + ash::vk::PipelineDiscardRectangleStateCreateInfoEXT { + flags: ash::vk::PipelineDiscardRectangleStateCreateFlagsEXT::empty(), + discard_rectangle_mode: (*mode).into(), + discard_rectangle_count, + p_discard_rectangles: discard_rectangles.as_ptr(), + ..Default::default() + }, + ); } - if let Some(render_pass) = render_pass { - match render_pass { - PipelineSubpassType::BeginRenderPass(subpass) => { - // VUID-VkGraphicsPipelineCreateInfo-commonparent - assert_eq!(device, subpass.render_pass().device().as_ref()); + /* + Create + */ - if subpass.render_pass().views_used() != 0 { - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06047 - if stages_present.intersects( - ShaderStages::TESSELLATION_CONTROL - | ShaderStages::TESSELLATION_EVALUATION, - ) && !device.enabled_features().multiview_tessellation_shader - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: - "`tessellation_shaders` are provided and `render_pass` has a \ - subpass where `view_mask` is not `0`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("multiview_tessellation_shader"), - ])]), - }); - } + let mut create_info_vk = ash::vk::GraphicsPipelineCreateInfo { + flags: flags.into(), + stage_count: stages_vk.len() as u32, + p_stages: stages_vk.as_ptr(), + p_vertex_input_state: vertex_input_state_vk + .as_ref() + .map(|p| p as *const _) + .unwrap_or(ptr::null()), + p_input_assembly_state: input_assembly_state_vk + .as_ref() + .map(|p| p as *const _) + .unwrap_or(ptr::null()), + p_tessellation_state: tessellation_state_vk + .as_ref() + .map(|p| p as *const _) + .unwrap_or(ptr::null()), + p_viewport_state: viewport_state_vk + .as_ref() + .map(|p| p as *const _) + .unwrap_or(ptr::null()), + p_rasterization_state: rasterization_state_vk + .as_ref() + .map(|p| p as *const _) + .unwrap_or(ptr::null()), + p_multisample_state: multisample_state_vk + .as_ref() + .map(|p| p as *const _) + .unwrap_or(ptr::null()), + p_depth_stencil_state: depth_stencil_state_vk + .as_ref() + .map(|p| p as *const _) + .unwrap_or(ptr::null()), + p_color_blend_state: color_blend_state_vk + .as_ref() + .map(|p| p as *const _) + .unwrap_or(ptr::null()), + p_dynamic_state: dynamic_state_vk + .as_ref() + .map(|s| s as *const _) + .unwrap_or(ptr::null()), + layout: layout.handle(), + render_pass: render_pass_vk, + subpass: subpass_vk, + base_pipeline_handle: ash::vk::Pipeline::null(), // TODO: + base_pipeline_index: -1, // TODO: + ..Default::default() + }; - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06048 - if stages_present.intersects(ShaderStages::GEOMETRY) - && !device.enabled_features().multiview_geometry_shader - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: - "`geometry_shader` is provided and `render_pass` has a \ - subpass where `view_mask` is not `0`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("multiview_geometry_shader"), - ])]), - }); - } - } - } - PipelineSubpassType::BeginRendering(rendering_info) => { - let &PipelineRenderingCreateInfo { - view_mask, - ref color_attachment_formats, - depth_attachment_format, - stencil_attachment_format, - _ne: _, - } = rendering_info; + if let Some(info) = discard_rectangle_state_vk.as_mut() { + info.p_next = create_info_vk.p_next; + create_info_vk.p_next = info as *const _ as *const _; + } - // VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06576 - if !device.enabled_features().dynamic_rendering { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: - "`render_pass` is `PipelineRenderPassType::BeginRendering`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "dynamic_rendering", - )])]), - }); - } + if let Some(info) = rendering_create_info_vk.as_mut() { + info.p_next = create_info_vk.p_next; + create_info_vk.p_next = info as *const _ as *const _; + } - // VUID-VkGraphicsPipelineCreateInfo-multiview-06577 - if view_mask != 0 && !device.enabled_features().multiview { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: - "`render_pass` is `PipelineRenderPassType::BeginRendering` \ - where `view_mask` is not `0`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "multiview", - )])]), - }); - } + let cache_handle = match cache.as_ref() { + Some(cache) => cache.handle(), + None => ash::vk::PipelineCache::null(), + }; - let view_count = u32::BITS - view_mask.leading_zeros(); + let handle = { + let fns = device.fns(); + let mut output = MaybeUninit::uninit(); + (fns.v1_0.create_graphics_pipelines)( + device.handle(), + cache_handle, + 1, + &create_info_vk, + ptr::null(), + output.as_mut_ptr(), + ) + .result() + .map_err(RuntimeError::from)?; - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06578 - if view_count > properties.max_multiview_view_count.unwrap_or(0) { - return Err( - GraphicsPipelineCreationError::MaxMultiviewViewCountExceeded { - view_count, - max: properties.max_multiview_view_count.unwrap_or(0), - }, - ); - } + output.assume_init() + }; - if need_fragment_output_state { - for (attachment_index, format) in color_attachment_formats - .iter() - .enumerate() - .flat_map(|(i, f)| f.map(|f| (i, f))) - { - let attachment_index = attachment_index as u32; + // Some drivers return `VK_SUCCESS` but provide a null handle if they + // fail to create the pipeline (due to invalid shaders, etc) + // This check ensures that we don't create an invalid `GraphicsPipeline` instance + if handle == ash::vk::Pipeline::null() { + panic!("vkCreateGraphicsPipelines provided a NULL handle"); + } - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06580 - format.validate_device(device)?; + Ok(Self::from_handle(device, handle, create_info)) + } - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06582 - // Use unchecked, because all validation has been done above. - if !unsafe { physical_device.format_properties_unchecked(format) } - .potential_format_features() - .intersects(FormatFeatures::COLOR_ATTACHMENT) - { - return Err( - GraphicsPipelineCreationError::ColorAttachmentFormatUsageNotSupported { - attachment_index, - }, - ); - } - } + /// Creates a new `GraphicsPipeline` from a raw object handle. + /// + /// # Safety + /// + /// - `handle` must be a valid Vulkan object handle created from `device`. + /// - `create_info` must match the info used to create the object. + #[inline] + pub unsafe fn from_handle( + device: Arc, + handle: ash::vk::Pipeline, + create_info: GraphicsPipelineCreateInfo, + ) -> Arc { + let GraphicsPipelineCreateInfo { + flags: _, + stages, - if let Some(format) = depth_attachment_format { - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06583 - format.validate_device(device)?; + vertex_input_state, + input_assembly_state, + tessellation_state, + viewport_state, + rasterization_state, + multisample_state, + depth_stencil_state, + color_blend_state, - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06585 - // Use unchecked, because all validation has been done above. - if !unsafe { physical_device.format_properties_unchecked(format) } - .potential_format_features() - .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) - { - return Err( - GraphicsPipelineCreationError::DepthAttachmentFormatUsageNotSupported, - ); - } + layout, + subpass: render_pass, - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06587 - if !format.aspects().intersects(ImageAspects::DEPTH) { - return Err( - GraphicsPipelineCreationError::DepthAttachmentFormatUsageNotSupported, - ); - } - } + discard_rectangle_state, - if let Some(format) = stencil_attachment_format { - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06584 - format.validate_device(device)?; + _ne: _, + } = create_info; - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06586 - // Use unchecked, because all validation has been done above. - if !unsafe { physical_device.format_properties_unchecked(format) } - .potential_format_features() - .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) - { - return Err( - GraphicsPipelineCreationError::StencilAttachmentFormatUsageNotSupported, - ); - } + let mut shaders = HashMap::default(); + let mut descriptor_binding_requirements: HashMap< + (u32, u32), + DescriptorBindingRequirements, + > = HashMap::default(); + let mut fragment_tests_stages = None; - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06588 - if !format.aspects().intersects(ImageAspects::STENCIL) { - return Err( - GraphicsPipelineCreationError::StencilAttachmentFormatUsageNotSupported, - ); - } - } + for stage in &stages { + let &PipelineShaderStageCreateInfo { + ref entry_point, .. + } = stage; - if let (Some(depth_format), Some(stencil_format)) = - (depth_attachment_format, stencil_attachment_format) - { - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06589 - if depth_format != stencil_format { - return Err( - GraphicsPipelineCreationError::DepthStencilAttachmentFormatMismatch, - ); - } - } - } + let entry_point_info = entry_point.info(); + let stage = ShaderStage::from(&entry_point_info.execution); + shaders.insert(stage, ()); - if view_mask != 0 { - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06057 - if stages_present.intersects( - ShaderStages::TESSELLATION_CONTROL - | ShaderStages::TESSELLATION_EVALUATION, - ) && !device.enabled_features().multiview_tessellation_shader - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: - "`tessellation_shaders` are provided and `render_pass` has a \ - subpass where `view_mask` is not `0`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("multiview_tessellation_shader"), - ])]), - }); - } + if let ShaderExecution::Fragment(FragmentShaderExecution { + fragment_tests_stages: s, + .. + }) = entry_point_info.execution + { + fragment_tests_stages = Some(s) + } - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06058 - if stages_present.intersects(ShaderStages::GEOMETRY) - && !device.enabled_features().multiview_geometry_shader - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: - "`geometry_shader` is provided and `render_pass` has a \ - subpass where `view_mask` is not `0`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::Feature("multiview_geometry_shader"), - ])]), - }); - } + for (&loc, reqs) in &entry_point_info.descriptor_binding_requirements { + match descriptor_binding_requirements.entry(loc) { + Entry::Occupied(entry) => { + entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements"); + } + Entry::Vacant(entry) => { + entry.insert(reqs.clone()); } } } } - if let Some(discard_rectangle_state) = discard_rectangle_state { - if !device.enabled_extensions().ext_discard_rectangles { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "`discard_rectangle_state` is `Some`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( - "ext_discard_rectangles", - )])]), - }); - } - - let DiscardRectangleState { mode, rectangles } = discard_rectangle_state; - - // VUID-VkPipelineDiscardRectangleStateCreateInfoEXT-discardRectangleMode-parameter - mode.validate_device(device)?; + let num_used_descriptor_sets = descriptor_binding_requirements + .keys() + .map(|loc| loc.0) + .max() + .map(|x| x + 1) + .unwrap_or(0); - let discard_rectangle_count = match rectangles { - PartialStateMode::Dynamic(count) => *count, - PartialStateMode::Fixed(rectangles) => rectangles.len() as u32, - }; + let mut dynamic_state: HashMap = HashMap::default(); - // VUID-VkPipelineDiscardRectangleStateCreateInfoEXT-discardRectangleCount-00582 - if discard_rectangle_count > properties.max_discard_rectangles.unwrap() { - return Err( - GraphicsPipelineCreationError::MaxDiscardRectanglesExceeded { - max: properties.max_discard_rectangles.unwrap(), - obtained: discard_rectangle_count, - }, - ); - } + if vertex_input_state.is_some() { + dynamic_state.insert(DynamicState::VertexInput, false); } - /* - Checks that rely on multiple pieces of state - */ - - if let (Some(vertex_stage), Some(vertex_input_state)) = (vertex_stage, vertex_input_state) { - for element in vertex_stage.entry_point.info().input_interface.elements() { - assert!(!element.ty.is_64bit); // TODO: implement - let location_range = - element.location..element.location + element.ty.num_locations(); - - for location in location_range { - // VUID-VkGraphicsPipelineCreateInfo-Input-07905 - let attribute_desc = match vertex_input_state.attributes.get(&location) { - Some(attribute_desc) => attribute_desc, - None => { - return Err( - GraphicsPipelineCreationError::VertexInputAttributeMissing { - location, - }, - ) - } - }; - - // TODO: Check component assignments too. Multiple variables can occupy the - // same location but in different components. - - let shader_type = element.ty.base_type; - let attribute_type = attribute_desc.format.type_color().unwrap(); + if let Some(input_assembly_state) = &input_assembly_state { + let &InputAssemblyState { + topology, + primitive_restart_enable, + } = input_assembly_state; - // VUID? - if !matches!( - (shader_type, attribute_type), - ( - ShaderScalarType::Float, - NumericType::SFLOAT - | NumericType::UFLOAT - | NumericType::SNORM - | NumericType::UNORM - | NumericType::SSCALED - | NumericType::USCALED - | NumericType::SRGB, - ) | (ShaderScalarType::Sint, NumericType::SINT) - | (ShaderScalarType::Uint, NumericType::UINT) - ) { - return Err( - GraphicsPipelineCreationError::VertexInputAttributeIncompatibleFormat { - location, - shader_type, - attribute_type, - }, - ); - } + match topology { + PartialStateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::PrimitiveTopology, false); + } + PartialStateMode::Dynamic(_) => { + dynamic_state.insert(DynamicState::PrimitiveTopology, true); } } - } - - if let (Some(_), Some(_)) = (tessellation_control_stage, tessellation_evaluation_stage) { - // FIXME: must check that the control shader and evaluation shader are compatible - - // TODO: - // VUID-VkGraphicsPipelineCreateInfo-pStages-00732 - // VUID-VkGraphicsPipelineCreateInfo-pStages-00733 - // VUID-VkGraphicsPipelineCreateInfo-pStages-00734 - // VUID-VkGraphicsPipelineCreateInfo-pStages-00735 - } - - if let (Some(_), Some(_)) = (tessellation_evaluation_stage, geometry_stage) { - // TODO: - // VUID-VkGraphicsPipelineCreateInfo-pStages-00739 - } - - if let (None, Some(geometry_stage), Some(input_assembly_state)) = ( - tessellation_evaluation_stage, - geometry_stage, - input_assembly_state, - ) { - let entry_point_info = geometry_stage.entry_point.info(); - let input = match entry_point_info.execution { - ShaderExecution::Geometry(execution) => execution.input, - _ => unreachable!(), - }; - if let PartialStateMode::Fixed(topology) = input_assembly_state.topology { - // VUID-VkGraphicsPipelineCreateInfo-pStages-00738 - if !input.is_compatible_with(topology) { - return Err(GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader); + match primitive_restart_enable { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::PrimitiveRestartEnable, false); + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::PrimitiveRestartEnable, true); } } } - if let (Some(fragment_stage), Some(render_pass)) = (fragment_stage, render_pass) { - let entry_point_info = fragment_stage.entry_point.info(); + if let Some(tessellation_state) = &tessellation_state { + let &TessellationState { + patch_control_points, + domain_origin: _, + } = tessellation_state; - // Check that the subpass can accept the output of the fragment shader. - match render_pass { - PipelineSubpassType::BeginRenderPass(subpass) => { - if !subpass.is_compatible_with(&entry_point_info.output_interface) { - return Err( - GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible, - ); - } + match patch_control_points { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::PatchControlPoints, false); } - PipelineSubpassType::BeginRendering(_) => { - // TODO: + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::PatchControlPoints, true); } } - - // TODO: - // VUID-VkGraphicsPipelineCreateInfo-pStages-01565 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06038 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06056 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06061 } - if let (Some(input_assembly_state), Some(_)) = (input_assembly_state, tessellation_state) { - // VUID-VkGraphicsPipelineCreateInfo-pStages-00736 - if !matches!( - input_assembly_state.topology, - PartialStateMode::Dynamic(PrimitiveTopologyClass::Patch) - | PartialStateMode::Fixed(PrimitiveTopology::PatchList) - ) { - return Err(GraphicsPipelineCreationError::InvalidPrimitiveTopology); + if let Some(viewport_state) = &viewport_state { + let ViewportState { + viewports, + scissors, + _ne: _, + } = viewport_state; + + match viewports { + PartialStateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::Viewport, false); + dynamic_state.insert(DynamicState::ViewportWithCount, false); + } + PartialStateMode::Dynamic(StateMode::Fixed(_)) => { + dynamic_state.insert(DynamicState::Viewport, true); + dynamic_state.insert(DynamicState::ViewportWithCount, false); + } + PartialStateMode::Dynamic(StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::Viewport, true); + dynamic_state.insert(DynamicState::ViewportWithCount, true); + } } - } - if let (Some(rasterization_state), Some(depth_stencil_state)) = - (rasterization_state, depth_stencil_state) - { - if let Some(stencil_state) = &depth_stencil_state.stencil { - if let (StateMode::Fixed(front_reference), StateMode::Fixed(back_reference)) = - (stencil_state.front.reference, stencil_state.back.reference) - { - // VUID-VkPipelineDepthStencilStateCreateInfo-separateStencilMaskRef-04453 - if device.enabled_extensions().khr_portability_subset - && !device.enabled_features().separate_stencil_mask_ref - && matches!( - rasterization_state.cull_mode, - StateMode::Fixed(CullMode::None) - ) - && front_reference != back_reference - { - return Err(GraphicsPipelineCreationError::RequirementNotMet { - required_for: "this device is a portability subset device, \ - `rasterization_state.cull_mode` is \ - `StateMode::Fixed(CullMode::None)`, and \ - `depth_stencil_state.stencil` is `Some(stencil_state)`, \ - where `stencil_state.front.reference` does not equal \ - `stencil_state.back.reference`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( - "separate_stencil_mask_ref", - )])]), - }); - } + match scissors { + PartialStateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::Scissor, false); + dynamic_state.insert(DynamicState::ScissorWithCount, false); + } + PartialStateMode::Dynamic(StateMode::Fixed(_)) => { + dynamic_state.insert(DynamicState::Scissor, true); + dynamic_state.insert(DynamicState::ScissorWithCount, false); + } + PartialStateMode::Dynamic(StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::Scissor, true); + dynamic_state.insert(DynamicState::ScissorWithCount, true); } } } - if let (Some(multisample_state), Some(render_pass)) = (multisample_state, render_pass) { - match render_pass { - PipelineSubpassType::BeginRenderPass(subpass) => { - if let Some(samples) = subpass.num_samples() { - // VUID-VkGraphicsPipelineCreateInfo-subpass-00757 - if multisample_state.rasterization_samples != samples { - return Err(GraphicsPipelineCreationError::MultisampleRasterizationSamplesMismatch); - } - } + if let Some(rasterization_state) = &rasterization_state { + let &RasterizationState { + rasterizer_discard_enable, + cull_mode, + front_face, + depth_bias, + line_width, + line_stipple, + .. + } = rasterization_state; - // TODO: - // VUID-VkGraphicsPipelineCreateInfo-subpass-00758 - // VUID-VkGraphicsPipelineCreateInfo-subpass-01505 - // VUID-VkGraphicsPipelineCreateInfo-subpass-01411 - // VUID-VkGraphicsPipelineCreateInfo-subpass-01412 + match rasterizer_discard_enable { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::RasterizerDiscardEnable, false); } - PipelineSubpassType::BeginRendering(_) => { - // No equivalent VUIDs for dynamic rendering, as no sample count information - // is provided until `begin_rendering`. + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::RasterizerDiscardEnable, true); } } - } - if let (Some(depth_stencil_state), Some(render_pass)) = (depth_stencil_state, render_pass) { - if let Some(depth_state) = &depth_stencil_state.depth { - let has_depth_attachment = match render_pass { - PipelineSubpassType::BeginRenderPass(subpass) => subpass - .subpass_desc() - .depth_stencil_attachment - .as_ref() - .map_or(false, |depth_stencil_attachment| { - subpass.render_pass().attachments() - [depth_stencil_attachment.attachment as usize] - .format - .unwrap() - .aspects() - .intersects(ImageAspects::DEPTH) - }), - PipelineSubpassType::BeginRendering(rendering_info) => { - rendering_info.depth_attachment_format.is_some() - } - }; - - // VUID? - if !has_depth_attachment { - return Err(GraphicsPipelineCreationError::NoDepthAttachment); + match cull_mode { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::CullMode, false); } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::CullMode, true); + } + } - if let StateMode::Fixed(true) = depth_state.write_enable { - match render_pass { - PipelineSubpassType::BeginRenderPass(subpass) => { - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06039 - if !subpass - .subpass_desc() - .depth_stencil_attachment - .as_ref() - .filter(|depth_stencil_attachment| { - depth_stencil_attachment - .layout - .is_writable(ImageAspect::Depth) - }) - .map_or(false, |depth_stencil_attachment| { - subpass.render_pass().attachments() - [depth_stencil_attachment.attachment as usize] - .format - .unwrap() - .aspects() - .intersects(ImageAspects::DEPTH) - }) - { - return Err(GraphicsPipelineCreationError::NoDepthAttachment); - } - } - PipelineSubpassType::BeginRendering(_) => { - // No VUID? - } - } + match front_face { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::FrontFace, false); + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::FrontFace, true); } } - if depth_stencil_state.stencil.is_some() { - let has_stencil_attachment = match render_pass { - PipelineSubpassType::BeginRenderPass(subpass) => subpass - .subpass_desc() - .depth_stencil_attachment - .as_ref() - .map_or(false, |depth_stencil_attachment| { - subpass.render_pass().attachments() - [depth_stencil_attachment.attachment as usize] - .format - .unwrap() - .aspects() - .intersects(ImageAspects::STENCIL) - }), - PipelineSubpassType::BeginRendering(rendering_info) => { - rendering_info.stencil_attachment_format.is_some() - } - }; + if let Some(depth_bias_state) = depth_bias { + if depth_bias_state.enable_dynamic { + dynamic_state.insert(DynamicState::DepthBiasEnable, true); + } else { + dynamic_state.insert(DynamicState::DepthBiasEnable, false); + } - if !has_stencil_attachment { - return Err(GraphicsPipelineCreationError::NoStencilAttachment); + match depth_bias_state.bias { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::DepthBias, false); + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::DepthBias, true); + } } } - } - if let (Some(color_blend_state), Some(render_pass)) = (color_blend_state, render_pass) { - let color_attachment_count = match render_pass { - PipelineSubpassType::BeginRenderPass(subpass) => { - subpass.subpass_desc().color_attachments.len() + match line_width { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::LineWidth, false); } - PipelineSubpassType::BeginRendering(rendering_info) => { - rendering_info.color_attachment_formats.len() + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::LineWidth, true); } - }; - - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06042 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06055 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06060 - if color_attachment_count != color_blend_state.attachments.len() { - return Err(GraphicsPipelineCreationError::MismatchBlendingAttachmentsCount); } - for (attachment_index, state) in color_blend_state.attachments.iter().enumerate() { - if state.blend.is_some() { - let attachment_format = match render_pass { - PipelineSubpassType::BeginRenderPass(subpass) => { - subpass.subpass_desc().color_attachments[attachment_index] - .as_ref() - .and_then(|color_attachment| { - subpass.render_pass().attachments() - [color_attachment.attachment as usize] - .format - }) + if device.enabled_extensions().ext_line_rasterization { + if let Some(line_stipple) = line_stipple { + match line_stipple { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::LineStipple, false); } - PipelineSubpassType::BeginRendering(rendering_info) => { - rendering_info.color_attachment_formats[attachment_index] + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::LineStipple, true); } - }; - - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06041 - // VUID-VkGraphicsPipelineCreateInfo-renderPass-06062 - // Use unchecked, because all validation has been done above or by the - // render pass creation. - if !attachment_format.map_or(false, |format| unsafe { - physical_device - .format_properties_unchecked(format) - .potential_format_features() - .intersects(FormatFeatures::COLOR_ATTACHMENT_BLEND) - }) { - return Err( - GraphicsPipelineCreationError::ColorAttachmentFormatBlendNotSupported { - attachment_index: attachment_index as u32, - }, - ); } } } } - Ok(()) - } + if let Some(depth_stencil_state) = &depth_stencil_state { + let DepthStencilState { + flags: _, + depth, + depth_bounds, + stencil, + } = depth_stencil_state; - #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] - pub unsafe fn new_unchecked( - device: Arc, - cache: Option>, - create_info: GraphicsPipelineCreateInfo, - ) -> Result, RuntimeError> { - let &GraphicsPipelineCreateInfo { - flags, - ref stages, + if let Some(depth_state) = depth { + let &DepthState { + enable_dynamic, + write_enable, + compare_op, + } = depth_state; - ref vertex_input_state, - ref input_assembly_state, - ref tessellation_state, - ref viewport_state, - ref rasterization_state, - ref multisample_state, - ref depth_stencil_state, - ref color_blend_state, + if enable_dynamic { + dynamic_state.insert(DynamicState::DepthTestEnable, true); + } else { + dynamic_state.insert(DynamicState::DepthTestEnable, false); + } - ref layout, - subpass: ref render_pass, + match write_enable { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::DepthWriteEnable, false); + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::DepthWriteEnable, true); + } + } - ref discard_rectangle_state, - _ne: _, - } = &create_info; + match compare_op { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::DepthCompareOp, false); + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::DepthCompareOp, true); + } + } + } - let mut dynamic_state: HashMap = HashMap::default(); + if let Some(depth_bounds_state) = depth_bounds { + let DepthBoundsState { + enable_dynamic, + bounds, + } = depth_bounds_state; - struct PerPipelineShaderStageCreateInfo { - name_vk: CString, - specialization_info_vk: ash::vk::SpecializationInfo, - specialization_map_entries_vk: Vec, - specialization_data_vk: Vec, - } + if *enable_dynamic { + dynamic_state.insert(DynamicState::DepthBoundsTestEnable, true); + } else { + dynamic_state.insert(DynamicState::DepthBoundsTestEnable, false); + } - let (mut stages_vk, mut per_stage_vk): (SmallVec<[_; 5]>, SmallVec<[_; 5]>) = stages - .iter() - .map(|stage| { - let &PipelineShaderStageCreateInfo { - flags, - ref entry_point, - ref specialization_info, - _ne: _, - } = stage; + match bounds.clone() { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::DepthBounds, false); + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::DepthBounds, true); + } + } + } - let entry_point_info = entry_point.info(); - let stage = ShaderStage::from(&entry_point_info.execution); + if let Some(stencil_state) = stencil { + let StencilState { + enable_dynamic, + front, + back, + } = stencil_state; - let mut specialization_data_vk: Vec = Vec::new(); - let specialization_map_entries_vk: Vec<_> = specialization_info - .iter() - .map(|(&constant_id, value)| { - let data = value.as_bytes(); - let offset = specialization_data_vk.len() as u32; - let size = data.len(); - specialization_data_vk.extend(data); + if *enable_dynamic { + dynamic_state.insert(DynamicState::StencilTestEnable, true); + } else { + dynamic_state.insert(DynamicState::StencilTestEnable, false); + } - ash::vk::SpecializationMapEntry { - constant_id, - offset, - size, - } - }) - .collect(); + match (front.ops, back.ops) { + (StateMode::Fixed(_), StateMode::Fixed(_)) => { + dynamic_state.insert(DynamicState::StencilOp, false); + } + (StateMode::Dynamic, StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::StencilOp, true); + } + _ => unreachable!(), + } - ( - ash::vk::PipelineShaderStageCreateInfo { - flags: flags.into(), - stage: stage.into(), - module: entry_point.module().handle(), - p_name: ptr::null(), - p_specialization_info: ptr::null(), - ..Default::default() - }, - PerPipelineShaderStageCreateInfo { - name_vk: CString::new(entry_point_info.name.as_str()).unwrap(), - specialization_info_vk: ash::vk::SpecializationInfo { - map_entry_count: specialization_map_entries_vk.len() as u32, - p_map_entries: ptr::null(), - data_size: specialization_data_vk.len(), - p_data: ptr::null(), - }, - specialization_map_entries_vk, - specialization_data_vk, - }, - ) - }) - .unzip(); - - for ( - stage_vk, - PerPipelineShaderStageCreateInfo { - name_vk, - specialization_info_vk, - specialization_map_entries_vk, - specialization_data_vk, - }, - ) in (stages_vk.iter_mut()).zip(per_stage_vk.iter_mut()) - { - *stage_vk = ash::vk::PipelineShaderStageCreateInfo { - p_name: name_vk.as_ptr(), - p_specialization_info: specialization_info_vk, - ..*stage_vk - }; - - *specialization_info_vk = ash::vk::SpecializationInfo { - p_map_entries: specialization_map_entries_vk.as_ptr(), - p_data: specialization_data_vk.as_ptr() as _, - ..*specialization_info_vk - }; - } - - let mut vertex_input_state_vk = None; - let mut vertex_binding_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new(); - let mut vertex_attribute_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new(); - let mut vertex_binding_divisor_state_vk = None; - let mut vertex_binding_divisor_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new(); - - if let Some(vertex_input_state) = vertex_input_state { - dynamic_state.insert(DynamicState::VertexInput, false); - - let VertexInputState { - bindings, - attributes, - } = vertex_input_state; - - vertex_binding_descriptions_vk.extend(bindings.iter().map( - |(&binding, binding_desc)| ash::vk::VertexInputBindingDescription { - binding, - stride: binding_desc.stride, - input_rate: binding_desc.input_rate.into(), - }, - )); - - vertex_attribute_descriptions_vk.extend(attributes.iter().map( - |(&location, attribute_desc)| ash::vk::VertexInputAttributeDescription { - location, - binding: attribute_desc.binding, - format: attribute_desc.format.into(), - offset: attribute_desc.offset, - }, - )); - - let vertex_input_state = - vertex_input_state_vk.insert(ash::vk::PipelineVertexInputStateCreateInfo { - flags: ash::vk::PipelineVertexInputStateCreateFlags::empty(), - vertex_binding_description_count: vertex_binding_descriptions_vk.len() as u32, - p_vertex_binding_descriptions: vertex_binding_descriptions_vk.as_ptr(), - vertex_attribute_description_count: vertex_attribute_descriptions_vk.len() - as u32, - p_vertex_attribute_descriptions: vertex_attribute_descriptions_vk.as_ptr(), - ..Default::default() - }); + match (front.compare_mask, back.compare_mask) { + (StateMode::Fixed(_), StateMode::Fixed(_)) => { + dynamic_state.insert(DynamicState::StencilCompareMask, false); + } + (StateMode::Dynamic, StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::StencilCompareMask, true); + } + _ => unreachable!(), + } - { - vertex_binding_divisor_descriptions_vk.extend( - bindings - .iter() - .filter_map(|(&binding, binding_desc)| match binding_desc.input_rate { - VertexInputRate::Instance { divisor } if divisor != 1 => { - Some((binding, divisor)) - } - _ => None, - }) - .map(|(binding, divisor)| { - ash::vk::VertexInputBindingDivisorDescriptionEXT { binding, divisor } - }), - ); + match (front.write_mask, back.write_mask) { + (StateMode::Fixed(_), StateMode::Fixed(_)) => { + dynamic_state.insert(DynamicState::StencilWriteMask, false); + } + (StateMode::Dynamic, StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::StencilWriteMask, true); + } + _ => unreachable!(), + } - // VUID-VkPipelineVertexInputDivisorStateCreateInfoEXT-vertexBindingDivisorCount-arraylength - if !vertex_binding_divisor_descriptions_vk.is_empty() { - vertex_input_state.p_next = vertex_binding_divisor_state_vk.insert( - ash::vk::PipelineVertexInputDivisorStateCreateInfoEXT { - vertex_binding_divisor_count: vertex_binding_divisor_descriptions_vk - .len() - as u32, - p_vertex_binding_divisors: vertex_binding_divisor_descriptions_vk - .as_ptr(), - ..Default::default() - }, - ) as *const _ as *const _; + match (front.reference, back.reference) { + (StateMode::Fixed(_), StateMode::Fixed(_)) => { + dynamic_state.insert(DynamicState::StencilReference, false); + } + (StateMode::Dynamic, StateMode::Dynamic) => { + dynamic_state.insert(DynamicState::StencilReference, true); + } + _ => unreachable!(), } } } - let mut input_assembly_state_vk = None; - - if let Some(input_assembly_state) = input_assembly_state { - let &InputAssemblyState { - topology, - primitive_restart_enable, - } = input_assembly_state; + if let Some(color_blend_state) = &color_blend_state { + let &ColorBlendState { + flags: _, + logic_op, + ref attachments, + blend_constants, + } = color_blend_state; - let topology = match topology { - PartialStateMode::Fixed(topology) => { - dynamic_state.insert(DynamicState::PrimitiveTopology, false); - topology.into() - } - PartialStateMode::Dynamic(topology_class) => { - dynamic_state.insert(DynamicState::PrimitiveTopology, true); - topology_class.example().into() + if let Some(logic_op) = logic_op { + match logic_op { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::LogicOp, false); + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::LogicOp, true); + } } - }; + } - let primitive_restart_enable = match primitive_restart_enable { - StateMode::Fixed(primitive_restart_enable) => { - dynamic_state.insert(DynamicState::PrimitiveRestartEnable, false); - primitive_restart_enable as ash::vk::Bool32 + match blend_constants { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::BlendConstants, false); } StateMode::Dynamic => { - dynamic_state.insert(DynamicState::PrimitiveRestartEnable, true); - Default::default() + dynamic_state.insert(DynamicState::BlendConstants, true); } - }; + } - let _ = input_assembly_state_vk.insert(ash::vk::PipelineInputAssemblyStateCreateInfo { - flags: ash::vk::PipelineInputAssemblyStateCreateFlags::empty(), - topology, - primitive_restart_enable, - ..Default::default() - }); - } + if device.enabled_extensions().ext_color_write_enable { + for color_blend_attachment_state in attachments { + let &ColorBlendAttachmentState { + blend: _, + color_write_mask: _, + color_write_enable, + } = color_blend_attachment_state; - let mut tessellation_state_vk = None; - let mut tessellation_domain_origin_state_vk = None; + match color_write_enable { + StateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::ColorWriteEnable, false); + } + StateMode::Dynamic => { + dynamic_state.insert(DynamicState::ColorWriteEnable, true); + } + } + } + } + } - if let Some(tessellation_state) = tessellation_state { - let &TessellationState { - patch_control_points, - domain_origin, - } = tessellation_state; + if let Some(discard_rectangle_state) = &discard_rectangle_state { + let DiscardRectangleState { rectangles, .. } = discard_rectangle_state; - let patch_control_points = match patch_control_points { - StateMode::Fixed(patch_control_points) => { - dynamic_state.insert(DynamicState::PatchControlPoints, false); - patch_control_points + match rectangles { + PartialStateMode::Fixed(_) => { + dynamic_state.insert(DynamicState::DiscardRectangle, false); } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::PatchControlPoints, true); - Default::default() + PartialStateMode::Dynamic(_) => { + dynamic_state.insert(DynamicState::DiscardRectangle, true); } - }; - - let tessellation_state_vk = - tessellation_state_vk.insert(ash::vk::PipelineTessellationStateCreateInfo { - flags: ash::vk::PipelineTessellationStateCreateFlags::empty(), - patch_control_points, - ..Default::default() - }); - - if domain_origin != TessellationDomainOrigin::default() { - let tessellation_domain_origin_state_vk = tessellation_domain_origin_state_vk - .insert(ash::vk::PipelineTessellationDomainOriginStateCreateInfo { - domain_origin: domain_origin.into(), - ..Default::default() - }); - - tessellation_domain_origin_state_vk.p_next = tessellation_state_vk.p_next; - tessellation_state_vk.p_next = - tessellation_domain_origin_state_vk as *const _ as *const _; } } - let mut viewport_state_vk = None; - let mut viewports_vk: SmallVec<[_; 2]> = SmallVec::new(); - let mut scissors_vk: SmallVec<[_; 2]> = SmallVec::new(); - - if let Some(viewport_state) = viewport_state { - let (viewport_count, scissor_count) = match viewport_state { - ViewportState::Fixed { data } => { - let count = data.len() as u32; - viewports_vk.extend(data.iter().map(|e| e.0.clone().into())); - dynamic_state.insert(DynamicState::Viewport, false); - dynamic_state.insert(DynamicState::ViewportWithCount, false); + Arc::new(Self { + handle, + device, + id: Self::next_id(), - scissors_vk.extend(data.iter().map(|e| e.1.into())); - dynamic_state.insert(DynamicState::Scissor, false); - dynamic_state.insert(DynamicState::ScissorWithCount, false); + shaders, + descriptor_binding_requirements, + num_used_descriptor_sets, + fragment_tests_stages, - (count, count) - } - ViewportState::FixedViewport { - viewports, - scissor_count_dynamic, - } => { - let viewport_count = viewports.len() as u32; - viewports_vk.extend(viewports.iter().map(|e| e.clone().into())); - dynamic_state.insert(DynamicState::Viewport, false); - dynamic_state.insert(DynamicState::ViewportWithCount, false); + vertex_input_state: vertex_input_state.unwrap(), // Can be None if there's a mesh shader, but we don't support that yet + input_assembly_state: input_assembly_state.unwrap(), // Can be None if there's a mesh shader, but we don't support that yet + tessellation_state, + viewport_state, + rasterization_state: rasterization_state.unwrap(), // Can be None for pipeline libraries, but we don't support that yet + multisample_state, + depth_stencil_state, + color_blend_state, + layout, + subpass: render_pass.unwrap(), + dynamic_state, - let scissor_count = if *scissor_count_dynamic { - dynamic_state.insert(DynamicState::Scissor, false); - dynamic_state.insert(DynamicState::ScissorWithCount, true); - 0 - } else { - dynamic_state.insert(DynamicState::Scissor, true); - dynamic_state.insert(DynamicState::ScissorWithCount, false); - viewport_count - }; + discard_rectangle_state, + }) + } - (viewport_count, scissor_count) - } - ViewportState::FixedScissor { - scissors, - viewport_count_dynamic, - } => { - let scissor_count = scissors.len() as u32; - scissors_vk.extend(scissors.iter().map(|&e| e.into())); - dynamic_state.insert(DynamicState::Scissor, false); - dynamic_state.insert(DynamicState::ScissorWithCount, false); + /// Returns the device used to create this pipeline. + #[inline] + pub fn device(&self) -> &Arc { + &self.device + } - let viewport_count = if *viewport_count_dynamic { - dynamic_state.insert(DynamicState::Viewport, false); - dynamic_state.insert(DynamicState::ViewportWithCount, true); - 0 - } else { - dynamic_state.insert(DynamicState::Viewport, true); - dynamic_state.insert(DynamicState::ViewportWithCount, false); - scissor_count - }; + /// Returns information about a particular shader. + /// + /// `None` is returned if the pipeline does not contain this shader. + /// + /// Compatibility note: `()` is temporary, it will be replaced with something else in the + /// future. + // TODO: ^ implement and make this public + #[inline] + pub(crate) fn shader(&self, stage: ShaderStage) -> Option<()> { + self.shaders.get(&stage).copied() + } - (viewport_count, scissor_count) - } - &ViewportState::Dynamic { - count, - viewport_count_dynamic, - scissor_count_dynamic, - } => { - let viewport_count = if viewport_count_dynamic { - dynamic_state.insert(DynamicState::Viewport, false); - dynamic_state.insert(DynamicState::ViewportWithCount, true); - - 0 - } else { - dynamic_state.insert(DynamicState::Viewport, true); - dynamic_state.insert(DynamicState::ViewportWithCount, false); + /// Returns the vertex input state used to create this pipeline. + #[inline] + pub fn vertex_input_state(&self) -> &VertexInputState { + &self.vertex_input_state + } - count - }; - let scissor_count = if scissor_count_dynamic { - dynamic_state.insert(DynamicState::Scissor, false); - dynamic_state.insert(DynamicState::ScissorWithCount, true); + /// Returns the input assembly state used to create this pipeline. + #[inline] + pub fn input_assembly_state(&self) -> &InputAssemblyState { + &self.input_assembly_state + } - 0 - } else { - dynamic_state.insert(DynamicState::Scissor, true); - dynamic_state.insert(DynamicState::ScissorWithCount, false); + /// Returns the tessellation state used to create this pipeline. + #[inline] + pub fn tessellation_state(&self) -> Option<&TessellationState> { + self.tessellation_state.as_ref() + } - count - }; + /// Returns the viewport state used to create this pipeline. + #[inline] + pub fn viewport_state(&self) -> Option<&ViewportState> { + self.viewport_state.as_ref() + } - (viewport_count, scissor_count) - } - }; + /// Returns the rasterization state used to create this pipeline. + #[inline] + pub fn rasterization_state(&self) -> &RasterizationState { + &self.rasterization_state + } - let _ = viewport_state_vk.insert(ash::vk::PipelineViewportStateCreateInfo { - flags: ash::vk::PipelineViewportStateCreateFlags::empty(), - viewport_count, - p_viewports: if viewports_vk.is_empty() { - ptr::null() - } else { - viewports_vk.as_ptr() - }, // validation layer crashes if you just pass the pointer - scissor_count, - p_scissors: if scissors_vk.is_empty() { - ptr::null() - } else { - scissors_vk.as_ptr() - }, // validation layer crashes if you just pass the pointer - ..Default::default() - }); - } + /// Returns the multisample state used to create this pipeline. + #[inline] + pub fn multisample_state(&self) -> Option<&MultisampleState> { + self.multisample_state.as_ref() + } - let mut rasterization_state_vk = None; - let mut rasterization_line_state_vk = None; + /// Returns the depth/stencil state used to create this pipeline. + #[inline] + pub fn depth_stencil_state(&self) -> Option<&DepthStencilState> { + self.depth_stencil_state.as_ref() + } - if let Some(rasterization_state) = rasterization_state { - let &RasterizationState { - depth_clamp_enable, - rasterizer_discard_enable, - polygon_mode, - cull_mode, - front_face, - depth_bias, - line_width, - line_rasterization_mode, - line_stipple, - } = rasterization_state; + /// Returns the color blend state used to create this pipeline. + #[inline] + pub fn color_blend_state(&self) -> Option<&ColorBlendState> { + self.color_blend_state.as_ref() + } - let rasterizer_discard_enable = match rasterizer_discard_enable { - StateMode::Fixed(rasterizer_discard_enable) => { - dynamic_state.insert(DynamicState::RasterizerDiscardEnable, false); - rasterizer_discard_enable as ash::vk::Bool32 - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::RasterizerDiscardEnable, true); - ash::vk::FALSE - } - }; + /// Returns the subpass this graphics pipeline is rendering to. + #[inline] + pub fn subpass(&self) -> &PipelineSubpassType { + &self.subpass + } - let cull_mode = match cull_mode { - StateMode::Fixed(cull_mode) => { - dynamic_state.insert(DynamicState::CullMode, false); - cull_mode.into() - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::CullMode, true); - CullMode::default().into() - } - }; + /// Returns whether a particular state is must be dynamically set. + /// + /// `None` is returned if the pipeline does not contain this state. Previously set dynamic + /// state is not disturbed when binding it. + #[inline] + pub fn dynamic_state(&self, state: DynamicState) -> Option { + self.dynamic_state.get(&state).copied() + } - let front_face = match front_face { - StateMode::Fixed(front_face) => { - dynamic_state.insert(DynamicState::FrontFace, false); - front_face.into() - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::FrontFace, true); - FrontFace::default().into() - } - }; + /// Returns all potentially dynamic states in the pipeline, and whether they are dynamic or not. + #[inline] + pub fn dynamic_states(&self) -> impl ExactSizeIterator + '_ { + self.dynamic_state.iter().map(|(k, v)| (*k, *v)) + } - let ( - depth_bias_enable, - depth_bias_constant_factor, - depth_bias_clamp, - depth_bias_slope_factor, - ) = if let Some(depth_bias_state) = depth_bias { - if depth_bias_state.enable_dynamic { - dynamic_state.insert(DynamicState::DepthBiasEnable, true); - } else { - dynamic_state.insert(DynamicState::DepthBiasEnable, false); - } + /// Returns the discard rectangle state used to create this pipeline. + #[inline] + pub fn discard_rectangle_state(&self) -> Option<&DiscardRectangleState> { + self.discard_rectangle_state.as_ref() + } - let (constant_factor, clamp, slope_factor) = match depth_bias_state.bias { - StateMode::Fixed(bias) => { - dynamic_state.insert(DynamicState::DepthBias, false); - (bias.constant_factor, bias.clamp, bias.slope_factor) - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::DepthBias, true); - (0.0, 0.0, 0.0) - } - }; + /// If the pipeline has a fragment shader, returns the fragment tests stages used. + #[inline] + pub fn fragment_tests_stages(&self) -> Option { + self.fragment_tests_stages + } +} - (ash::vk::TRUE, constant_factor, clamp, slope_factor) - } else { - (ash::vk::FALSE, 0.0, 0.0, 0.0) - }; +impl Pipeline for GraphicsPipeline { + #[inline] + fn bind_point(&self) -> PipelineBindPoint { + PipelineBindPoint::Graphics + } - let line_width = match line_width { - StateMode::Fixed(line_width) => { - dynamic_state.insert(DynamicState::LineWidth, false); - line_width - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::LineWidth, true); - 1.0 - } - }; + #[inline] + fn layout(&self) -> &Arc { + &self.layout + } - let rasterization_state = - rasterization_state_vk.insert(ash::vk::PipelineRasterizationStateCreateInfo { - flags: ash::vk::PipelineRasterizationStateCreateFlags::empty(), - depth_clamp_enable: depth_clamp_enable as ash::vk::Bool32, - rasterizer_discard_enable, - polygon_mode: polygon_mode.into(), - cull_mode, - front_face, - depth_bias_enable, - depth_bias_constant_factor, - depth_bias_clamp, - depth_bias_slope_factor, - line_width, - ..Default::default() - }); + #[inline] + fn num_used_descriptor_sets(&self) -> u32 { + self.num_used_descriptor_sets + } - if device.enabled_extensions().ext_line_rasterization { - let (stippled_line_enable, line_stipple_factor, line_stipple_pattern) = - if let Some(line_stipple) = line_stipple { - let (factor, pattern) = match line_stipple { - StateMode::Fixed(line_stipple) => { - dynamic_state.insert(DynamicState::LineStipple, false); - (line_stipple.factor, line_stipple.pattern) - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::LineStipple, true); - (1, 0) - } - }; - - (ash::vk::TRUE, factor, pattern) - } else { - (ash::vk::FALSE, 1, 0) - }; + #[inline] + fn descriptor_binding_requirements( + &self, + ) -> &HashMap<(u32, u32), DescriptorBindingRequirements> { + &self.descriptor_binding_requirements + } +} - rasterization_state.p_next = rasterization_line_state_vk.insert( - ash::vk::PipelineRasterizationLineStateCreateInfoEXT { - line_rasterization_mode: line_rasterization_mode.into(), - stippled_line_enable, - line_stipple_factor, - line_stipple_pattern, - ..Default::default() - }, - ) as *const _ as *const _; - } - } +unsafe impl DeviceOwned for GraphicsPipeline { + #[inline] + fn device(&self) -> &Arc { + &self.device + } +} - let mut multisample_state_vk = None; +impl Debug for GraphicsPipeline { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + write!(f, "", self.handle) + } +} - if let Some(multisample_state) = multisample_state { - let &MultisampleState { - rasterization_samples, - sample_shading, - ref sample_mask, - alpha_to_coverage_enable, - alpha_to_one_enable, - } = multisample_state; +unsafe impl VulkanObject for GraphicsPipeline { + type Handle = ash::vk::Pipeline; - let (sample_shading_enable, min_sample_shading) = - if let Some(min_sample_shading) = sample_shading { - (ash::vk::TRUE, min_sample_shading) - } else { - (ash::vk::FALSE, 0.0) - }; + #[inline] + fn handle(&self) -> Self::Handle { + self.handle + } +} - let _ = multisample_state_vk.insert(ash::vk::PipelineMultisampleStateCreateInfo { - flags: ash::vk::PipelineMultisampleStateCreateFlags::empty(), - rasterization_samples: rasterization_samples.into(), - sample_shading_enable, - min_sample_shading, - p_sample_mask: sample_mask as _, - alpha_to_coverage_enable: alpha_to_coverage_enable as ash::vk::Bool32, - alpha_to_one_enable: alpha_to_one_enable as ash::vk::Bool32, - ..Default::default() - }); +impl Drop for GraphicsPipeline { + #[inline] + fn drop(&mut self) { + unsafe { + let fns = self.device.fns(); + (fns.v1_0.destroy_pipeline)(self.device.handle(), self.handle, ptr::null()); } + } +} - let mut depth_stencil_state_vk = None; +impl_id_counter!(GraphicsPipeline); - if let Some(depth_stencil_state) = depth_stencil_state { - let DepthStencilState { - depth, - depth_bounds, - stencil, - } = depth_stencil_state; +/// Parameters to create a new `GraphicsPipeline`. +#[derive(Clone, Debug)] +pub struct GraphicsPipelineCreateInfo { + /// Additional properties of the pipeline. + /// + /// The default value is empty. + pub flags: PipelineCreateFlags, - let (depth_test_enable, depth_write_enable, depth_compare_op) = - if let Some(depth_state) = depth { - let &DepthState { - enable_dynamic, - write_enable, - compare_op, - } = depth_state; + /// The shader stages to use. + /// + /// A vertex shader must always be included. Other stages are optional. + /// + /// The default value is empty. + pub stages: SmallVec<[PipelineShaderStageCreateInfo; 5]>, - if enable_dynamic { - dynamic_state.insert(DynamicState::DepthTestEnable, true); - } else { - dynamic_state.insert(DynamicState::DepthTestEnable, false); - } + /// The vertex input state. + /// + /// This state is always used, and must be provided. + /// + /// The default value is `None`. + pub vertex_input_state: Option, - let write_enable = match write_enable { - StateMode::Fixed(write_enable) => { - dynamic_state.insert(DynamicState::DepthWriteEnable, false); - write_enable as ash::vk::Bool32 - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::DepthWriteEnable, true); - ash::vk::TRUE - } - }; + /// The input assembly state. + /// + /// This state is always used, and must be provided. + /// + /// The default value is `None`. + pub input_assembly_state: Option, - let compare_op = match compare_op { - StateMode::Fixed(compare_op) => { - dynamic_state.insert(DynamicState::DepthCompareOp, false); - compare_op.into() - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::DepthCompareOp, true); - ash::vk::CompareOp::ALWAYS - } - }; + /// The tessellation state. + /// + /// This state is used if `stages` contains tessellation shaders. + /// + /// The default value is `None`. + pub tessellation_state: Option, - (ash::vk::TRUE, write_enable, compare_op) - } else { - (ash::vk::FALSE, ash::vk::FALSE, ash::vk::CompareOp::ALWAYS) - }; + /// The viewport state. + /// + /// This state is used if [rasterizer discarding] is not enabled. + /// + /// The default value is `None`. + /// + /// [rasterizer discarding]: RasterizationState::rasterizer_discard_enable + pub viewport_state: Option, - let (depth_bounds_test_enable, min_depth_bounds, max_depth_bounds) = - if let Some(depth_bounds_state) = depth_bounds { - let depth_stencil::DepthBoundsState { - enable_dynamic, - bounds, - } = depth_bounds_state; + /// The rasterization state. + /// + /// This state is always used, and must be provided. + /// + /// The default value is `None`. + pub rasterization_state: Option, - if *enable_dynamic { - dynamic_state.insert(DynamicState::DepthBoundsTestEnable, true); - } else { - dynamic_state.insert(DynamicState::DepthBoundsTestEnable, false); - } + /// The multisample state. + /// + /// This state is used if [rasterizer discarding] is not enabled. + /// + /// The default value is `None`. + /// + /// [rasterizer discarding]: RasterizationState::rasterizer_discard_enable + pub multisample_state: Option, - let (min_bounds, max_bounds) = match bounds.clone() { - StateMode::Fixed(bounds) => { - dynamic_state.insert(DynamicState::DepthBounds, false); - bounds.into_inner() - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::DepthBounds, true); - (0.0, 1.0) - } - }; + /// The depth/stencil state. + /// + /// This state is used if `render_pass` has depth/stencil attachments, or if + /// [rasterizer discarding] is enabled. + /// + /// The default value is `None`. + /// + /// [rasterizer discarding]: RasterizationState::rasterizer_discard_enable + pub depth_stencil_state: Option, - (ash::vk::TRUE, min_bounds, max_bounds) - } else { - (ash::vk::FALSE, 0.0, 1.0) - }; + /// The color blend state. + /// + /// This state is used if `render_pass` has color attachments, and [rasterizer discarding] is + /// not enabled. + /// + /// The default value is `None`. + /// + /// [rasterizer discarding]: RasterizationState::rasterizer_discard_enable + pub color_blend_state: Option, - let (stencil_test_enable, front, back) = if let Some(stencil_state) = stencil { - let StencilState { - enable_dynamic, - front, - back, - } = stencil_state; + /// The pipeline layout to use for the pipeline. + /// + /// There is no default value. + pub layout: Arc, - if *enable_dynamic { - dynamic_state.insert(DynamicState::StencilTestEnable, true); - } else { - dynamic_state.insert(DynamicState::StencilTestEnable, false); - } + /// The render subpass to use. + /// + /// This state is always used, and must be provided. + /// + /// The default value is `None`. + pub subpass: Option, - match (front.ops, back.ops) { - (StateMode::Fixed(_), StateMode::Fixed(_)) => { - dynamic_state.insert(DynamicState::StencilOp, false); - } - (StateMode::Dynamic, StateMode::Dynamic) => { - dynamic_state.insert(DynamicState::StencilOp, true); - } - _ => unreachable!(), - }; + /// The discard rectangle state. + /// + /// This state is always used if it is provided. + /// + /// The default value is `None`. + pub discard_rectangle_state: Option, - match (front.compare_mask, back.compare_mask) { - (StateMode::Fixed(_), StateMode::Fixed(_)) => { - dynamic_state.insert(DynamicState::StencilCompareMask, false); - } - (StateMode::Dynamic, StateMode::Dynamic) => { - dynamic_state.insert(DynamicState::StencilCompareMask, true); - } - _ => unreachable!(), - }; - - match (front.write_mask, back.write_mask) { - (StateMode::Fixed(_), StateMode::Fixed(_)) => { - dynamic_state.insert(DynamicState::StencilWriteMask, false); - } - (StateMode::Dynamic, StateMode::Dynamic) => { - dynamic_state.insert(DynamicState::StencilWriteMask, true); - } - _ => unreachable!(), - }; - - match (front.reference, back.reference) { - (StateMode::Fixed(_), StateMode::Fixed(_)) => { - dynamic_state.insert(DynamicState::StencilReference, false); - } - (StateMode::Dynamic, StateMode::Dynamic) => { - dynamic_state.insert(DynamicState::StencilReference, true); - } - _ => unreachable!(), - }; - - let [front, back] = [front, back].map(|stencil_op_state| { - let &StencilOpState { - ops, - compare_mask, - write_mask, - reference, - } = stencil_op_state; - - let ops = match ops { - StateMode::Fixed(x) => x, - StateMode::Dynamic => Default::default(), - }; - let compare_mask = match compare_mask { - StateMode::Fixed(x) => x, - StateMode::Dynamic => Default::default(), - }; - let write_mask = match write_mask { - StateMode::Fixed(x) => x, - StateMode::Dynamic => Default::default(), - }; - let reference = match reference { - StateMode::Fixed(x) => x, - StateMode::Dynamic => Default::default(), - }; - - ash::vk::StencilOpState { - fail_op: ops.fail_op.into(), - pass_op: ops.pass_op.into(), - depth_fail_op: ops.depth_fail_op.into(), - compare_op: ops.compare_op.into(), - compare_mask, - write_mask, - reference, - } - }); - - (ash::vk::TRUE, front, back) - } else { - (ash::vk::FALSE, Default::default(), Default::default()) - }; + pub _ne: crate::NonExhaustive, +} - let _ = depth_stencil_state_vk.insert(ash::vk::PipelineDepthStencilStateCreateInfo { - flags: ash::vk::PipelineDepthStencilStateCreateFlags::empty(), - depth_test_enable, - depth_write_enable, - depth_compare_op, - depth_bounds_test_enable, - stencil_test_enable, - front, - back, - min_depth_bounds, - max_depth_bounds, - ..Default::default() - }); +impl GraphicsPipelineCreateInfo { + /// Returns a `GraphicsPipelineCreateInfo` with the specified `layout`. + #[inline] + pub fn layout(layout: Arc) -> Self { + Self { + flags: PipelineCreateFlags::empty(), + stages: SmallVec::new(), + vertex_input_state: None, + input_assembly_state: None, + tessellation_state: None, + viewport_state: None, + rasterization_state: None, + multisample_state: None, + depth_stencil_state: None, + color_blend_state: None, + layout, + subpass: None, + discard_rectangle_state: None, + _ne: crate::NonExhaustive(()), } + } - let mut color_blend_state_vk = None; - let mut color_blend_attachments_vk: SmallVec<[_; 4]> = SmallVec::new(); - let mut color_write_vk = None; - let mut color_write_enables_vk: SmallVec<[_; 4]> = SmallVec::new(); + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + flags, + ref stages, - if let Some(color_blend_state) = color_blend_state { - let &ColorBlendState { - logic_op, - ref attachments, - blend_constants, - } = color_blend_state; + ref vertex_input_state, + ref input_assembly_state, + ref tessellation_state, + ref viewport_state, + ref rasterization_state, + ref multisample_state, + ref depth_stencil_state, + ref color_blend_state, - color_blend_attachments_vk.extend(attachments.iter().map( - |color_blend_attachment_state| { - let &ColorBlendAttachmentState { - blend, - color_write_mask, - color_write_enable: _, - } = color_blend_attachment_state; + ref layout, + ref subpass, - let blend = if let Some(blend) = blend { - blend.into() - } else { - Default::default() - }; + ref discard_rectangle_state, + _ne: _, + } = self; - ash::vk::PipelineColorBlendAttachmentState { - color_write_mask: color_write_mask.into(), - ..blend - } - }, - )); + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; - let (logic_op_enable, logic_op) = if let Some(logic_op) = logic_op { - let logic_op = match logic_op { - StateMode::Fixed(logic_op) => { - dynamic_state.insert(DynamicState::LogicOp, false); - logic_op.into() - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::LogicOp, true); - Default::default() - } - }; + /* + Gather shader stages + */ - (ash::vk::TRUE, logic_op) - } else { - (ash::vk::FALSE, Default::default()) - }; + let mut stages_present = ShaderStages::empty(); + let mut vertex_stage = None; + let mut tessellation_control_stage = None; + let mut tessellation_evaluation_stage = None; + let mut geometry_stage = None; + let mut fragment_stage = None; - let blend_constants = match blend_constants { - StateMode::Fixed(blend_constants) => { - dynamic_state.insert(DynamicState::BlendConstants, false); - blend_constants - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::BlendConstants, true); - Default::default() - } - }; + for (stage_index, stage) in stages.iter().enumerate() { + let entry_point_info = stage.entry_point.info(); + let stage_enum = ShaderStage::from(&entry_point_info.execution); + let stage_flag = ShaderStages::from(stage_enum); - let mut color_blend_state_vk = - color_blend_state_vk.insert(ash::vk::PipelineColorBlendStateCreateInfo { - flags: ash::vk::PipelineColorBlendStateCreateFlags::empty(), - logic_op_enable, - logic_op, - attachment_count: color_blend_attachments_vk.len() as u32, - p_attachments: color_blend_attachments_vk.as_ptr(), - blend_constants, + if stages_present.intersects(stage_flag) { + return Err(ValidationError { + context: "stages".into(), + problem: format!( + "contains more than one element whose stage is \ + `ShaderStage::{:?}`", + stage_flag + ) + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-stage-06897"], ..Default::default() }); + } - if device.enabled_extensions().ext_color_write_enable { - color_write_enables_vk.extend(attachments.iter().map( - |color_blend_attachment_state| { - let &ColorBlendAttachmentState { - blend: _, - color_write_mask: _, - color_write_enable, - } = color_blend_attachment_state; + const PRIMITIVE_SHADING_STAGES: ShaderStages = ShaderStages::VERTEX + .union(ShaderStages::TESSELLATION_CONTROL) + .union(ShaderStages::TESSELLATION_CONTROL) + .union(ShaderStages::GEOMETRY); + const MESH_SHADING_STAGES: ShaderStages = ShaderStages::MESH.union(ShaderStages::TASK); - match color_write_enable { - StateMode::Fixed(enable) => { - dynamic_state.insert(DynamicState::ColorWriteEnable, false); - enable as ash::vk::Bool32 - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::ColorWriteEnable, true); - ash::vk::TRUE - } - } - }, - )); + if stage_flag.intersects(PRIMITIVE_SHADING_STAGES) + && stages_present.intersects(MESH_SHADING_STAGES) + || stage_flag.intersects(MESH_SHADING_STAGES) + && stages_present.intersects(PRIMITIVE_SHADING_STAGES) + { + return Err(ValidationError { + context: "stages".into(), + problem: "contains both primitive shading stages and mesh shading stages" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-02095"], + ..Default::default() + }); + } - color_blend_state_vk.p_next = - color_write_vk.insert(ash::vk::PipelineColorWriteCreateInfoEXT { - attachment_count: color_write_enables_vk.len() as u32, - p_color_write_enables: color_write_enables_vk.as_ptr(), + let stage_slot = match stage_enum { + ShaderStage::Vertex => &mut vertex_stage, + ShaderStage::TessellationControl => &mut tessellation_control_stage, + ShaderStage::TessellationEvaluation => &mut tessellation_evaluation_stage, + ShaderStage::Geometry => &mut geometry_stage, + ShaderStage::Fragment => &mut fragment_stage, + _ => { + return Err(ValidationError { + context: format!("stages[{}]", stage_index).into(), + problem: "is not a pre-rasterization or fragment shader stage".into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06896"], ..Default::default() - }) as *const _ as *const _; - } + }); + } + }; + + *stage_slot = Some(stage); + stages_present |= stage_flag; } - let mut dynamic_state_list: SmallVec<[_; 4]> = SmallVec::new(); - let mut dynamic_state_vk = None; + /* + Validate needed/unused state + */ - { - dynamic_state_list.extend( - dynamic_state - .iter() - .filter(|(_, d)| **d) - .map(|(&state, _)| state.into()), - ); + let need_pre_rasterization_shader_state = true; - if !dynamic_state_list.is_empty() { - let _ = dynamic_state_vk.insert(ash::vk::PipelineDynamicStateCreateInfo { - flags: ash::vk::PipelineDynamicStateCreateFlags::empty(), - dynamic_state_count: dynamic_state_list.len() as u32, - p_dynamic_states: dynamic_state_list.as_ptr(), + // Check this first because everything else depends on it. + match ( + rasterization_state.is_some(), + need_pre_rasterization_shader_state, + ) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + pre-rasterization shader state, but \ + `rasterization_state` is `Some`" + .into(), + // vuids? ..Default::default() }); } - } - - let render_pass = render_pass.as_ref().unwrap(); - let mut render_pass_vk = ash::vk::RenderPass::null(); - let mut subpass_vk = 0; - let mut color_attachment_formats_vk: SmallVec<[_; 4]> = SmallVec::new(); - let mut rendering_create_info_vk = None; - - match render_pass { - PipelineSubpassType::BeginRenderPass(subpass) => { - render_pass_vk = subpass.render_pass().handle(); - subpass_vk = subpass.index(); + (false, true) => { + return Err(ValidationError { + problem: "the pipeline is being created with \ + pre-rasterization shader state, but \ + `rasterization_state` is `None`" + .into(), + // vuids? + ..Default::default() + }); } - PipelineSubpassType::BeginRendering(rendering_info) => { - let &PipelineRenderingCreateInfo { - view_mask, - ref color_attachment_formats, - depth_attachment_format, - stencil_attachment_format, - _ne: _, - } = rendering_info; + _ => (), + } - color_attachment_formats_vk.extend( - color_attachment_formats - .iter() - .map(|format| format.map_or(ash::vk::Format::UNDEFINED, Into::into)), - ); + let need_vertex_input_state = need_pre_rasterization_shader_state + && stages + .iter() + .any(|stage| matches!(stage.entry_point.info().execution, ShaderExecution::Vertex)); + let need_fragment_shader_state = need_pre_rasterization_shader_state + && rasterization_state + .as_ref() + .unwrap() + .rasterizer_discard_enable + != StateMode::Fixed(true); + let need_fragment_output_state = need_pre_rasterization_shader_state + && rasterization_state + .as_ref() + .unwrap() + .rasterizer_discard_enable + != StateMode::Fixed(true); - let _ = rendering_create_info_vk.insert(ash::vk::PipelineRenderingCreateInfo { - view_mask, - color_attachment_count: color_attachment_formats_vk.len() as u32, - p_color_attachment_formats: color_attachment_formats_vk.as_ptr(), - depth_attachment_format: depth_attachment_format - .map_or(ash::vk::Format::UNDEFINED, Into::into), - stencil_attachment_format: stencil_attachment_format - .map_or(ash::vk::Format::UNDEFINED, Into::into), + match (vertex_stage.is_some(), need_pre_rasterization_shader_state) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + pre-rasterization shader state, but `stages` contains a \ + `ShaderStage::Vertex` stage" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06895"], + ..Default::default() + }); + } + (false, true) => { + return Err(ValidationError { + problem: "the pipeline is being created with \ + pre-rasterization shader state, but `stages` does not contain a \ + `ShaderStage::Vertex` stage" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-stage-02096"], ..Default::default() }); } + _ => (), } - let mut discard_rectangle_state_vk = None; - let mut discard_rectangles: SmallVec<[_; 2]> = SmallVec::new(); - - if let Some(discard_rectangle_state) = discard_rectangle_state { - let DiscardRectangleState { mode, rectangles } = discard_rectangle_state; + match ( + tessellation_control_stage.is_some(), + need_pre_rasterization_shader_state, + ) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + pre-rasterization shader state, but `stages` contains a \ + `ShaderStage::TessellationControl` stage" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06895"], + ..Default::default() + }); + } + (false, true) => (), + _ => (), + } - let discard_rectangle_count = match rectangles { - PartialStateMode::Fixed(rectangles) => { - dynamic_state.insert(DynamicState::DiscardRectangle, false); - discard_rectangles.extend(rectangles.iter().map(|&rect| rect.into())); + match ( + tessellation_evaluation_stage.is_some(), + need_pre_rasterization_shader_state, + ) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + pre-rasterization shader state, but `stages` contains a \ + `ShaderStage::TessellationEvaluation` stage" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06895"], + ..Default::default() + }); + } + (false, true) => (), + _ => (), + } - discard_rectangles.len() as u32 - } - PartialStateMode::Dynamic(count) => { - dynamic_state.insert(DynamicState::DiscardRectangle, true); + if stages_present.intersects(ShaderStages::TESSELLATION_CONTROL) + && !stages_present.intersects(ShaderStages::TESSELLATION_EVALUATION) + { + return Err(ValidationError { + context: "stages".into(), + problem: "contains a `ShaderStage::TessellationControl` stage, but not a \ + `ShaderStage::TessellationEvaluation` stage" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-00729"], + ..Default::default() + }); + } else if stages_present.intersects(ShaderStages::TESSELLATION_EVALUATION) + && !stages_present.intersects(ShaderStages::TESSELLATION_CONTROL) + { + return Err(ValidationError { + context: "stages".into(), + problem: "contains a `ShaderStage::TessellationEvaluation` stage, but not a \ + `ShaderStage::TessellationControl` stage" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-00730"], + ..Default::default() + }); + } - *count - } - }; + match ( + geometry_stage.is_some(), + need_pre_rasterization_shader_state, + ) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + pre-rasterization shader state, but `stages` contains a \ + `ShaderStage::Geometry` stage" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06895"], + ..Default::default() + }); + } + (false, true) => (), + _ => (), + } - let _ = discard_rectangle_state_vk.insert( - ash::vk::PipelineDiscardRectangleStateCreateInfoEXT { - flags: ash::vk::PipelineDiscardRectangleStateCreateFlagsEXT::empty(), - discard_rectangle_mode: (*mode).into(), - discard_rectangle_count, - p_discard_rectangles: discard_rectangles.as_ptr(), + match (fragment_stage.is_some(), need_fragment_shader_state) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + fragment shader state, but `stages` contains a \ + `ShaderStage::Geometry` stage" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-06894"], ..Default::default() - }, - ); + }); + } + (false, true) => (), + _ => (), } - /* - Create - */ + match (vertex_input_state.is_some(), need_vertex_input_state) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + vertex input state, but \ + `vertex_input_state` is `Some`" + .into(), + ..Default::default() + }); + } + (false, true) => { + return Err(ValidationError { + problem: "the pipeline is being created with \ + vertex input state, but \ + `vertex_input_state` is `None`" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-02097"], + ..Default::default() + }); + } + _ => (), + } - let mut create_info_vk = ash::vk::GraphicsPipelineCreateInfo { - flags: flags.into(), - stage_count: stages_vk.len() as u32, - p_stages: stages_vk.as_ptr(), - p_vertex_input_state: vertex_input_state_vk - .as_ref() - .map(|p| p as *const _) - .unwrap_or(ptr::null()), - p_input_assembly_state: input_assembly_state_vk - .as_ref() - .map(|p| p as *const _) - .unwrap_or(ptr::null()), - p_tessellation_state: tessellation_state_vk - .as_ref() - .map(|p| p as *const _) - .unwrap_or(ptr::null()), - p_viewport_state: viewport_state_vk - .as_ref() - .map(|p| p as *const _) - .unwrap_or(ptr::null()), - p_rasterization_state: rasterization_state_vk - .as_ref() - .map(|p| p as *const _) - .unwrap_or(ptr::null()), - p_multisample_state: multisample_state_vk - .as_ref() - .map(|p| p as *const _) - .unwrap_or(ptr::null()), - p_depth_stencil_state: depth_stencil_state_vk - .as_ref() - .map(|p| p as *const _) - .unwrap_or(ptr::null()), - p_color_blend_state: color_blend_state_vk - .as_ref() - .map(|p| p as *const _) - .unwrap_or(ptr::null()), - p_dynamic_state: dynamic_state_vk - .as_ref() - .map(|s| s as *const _) - .unwrap_or(ptr::null()), - layout: layout.handle(), - render_pass: render_pass_vk, - subpass: subpass_vk, - base_pipeline_handle: ash::vk::Pipeline::null(), // TODO: - base_pipeline_index: -1, // TODO: - ..Default::default() - }; + match (input_assembly_state.is_some(), need_vertex_input_state) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + vertex input state, but \ + `input_assembly_state` is `Some`" + .into(), + ..Default::default() + }); + } + (false, true) => { + return Err(ValidationError { + problem: "the pipeline is being created with \ + vertex input state, but \ + `input_assembly_state` is `None`" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-02098"], + ..Default::default() + }); + } + _ => (), + } - if let Some(info) = discard_rectangle_state_vk.as_mut() { - info.p_next = create_info_vk.p_next; - create_info_vk.p_next = info as *const _ as *const _; + match ( + tessellation_state.is_some(), + need_pre_rasterization_shader_state + && stages_present.contains( + ShaderStages::TESSELLATION_CONTROL | ShaderStages::TESSELLATION_EVALUATION, + ), + ) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + pre-rasterization state, or \ + `stages` does not contain tessellation shader stages, but \ + `tessellation_state` is `Some`" + .into(), + ..Default::default() + }); + } + (false, true) => { + return Err(ValidationError { + problem: "the pipeline is being created with \ + pre-rasterization state, and \ + `stages` contains tessellation shader stages, but \ + `tessellation_state` is `None`" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-00731"], + ..Default::default() + }); + } + _ => (), } - if let Some(info) = rendering_create_info_vk.as_mut() { - info.p_next = create_info_vk.p_next; - create_info_vk.p_next = info as *const _ as *const _; + match ( + viewport_state.is_some(), + need_pre_rasterization_shader_state + && rasterization_state + .as_ref() + .unwrap() + .rasterizer_discard_enable + != StateMode::Fixed(true), + ) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + pre-rasterization state, or \ + `rasterization_state.rasterization_discard_enable` is `true`, but \ + `viewport_state` is `Some`" + .into(), + ..Default::default() + }); + } + (false, true) => { + return Err(ValidationError { + problem: "the pipeline is being created with \ + pre-rasterization state, and \ + `rasterization_state.rasterization_discard_enable` is `false` \ + or dynamic, but `viewport_state` is `None`" + .into(), + vuids: &[ + "VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00750", + "VUID-VkGraphicsPipelineCreateInfo-pViewportState-04892", + ], + ..Default::default() + }); + } + _ => (), } - let cache_handle = match cache.as_ref() { - Some(cache) => cache.handle(), - None => ash::vk::PipelineCache::null(), - }; + match (multisample_state.is_some(), need_fragment_output_state) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + fragment output state, but \ + `multisample_state` is `Some`" + .into(), + ..Default::default() + }); + } + (false, true) => { + return Err(ValidationError { + problem: "the pipeline is being created with \ + fragment output state, but \ + `multisample_state` is `None`" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00751"], + ..Default::default() + }); + } + _ => (), + } - let handle = { - let fns = device.fns(); - let mut output = MaybeUninit::uninit(); - (fns.v1_0.create_graphics_pipelines)( - device.handle(), - cache_handle, - 1, - &create_info_vk, - ptr::null(), - output.as_mut_ptr(), - ) - .result() - .map_err(RuntimeError::from)?; - - output.assume_init() - }; - - // Some drivers return `VK_SUCCESS` but provide a null handle if they - // fail to create the pipeline (due to invalid shaders, etc) - // This check ensures that we don't create an invalid `GraphicsPipeline` instance - if handle == ash::vk::Pipeline::null() { - panic!("vkCreateGraphicsPipelines provided a NULL handle"); - } - - Ok(Self::from_handle(device, handle, create_info)) - } - - /// Creates a new `GraphicsPipeline` from a raw object handle. - /// - /// # Safety - /// - /// - `handle` must be a valid Vulkan object handle created from `device`. - /// - `create_info` must match the info used to create the object. - #[inline] - pub unsafe fn from_handle( - device: Arc, - handle: ash::vk::Pipeline, - create_info: GraphicsPipelineCreateInfo, - ) -> Arc { - let GraphicsPipelineCreateInfo { - flags: _, - stages, - - vertex_input_state, - input_assembly_state, - tessellation_state, - viewport_state, - rasterization_state, - multisample_state, - depth_stencil_state, - color_blend_state, - - layout, - subpass: render_pass, - - discard_rectangle_state, - - _ne: _, - } = create_info; - - let mut shaders = HashMap::default(); - let mut descriptor_binding_requirements: HashMap< - (u32, u32), - DescriptorBindingRequirements, - > = HashMap::default(); - let mut fragment_tests_stages = None; - - for stage in &stages { - let &PipelineShaderStageCreateInfo { - ref entry_point, .. - } = stage; - - let entry_point_info = entry_point.info(); - let stage = ShaderStage::from(&entry_point_info.execution); - shaders.insert(stage, ()); - - if let ShaderExecution::Fragment(FragmentShaderExecution { - fragment_tests_stages: s, - .. - }) = entry_point_info.execution - { - fragment_tests_stages = Some(s) - } - - for (&loc, reqs) in &entry_point_info.descriptor_binding_requirements { - match descriptor_binding_requirements.entry(loc) { - Entry::Occupied(entry) => { - entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements"); + match ( + depth_stencil_state.is_some(), + !need_fragment_output_state + || match subpass { + Some(PipelineSubpassType::BeginRenderPass(subpass)) => { + subpass.subpass_desc().depth_stencil_attachment.is_some() } - Entry::Vacant(entry) => { - entry.insert(reqs.clone()); + Some(PipelineSubpassType::BeginRendering(rendering_info)) => { + rendering_info.depth_attachment_format.is_some() + || rendering_info.stencil_attachment_format.is_some() } - } - } - } - - let num_used_descriptor_sets = descriptor_binding_requirements - .keys() - .map(|loc| loc.0) - .max() - .map(|x| x + 1) - .unwrap_or(0); - - let mut dynamic_state: HashMap = HashMap::default(); - - if vertex_input_state.is_some() { - dynamic_state.insert(DynamicState::VertexInput, false); - } - - if let Some(input_assembly_state) = &input_assembly_state { - let &InputAssemblyState { - topology, - primitive_restart_enable, - } = input_assembly_state; - - match topology { - PartialStateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::PrimitiveTopology, false); - } - PartialStateMode::Dynamic(_) => { - dynamic_state.insert(DynamicState::PrimitiveTopology, true); - } - } - - match primitive_restart_enable { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::PrimitiveRestartEnable, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::PrimitiveRestartEnable, true); - } + None => false, + }, + ) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is being created with \ + fragment output state, and \ + `subpass` does not have a depth/stencil attachment, but \ + `depth_stencil_state` is `Some`" + .into(), + ..Default::default() + }); } - } - - if let Some(tessellation_state) = &tessellation_state { - let &TessellationState { - patch_control_points, - domain_origin: _, - } = tessellation_state; - - match patch_control_points { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::PatchControlPoints, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::PatchControlPoints, true); - } + (false, true) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + fragment output state, or \ + `subpass` has a depth/stencil attachment, but \ + `depth_stencil_state` is `None`" + .into(), + vuids: &[ + "VUID-VkGraphicsPipelineCreateInfo-renderPass-06590", + "VUID-VkGraphicsPipelineCreateInfo-renderPass-06043", + "VUID-VkGraphicsPipelineCreateInfo-renderPass-06053", + ], + ..Default::default() + }); } + _ => (), } - if let Some(viewport_state) = &viewport_state { - match viewport_state { - ViewportState::Fixed { .. } => { - dynamic_state.insert(DynamicState::Viewport, false); - dynamic_state.insert(DynamicState::ViewportWithCount, false); - - dynamic_state.insert(DynamicState::Scissor, false); - dynamic_state.insert(DynamicState::ScissorWithCount, false); - } - &ViewportState::FixedViewport { - scissor_count_dynamic, - .. - } => { - dynamic_state.insert(DynamicState::Viewport, false); - dynamic_state.insert(DynamicState::ViewportWithCount, false); - - if scissor_count_dynamic { - dynamic_state.insert(DynamicState::Scissor, false); - dynamic_state.insert(DynamicState::ScissorWithCount, true); - } else { - dynamic_state.insert(DynamicState::Scissor, true); - dynamic_state.insert(DynamicState::ScissorWithCount, false); - } - } - &ViewportState::FixedScissor { - viewport_count_dynamic, - .. - } => { - dynamic_state.insert(DynamicState::Scissor, false); - dynamic_state.insert(DynamicState::ScissorWithCount, false); - - if viewport_count_dynamic { - dynamic_state.insert(DynamicState::Viewport, false); - dynamic_state.insert(DynamicState::ViewportWithCount, true); - } else { - dynamic_state.insert(DynamicState::Viewport, true); - dynamic_state.insert(DynamicState::ViewportWithCount, false); - } - } - &ViewportState::Dynamic { - viewport_count_dynamic, - scissor_count_dynamic, - .. - } => { - if viewport_count_dynamic { - dynamic_state.insert(DynamicState::Viewport, false); - dynamic_state.insert(DynamicState::ViewportWithCount, true); - } else { - dynamic_state.insert(DynamicState::Viewport, true); - dynamic_state.insert(DynamicState::ViewportWithCount, false); + match ( + color_blend_state.is_some(), + need_fragment_output_state + && match subpass { + Some(PipelineSubpassType::BeginRenderPass(subpass)) => { + !subpass.subpass_desc().color_attachments.is_empty() } - - if scissor_count_dynamic { - dynamic_state.insert(DynamicState::Scissor, false); - dynamic_state.insert(DynamicState::ScissorWithCount, true); - } else { - dynamic_state.insert(DynamicState::Scissor, true); - dynamic_state.insert(DynamicState::ScissorWithCount, false); + Some(PipelineSubpassType::BeginRendering(rendering_info)) => { + !rendering_info.color_attachment_formats.is_empty() } - } - }; - } - - if let Some(rasterization_state) = &rasterization_state { - let &RasterizationState { - rasterizer_discard_enable, - cull_mode, - front_face, - depth_bias, - line_width, - line_stipple, - .. - } = rasterization_state; - - match rasterizer_discard_enable { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::RasterizerDiscardEnable, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::RasterizerDiscardEnable, true); - } - } - - match cull_mode { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::CullMode, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::CullMode, true); - } - } - - match front_face { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::FrontFace, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::FrontFace, true); - } + None => false, + }, + ) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + fragment output state, or \ + `subpass` does not have any color attachments, but \ + `color_blend_state` is `Some`" + .into(), + ..Default::default() + }); } - - if let Some(depth_bias_state) = depth_bias { - if depth_bias_state.enable_dynamic { - dynamic_state.insert(DynamicState::DepthBiasEnable, true); - } else { - dynamic_state.insert(DynamicState::DepthBiasEnable, false); - } - - match depth_bias_state.bias { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::DepthBias, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::DepthBias, true); - } - } + (false, true) => { + return Err(ValidationError { + problem: "the pipeline is being created with \ + fragment output state, and \ + `subpass` has a color attachment, but \ + `color_blend_state` is `None`" + .into(), + vuids: &[ + "VUID-VkGraphicsPipelineCreateInfo-renderPass-06044", + "VUID-VkGraphicsPipelineCreateInfo-renderPass-06054", + ], + ..Default::default() + }); } + _ => (), + } - match line_width { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::LineWidth, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::LineWidth, true); - } - } - - if device.enabled_extensions().ext_line_rasterization { - if let Some(line_stipple) = line_stipple { - match line_stipple { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::LineStipple, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::LineStipple, true); - } - } - } - } - } - - if let Some(depth_stencil_state) = &depth_stencil_state { - let DepthStencilState { - depth, - depth_bounds, - stencil, - } = depth_stencil_state; - - if let Some(depth_state) = depth { - let &DepthState { - enable_dynamic, - write_enable, - compare_op, - } = depth_state; - - if enable_dynamic { - dynamic_state.insert(DynamicState::DepthTestEnable, true); - } else { - dynamic_state.insert(DynamicState::DepthTestEnable, false); - } - - match write_enable { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::DepthWriteEnable, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::DepthWriteEnable, true); - } - } - - match compare_op { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::DepthCompareOp, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::DepthCompareOp, true); - } - } - } - - if let Some(depth_bounds_state) = depth_bounds { - let DepthBoundsState { - enable_dynamic, - bounds, - } = depth_bounds_state; - - if *enable_dynamic { - dynamic_state.insert(DynamicState::DepthBoundsTestEnable, true); - } else { - dynamic_state.insert(DynamicState::DepthBoundsTestEnable, false); - } - - match bounds.clone() { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::DepthBounds, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::DepthBounds, true); - } - } - } - - if let Some(stencil_state) = stencil { - let StencilState { - enable_dynamic, - front, - back, - } = stencil_state; - - if *enable_dynamic { - dynamic_state.insert(DynamicState::StencilTestEnable, true); - } else { - dynamic_state.insert(DynamicState::StencilTestEnable, false); - } - - match (front.ops, back.ops) { - (StateMode::Fixed(_), StateMode::Fixed(_)) => { - dynamic_state.insert(DynamicState::StencilOp, false); - } - (StateMode::Dynamic, StateMode::Dynamic) => { - dynamic_state.insert(DynamicState::StencilOp, true); - } - _ => unreachable!(), - } - - match (front.compare_mask, back.compare_mask) { - (StateMode::Fixed(_), StateMode::Fixed(_)) => { - dynamic_state.insert(DynamicState::StencilCompareMask, false); - } - (StateMode::Dynamic, StateMode::Dynamic) => { - dynamic_state.insert(DynamicState::StencilCompareMask, true); - } - _ => unreachable!(), - } - - match (front.write_mask, back.write_mask) { - (StateMode::Fixed(_), StateMode::Fixed(_)) => { - dynamic_state.insert(DynamicState::StencilWriteMask, false); - } - (StateMode::Dynamic, StateMode::Dynamic) => { - dynamic_state.insert(DynamicState::StencilWriteMask, true); - } - _ => unreachable!(), - } - - match (front.reference, back.reference) { - (StateMode::Fixed(_), StateMode::Fixed(_)) => { - dynamic_state.insert(DynamicState::StencilReference, false); - } - (StateMode::Dynamic, StateMode::Dynamic) => { - dynamic_state.insert(DynamicState::StencilReference, true); - } - _ => unreachable!(), - } - } - } - - if let Some(color_blend_state) = &color_blend_state { - let &ColorBlendState { - logic_op, - ref attachments, - blend_constants, - } = color_blend_state; - - if let Some(logic_op) = logic_op { - match logic_op { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::LogicOp, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::LogicOp, true); - } - } - } - - match blend_constants { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::BlendConstants, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::BlendConstants, true); - } - } - - if device.enabled_extensions().ext_color_write_enable { - for color_blend_attachment_state in attachments { - let &ColorBlendAttachmentState { - blend: _, - color_write_mask: _, - color_write_enable, - } = color_blend_attachment_state; - - match color_write_enable { - StateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::ColorWriteEnable, false); - } - StateMode::Dynamic => { - dynamic_state.insert(DynamicState::ColorWriteEnable, true); - } - } - } - } - } - - if let Some(discard_rectangle_state) = &discard_rectangle_state { - let DiscardRectangleState { rectangles, .. } = discard_rectangle_state; - - match rectangles { - PartialStateMode::Fixed(_) => { - dynamic_state.insert(DynamicState::DiscardRectangle, false); - } - PartialStateMode::Dynamic(_) => { - dynamic_state.insert(DynamicState::DiscardRectangle, true); - } - } - } - - Arc::new(Self { - handle, - device, - id: Self::next_id(), - - shaders, - descriptor_binding_requirements, - num_used_descriptor_sets, - fragment_tests_stages, - - vertex_input_state: vertex_input_state.unwrap(), // Can be None if there's a mesh shader, but we don't support that yet - input_assembly_state: input_assembly_state.unwrap(), // Can be None if there's a mesh shader, but we don't support that yet - tessellation_state, - viewport_state, - rasterization_state: rasterization_state.unwrap(), // Can be None for pipeline libraries, but we don't support that yet - multisample_state, - depth_stencil_state, - color_blend_state, - layout, - subpass: render_pass.unwrap(), - dynamic_state, - - discard_rectangle_state, - }) - } - - /// Returns the device used to create this pipeline. - #[inline] - pub fn device(&self) -> &Arc { - &self.device - } - - /// Returns information about a particular shader. - /// - /// `None` is returned if the pipeline does not contain this shader. - /// - /// Compatibility note: `()` is temporary, it will be replaced with something else in the - /// future. - // TODO: ^ implement and make this public - #[inline] - pub(crate) fn shader(&self, stage: ShaderStage) -> Option<()> { - self.shaders.get(&stage).copied() - } - - /// Returns the vertex input state used to create this pipeline. - #[inline] - pub fn vertex_input_state(&self) -> &VertexInputState { - &self.vertex_input_state - } - - /// Returns the input assembly state used to create this pipeline. - #[inline] - pub fn input_assembly_state(&self) -> &InputAssemblyState { - &self.input_assembly_state - } - - /// Returns the tessellation state used to create this pipeline. - #[inline] - pub fn tessellation_state(&self) -> Option<&TessellationState> { - self.tessellation_state.as_ref() - } - - /// Returns the viewport state used to create this pipeline. - #[inline] - pub fn viewport_state(&self) -> Option<&ViewportState> { - self.viewport_state.as_ref() - } - - /// Returns the rasterization state used to create this pipeline. - #[inline] - pub fn rasterization_state(&self) -> &RasterizationState { - &self.rasterization_state - } - - /// Returns the multisample state used to create this pipeline. - #[inline] - pub fn multisample_state(&self) -> Option<&MultisampleState> { - self.multisample_state.as_ref() - } - - /// Returns the depth/stencil state used to create this pipeline. - #[inline] - pub fn depth_stencil_state(&self) -> Option<&DepthStencilState> { - self.depth_stencil_state.as_ref() - } - - /// Returns the color blend state used to create this pipeline. - #[inline] - pub fn color_blend_state(&self) -> Option<&ColorBlendState> { - self.color_blend_state.as_ref() - } - - /// Returns the subpass this graphics pipeline is rendering to. - #[inline] - pub fn subpass(&self) -> &PipelineSubpassType { - &self.subpass - } - - /// Returns whether a particular state is must be dynamically set. - /// - /// `None` is returned if the pipeline does not contain this state. Previously set dynamic - /// state is not disturbed when binding it. - #[inline] - pub fn dynamic_state(&self, state: DynamicState) -> Option { - self.dynamic_state.get(&state).copied() - } - - /// Returns all potentially dynamic states in the pipeline, and whether they are dynamic or not. - #[inline] - pub fn dynamic_states(&self) -> impl ExactSizeIterator + '_ { - self.dynamic_state.iter().map(|(k, v)| (*k, *v)) - } - - /// Returns the discard rectangle state used to create this pipeline. - #[inline] - pub fn discard_rectangle_state(&self) -> Option<&DiscardRectangleState> { - self.discard_rectangle_state.as_ref() - } - - /// If the pipeline has a fragment shader, returns the fragment tests stages used. - #[inline] - pub fn fragment_tests_stages(&self) -> Option { - self.fragment_tests_stages - } -} - -impl Pipeline for GraphicsPipeline { - #[inline] - fn bind_point(&self) -> PipelineBindPoint { - PipelineBindPoint::Graphics - } - - #[inline] - fn layout(&self) -> &Arc { - &self.layout - } - - #[inline] - fn num_used_descriptor_sets(&self) -> u32 { - self.num_used_descriptor_sets - } - - #[inline] - fn descriptor_binding_requirements( - &self, - ) -> &HashMap<(u32, u32), DescriptorBindingRequirements> { - &self.descriptor_binding_requirements - } -} - -unsafe impl DeviceOwned for GraphicsPipeline { - #[inline] - fn device(&self) -> &Arc { - &self.device - } -} - -impl Debug for GraphicsPipeline { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "", self.handle) - } -} - -unsafe impl VulkanObject for GraphicsPipeline { - type Handle = ash::vk::Pipeline; - - #[inline] - fn handle(&self) -> Self::Handle { - self.handle - } -} - -impl Drop for GraphicsPipeline { - #[inline] - fn drop(&mut self) { - unsafe { - let fns = self.device.fns(); - (fns.v1_0.destroy_pipeline)(self.device.handle(), self.handle, ptr::null()); - } - } -} - -impl_id_counter!(GraphicsPipeline); - -/// Parameters to create a new `GraphicsPipeline`. -#[derive(Clone, Debug)] -pub struct GraphicsPipelineCreateInfo { - /// Specifies how to create the pipeline. - /// - /// The default value is empty. - pub flags: PipelineCreateFlags, - - /// The shader stages to use. - /// - /// A vertex shader must always be included. Other stages are optional. - /// - /// The default value is empty. - pub stages: SmallVec<[PipelineShaderStageCreateInfo; 5]>, - - /// The vertex input state. - /// - /// This state is always used, and must be provided. - /// - /// The default value is `None`. - pub vertex_input_state: Option, - - /// The input assembly state. - /// - /// This state is always used, and must be provided. - /// - /// The default value is `None`. - pub input_assembly_state: Option, - - /// The tessellation state. - /// - /// This state is used if `stages` contains tessellation shaders. - /// - /// The default value is `None`. - pub tessellation_state: Option, - - /// The viewport state. - /// - /// This state is used if [rasterizer discarding] is not enabled. - /// - /// The default value is `None`. - /// - /// [rasterizer discarding]: RasterizationState::rasterizer_discard_enable - pub viewport_state: Option, - - /// The rasterization state. - /// - /// This state is always used, and must be provided. - /// - /// The default value is `None`. - pub rasterization_state: Option, + match ( + subpass.is_some(), + need_pre_rasterization_shader_state + || need_fragment_shader_state + || need_fragment_output_state, + ) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + pre-rasterization, fragment shader or fragment output state, but \ + `subpass` is `Some`" + .into(), + ..Default::default() + }); + } + (false, true) => { + return Err(ValidationError { + problem: "the pipeline is being created with \ + pre-rasterization, fragment shader or fragment output state, but \ + `subpass` is `None`" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06575"], + ..Default::default() + }); + } + _ => (), + } - /// The multisample state. - /// - /// This state is used if [rasterizer discarding] is not enabled. - /// - /// The default value is `None`. - /// - /// [rasterizer discarding]: RasterizationState::rasterizer_discard_enable - pub multisample_state: Option, + match ( + discard_rectangle_state.is_some(), + need_pre_rasterization_shader_state, + ) { + (true, false) => { + return Err(ValidationError { + problem: "the pipeline is not being created with \ + pre-rasterization state, but \ + `discard_rectangle_state` is `Some`" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04058"], + ..Default::default() + }); + } + (false, true) => (), + _ => (), + } - /// The depth/stencil state. - /// - /// This state is used if `render_pass` has depth/stencil attachments, or if - /// [rasterizer discarding] is enabled. - /// - /// The default value is `None`. - /// - /// [rasterizer discarding]: RasterizationState::rasterizer_discard_enable - pub depth_stencil_state: Option, + /* + Validate shader stages individually + */ - /// The color blend state. - /// - /// This state is used if `render_pass` has color attachments, and [rasterizer discarding] is - /// not enabled. - /// - /// The default value is `None`. - /// - /// [rasterizer discarding]: RasterizationState::rasterizer_discard_enable - pub color_blend_state: Option, + for (stage_index, stage) in stages.iter().enumerate() { + stage + .validate(device) + .map_err(|err| err.add_context(format!("stages[{}]", stage_index)))?; - /// The pipeline layout to use for the pipeline. - /// - /// There is no default value. - pub layout: Arc, + let &PipelineShaderStageCreateInfo { + flags: _, + ref entry_point, + specialization_info: _, + _ne: _, + } = stage; - /// The render subpass to use. - /// - /// This state is always used, and must be provided. - /// - /// The default value is `None`. - pub subpass: Option, + let entry_point_info = entry_point.info(); - /// The discard rectangle state. - /// - /// This state is always used if it is provided. - /// - /// The default value is `None`. - pub discard_rectangle_state: Option, + layout + .ensure_compatible_with_shader( + entry_point_info + .descriptor_binding_requirements + .iter() + .map(|(k, v)| (*k, v)), + entry_point_info.push_constant_requirements.as_ref(), + ) + .map_err(|err| ValidationError { + context: format!("stages[{}].entry_point", stage_index).into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-layout-00756"], + ..ValidationError::from_error(err) + })?; + } - pub _ne: crate::NonExhaustive, -} + let ordered_stages: SmallVec<[_; 5]> = [ + vertex_stage, + tessellation_control_stage, + tessellation_evaluation_stage, + geometry_stage, + fragment_stage, + ] + .into_iter() + .flatten() + .collect(); -impl GraphicsPipelineCreateInfo { - /// Returns a `GraphicsPipelineCreateInfo` with the specified `layout`. - #[inline] - pub fn layout(layout: Arc) -> Self { - Self { - flags: PipelineCreateFlags::empty(), - stages: SmallVec::new(), - vertex_input_state: None, - input_assembly_state: None, - tessellation_state: None, - viewport_state: None, - rasterization_state: None, - multisample_state: None, - depth_stencil_state: None, - color_blend_state: None, - layout, - subpass: None, - discard_rectangle_state: None, - _ne: crate::NonExhaustive(()), + // TODO: this check is too strict; the output only has to be a superset, any variables + // not used in the input of the next shader are just ignored. + for (output, input) in ordered_stages.iter().zip(ordered_stages.iter().skip(1)) { + if let Err(err) = (input.entry_point.info().input_interface) + .matches(&output.entry_point.info().output_interface) + { + return Err(ValidationError { + context: "stages".into(), + problem: format!( + "the output interface of the `ShaderStage::{:?}` stage does not \ + match the input interface of the `ShaderStage::{:?}` stage: {}", + ShaderStage::from(&output.entry_point.info().execution), + ShaderStage::from(&input.entry_point.info().execution), + err + ) + .into(), + vuids: &[ + "VUID-VkGraphicsPipelineCreateInfo-pStages-00742", + "VUID-VkGraphicsPipelineCreateInfo-None-04889", + ], + ..Default::default() + }); + } } - } -} -/// Error that can happen when creating a graphics pipeline. -#[derive(Clone, Debug, PartialEq)] -pub enum GraphicsPipelineCreationError { - RequirementNotMet { - required_for: &'static str, - requires_one_of: RequiresOneOf, - }, + // VUID-VkGraphicsPipelineCreateInfo-layout-01688 + // Checked at pipeline layout creation time. - /// A color attachment has a format that does not support blending. - ColorAttachmentFormatBlendNotSupported { attachment_index: u32 }, + /* + Validate states individually + */ - /// A color attachment has a format that does not support that usage. - ColorAttachmentFormatUsageNotSupported { attachment_index: u32 }, + if let Some(vertex_input_state) = vertex_input_state { + vertex_input_state + .validate(device) + .map_err(|err| err.add_context("vertex_input_state"))?; + } - /// The depth attachment has a format that does not support that usage. - DepthAttachmentFormatUsageNotSupported, + if let Some(input_assembly_state) = input_assembly_state { + input_assembly_state + .validate(device) + .map_err(|err| err.add_context("input_assembly_state"))?; - /// The depth and stencil attachments have different formats. - DepthStencilAttachmentFormatMismatch, + // TODO: + // VUID-VkGraphicsPipelineCreateInfo-topology-00737 + } - /// The output of the fragment shader is not compatible with what the render pass subpass - /// expects. - FragmentShaderRenderPassIncompatible, + if let Some(tessellation_state) = tessellation_state { + tessellation_state + .validate(device) + .map_err(|err| err.add_context("tessellation_state"))?; + } - /// The pipeline layout is not compatible with what the shaders expect. - IncompatiblePipelineLayout(PipelineLayoutSupersetError), + if let Some(viewport_state) = viewport_state { + viewport_state + .validate(device) + .map_err(|err| err.add_context("viewport_state"))?; - /// Tried to use a patch list without a tessellation shader, or a non-patch-list with a - /// tessellation shader. - InvalidPrimitiveTopology, + // TODO: + // VUID-VkGraphicsPipelineCreateInfo-primitiveFragmentShadingRateWithMultipleViewports-04503 + // VUID-VkGraphicsPipelineCreateInfo-primitiveFragmentShadingRateWithMultipleViewports-04504 + } - /// `patch_control_points` was not greater than 0 and less than or equal to the `max_tessellation_patch_size` limit. - InvalidNumPatchControlPoints, + if let Some(rasterization_state) = rasterization_state { + rasterization_state + .validate(device) + .map_err(|err| err.add_context("rasterization_state"))?; - /// The maximum number of discard rectangles has been exceeded. - MaxDiscardRectanglesExceeded { - /// Maximum allowed value. - max: u32, - /// Value that was passed. - obtained: u32, - }, + // TODO: + // VUID-VkGraphicsPipelineCreateInfo-pStages-00740 + // VUID-VkGraphicsPipelineCreateInfo-renderPass-06049 + // VUID-VkGraphicsPipelineCreateInfo-renderPass-06050 + // VUID-VkGraphicsPipelineCreateInfo-renderPass-06059 + } - /// The `max_multiview_view_count` limit has been exceeded. - MaxMultiviewViewCountExceeded { view_count: u32, max: u32 }, - - /// The maximum value for the instance rate divisor has been exceeded. - MaxVertexAttribDivisorExceeded { - /// Index of the faulty binding. - binding: u32, - /// Maximum allowed value. - max: u32, - /// Value that was passed. - obtained: u32, - }, + if let Some(multisample_state) = multisample_state { + multisample_state + .validate(device) + .map_err(|err| err.add_context("multisample_state"))?; - /// The maximum number of vertex attributes has been exceeded. - MaxVertexInputAttributesExceeded { - /// Maximum allowed value. - max: u32, - /// Value that was passed. - obtained: usize, - }, + // TODO: + // VUID-VkGraphicsPipelineCreateInfo-lineRasterizationMode-02766 + } - /// The maximum offset for a vertex attribute has been exceeded. This means that your vertex - /// struct is too large. - MaxVertexInputAttributeOffsetExceeded { - /// Maximum allowed value. - max: u32, - /// Value that was passed. - obtained: u32, - }, + if let Some(depth_stencil_state) = depth_stencil_state { + depth_stencil_state + .validate(device) + .map_err(|err| err.add_context("depth_stencil_state"))?; - /// The maximum number of vertex sources has been exceeded. - MaxVertexInputBindingsExceeded { - /// Maximum allowed value. - max: u32, - /// Value that was passed. - obtained: u32, - }, + // TODO: + // VUID-VkGraphicsPipelineCreateInfo-renderPass-06040 + } - /// The maximum stride value for vertex input (ie. the distance between two vertex elements) - /// has been exceeded. - MaxVertexInputBindingStrideExceeded { - /// Index of the faulty binding. - binding: u32, - /// Maximum allowed value. - max: u32, - /// Value that was passed. - obtained: u32, - }, + if let Some(color_blend_state) = color_blend_state { + color_blend_state + .validate(device) + .map_err(|err| err.add_context("color_blend_state"))?; + } - /// The maximum number of viewports has been exceeded. - MaxViewportsExceeded { - /// Maximum allowed value. - max: u32, - /// Value that was passed. - obtained: u32, - }, + if let Some(subpass) = subpass { + match subpass { + PipelineSubpassType::BeginRenderPass(subpass) => { + // VUID-VkGraphicsPipelineCreateInfo-commonparent + assert_eq!(device, subpass.render_pass().device().as_ref()); - /// The `min_vertex_input_binding_stride_alignment` limit was exceeded. - MinVertexInputBindingStrideAlignmentExceeded { - /// Index of the faulty binding. - binding: u32, - /// Maximum allowed value. - max: u32, - /// Value that was passed. - obtained: u32, - }, + if subpass.subpass_desc().view_mask != 0 { + if stages_present.intersects( + ShaderStages::TESSELLATION_CONTROL + | ShaderStages::TESSELLATION_EVALUATION, + ) && !device.enabled_features().multiview_tessellation_shader + { + return Err(ValidationError { + problem: "`stages` contains tessellation shaders, and \ + `subpass` has a non-zero `view_mask`" + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("multiview_tessellation_shader"), + ])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06047"], + ..Default::default() + }); + } - /// The maximum dimensions of viewports has been exceeded. - MaxViewportDimensionsExceeded, + if stages_present.intersects(ShaderStages::GEOMETRY) + && !device.enabled_features().multiview_geometry_shader + { + return Err(ValidationError { + problem: "`stages` contains a geometry shader, and \ + `subpass` has a non-zero `view_mask`" + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("multiview_geometry_shader"), + ])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06048"], + ..Default::default() + }); + } + } + } + PipelineSubpassType::BeginRendering(rendering_info) => { + if !device.enabled_features().dynamic_rendering { + return Err(ValidationError { + context: "subpass".into(), + problem: "is `PipelineRenderPassType::BeginRendering`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "dynamic_rendering", + )])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06576"], + }); + } - /// The number of attachments specified in the blending does not match the number of - /// attachments in the subpass. - MismatchBlendingAttachmentsCount, + rendering_info + .validate(device) + .map_err(|err| err.add_context("subpass"))?; - /// The provided `rasterization_samples` does not match the number of samples of the render - /// subpass. - MultisampleRasterizationSamplesMismatch, + let &PipelineRenderingCreateInfo { + view_mask, + color_attachment_formats: _, + depth_attachment_format: _, + stencil_attachment_format: _, + _ne: _, + } = rendering_info; - /// The depth test requires a depth attachment but render pass has no depth attachment, or - /// depth writing is enabled and the depth attachment is read-only. - NoDepthAttachment, + if view_mask != 0 { + if stages_present.intersects( + ShaderStages::TESSELLATION_CONTROL + | ShaderStages::TESSELLATION_EVALUATION, + ) && !device.enabled_features().multiview_tessellation_shader + { + return Err(ValidationError { + problem: "`stages` contains tessellation shaders, and \ + `subpass.view_mask` is not 0" + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("multiview_tessellation_shader"), + ])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06057"], + ..Default::default() + }); + } - /// The stencil test requires a stencil attachment but render pass has no stencil attachment, or - /// stencil writing is enabled and the stencil attachment is read-only. - NoStencilAttachment, + if stages_present.intersects(ShaderStages::GEOMETRY) + && !device.enabled_features().multiview_geometry_shader + { + return Err(ValidationError { + problem: "`stages` contains a geometry shader, and \ + `subpass.view_mask` is not 0" + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::Feature("multiview_geometry_shader"), + ])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06058"], + ..Default::default() + }); + } + } + } + } + } - /// Not enough memory. - OomError(OomError), + if let Some(discard_rectangle_state) = discard_rectangle_state { + if !device.enabled_extensions().ext_discard_rectangles { + return Err(ValidationError { + context: "discard_rectangle_state".into(), + problem: "is `Some`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_discard_rectangles", + )])]), + ..Default::default() + }); + } - /// Only one tessellation shader stage was provided, the other was not. - OtherTessellationShaderStageMissing, + discard_rectangle_state + .validate(device) + .map_err(|err| err.add_context("discard_rectangle_state"))?; + } - /// The value provided for a shader specialization constant has a - /// different type than the constant's default value. - ShaderSpecializationConstantTypeMismatch { - stage_index: usize, - constant_id: u32, - default_value: SpecializationConstant, - provided_value: SpecializationConstant, - }, + /* + Checks that rely on multiple pieces of state + */ - /// A shader stage was provided more than once. - ShaderStageDuplicate { - stage_index: usize, - stage: ShaderStage, - }, + if let (Some(vertex_stage), Some(vertex_input_state)) = (vertex_stage, vertex_input_state) { + for element in vertex_stage.entry_point.info().input_interface.elements() { + assert!(!element.ty.is_64bit); // TODO: implement + let location_range = + element.location..element.location + element.ty.num_locations(); - /// A shader stage is not a graphics shader. - ShaderStageInvalid { - stage_index: usize, - stage: ShaderStage, - }, + for location in location_range { + let attribute_desc = match vertex_input_state.attributes.get(&location) { + Some(attribute_desc) => attribute_desc, + None => { + return Err(ValidationError { + problem: format!( + "the vertex shader has an input variable with location {0}, but \ + `vertex_input_state.attributes` does not contain {0}", + location, + ) + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-Input-07905"], + ..Default::default() + }); + } + }; - /// The configuration of the pipeline does not use a shader stage, but it was provided. - ShaderStageUnused { stage: ShaderStage }, + // TODO: Check component assignments too. Multiple variables can occupy the + // same location but in different components. - /// The output interface of one shader and the input interface of the next shader do not match. - ShaderStagesMismatch(ShaderInterfaceMismatchError), + let shader_type = element.ty.base_type; + let attribute_type = attribute_desc.format.type_color().unwrap(); - /// The configuration of the pipeline requires a state to be provided, but it was not. - StateMissing { state: &'static str }, + // VUID? + if !matches!( + (shader_type, attribute_type), + ( + ShaderScalarType::Float, + NumericType::SFLOAT + | NumericType::UFLOAT + | NumericType::SNORM + | NumericType::UNORM + | NumericType::SSCALED + | NumericType::USCALED + | NumericType::SRGB, + ) | (ShaderScalarType::Sint, NumericType::SINT) + | (ShaderScalarType::Uint, NumericType::UINT) + ) { + return Err(ValidationError { + problem: format!( + "`vertex_input_state.attributes[{}].format` has a different \ + scalar type than the vertex shader input variable with \ + location {0}", + location, + ) + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-Input-07905"], + ..Default::default() + }); + } + } + } + } - /// The configuration of the pipeline does not use a state, but it was provided. - StateUnused { state: &'static str }, + if let (Some(_), Some(_)) = (tessellation_control_stage, tessellation_evaluation_stage) { + // FIXME: must check that the control shader and evaluation shader are compatible - /// The stencil attachment has a format that does not support that usage. - StencilAttachmentFormatUsageNotSupported, + // TODO: + // VUID-VkGraphicsPipelineCreateInfo-pStages-00732 + // VUID-VkGraphicsPipelineCreateInfo-pStages-00733 + // VUID-VkGraphicsPipelineCreateInfo-pStages-00734 + // VUID-VkGraphicsPipelineCreateInfo-pStages-00735 + } - /// The [`strict_lines`](crate::device::Properties::strict_lines) device property was `false`. - StrictLinesNotSupported, + if let (Some(_), Some(_)) = (tessellation_evaluation_stage, geometry_stage) { + // TODO: + // VUID-VkGraphicsPipelineCreateInfo-pStages-00739 + } - /// The primitives topology does not match what the geometry shader expects. - TopologyNotMatchingGeometryShader, + if let (None, Some(geometry_stage), Some(input_assembly_state)) = ( + tessellation_evaluation_stage, + geometry_stage, + input_assembly_state, + ) { + let entry_point_info = geometry_stage.entry_point.info(); + let input = match entry_point_info.execution { + ShaderExecution::Geometry(execution) => execution.input, + _ => unreachable!(), + }; - /// The type of the shader input variable at the given location is not compatible with the - /// format of the corresponding vertex input attribute. - VertexInputAttributeIncompatibleFormat { - location: u32, - shader_type: ShaderScalarType, - attribute_type: NumericType, - }, + if let PartialStateMode::Fixed(topology) = input_assembly_state.topology { + if !input.is_compatible_with(topology) { + return Err(ValidationError { + problem: "`input_assembly_state.topology` is not compatible with the \ + input topology of the geometry shader" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-00738"], + ..Default::default() + }); + } + } + } - /// The location provided is assigned, but expected to unassigned due to the format of the - /// prior location. - VertexInputAttributeInvalidAssignedLocation { location: u32 }, + if let (Some(fragment_stage), Some(subpass)) = (fragment_stage, subpass) { + let entry_point_info = fragment_stage.entry_point.info(); - /// The binding number specified by a vertex input attribute does not exist in the provided list - /// of binding descriptions. - VertexInputAttributeInvalidBinding { location: u32, binding: u32 }, + // Check that the subpass can accept the output of the fragment shader. + match subpass { + PipelineSubpassType::BeginRenderPass(subpass) => { + if !subpass.is_compatible_with(&entry_point_info.output_interface) { + return Err(ValidationError { + problem: "`subpass` is not compatible with the \ + output interface of the fragment shader" + .into(), + ..Default::default() + }); + } + } + PipelineSubpassType::BeginRendering(_) => { + // TODO: + } + } - /// The vertex shader expects an input variable at the given location, but no vertex input - /// attribute exists for that location. - VertexInputAttributeMissing { location: u32 }, + // TODO: + // VUID-VkGraphicsPipelineCreateInfo-pStages-01565 + // VUID-VkGraphicsPipelineCreateInfo-renderPass-06038 + // VUID-VkGraphicsPipelineCreateInfo-renderPass-06056 + // VUID-VkGraphicsPipelineCreateInfo-renderPass-06061 + } - /// The format specified by a vertex input attribute is not supported for vertex buffers. - VertexInputAttributeUnsupportedFormat { location: u32, format: Format }, + if let (Some(input_assembly_state), Some(_)) = (input_assembly_state, tessellation_state) { + if !matches!( + input_assembly_state.topology, + PartialStateMode::Dynamic(PrimitiveTopologyClass::Patch) + | PartialStateMode::Fixed(PrimitiveTopology::PatchList) + ) { + return Err(ValidationError { + problem: "`stages` contains tessellation shaders, but \ + `input_assembly_state.topology` is not `PrimitiveTopology::PatchList`" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pStages-00736"], + ..Default::default() + }); + } + } - /// No vertex shader stage was provided. - VertexShaderStageMissing, + if let (Some(rasterization_state), Some(depth_stencil_state)) = + (rasterization_state, depth_stencil_state) + { + if let Some(stencil_state) = &depth_stencil_state.stencil { + if let (StateMode::Fixed(front_reference), StateMode::Fixed(back_reference)) = + (stencil_state.front.reference, stencil_state.back.reference) + { + if device.enabled_extensions().khr_portability_subset + && !device.enabled_features().separate_stencil_mask_ref + && matches!( + rasterization_state.cull_mode, + StateMode::Fixed(CullMode::None) + ) + && front_reference != back_reference + { + return Err(ValidationError { + problem: "this device is a portability subset device, \ + `rasterization_state.cull_mode` is `CullMode::None`, and \ + `depth_stencil_state.stencil.front.reference` does not equal \ + `depth_stencil_state.stencil.back.reference`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "separate_stencil_mask_ref", + )])]), + vuids: &["VUID-VkPipelineDepthStencilStateCreateInfo-separateStencilMaskRef-04453"], + ..Default::default() + }); + } + } + } + } - /// The minimum or maximum bounds of viewports have been exceeded. - ViewportBoundsExceeded, + if let (Some(multisample_state), Some(subpass)) = (multisample_state, subpass) { + match subpass { + PipelineSubpassType::BeginRenderPass(subpass) => { + if let Some(samples) = subpass.num_samples() { + if multisample_state.rasterization_samples != samples { + return Err(ValidationError { + problem: "`multisample_state.rasterization_samples` does not \ + equal the number of samples in the color and depth/stencil \ + attachments of `subpass`" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-subpass-00757"], + ..Default::default() + }); + } + } - /// The wrong type of shader has been passed. - /// - /// For example you passed a vertex shader as the fragment shader. - WrongShaderType, + // TODO: + // VUID-VkGraphicsPipelineCreateInfo-subpass-00758 + // VUID-VkGraphicsPipelineCreateInfo-subpass-01505 + // VUID-VkGraphicsPipelineCreateInfo-subpass-01411 + // VUID-VkGraphicsPipelineCreateInfo-subpass-01412 + } + PipelineSubpassType::BeginRendering(_) => { + // No equivalent VUIDs for dynamic rendering, as no sample count information + // is provided until `begin_rendering`. + } + } + } - /// The requested stencil test is invalid. - WrongStencilState, -} + if let (Some(depth_stencil_state), Some(subpass)) = (depth_stencil_state, subpass) { + if let Some(depth_state) = &depth_stencil_state.depth { + let has_depth_attachment = match subpass { + PipelineSubpassType::BeginRenderPass(subpass) => subpass + .subpass_desc() + .depth_stencil_attachment + .as_ref() + .map_or(false, |depth_stencil_attachment| { + subpass.render_pass().attachments() + [depth_stencil_attachment.attachment as usize] + .format + .unwrap() + .aspects() + .intersects(ImageAspects::DEPTH) + }), + PipelineSubpassType::BeginRendering(rendering_info) => { + rendering_info.depth_attachment_format.is_some() + } + }; -impl Error for GraphicsPipelineCreationError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - Self::OomError(err) => Some(err), - Self::IncompatiblePipelineLayout(err) => Some(err), - Self::ShaderStagesMismatch(err) => Some(err), - _ => None, - } - } -} + if !has_depth_attachment { + return Err(ValidationError { + problem: "`depth_stencil_state.depth` is `Some`, but `subpass` does not \ + have a depth attachment" + .into(), + // vuids? + ..Default::default() + }); + } -impl Display for GraphicsPipelineCreationError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - Self::RequirementNotMet { - required_for, - requires_one_of, - } => write!( - f, - "a requirement was not met for: {}; requires one of: {}", - required_for, requires_one_of, - ), - Self::ColorAttachmentFormatBlendNotSupported { attachment_index } => write!( - f, - "color attachment {} has a format that does not support blending", - attachment_index, - ), - Self::ColorAttachmentFormatUsageNotSupported { attachment_index } => write!( - f, - "color attachment {} has a format that does not support that usage", - attachment_index, - ), - Self::DepthAttachmentFormatUsageNotSupported => write!( - f, - "the depth attachment has a format that does not support that usage", - ), - Self::DepthStencilAttachmentFormatMismatch => write!( - f, - "the depth and stencil attachments have different formats", - ), - Self::FragmentShaderRenderPassIncompatible => write!( - f, - "the output of the fragment shader is not compatible with what the render pass \ - subpass expects", - ), - Self::IncompatiblePipelineLayout(_) => write!( - f, - "the pipeline layout is not compatible with what the shaders expect", - ), - Self::InvalidPrimitiveTopology => write!( - f, - "trying to use a patch list without a tessellation shader, or a non-patch-list \ - with a tessellation shader", - ), - Self::InvalidNumPatchControlPoints => write!( - f, - "patch_control_points was not greater than 0 and less than or equal to the \ - max_tessellation_patch_size limit", - ), - Self::MaxDiscardRectanglesExceeded { .. } => write!( - f, - "the maximum number of discard rectangles has been exceeded", - ), - Self::MaxMultiviewViewCountExceeded { .. } => { - write!(f, "the `max_multiview_view_count` limit has been exceeded") - } - Self::MaxVertexAttribDivisorExceeded { .. } => write!( - f, - "the maximum value for the instance rate divisor has been exceeded", - ), - Self::MaxVertexInputAttributesExceeded { .. } => write!( - f, - "the maximum number of vertex attributes has been exceeded", - ), - Self::MaxVertexInputAttributeOffsetExceeded { .. } => write!( - f, - "the maximum offset for a vertex attribute has been exceeded", - ), - Self::MaxVertexInputBindingsExceeded { .. } => { - write!(f, "the maximum number of vertex sources has been exceeded") - } - Self::MaxVertexInputBindingStrideExceeded { .. } => write!( - f, - "the maximum stride value for vertex input (ie. the distance between two vertex \ - elements) has been exceeded", - ), - Self::MaxViewportsExceeded { .. } => { - write!(f, "the maximum number of viewports has been exceeded") - } - Self::MaxViewportDimensionsExceeded => { - write!(f, "the maximum dimensions of viewports has been exceeded") + if let StateMode::Fixed(true) = depth_state.write_enable { + match subpass { + PipelineSubpassType::BeginRenderPass(subpass) => { + if !subpass + .subpass_desc() + .depth_stencil_attachment + .as_ref() + .filter(|depth_stencil_attachment| { + depth_stencil_attachment + .layout + .is_writable(ImageAspect::Depth) + }) + .map_or(false, |depth_stencil_attachment| { + subpass.render_pass().attachments() + [depth_stencil_attachment.attachment as usize] + .format + .unwrap() + .aspects() + .intersects(ImageAspects::DEPTH) + }) + { + return Err(ValidationError { + problem: "`depth_stencil_state.depth.write_enable` is `true`, \ + but `subpass` does not have a depth attachment whose \ + layout for the depth aspect allows writing" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06039"], + ..Default::default() + }); + } + } + PipelineSubpassType::BeginRendering(_) => { + // No VUID? + } + } + } } - Self::MinVertexInputBindingStrideAlignmentExceeded { .. } => write!( - f, - "the `min_vertex_input_binding_stride_alignment` limit has been exceeded", - ), - Self::MismatchBlendingAttachmentsCount => write!( - f, - "the number of attachments specified in the blending does not match the number of \ - attachments in the subpass", - ), - Self::MultisampleRasterizationSamplesMismatch => write!( - f, - "the provided `rasterization_samples` does not match the number of samples of the \ - render subpass", - ), - Self::NoDepthAttachment => write!( - f, - "the depth attachment of the render pass does not match the depth test", - ), - Self::NoStencilAttachment => write!( - f, - "the stencil attachment of the render pass does not match the stencil test", - ), - Self::OomError(_) => write!(f, "not enough memory available"), - Self::OtherTessellationShaderStageMissing => write!( - f, - "only one tessellation shader stage was provided, the other was not", - ), - Self::ShaderSpecializationConstantTypeMismatch { - stage_index, - constant_id, - default_value, - provided_value, - } => write!( - f, - "the value provided for shader {} specialization constant id {} ({:?}) has a \ - different type than the constant's default value ({:?})", - stage_index, constant_id, provided_value, default_value, - ), - Self::ShaderStageDuplicate { - stage_index, - stage, - } => write!( - f, - "the shader stage at index {} (stage: {:?}) was provided more than once", - stage_index, stage, - ), - Self::ShaderStageInvalid { - stage_index, - stage, - } => write!( - f, - "the shader stage at index {} (stage: {:?}) is not a graphics shader", - stage_index, stage, - ), - Self::ShaderStageUnused { - stage, - } => write!( - f, - "the configuration of the pipeline does not use the `{:?}` shader stage, but it was provided", - stage, - ), - Self::ShaderStagesMismatch(_) => write!( - f, - "the output interface of one shader and the input interface of the next shader do \ - not match", - ), - Self::StateMissing { state } => write!( - f, - "the configuration of the pipeline requires `{}` to be provided, but it was not", - state, - ), - Self::StateUnused { state } => write!( - f, - "the configuration of the pipeline does not use `{}`, but it was provided", - state, - ), - Self::StencilAttachmentFormatUsageNotSupported => write!( - f, - "the stencil attachment has a format that does not support that usage", - ), - Self::StrictLinesNotSupported => { - write!(f, "the strict_lines device property was false") + + if depth_stencil_state.stencil.is_some() { + let has_stencil_attachment = match subpass { + PipelineSubpassType::BeginRenderPass(subpass) => subpass + .subpass_desc() + .depth_stencil_attachment + .as_ref() + .map_or(false, |depth_stencil_attachment| { + subpass.render_pass().attachments() + [depth_stencil_attachment.attachment as usize] + .format + .unwrap() + .aspects() + .intersects(ImageAspects::STENCIL) + }), + PipelineSubpassType::BeginRendering(rendering_info) => { + rendering_info.stencil_attachment_format.is_some() + } + }; + + if !has_stencil_attachment { + return Err(ValidationError { + problem: "`depth_stencil_state.stencil` is `Some`, but `subpass` does not \ + have a stencil attachment" + .into(), + // vuids? + ..Default::default() + }); + } } - Self::TopologyNotMatchingGeometryShader => write!( - f, - "the primitives topology does not match what the geometry shader expects", - ), - Self::VertexInputAttributeIncompatibleFormat { - location, - shader_type, - attribute_type, - } => write!( - f, - "the type of the shader input variable at location {} ({:?}) is not compatible \ - with the format of the corresponding vertex input attribute ({:?})", - location, shader_type, attribute_type, - ), - Self::VertexInputAttributeInvalidAssignedLocation { location } => write!( - f, - "input attribute location {} is expected to be unassigned due to the format of the prior location", - location, - ), - Self::VertexInputAttributeInvalidBinding { location, binding } => write!( - f, - "the binding number {} specified by vertex input attribute location {} does not \ - exist in the provided list of binding descriptions", - binding, location, - ), - Self::VertexInputAttributeMissing { location } => write!( - f, - "the vertex shader expects an input variable at location {}, but no vertex input \ - attribute exists for that location", - location, - ), - Self::VertexInputAttributeUnsupportedFormat { location, format } => write!( - f, - "the format {:?} specified by vertex input attribute location {} is not supported \ - for vertex buffers", - format, location, - ), - Self::VertexShaderStageMissing => write!( - f, - "no vertex shader stage was provided", - ), - Self::ViewportBoundsExceeded => write!( - f, - "the minimum or maximum bounds of viewports have been exceeded", - ), - Self::WrongShaderType => write!(f, "the wrong type of shader has been passed"), - Self::WrongStencilState => write!(f, "the requested stencil test is invalid"), } - } -} -impl From for GraphicsPipelineCreationError { - fn from(err: OomError) -> GraphicsPipelineCreationError { - Self::OomError(err) - } -} + if let (Some(color_blend_state), Some(subpass)) = (color_blend_state, subpass) { + let color_attachment_count = match subpass { + PipelineSubpassType::BeginRenderPass(subpass) => { + subpass.subpass_desc().color_attachments.len() + } + PipelineSubpassType::BeginRendering(rendering_info) => { + rendering_info.color_attachment_formats.len() + } + }; -impl From for GraphicsPipelineCreationError { - fn from(err: PipelineLayoutSupersetError) -> Self { - Self::IncompatiblePipelineLayout(err) - } -} + if color_attachment_count != color_blend_state.attachments.len() { + return Err(ValidationError { + problem: "the length of `color_blend_state.attachments` does not equal the \ + number of color attachments in `subpass`" + .into(), + vuids: &[ + "VUID-VkGraphicsPipelineCreateInfo-renderPass-06042", + "VUID-VkGraphicsPipelineCreateInfo-renderPass-06055", + "VUID-VkGraphicsPipelineCreateInfo-renderPass-06060", + ], + ..Default::default() + }); + } -impl From for GraphicsPipelineCreationError { - fn from(err: RuntimeError) -> Self { - match err { - err @ RuntimeError::OutOfHostMemory => Self::OomError(OomError::from(err)), - err @ RuntimeError::OutOfDeviceMemory => Self::OomError(OomError::from(err)), - _ => panic!("unexpected error: {:?}", err), - } - } -} + for (attachment_index, state) in color_blend_state.attachments.iter().enumerate() { + if state.blend.is_some() { + let attachment_format = match subpass { + PipelineSubpassType::BeginRenderPass(subpass) => { + subpass.subpass_desc().color_attachments[attachment_index] + .as_ref() + .and_then(|color_attachment| { + subpass.render_pass().attachments() + [color_attachment.attachment as usize] + .format + }) + } + PipelineSubpassType::BeginRendering(rendering_info) => { + rendering_info.color_attachment_formats[attachment_index] + } + }; -impl From for GraphicsPipelineCreationError { - fn from(err: RequirementNotMet) -> Self { - Self::RequirementNotMet { - required_for: err.required_for, - requires_one_of: err.requires_one_of, + if !attachment_format.map_or(false, |format| unsafe { + device + .physical_device() + .format_properties_unchecked(format) + .potential_format_features() + .intersects(FormatFeatures::COLOR_ATTACHMENT_BLEND) + }) { + return Err(ValidationError { + problem: format!( + "`color_blend_state.attachments[{}].blend` is `Some`, but \ + the format features of that color attachment in `subpass` \ + do not contain `FormatFeatures::COLOR_ATTACHMENT_BLEND`", + attachment_index + ) + .into(), + vuids: &[ + "VUID-VkGraphicsPipelineCreateInfo-renderPass-06041", + "VUID-VkGraphicsPipelineCreateInfo-renderPass-06062", + ], + ..Default::default() + }); + } + } + } } + + Ok(()) } } diff --git a/vulkano/src/pipeline/graphics/multisample.rs b/vulkano/src/pipeline/graphics/multisample.rs index 67476cc69f..aa23cc9a2c 100644 --- a/vulkano/src/pipeline/graphics/multisample.rs +++ b/vulkano/src/pipeline/graphics/multisample.rs @@ -10,7 +10,9 @@ //! Generates multiple fragments per framebuffer pixel when rasterizing. This can be used for //! anti-aliasing. -use crate::image::SampleCount; +use crate::{ + device::Device, image::SampleCount, Requires, RequiresAllOf, RequiresOneOf, ValidationError, +}; // TODO: handle some weird behaviors with non-floating-point targets @@ -69,6 +71,61 @@ impl MultisampleState { alpha_to_one_enable: false, } } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + rasterization_samples, + sample_shading, + sample_mask: _, + alpha_to_coverage_enable: _, + alpha_to_one_enable, + } = self; + + rasterization_samples + .validate_device(device) + .map_err(|err| ValidationError { + context: "rasterization_samples".into(), + vuids: &[ + "VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-parameter", + ], + ..ValidationError::from_requirement(err) + })?; + + if let Some(min_sample_shading) = sample_shading { + if !device.enabled_features().sample_rate_shading { + return Err(ValidationError { + context: "min_sample_shading".into(), + problem: "is `Some`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "sample_rate_shading", + )])]), + vuids: &["VUID-VkPipelineMultisampleStateCreateInfo-sampleShadingEnable-00784"], + }); + } + + if !(0.0..=1.0).contains(&min_sample_shading) { + return Err(ValidationError { + context: "min_sample_shading".into(), + problem: "is not between 0.0 and 1.0 inclusive".into(), + vuids: &["VUID-VkPipelineMultisampleStateCreateInfo-minSampleShading-00786"], + ..Default::default() + }); + } + } + + if alpha_to_one_enable && !device.enabled_features().alpha_to_one { + return Err(ValidationError { + context: "alpha_to_one_enable".into(), + problem: "is `true`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "alpha_to_one", + )])]), + vuids: &["VUID-VkPipelineMultisampleStateCreateInfo-alphaToOneEnable-00785"], + }); + } + + Ok(()) + } } impl Default for MultisampleState { diff --git a/vulkano/src/pipeline/graphics/rasterization.rs b/vulkano/src/pipeline/graphics/rasterization.rs index 7ab586698e..7af35003ce 100644 --- a/vulkano/src/pipeline/graphics/rasterization.rs +++ b/vulkano/src/pipeline/graphics/rasterization.rs @@ -9,7 +9,10 @@ //! Configures how primitives should be converted into collections of fragments. -use crate::{macros::vulkan_enum, pipeline::StateMode}; +use crate::{ + device::Device, macros::vulkan_enum, pipeline::StateMode, Requires, RequiresAllOf, + RequiresOneOf, ValidationError, Version, +}; /// The state in a graphics pipeline describing how the rasterization stage should behave. #[derive(Clone, Debug)] @@ -133,6 +136,354 @@ impl RasterizationState { self.front_face = StateMode::Dynamic; self } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + depth_clamp_enable, + rasterizer_discard_enable, + polygon_mode, + cull_mode, + front_face, + ref depth_bias, + line_width, + line_rasterization_mode, + ref line_stipple, + } = self; + + let properties = device.physical_device().properties(); + + polygon_mode + .validate_device(device) + .map_err(|err| ValidationError { + context: "polygon_mode".into(), + vuids: &["VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-parameter"], + ..ValidationError::from_requirement(err) + })?; + + line_rasterization_mode + .validate_device(device) + .map_err(|err| ValidationError { + context: "line_rasterization_mode".into(), + vuids: &["VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if depth_clamp_enable && !device.enabled_features().depth_clamp { + return Err(ValidationError { + context: "depth_clamp_enable".into(), + problem: "is `true`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "depth_clamp", + )])]), + vuids: &["VUID-VkPipelineRasterizationStateCreateInfo-depthClampEnable-00782"], + }); + } + + if polygon_mode != PolygonMode::Fill && !device.enabled_features().fill_mode_non_solid { + return Err(ValidationError { + context: "polygon_mode".into(), + problem: "is not `PolygonMode::Fill`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "fill_mode_non_solid", + )])]), + vuids: &["VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-01507"], + }); + } + + match rasterizer_discard_enable { + StateMode::Fixed(false) => { + if device.enabled_extensions().khr_portability_subset + && !device.enabled_features().point_polygons + && polygon_mode == PolygonMode::Point + { + return Err(ValidationError { + problem: "this device is a portability subset device, \ + `rasterizer_discard_enable` is `false`, and \ + `polygon_mode` is `PolygonMode::Point`" + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "point_polygons", + )])]), + vuids: &["VUID-VkPipelineRasterizationStateCreateInfo-pointPolygons-04458"], + ..Default::default() + }); + } + } + StateMode::Dynamic => { + if !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state2) + { + return Err(ValidationError { + context: "rasterizer_discard_enable".into(), + problem: "is dynamic".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), + // vuids? + ..Default::default() + }); + } + } + _ => (), + } + + match cull_mode { + StateMode::Fixed(cull_mode) => { + cull_mode + .validate_device(device) + .map_err(|err| ValidationError { + context: "cull_mode".into(), + vuids: &["VUID-VkPipelineRasterizationStateCreateInfo-cullMode-parameter"], + ..ValidationError::from_requirement(err) + })?; + } + StateMode::Dynamic => { + if !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state) + { + return Err(ValidationError { + context: "cull_mode".into(), + problem: "is dynamic".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), + // vuids? + ..Default::default() + }); + } + } + } + + match front_face { + StateMode::Fixed(front_face) => { + front_face + .validate_device(device) + .map_err(|err| ValidationError { + context: "front_face".into(), + vuids: &["VUID-VkPipelineRasterizationStateCreateInfo-frontFace-parameter"], + ..ValidationError::from_requirement(err) + })?; + } + StateMode::Dynamic => { + if !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state) + { + return Err(ValidationError { + context: "front_face".into(), + problem: "is dynamic".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]), + ]), + // vuids? + ..Default::default() + }); + } + } + } + + if let Some(depth_bias_state) = depth_bias { + let &DepthBiasState { + enable_dynamic, + bias, + } = depth_bias_state; + + if enable_dynamic + && !(device.api_version() >= Version::V1_3 + || device.enabled_features().extended_dynamic_state2) + { + return Err(ValidationError { + context: "depth_bias.enable_dynamic".into(), + problem: "is `true`".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]), + RequiresAllOf(&[Requires::Feature("extended_dynamic_state2")]), + ]), + // vuids? + ..Default::default() + }); + } + + if matches!(bias, StateMode::Fixed(bias) if bias.clamp != 0.0) + && !device.enabled_features().depth_bias_clamp + { + return Err(ValidationError { + context: "depth_bias.bias.clamp".into(), + problem: "is not 0.0".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "depth_bias_clamp", + )])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00754"], + }); + } + } + + if matches!(line_width, StateMode::Fixed(line_width) if line_width != 1.0) + && !device.enabled_features().wide_lines + { + return Err(ValidationError { + context: "line_width".into(), + problem: "is not 1.0".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "wide_lines", + )])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00749"], + }); + } + + if line_rasterization_mode != LineRasterizationMode::Default { + if !device.enabled_extensions().ext_line_rasterization { + return Err(ValidationError { + context: "line_rasterization_mode".into(), + problem: "`is not `LineRasterizationMode::Default`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_line_rasterization", + )])]), + ..Default::default() + }); + } + + match line_rasterization_mode { + LineRasterizationMode::Default => (), + LineRasterizationMode::Rectangular => { + if !device.enabled_features().rectangular_lines { + return Err(ValidationError { + context: "line_rasterization_mode".into(), + problem: "is `LineRasterizationMode::Rectangular`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "rectangular_lines", + )])]), + vuids: &["VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02768"], + }); + } + } + LineRasterizationMode::Bresenham => { + if !device.enabled_features().bresenham_lines { + return Err(ValidationError { + context: "line_rasterization_mode".into(), + problem: "is `LineRasterizationMode::Bresenham`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "bresenham_lines", + )])]), + vuids: &["VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02769"], + }); + } + } + LineRasterizationMode::RectangularSmooth => { + if !device.enabled_features().smooth_lines { + return Err(ValidationError { + context: "line_rasterization_mode".into(), + problem: "is `LineRasterizationMode::RectangularSmooth`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "smooth_lines", + )])]), + vuids: &["VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02770"], + }); + } + } + } + } + + if let Some(line_stipple) = line_stipple { + if !device.enabled_extensions().ext_line_rasterization { + return Err(ValidationError { + context: "line_stipple".into(), + problem: "is `Some`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_line_rasterization", + )])]), + ..Default::default() + }); + } + + if let StateMode::Fixed(line_stipple) = line_stipple { + let &LineStipple { factor, pattern: _ } = line_stipple; + + if !(1..=256).contains(&factor) { + return Err(ValidationError { + context: "line_stipple.factor".into(), + problem: "is not between 1 and 256 inclusive".into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-stippledLineEnable-02767"], + ..Default::default() + }); + } + } + + match line_rasterization_mode { + LineRasterizationMode::Default => { + if !device.enabled_features().stippled_rectangular_lines { + return Err(ValidationError { + problem: "`line_stipple` is `Some`, and \ + `line_rasterization_mode` is \ + `LineRasterizationMode::Default`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "stippled_rectangular_lines", + )])]), + vuids: &["VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02774"], + ..Default::default() + }); + } + + if !properties.strict_lines { + return Err(ValidationError { + problem: "`line_stipple` is `Some`, and \ + `line_rasterization_mode` is \ + `LineRasterizationMode::Default`, \ + but the `strict_lines` property is `false`".into(), + vuids: &["VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02774"], + ..Default::default() + }); + } + } + LineRasterizationMode::Rectangular => { + if !device.enabled_features().stippled_rectangular_lines { + return Err(ValidationError { + problem: "`line_stipple` is `Some`, and \ + `line_rasterization_mode` is \ + `LineRasterizationMode::Rectangular`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "stippled_rectangular_lines", + )])]), + vuids: &["VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02771"], + ..Default::default() + }); + } + } + LineRasterizationMode::Bresenham => { + if !device.enabled_features().stippled_bresenham_lines { + return Err(ValidationError { + problem: "`line_stipple` is `Some`, and \ + `line_rasterization_mode` is \ + `LineRasterizationMode::Bresenham`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "stippled_bresenham_lines", + )])]), + vuids: &["VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02772"], + ..Default::default() + }); + } + } + LineRasterizationMode::RectangularSmooth => { + if !device.enabled_features().stippled_smooth_lines { + return Err(ValidationError { + problem: "`line_stipple` is `Some`, and \ + `line_rasterization_mode` is \ + `LineRasterizationMode::RectangularSmooth`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "stippled_smooth_lines", + )])]), + vuids: &["VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02773"], + ..Default::default() + }); + } + } + } + } + + Ok(()) + } } impl Default for RasterizationState { diff --git a/vulkano/src/pipeline/graphics/subpass.rs b/vulkano/src/pipeline/graphics/subpass.rs index a3091a2684..8fe541d80b 100644 --- a/vulkano/src/pipeline/graphics/subpass.rs +++ b/vulkano/src/pipeline/graphics/subpass.rs @@ -9,9 +9,11 @@ use crate::{ command_buffer::{CommandBufferInheritanceRenderingInfo, RenderingInfo}, - format::Format, + device::Device, + format::{Format, FormatFeatures}, image::ImageAspects, render_pass::Subpass, + Requires, RequiresAllOf, RequiresOneOf, ValidationError, }; /// Selects the type of subpass that a graphics pipeline is created for. @@ -148,4 +150,150 @@ impl PipelineRenderingCreateInfo { _ne: crate::NonExhaustive(()), } } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + view_mask, + ref color_attachment_formats, + depth_attachment_format, + stencil_attachment_format, + _ne: _, + } = self; + + let properties = device.physical_device().properties(); + + if view_mask != 0 && !device.enabled_features().multiview { + return Err(ValidationError { + context: "view_mask".into(), + problem: "is not zero".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("multiview")])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-multiview-06577"], + }); + } + + let view_count = u32::BITS - view_mask.leading_zeros(); + + if view_count > properties.max_multiview_view_count.unwrap_or(0) { + return Err(ValidationError { + context: "view_mask".into(), + problem: "the number of views exceeds the \ + `max_multiview_view_count` limit" + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("multiview")])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06578"], + }); + } + + for (attachment_index, format) in color_attachment_formats + .iter() + .enumerate() + .flat_map(|(i, f)| f.map(|f| (i, f))) + { + let attachment_index = attachment_index as u32; + + format + .validate_device(device) + .map_err(|err| ValidationError { + context: "format".into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06580"], + ..ValidationError::from_requirement(err) + })?; + + if !unsafe { device.physical_device().format_properties_unchecked(format) } + .potential_format_features() + .intersects(FormatFeatures::COLOR_ATTACHMENT) + { + return Err(ValidationError { + context: format!("color_attachment_formats[{}]", attachment_index).into(), + problem: "format features do not contain \ + `FormatFeature::COLOR_ATTACHMENT`" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06582"], + ..Default::default() + }); + } + } + + if let Some(format) = depth_attachment_format { + format + .validate_device(device) + .map_err(|err| ValidationError { + context: "format".into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06583"], + ..ValidationError::from_requirement(err) + })?; + + if !unsafe { device.physical_device().format_properties_unchecked(format) } + .potential_format_features() + .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) + { + return Err(ValidationError { + context: "depth_attachment_format".into(), + problem: "format features do not contain \ + `FormatFeature::DEPTH_STENCIL_ATTACHMENT`" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06585"], + ..Default::default() + }); + } + + if !format.aspects().intersects(ImageAspects::DEPTH) { + return Err(ValidationError { + context: "depth_attachment_format".into(), + problem: "does not have a depth aspect".into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06587"], + ..Default::default() + }); + } + } + + if let Some(format) = stencil_attachment_format { + format + .validate_device(device) + .map_err(|err| ValidationError { + context: "format".into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06584"], + ..ValidationError::from_requirement(err) + })?; + + if !unsafe { device.physical_device().format_properties_unchecked(format) } + .potential_format_features() + .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) + { + return Err(ValidationError { + context: "render_pass.stencil_attachment_format".into(), + problem: "format features do not contain \ + `FormatFeature::DEPTH_STENCIL_ATTACHMENT`" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06586"], + ..Default::default() + }); + } + + if !format.aspects().intersects(ImageAspects::STENCIL) { + return Err(ValidationError { + context: "render_pass.stencil_attachment_format".into(), + problem: "does not have a stencil aspect".into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06588"], + ..Default::default() + }); + } + } + + if let (Some(depth_format), Some(stencil_format)) = + (depth_attachment_format, stencil_attachment_format) + { + if depth_format != stencil_format { + return Err(ValidationError { + problem: "`depth_attachment_format` and `stencil_attachment_format` are both \ + `Some`, but are not equal" + .into(), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-renderPass-06589"], + ..Default::default() + }); + } + } + + Ok(()) + } } diff --git a/vulkano/src/pipeline/graphics/tessellation.rs b/vulkano/src/pipeline/graphics/tessellation.rs index e508b52b4a..8c0b77d9bc 100644 --- a/vulkano/src/pipeline/graphics/tessellation.rs +++ b/vulkano/src/pipeline/graphics/tessellation.rs @@ -9,7 +9,10 @@ //! Subdivides primitives into smaller primitives. -use crate::{macros::vulkan_enum, pipeline::StateMode}; +use crate::{ + device::Device, macros::vulkan_enum, pipeline::StateMode, Requires, RequiresAllOf, + RequiresOneOf, ValidationError, Version, +}; /// The state in a graphics pipeline describing the tessellation shader execution of a graphics /// pipeline. @@ -55,6 +58,83 @@ impl TessellationState { self.patch_control_points = StateMode::Dynamic; self } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + patch_control_points, + domain_origin, + } = self; + + let properties = device.physical_device().properties(); + + match patch_control_points { + StateMode::Fixed(patch_control_points) => { + if patch_control_points == 0 { + return Err(ValidationError { + context: "patch_control_points".into(), + problem: "is zero".into(), + vuids: &[ + "VUID-VkPipelineTessellationStateCreateInfo-patchControlPoints-01214", + ], + ..Default::default() + }); + } + + if patch_control_points > properties.max_tessellation_patch_size { + return Err(ValidationError { + context: "patch_control_points".into(), + problem: "exceeds the `max_tessellation_patch_size` limit".into(), + vuids: &[ + "VUID-VkPipelineTessellationStateCreateInfo-patchControlPoints-01214", + ], + ..Default::default() + }); + } + } + StateMode::Dynamic => { + if !device + .enabled_features() + .extended_dynamic_state2_patch_control_points + { + return Err(ValidationError { + context: "patch_control_points".into(), + problem: "is dynamic".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "extended_dynamic_state2_patch_control_points", + )])]), + vuids: &["VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04870"], + }); + } + } + }; + + domain_origin + .validate_device(device) + .map_err(|err| ValidationError { + context: "domain_origin".into(), + vuids: &[ + "VUID-VkPipelineTessellationDomainOriginStateCreateInfo-domainOrigin-parameter", + ], + ..ValidationError::from_requirement(err) + })?; + + if domain_origin != TessellationDomainOrigin::UpperLeft + && !(device.api_version() >= Version::V1_1 + || device.enabled_extensions().khr_maintenance2) + { + return Err(ValidationError { + context: "domain_origin".into(), + problem: "is not `TessellationDomainOrigin::UpperLeft`".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_maintenance2")]), + ]), + ..Default::default() + }); + } + + Ok(()) + } } impl Default for TessellationState { diff --git a/vulkano/src/pipeline/graphics/vertex_input/buffers.rs b/vulkano/src/pipeline/graphics/vertex_input/buffers.rs index b7637e6cdd..8f45c59195 100644 --- a/vulkano/src/pipeline/graphics/vertex_input/buffers.rs +++ b/vulkano/src/pipeline/graphics/vertex_input/buffers.rs @@ -9,10 +9,9 @@ use super::VertexBufferDescription; use crate::{ - pipeline::graphics::vertex_input::{ - IncompatibleVertexDefinitionError, Vertex, VertexDefinition, VertexInputState, - }, + pipeline::graphics::vertex_input::{Vertex, VertexDefinition, VertexInputState}, shader::ShaderInterface, + ValidationError, }; /// A vertex definition for any number of vertex and instance buffers. @@ -63,10 +62,7 @@ impl BuffersDefinition { #[allow(deprecated)] unsafe impl VertexDefinition for BuffersDefinition { #[inline] - fn definition( - &self, - interface: &ShaderInterface, - ) -> Result { + fn definition(&self, interface: &ShaderInterface) -> Result { self.0.definition(interface) } } diff --git a/vulkano/src/pipeline/graphics/vertex_input/definition.rs b/vulkano/src/pipeline/graphics/vertex_input/definition.rs index d82ee0253c..0bc6511ebc 100644 --- a/vulkano/src/pipeline/graphics/vertex_input/definition.rs +++ b/vulkano/src/pipeline/graphics/vertex_input/definition.rs @@ -11,65 +11,19 @@ use super::{ VertexBufferDescription, VertexInputAttributeDescription, VertexInputBindingDescription, }; use crate::{ - pipeline::graphics::vertex_input::{VertexInputState, VertexMemberInfo}, - shader::{ShaderInterface, ShaderInterfaceEntryType}, - DeviceSize, -}; -use std::{ - error::Error, - fmt::{Display, Error as FmtError, Formatter}, + pipeline::graphics::vertex_input::VertexInputState, shader::ShaderInterface, DeviceSize, + ValidationError, }; /// Trait for types that can create a [`VertexInputState`] from a [`ShaderInterface`]. pub unsafe trait VertexDefinition { /// Builds the `VertexInputState` for the provided `interface`. - fn definition( - &self, - interface: &ShaderInterface, - ) -> Result; -} - -/// Error that can happen when the vertex definition doesn't match the input of the vertex shader. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum IncompatibleVertexDefinitionError { - /// An attribute of the vertex shader is missing in the vertex source. - MissingAttribute { - /// Name of the missing attribute. - attribute: String, - }, - - /// The format of an attribute does not match. - FormatMismatch { - /// Name of the attribute. - attribute: String, - /// The format in the vertex shader. - shader: ShaderInterfaceEntryType, - /// The format in the vertex definition. - definition: VertexMemberInfo, - }, -} - -impl Error for IncompatibleVertexDefinitionError {} - -impl Display for IncompatibleVertexDefinitionError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - IncompatibleVertexDefinitionError::MissingAttribute { .. } => { - write!(f, "an attribute is missing") - } - IncompatibleVertexDefinitionError::FormatMismatch { .. } => { - write!(f, "the format of an attribute does not match") - } - } - } + fn definition(&self, interface: &ShaderInterface) -> Result; } unsafe impl VertexDefinition for &[VertexBufferDescription] { #[inline] - fn definition( - &self, - interface: &ShaderInterface, - ) -> Result { + fn definition(&self, interface: &ShaderInterface) -> Result { let bindings = self.iter().enumerate().map(|(binding, buffer)| { ( binding as u32, @@ -82,7 +36,7 @@ unsafe impl VertexDefinition for &[VertexBufferDescription] { let mut attributes: Vec<(u32, VertexInputAttributeDescription)> = Vec::new(); for element in interface.elements() { - let name = element.name.as_ref().unwrap().clone().into_owned(); + let name = element.name.as_ref().unwrap(); let (infos, binding) = self .iter() @@ -90,11 +44,17 @@ unsafe impl VertexDefinition for &[VertexBufferDescription] { .find_map(|(binding, buffer)| { buffer .members - .get(&name) + .get(name.as_ref()) .map(|infos| (infos.clone(), binding as u32)) }) - .ok_or_else(|| IncompatibleVertexDefinitionError::MissingAttribute { - attribute: name.clone(), + .ok_or_else(|| ValidationError { + problem: format!( + "the shader interface contains a variable named \"{}\", \ + but no such attribute exists in the vertex definition", + name, + ) + .into(), + ..Default::default() })?; // TODO: ShaderInterfaceEntryType does not properly support 64bit. @@ -103,10 +63,15 @@ unsafe impl VertexDefinition for &[VertexBufferDescription] { if infos.num_components() != element.ty.num_components || infos.num_elements != element.ty.num_locations() { - return Err(IncompatibleVertexDefinitionError::FormatMismatch { - attribute: name, - shader: element.ty, - definition: infos, + return Err(ValidationError { + problem: format!( + "for the variable \"{}\", the number of locations and components \ + required by the shader don't match the number of locations and components \ + of the type provided in the vertex definition", + name, + ) + .into(), + ..Default::default() }); } @@ -141,30 +106,21 @@ unsafe impl VertexDefinition for &[VertexBufferDescription] { unsafe impl VertexDefinition for [VertexBufferDescription; N] { #[inline] - fn definition( - &self, - interface: &ShaderInterface, - ) -> Result { + fn definition(&self, interface: &ShaderInterface) -> Result { self.as_slice().definition(interface) } } unsafe impl VertexDefinition for Vec { #[inline] - fn definition( - &self, - interface: &ShaderInterface, - ) -> Result { + fn definition(&self, interface: &ShaderInterface) -> Result { self.as_slice().definition(interface) } } unsafe impl VertexDefinition for VertexBufferDescription { #[inline] - fn definition( - &self, - interface: &ShaderInterface, - ) -> Result { + fn definition(&self, interface: &ShaderInterface) -> Result { std::slice::from_ref(self).definition(interface) } } diff --git a/vulkano/src/pipeline/graphics/vertex_input/mod.rs b/vulkano/src/pipeline/graphics/vertex_input/mod.rs index 2ccc73d97c..04c0ac3f19 100644 --- a/vulkano/src/pipeline/graphics/vertex_input/mod.rs +++ b/vulkano/src/pipeline/graphics/vertex_input/mod.rs @@ -102,11 +102,15 @@ pub use self::{ buffers::BuffersDefinition, collection::VertexBuffersCollection, - definition::{IncompatibleVertexDefinitionError, VertexDefinition}, + definition::VertexDefinition, impl_vertex::VertexMember, vertex::{Vertex, VertexBufferDescription, VertexMemberInfo}, }; -use crate::format::Format; +use crate::{ + device::Device, + format::{Format, FormatFeatures}, + DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError, +}; use ahash::HashMap; mod buffers; @@ -171,6 +175,128 @@ impl VertexInputState { self.attributes = attributes.into_iter().collect(); self } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let Self { + bindings, + attributes, + } = self; + + let properties = device.physical_device().properties(); + + if bindings.len() > properties.max_vertex_input_bindings as usize { + return Err(ValidationError { + context: "bindings".into(), + problem: "the length exceeds the `max_vertex_input_bindings` limit".into(), + vuids: &[ + "VUID-VkPipelineVertexInputStateCreateInfo-vertexBindingDescriptionCount-00613", + ], + ..Default::default() + }); + } + + // VUID-VkPipelineVertexInputStateCreateInfo-pVertexBindingDescriptions-00616 + // Ensured by HashMap. + + for (&binding, binding_desc) in bindings { + binding_desc + .validate(device) + .map_err(|err| err.add_context(format!("bindings[{}]", binding)))?; + } + + if attributes.len() > properties.max_vertex_input_attributes as usize { + return Err(ValidationError { + context: "attributes".into(), + problem: "the length exceeds the `max_vertex_input_attributes` limit".into(), + vuids: &[ + "VUID-VkPipelineVertexInputStateCreateInfo-vertexAttributeDescriptionCount-00614", + ], + ..Default::default() + }); + } + + for (&location, attribute_desc) in attributes { + attribute_desc + .validate(device) + .map_err(|err| err.add_context(format!("attributes[{}]", location)))?; + + let &VertexInputAttributeDescription { + binding, + format, + offset, + } = attribute_desc; + + if location > properties.max_vertex_input_attributes { + return Err(ValidationError { + context: "attributes".into(), + problem: format!( + "the location {} exceeds the `max_vertex_input_attributes` limit", + location + ) + .into(), + vuids: &["VUID-VkVertexInputAttributeDescription-location-00620"], + ..Default::default() + }); + } + + let binding_desc = bindings.get(&binding).ok_or(ValidationError { + problem: format!( + "`attributes[{}].binding` is not present in `bindings`", + binding + ) + .into(), + vuids: &["VUID-VkPipelineVertexInputStateCreateInfo-binding-00615"], + ..Default::default() + })?; + + if device.enabled_extensions().khr_portability_subset + && !device + .enabled_features() + .vertex_attribute_access_beyond_stride + && offset as DeviceSize + format.block_size().unwrap() + > binding_desc.stride as DeviceSize + { + return Err(ValidationError { + problem: format!( + "this device is a portability subset device, and \ + `attributes[{0}].offset + attributes[{0}].format.block_size()` \ + is greater than `bindings[attributes[{0}]].stride`", + location, + ) + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "vertex_attribute_access_beyond_stride", + )])]), + vuids: &["VUID-VkVertexInputAttributeDescription-vertexAttributeAccessBeyondStride-04457"], + ..Default::default() + }); + } + } + + // When a format exceeds a single location (e.g. R64B64G64_SFLOAT), + // the location following it needs to be empty. + let unassigned_locations = attributes + .iter() + .filter(|&(_, attribute_desc)| attribute_desc.format.block_size().unwrap() > 16) + .map(|(location, _)| location + 1); + + for location in unassigned_locations { + if !attributes.get(&location).is_none() { + return Err(ValidationError { + problem: format!( + "`attributes[{}].format` takes up two locations, but \ + `attributes` also contains a description for location {}", + location - 1, location, + ) + .into(), + vuids: &["VUID-VkPipelineVertexInputStateCreateInfo-pVertexAttributeDescriptions-00617"], + ..Default::default() + }); + } + } + + Ok(()) + } } /// Describes a single vertex buffer binding. @@ -185,6 +311,90 @@ pub struct VertexInputBindingDescription { pub input_rate: VertexInputRate, } +impl VertexInputBindingDescription { + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { stride, input_rate } = self; + + let properties = device.physical_device().properties(); + + if stride > properties.max_vertex_input_binding_stride { + return Err(ValidationError { + context: "stride".into(), + problem: "exceeds the `max_vertex_input_binding_stride` limit".into(), + vuids: &["VUID-VkVertexInputBindingDescription-stride-00619"], + ..Default::default() + }); + } + + if device.enabled_extensions().khr_portability_subset + && (stride == 0 + || stride + % properties + .min_vertex_input_binding_stride_alignment + .unwrap() + != 0) + { + return Err(ValidationError { + problem: "this device is a portability subset device, and \ + `stride` is not a multiple of, and at least as large as, the \ + `min_vertex_input_binding_stride_alignment` limit" + .into(), + vuids: &["VUID-VkVertexInputBindingDescription-stride-04456"], + ..Default::default() + }); + } + + match input_rate { + VertexInputRate::Instance { divisor } if divisor != 1 => { + if !device + .enabled_features() + .vertex_attribute_instance_rate_divisor + { + return Err(ValidationError { + context: "input_rate".into(), + problem: "is `VertexInputRate::Instance`, and \ + its `divisor` value is not 1".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "vertex_attribute_instance_rate_divisor", + )])]), + vuids: &["VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateDivisor-02229"], + }); + } + + if divisor == 0 + && !device + .enabled_features() + .vertex_attribute_instance_rate_zero_divisor + { + return Err(ValidationError { + context: "input_rate".into(), + problem: "is `VertexInputRate::Instance`, and \ + its `divisor` value is 0".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "vertex_attribute_instance_rate_zero_divisor", + )])]), + vuids: &["VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateZeroDivisor-02228"], + }); + } + + if divisor > properties.max_vertex_attrib_divisor.unwrap() { + return Err(ValidationError { + context: "input_rate".into(), + problem: "is `VertexInputRate::Instance`, and \ + its `divisor` value exceeds the `max_vertex_attrib_divisor` limit" + .into(), + vuids: &["VUID-VkVertexInputBindingDivisorDescriptionEXT-divisor-01870"], + ..Default::default() + }); + } + } + _ => (), + } + + Ok(()) + } +} + /// Describes a single vertex buffer attribute mapping. #[derive(Clone, Copy, Debug)] pub struct VertexInputAttributeDescription { @@ -204,6 +414,63 @@ pub struct VertexInputAttributeDescription { pub offset: u32, } +impl VertexInputAttributeDescription { + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + binding, + format, + offset, + } = self; + + let properties = device.physical_device().properties(); + + format + .validate_device(device) + .map_err(|err| ValidationError { + context: "format".into(), + vuids: &["VUID-VkVertexInputAttributeDescription-format-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if binding > properties.max_vertex_input_bindings { + return Err(ValidationError { + context: "binding".into(), + problem: "exceeds the `max_vertex_input_bindings` limit".into(), + vuids: &["VUID-VkVertexInputAttributeDescription-binding-00621"], + ..Default::default() + }); + } + + if offset > properties.max_vertex_input_attribute_offset { + return Err(ValidationError { + context: "offset".into(), + problem: "exceeds the `max_vertex_input_attribute_offset` limit".into(), + vuids: &["VUID-VkVertexInputAttributeDescription-offset-00622"], + ..Default::default() + }); + } + + let format_features = unsafe { + device + .physical_device() + .format_properties_unchecked(format) + .buffer_features + }; + + if !format_features.intersects(FormatFeatures::VERTEX_BUFFER) { + return Err(ValidationError { + context: "format".into(), + problem: "the format features do not include `FormatFeatures::VERTEX_BUFFER`" + .into(), + vuids: &["VUID-VkVertexInputAttributeDescription-format-00623"], + ..Default::default() + }); + } + + Ok(()) + } +} + /// How the vertex source should be unrolled. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum VertexInputRate { diff --git a/vulkano/src/pipeline/graphics/viewport.rs b/vulkano/src/pipeline/graphics/viewport.rs index aeb3810af9..304003ef7f 100644 --- a/vulkano/src/pipeline/graphics/viewport.rs +++ b/vulkano/src/pipeline/graphics/viewport.rs @@ -48,94 +48,86 @@ //! In all cases the number of viewports and scissor boxes must be the same. //! -use std::ops::Range; +use crate::{ + device::Device, + pipeline::{PartialStateMode, StateMode}, + Requires, RequiresAllOf, RequiresOneOf, ValidationError, Version, +}; +use smallvec::{smallvec, SmallVec}; +use std::ops::RangeInclusive; /// List of viewports and scissors that are used when creating a graphics pipeline object. /// /// Note that the number of viewports and scissors must be the same. -#[derive(Debug, Clone)] -pub enum ViewportState { - /// The state is known in advance. - Fixed { - /// State of the viewports and scissors. - data: Vec<(Viewport, Scissor)>, - }, - - /// The state of viewports is known in advance, but the state of scissors is dynamic and will - /// be set when drawing. - FixedViewport { - /// State of the viewports. - viewports: Vec, - - /// Sets whether the scissor count is also dynamic, or only the scissors themselves. - /// - /// If set to `true`, the device API version must be at least 1.3, or the - /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must - /// be enabled on the device. - scissor_count_dynamic: bool, - }, - - /// The state of scissors is known in advance, but the state of viewports is dynamic and will - /// be set when drawing. - FixedScissor { - /// State of the scissors. - scissors: Vec, - - /// Sets whether the viewport count is also dynamic, or only the viewports themselves. - /// - /// If set to `true`, the device API version must be at least 1.3, or the - /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must - /// be enabled on the device. - viewport_count_dynamic: bool, - }, - - /// The state of both the viewports and scissors is dynamic and will be set when drawing. - Dynamic { - /// Number of viewports and scissors. - /// - /// This is ignored if both `viewport_count_dynamic` and `scissor_count_dynamic` are `true`. - count: u32, - - /// Sets whether the viewport count is also dynamic, or only the viewports themselves. - /// - /// If set to `true`, the device API version must be at least 1.3, or the - /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must - /// be enabled on the device. - viewport_count_dynamic: bool, - - /// Sets whether the scissor count is also dynamic, or only the scissors themselves. - /// - /// If set to `true`, the device API version must be at least 1.3, or the - /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must - /// be enabled on the device. - scissor_count_dynamic: bool, - }, +#[derive(Clone, Debug)] +pub struct ViewportState { + /// Specifies the viewport transforms. + /// + /// If the value is `PartialStateMode::Dynamic`, then the viewports are set dynamically, but + /// the number of viewports is still fixed. + /// + /// If the value is `PartialStateMode::Dynamic(StateMode::Dynamic)`, then the number of + /// viewports is also dynamic. The device API version must be at least 1.3, or the + /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must + /// be enabled on the device. + /// + /// If neither the number of viewports nor the number of scissors is dynamic, then the + /// number of both must be identical. + /// + /// The default value is `PartialStateMode::Fixed` with no viewports. + pub viewports: PartialStateMode, StateMode>, + + /// Specifies the scissor rectangles. + /// + /// If the value is `PartialStateMode::Dynamic`, then the scissors are set dynamically, but + /// the number of scissors is still fixed. + /// + /// If the value is `PartialStateMode::Dynamic(StateMode::Dynamic)`, then the number of + /// scissors is also dynamic. The device API version must be at least 1.3, or the + /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must + /// be enabled on the device. + /// + /// If neither the number of viewports nor the number of scissors is dynamic, then the + /// number of both must be identical. + /// + /// The default value is `PartialStateMode::Fixed` with no scissors. + pub scissors: PartialStateMode, StateMode>, + + pub _ne: crate::NonExhaustive, } impl ViewportState { /// Creates a `ViewportState` with fixed state and no viewports or scissors. #[inline] pub fn new() -> Self { - Self::Fixed { data: Vec::new() } + Self { + viewports: PartialStateMode::Fixed(SmallVec::new()), + scissors: PartialStateMode::Fixed(SmallVec::new()), + _ne: crate::NonExhaustive(()), + } } /// Creates a `ViewportState` with fixed state from the given viewports and scissors. pub fn viewport_fixed_scissor_fixed( data: impl IntoIterator, ) -> Self { - Self::Fixed { - data: data.into_iter().collect(), + let (viewports, scissors) = data.into_iter().unzip(); + Self { + viewports: PartialStateMode::Fixed(viewports), + scissors: PartialStateMode::Fixed(scissors), + _ne: crate::NonExhaustive(()), } } /// Creates a `ViewportState` with fixed state from the given viewports, and matching scissors /// that cover the whole viewport. pub fn viewport_fixed_scissor_irrelevant(data: impl IntoIterator) -> Self { - Self::Fixed { - data: data - .into_iter() - .map(|viewport| (viewport, Scissor::irrelevant())) - .collect(), + let viewports: SmallVec<_> = data.into_iter().collect(); + let scissors = smallvec![Scissor::irrelevant(); viewports.len()]; + Self { + viewports: PartialStateMode::Fixed(viewports), + scissors: PartialStateMode::Fixed(scissors), + _ne: crate::NonExhaustive(()), } } @@ -143,48 +135,213 @@ impl ViewportState { /// the whole viewport. #[inline] pub fn viewport_dynamic_scissor_irrelevant() -> Self { - Self::FixedScissor { - scissors: vec![Scissor::irrelevant()], - viewport_count_dynamic: false, + Self { + viewports: PartialStateMode::Dynamic(StateMode::Fixed(1)), + scissors: PartialStateMode::Fixed(smallvec![Scissor::irrelevant(); 1]), + _ne: crate::NonExhaustive(()), } } /// Creates a `ViewportState` with dynamic viewports and scissors, but a fixed count. #[inline] pub fn viewport_dynamic_scissor_dynamic(count: u32) -> Self { - Self::Dynamic { - count, - viewport_count_dynamic: false, - scissor_count_dynamic: false, + Self { + viewports: PartialStateMode::Dynamic(StateMode::Fixed(count)), + scissors: PartialStateMode::Dynamic(StateMode::Fixed(count)), + _ne: crate::NonExhaustive(()), } } /// Creates a `ViewportState` with dynamic viewport count and scissor count. #[inline] pub fn viewport_count_dynamic_scissor_count_dynamic() -> Self { - Self::Dynamic { - count: 0, - viewport_count_dynamic: true, - scissor_count_dynamic: true, + Self { + viewports: PartialStateMode::Dynamic(StateMode::Dynamic), + scissors: PartialStateMode::Dynamic(StateMode::Dynamic), + _ne: crate::NonExhaustive(()), } } /// Returns the number of viewports and scissors. /// - /// `None` is returned if both `viewport_count_dynamic` and `scissor_count_dynamic` are `true`. + /// `None` is returned if both counts are dynamic. #[inline] - pub fn count(&self) -> Option { - Some(match *self { - ViewportState::Fixed { ref data } => data.len() as u32, - ViewportState::FixedViewport { ref viewports, .. } => viewports.len() as u32, - ViewportState::FixedScissor { ref scissors, .. } => scissors.len() as u32, - ViewportState::Dynamic { - viewport_count_dynamic: true, - scissor_count_dynamic: true, - .. - } => return None, - ViewportState::Dynamic { count, .. } => count, - }) + pub(crate) fn count(&self) -> Option { + match &self.viewports { + PartialStateMode::Fixed(viewports) => return Some(viewports.len() as u32), + PartialStateMode::Dynamic(StateMode::Fixed(count)) => return Some(*count), + PartialStateMode::Dynamic(StateMode::Dynamic) => (), + } + + match &self.scissors { + PartialStateMode::Fixed(scissors) => return Some(scissors.len() as u32), + PartialStateMode::Dynamic(StateMode::Fixed(count)) => return Some(*count), + PartialStateMode::Dynamic(StateMode::Dynamic) => (), + } + + None + } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let Self { + viewports, + scissors, + _ne: _, + } = self; + + let properties = device.physical_device().properties(); + + let viewport_count = match viewports { + PartialStateMode::Fixed(viewports) => { + if viewports.is_empty() { + return Err(ValidationError { + context: "viewports".into(), + problem: "is empty".into(), + vuids: &["VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135"], + ..Default::default() + }); + } + + for (index, viewport) in viewports.iter().enumerate() { + viewport + .validate(device) + .map_err(|err| err.add_context(format!("viewports[{}].0", index)))?; + } + + viewports.len() as u32 + } + PartialStateMode::Dynamic(StateMode::Fixed(count)) => { + if *count == 0 { + return Err(ValidationError { + context: "viewports".into(), + problem: "is empty".into(), + vuids: &["VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135"], + ..Default::default() + }); + } + + *count + } + PartialStateMode::Dynamic(StateMode::Dynamic) => { + // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135 + 0 + } + }; + + let scissor_count = match scissors { + PartialStateMode::Fixed(scissors) => { + if scissors.is_empty() { + return Err(ValidationError { + context: "scissors".into(), + problem: "is empty".into(), + vuids: &["VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136"], + ..Default::default() + }); + } + + for (index, scissor) in scissors.iter().enumerate() { + let &Scissor { offset, extent } = scissor; + + // VUID-VkPipelineViewportStateCreateInfo-x-02821 + // Ensured by the use of an unsigned integer. + + if (i32::try_from(offset[0]).ok()) + .zip(i32::try_from(extent[0]).ok()) + .and_then(|(o, e)| o.checked_add(e)) + .is_none() + { + return Err(ValidationError { + context: format!("scissors[{}]", index).into(), + problem: "`offset[0] + extent[0]` is greater than `i32::MAX`".into(), + vuids: &["VUID-VkPipelineViewportStateCreateInfo-offset-02822"], + ..Default::default() + }); + } + + if (i32::try_from(offset[1]).ok()) + .zip(i32::try_from(extent[1]).ok()) + .and_then(|(o, e)| o.checked_add(e)) + .is_none() + { + return Err(ValidationError { + context: format!("scissors[{}]", index).into(), + problem: "`offset[1] + extent[1]` is greater than `i32::MAX`".into(), + vuids: &["VUID-VkPipelineViewportStateCreateInfo-offset-02823"], + ..Default::default() + }); + } + } + + scissors.len() as u32 + } + PartialStateMode::Dynamic(StateMode::Fixed(count)) => { + if *count == 0 { + return Err(ValidationError { + context: "scissors".into(), + problem: "is empty".into(), + vuids: &["VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136"], + ..Default::default() + }); + } + + *count + } + PartialStateMode::Dynamic(StateMode::Dynamic) => { + // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136 + 0 + } + }; + + if viewport_count != 0 && scissor_count != 0 && viewport_count != scissor_count { + return Err(ValidationError { + problem: "the length of `viewports` and the length of `scissors` are not equal" + .into(), + vuids: &["VUID-VkPipelineViewportStateCreateInfo-scissorCount-04134"], + ..Default::default() + }); + } + + if viewport_count > 1 && !device.enabled_features().multi_viewport { + return Err(ValidationError { + context: "viewports".into(), + problem: "the length is greater than 1".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multi_viewport", + )])]), + vuids: &["VUID-VkPipelineViewportStateCreateInfo-viewportCount-01216"], + }); + } + + if scissor_count > 1 && !device.enabled_features().multi_viewport { + return Err(ValidationError { + context: "scissors".into(), + problem: "the length is greater than 1".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "multi_viewport", + )])]), + vuids: &["VUID-VkPipelineViewportStateCreateInfo-scissorCount-01217"], + }); + } + + if viewport_count > properties.max_viewports { + return Err(ValidationError { + context: "viewports".into(), + problem: "the length exceeds the `max_viewports` limit".into(), + vuids: &["VUID-VkPipelineViewportStateCreateInfo-viewportCount-01218"], + ..Default::default() + }); + } + + if scissor_count > properties.max_viewports { + return Err(ValidationError { + context: "scissors".into(), + problem: "the length exceeds the `max_viewports` limit".into(), + vuids: &["VUID-VkPipelineViewportStateCreateInfo-scissorCount-01219"], + ..Default::default() + }); + } + + Ok(()) } } @@ -197,16 +354,13 @@ impl Default for ViewportState { } /// State of a single viewport. -// FIXME: check that: -// x + width must be less than or equal to viewportBoundsRange[0] -// y + height must be less than or equal to viewportBoundsRange[1] #[derive(Debug, Clone, PartialEq)] pub struct Viewport { /// Coordinates in pixels of the top-left hand corner of the viewport. - pub origin: [f32; 2], + pub offset: [f32; 2], /// Dimensions in pixels of the viewport. - pub dimensions: [f32; 2], + pub extent: [f32; 2], /// Minimum and maximum values of the depth. /// @@ -215,34 +369,166 @@ pub struct Viewport { /// /// This is equivalents to `glDepthRange` in OpenGL, except that OpenGL uses the Z coordinate /// range from `-1.0` to `1.0` instead. - pub depth_range: Range, + pub depth_range: RangeInclusive, +} + +impl Viewport { + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + offset, + extent, + ref depth_range, + } = self; + + let properties = device.physical_device().properties(); + + if extent[0] <= 0.0 { + return Err(ValidationError { + context: "extent[0]".into(), + problem: "is not greater than zero".into(), + vuids: &["VUID-VkViewport-width-01770"], + ..Default::default() + }); + } + + if extent[0] > properties.max_viewport_dimensions[0] as f32 { + return Err(ValidationError { + context: "extent[0]".into(), + problem: "exceeds the `max_viewport_dimensions[0]` limit".into(), + vuids: &["VUID-VkViewport-width-01771"], + ..Default::default() + }); + } + + if extent[1] <= 0.0 + && !(device.api_version() >= Version::V1_1 + || device.enabled_extensions().khr_maintenance1) + { + return Err(ValidationError { + context: "extent[1]".into(), + problem: "is not greater than zero".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_maintenance1")]), + ]), + vuids: &["VUID-VkViewport-apiVersion-07917"], + }); + } + + if extent[1].abs() > properties.max_viewport_dimensions[1] as f32 { + return Err(ValidationError { + context: "extent[1]".into(), + problem: "exceeds the `max_viewport_dimensions[1]` limit".into(), + vuids: &["VUID-VkViewport-height-01773"], + ..Default::default() + }); + } + + if offset[0] < properties.viewport_bounds_range[0] { + return Err(ValidationError { + problem: "`offset[0]` is less than the `viewport_bounds_range[0]` property".into(), + vuids: &["VUID-VkViewport-x-01774"], + ..Default::default() + }); + } + + if offset[0] + extent[0] > properties.viewport_bounds_range[1] { + return Err(ValidationError { + problem: "`offset[0] + extent[0]` is greater than the \ + `viewport_bounds_range[1]` property" + .into(), + vuids: &["VUID-VkViewport-x-01232"], + ..Default::default() + }); + } + + if offset[1] < properties.viewport_bounds_range[0] { + return Err(ValidationError { + problem: "`offset[1]` is less than the `viewport_bounds_range[0]` property".into(), + vuids: &["VUID-VkViewport-y-01775"], + ..Default::default() + }); + } + + if offset[1] > properties.viewport_bounds_range[1] { + return Err(ValidationError { + problem: "`offset[1]` is greater than the `viewport_bounds_range[1]` property" + .into(), + vuids: &["VUID-VkViewport-y-01776"], + ..Default::default() + }); + } + + if offset[1] + extent[1] < properties.viewport_bounds_range[0] { + return Err(ValidationError { + problem: "`offset[1] + extent[1]` is less than the \ + `viewport_bounds_range[0]` property" + .into(), + vuids: &["VUID-VkViewport-y-01777"], + ..Default::default() + }); + } + + if offset[1] + extent[1] > properties.viewport_bounds_range[1] { + return Err(ValidationError { + problem: "`offset[1] + extent[1]` is greater than the \ + `viewport_bounds_range[1]` property" + .into(), + vuids: &["VUID-VkViewport-y-01233"], + ..Default::default() + }); + } + + if !device.enabled_extensions().ext_depth_range_unrestricted { + if *depth_range.start() < 0.0 || *depth_range.start() > 1.0 { + return Err(ValidationError { + problem: "`depth_range.start` is not between 0.0 and 1.0 inclusive".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_depth_range_unrestricted", + )])]), + vuids: &["VUID-VkViewport-minDepth-01234"], + ..Default::default() + }); + } + + if *depth_range.end() < 0.0 || *depth_range.end() > 1.0 { + return Err(ValidationError { + problem: "`depth_range.end` is not between 0.0 and 1.0 inclusive".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( + "ext_depth_range_unrestricted", + )])]), + vuids: &["VUID-VkViewport-maxDepth-01235"], + ..Default::default() + }); + } + } + + Ok(()) + } } -impl From for ash::vk::Viewport { +impl From<&Viewport> for ash::vk::Viewport { #[inline] - fn from(val: Viewport) -> Self { + fn from(val: &Viewport) -> Self { ash::vk::Viewport { - x: val.origin[0], - y: val.origin[1], - width: val.dimensions[0], - height: val.dimensions[1], - min_depth: val.depth_range.start, - max_depth: val.depth_range.end, + x: val.offset[0], + y: val.offset[1], + width: val.extent[0], + height: val.extent[1], + min_depth: *val.depth_range.start(), + max_depth: *val.depth_range.end(), } } } /// State of a single scissor box. -// FIXME: add a check: -// Evaluation of (offset.x + extent.width) must not cause a signed integer addition overflow -// Evaluation of (offset.y + extent.height) must not cause a signed integer addition overflow #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct Scissor { /// Coordinates in pixels of the top-left hand corner of the box. - pub origin: [u32; 2], + pub offset: [u32; 2], /// Dimensions in pixels of the box. - pub dimensions: [u32; 2], + pub extent: [u32; 2], } impl Scissor { @@ -251,8 +537,8 @@ impl Scissor { #[inline] pub fn irrelevant() -> Scissor { Scissor { - origin: [0, 0], - dimensions: [0x7fffffff, 0x7fffffff], + offset: [0, 0], + extent: [0x7fffffff, 0x7fffffff], } } } @@ -264,17 +550,17 @@ impl Default for Scissor { } } -impl From for ash::vk::Rect2D { +impl From<&Scissor> for ash::vk::Rect2D { #[inline] - fn from(val: Scissor) -> Self { + fn from(val: &Scissor) -> Self { ash::vk::Rect2D { offset: ash::vk::Offset2D { - x: val.origin[0] as i32, - y: val.origin[1] as i32, + x: val.offset[0] as i32, + y: val.offset[1] as i32, }, extent: ash::vk::Extent2D { - width: val.dimensions[0], - height: val.dimensions[1], + width: val.extent[0], + height: val.extent[1], }, } } diff --git a/vulkano/src/pipeline/layout.rs b/vulkano/src/pipeline/layout.rs index cbe092516e..e38b073a89 100644 --- a/vulkano/src/pipeline/layout.rs +++ b/vulkano/src/pipeline/layout.rs @@ -63,16 +63,15 @@ //! A pipeline layout is a Vulkan object type, represented in Vulkano with the `PipelineLayout` //! type. Each pipeline that you create holds a pipeline layout object. +use super::PipelineShaderStageCreateInfo; use crate::{ descriptor_set::layout::{ - DescriptorRequirementsNotMet, DescriptorSetLayout, DescriptorSetLayoutBinding, - DescriptorSetLayoutCreateFlags, DescriptorSetLayoutCreateInfo, DescriptorType, + DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorSetLayoutCreateFlags, + DescriptorSetLayoutCreateInfo, DescriptorType, }, device::{Device, DeviceOwned, Properties}, macros::{impl_id_counter, vulkan_bitflags}, - shader::{ - DescriptorBindingRequirements, PipelineShaderStageCreateInfo, ShaderStage, ShaderStages, - }, + shader::{DescriptorBindingRequirements, ShaderStage, ShaderStages}, RuntimeError, ValidationError, VulkanError, VulkanObject, }; use ahash::HashMap; @@ -82,7 +81,7 @@ use std::{ cmp::max, collections::hash_map::Entry, error::Error, - fmt::{Display, Error as FmtError, Formatter, Write}, + fmt::{Display, Formatter, Write}, mem::MaybeUninit, num::NonZeroU64, ptr, @@ -323,7 +322,7 @@ impl PipelineLayout { Item = ((u32, u32), &'a DescriptorBindingRequirements), >, push_constant_range: Option<&PushConstantRange>, - ) -> Result<(), PipelineLayoutSupersetError> { + ) -> Result<(), ValidationError> { for ((set_num, binding_num), reqs) in descriptor_requirements.into_iter() { let layout_binding = self .set_layouts @@ -333,32 +332,41 @@ impl PipelineLayout { let layout_binding = match layout_binding { Some(x) => x, None => { - return Err(PipelineLayoutSupersetError::DescriptorMissing { - set_num, - binding_num, - }) + return Err(ValidationError { + problem: format!( + "the requirements for descriptor set {} binding {} were not met: \ + no such binding exists in the pipeline layout", + set_num, binding_num, + ) + .into(), + ..Default::default() + }); } }; if let Err(error) = layout_binding.ensure_compatible_with_shader(reqs) { - return Err(PipelineLayoutSupersetError::DescriptorRequirementsNotMet { - set_num, - binding_num, - error, + return Err(ValidationError { + problem: format!( + "the requirements for descriptor set {} binding {} were not met: {}", + set_num, binding_num, error, + ) + .into(), + ..Default::default() }); } } - // FIXME: check push constants if let Some(range) = push_constant_range { for own_range in self.push_constant_ranges.iter() { if range.stages.intersects(own_range.stages) && // check if it shares any stages (range.offset < own_range.offset || // our range must start before and end after the given range own_range.offset + own_range.size < range.offset + range.size) { - return Err(PipelineLayoutSupersetError::PushConstantRange { - first_range: *own_range, - second_range: *range, + return Err(ValidationError { + problem: "the required push constant range is larger than the \ + push constant range in the pipeline layout" + .into(), + ..Default::default() }); } } @@ -399,7 +407,9 @@ impl_id_counter!(PipelineLayout); /// Parameters to create a new `PipelineLayout`. #[derive(Clone, Debug)] pub struct PipelineLayoutCreateInfo { - /// Specifies how to create the pipeline layout. + /// Additional properties of the pipeline layout. + /// + /// The default value is empty. pub flags: PipelineLayoutCreateFlags, /// The descriptor set layouts that should be part of the pipeline layout. @@ -752,7 +762,7 @@ impl PipelineLayoutCreateInfo { vulkan_bitflags! { #[non_exhaustive] - /// Flags that control how a pipeline layout is created. + /// Flags specifying additional properties of a pipeline layout. PipelineLayoutCreateFlags = PipelineLayoutCreateFlags(u32); /* TODO: enable @@ -876,78 +886,6 @@ impl PushConstantRange { } } -/// Error when checking whether a pipeline layout is a superset of another one. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum PipelineLayoutSupersetError { - DescriptorMissing { - set_num: u32, - binding_num: u32, - }, - DescriptorRequirementsNotMet { - set_num: u32, - binding_num: u32, - error: DescriptorRequirementsNotMet, - }, - PushConstantRange { - first_range: PushConstantRange, - second_range: PushConstantRange, - }, -} - -impl Error for PipelineLayoutSupersetError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - PipelineLayoutSupersetError::DescriptorRequirementsNotMet { error, .. } => Some(error), - _ => None, - } - } -} - -impl Display for PipelineLayoutSupersetError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - PipelineLayoutSupersetError::DescriptorRequirementsNotMet { - set_num, - binding_num, - .. - } => write!( - f, - "the descriptor at set {} binding {} does not meet the requirements", - set_num, binding_num, - ), - PipelineLayoutSupersetError::DescriptorMissing { - set_num, - binding_num, - } => write!( - f, - "a descriptor at set {} binding {} is required by the shaders, but is missing from \ - the pipeline layout", - set_num, binding_num, - ), - PipelineLayoutSupersetError::PushConstantRange { - first_range, - second_range, - } => { - writeln!(f, "our range did not completely encompass the other range")?; - writeln!(f, " our stages: {:?}", first_range.stages)?; - writeln!( - f, - " our range: {} - {}", - first_range.offset, - first_range.offset + first_range.size, - )?; - writeln!(f, " other stages: {:?}", second_range.stages)?; - write!( - f, - " other range: {} - {}", - second_range.offset, - second_range.offset + second_range.size, - ) - } - } - } -} - /// Parameters to create a new `PipelineLayout` as well as its accompanying `DescriptorSetLayout` /// objects. #[derive(Clone, Debug)] diff --git a/vulkano/src/pipeline/mod.rs b/vulkano/src/pipeline/mod.rs index 8f3fcad093..c16a3fefe9 100644 --- a/vulkano/src/pipeline/mod.rs +++ b/vulkano/src/pipeline/mod.rs @@ -19,9 +19,10 @@ pub use self::{compute::ComputePipeline, graphics::GraphicsPipeline, layout::PipelineLayout}; use crate::{ - device::DeviceOwned, + device::{Device, DeviceOwned}, macros::{vulkan_bitflags, vulkan_enum}, - shader::DescriptorBindingRequirements, + shader::{DescriptorBindingRequirements, EntryPoint, ShaderStage, SpecializationConstant}, + Requires, RequiresAllOf, RequiresOneOf, ValidationError, }; use ahash::HashMap; use std::sync::Arc; @@ -85,7 +86,7 @@ vulkan_enum! { vulkan_bitflags! { #[non_exhaustive] - /// Flags that control how a pipeline is created. + /// Flags specifying additional properties of a pipeline. PipelineCreateFlags = PipelineCreateFlags(u32); /// The pipeline will not be optimized. @@ -297,6 +298,212 @@ vulkan_bitflags! { ]),*/ } +/// Specifies a single shader stage when creating a pipeline. +#[derive(Clone, Debug)] +pub struct PipelineShaderStageCreateInfo { + /// Additional properties of the shader stage. + /// + /// The default value is empty. + pub flags: PipelineShaderStageCreateFlags, + + /// The shader entry point for the stage. + /// + /// There is no default value. + pub entry_point: EntryPoint, + + /// Values for the specialization constants in the shader, indexed by their `constant_id`. + /// + /// Specialization constants are constants whose value can be overridden when you create + /// a pipeline. When provided, they must have the same type as defined in the shader. + /// Constants that are not given a value here will have the default value that was specified + /// for them in the shader code. + /// + /// The default value is empty. + pub specialization_info: HashMap, + + pub _ne: crate::NonExhaustive, +} + +impl PipelineShaderStageCreateInfo { + /// Returns a `PipelineShaderStageCreateInfo` with the specified `entry_point`. + #[inline] + pub fn new(entry_point: EntryPoint) -> Self { + Self { + flags: PipelineShaderStageCreateFlags::empty(), + entry_point, + specialization_info: HashMap::default(), + _ne: crate::NonExhaustive(()), + } + } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), ValidationError> { + let &Self { + flags, + ref entry_point, + ref specialization_info, + _ne: _, + } = self; + + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkPipelineShaderStageCreateInfo-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; + + let entry_point_info = entry_point.info(); + let stage_enum = ShaderStage::from(&entry_point_info.execution); + + stage_enum + .validate_device(device) + .map_err(|err| ValidationError { + context: "entry_point.info().execution".into(), + vuids: &["VUID-VkPipelineShaderStageCreateInfo-stage-parameter"], + ..ValidationError::from_requirement(err) + })?; + + // VUID-VkPipelineShaderStageCreateInfo-pName-00707 + // Guaranteed by definition of `EntryPoint`. + + // TODO: + // VUID-VkPipelineShaderStageCreateInfo-maxClipDistances-00708 + // VUID-VkPipelineShaderStageCreateInfo-maxCullDistances-00709 + // VUID-VkPipelineShaderStageCreateInfo-maxCombinedClipAndCullDistances-00710 + // VUID-VkPipelineShaderStageCreateInfo-maxSampleMaskWords-00711 + // VUID-VkPipelineShaderStageCreateInfo-stage-02596 + // VUID-VkPipelineShaderStageCreateInfo-stage-02597 + + match stage_enum { + ShaderStage::Vertex => { + // VUID-VkPipelineShaderStageCreateInfo-stage-00712 + // TODO: + } + ShaderStage::TessellationControl | ShaderStage::TessellationEvaluation => { + if !device.enabled_features().tessellation_shader { + return Err(ValidationError { + context: "entry_point".into(), + problem: "specifies a `ShaderStage::TessellationControl` or \ + `ShaderStage::TessellationEvaluation` entry point" + .into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "tessellation_shader", + )])]), + vuids: &["VUID-VkPipelineShaderStageCreateInfo-stage-00705"], + }); + } + + // VUID-VkPipelineShaderStageCreateInfo-stage-00713 + // TODO: + } + ShaderStage::Geometry => { + if !device.enabled_features().geometry_shader { + return Err(ValidationError { + context: "entry_point".into(), + problem: "specifies a `ShaderStage::Geometry` entry point".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "geometry_shader", + )])]), + vuids: &["VUID-VkPipelineShaderStageCreateInfo-stage-00704"], + }); + } + + // TODO: + // VUID-VkPipelineShaderStageCreateInfo-stage-00714 + // VUID-VkPipelineShaderStageCreateInfo-stage-00715 + } + ShaderStage::Fragment => { + // TODO: + // VUID-VkPipelineShaderStageCreateInfo-stage-00718 + // VUID-VkPipelineShaderStageCreateInfo-stage-06685 + // VUID-VkPipelineShaderStageCreateInfo-stage-06686 + } + ShaderStage::Compute => (), + ShaderStage::Raygen => (), + ShaderStage::AnyHit => (), + ShaderStage::ClosestHit => (), + ShaderStage::Miss => (), + ShaderStage::Intersection => (), + ShaderStage::Callable => (), + ShaderStage::Task => { + if !device.enabled_features().task_shader { + return Err(ValidationError { + context: "entry_point".into(), + problem: "specifies a `ShaderStage::Task` entry point".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "task_shader", + )])]), + vuids: &["VUID-VkPipelineShaderStageCreateInfo-stage-02092"], + }); + } + } + ShaderStage::Mesh => { + if !device.enabled_features().mesh_shader { + return Err(ValidationError { + context: "entry_point".into(), + problem: "specifies a `ShaderStage::Mesh` entry point".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "mesh_shader", + )])]), + vuids: &["VUID-VkPipelineShaderStageCreateInfo-stage-02091"], + }); + } + } + ShaderStage::SubpassShading => (), + } + + for (&constant_id, provided_value) in specialization_info { + // Per `VkSpecializationMapEntry` spec: + // "If a constantID value is not a specialization constant ID used in the shader, + // that map entry does not affect the behavior of the pipeline." + // We *may* want to be stricter than this for the sake of catching user errors? + if let Some(default_value) = entry_point_info.specialization_constants.get(&constant_id) + { + // Check for equal types rather than only equal size. + if !provided_value.eq_type(default_value) { + return Err(ValidationError { + problem: format!( + "`specialization_info[{0}]` does not have the same type as \ + `entry_point.info().specialization_constants[{0}]`", + constant_id + ) + .into(), + vuids: &["VUID-VkSpecializationMapEntry-constantID-00776"], + ..Default::default() + }); + } + } + } + + Ok(()) + } +} + +vulkan_bitflags! { + #[non_exhaustive] + + /// Flags specifying additional properties of a pipeline shader stage. + PipelineShaderStageCreateFlags = PipelineShaderStageCreateFlags(u32); + + /* TODO: enable + // TODO: document + ALLOW_VARYING_SUBGROUP_SIZE = ALLOW_VARYING_SUBGROUP_SIZE + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_subgroup_size_control)]), + ]), + */ + + /* TODO: enable + // TODO: document + REQUIRE_FULL_SUBGROUPS = REQUIRE_FULL_SUBGROUPS + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(ext_subgroup_size_control)]), + ]), + */ +} + vulkan_enum! { #[non_exhaustive] diff --git a/vulkano/src/shader/mod.rs b/vulkano/src/shader/mod.rs index 2a8161ec54..de8011435a 100644 --- a/vulkano/src/shader/mod.rs +++ b/vulkano/src/shader/mod.rs @@ -136,7 +136,7 @@ use crate::{ device::{Device, DeviceOwned}, format::{Format, NumericType}, image::view::ImageViewType, - macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum}, + macros::{impl_id_counter, vulkan_bitflags_enum}, pipeline::{graphics::input_assembly::PrimitiveTopology, layout::PushConstantRange}, shader::spirv::{Capability, Spirv, SpirvError}, sync::PipelineStages, @@ -727,70 +727,6 @@ impl DescriptorRequirements { } } -/// Specifies a single shader stage when creating a pipeline. -#[derive(Clone, Debug)] -pub struct PipelineShaderStageCreateInfo { - /// Specifies how to create the shader stage. - /// - /// The default value is empty. - pub flags: PipelineShaderStageCreateFlags, - - /// The shader entry point for the stage. - /// - /// There is no default value. - pub entry_point: EntryPoint, - - /// Values for the specialization constants in the shader, indexed by their `constant_id`. - /// - /// Specialization constants are constants whose value can be overridden when you create - /// a pipeline. When provided, they must have the same type as defined in the shader. - /// Constants that are not given a value here will have the default value that was specified - /// for them in the shader code. - /// - /// The default value is empty. - pub specialization_info: HashMap, - - pub _ne: crate::NonExhaustive, -} - -impl PipelineShaderStageCreateInfo { - /// Returns a `PipelineShaderStageCreateInfo` with the specified `entry_point`. - #[inline] - pub fn entry_point(entry_point: EntryPoint) -> Self { - Self { - flags: PipelineShaderStageCreateFlags::empty(), - entry_point, - specialization_info: HashMap::default(), - _ne: crate::NonExhaustive(()), - } - } -} - -vulkan_bitflags! { - #[non_exhaustive] - - /// Flags that control how a pipeline shader stage is created. - PipelineShaderStageCreateFlags = PipelineShaderStageCreateFlags(u32); - - /* TODO: enable - // TODO: document - ALLOW_VARYING_SUBGROUP_SIZE = ALLOW_VARYING_SUBGROUP_SIZE - RequiresOneOf([ - RequiresAllOf([APIVersion(V1_3)]), - RequiresAllOf([DeviceExtension(ext_subgroup_size_control)]), - ]), - */ - - /* TODO: enable - // TODO: document - REQUIRE_FULL_SUBGROUPS = REQUIRE_FULL_SUBGROUPS - RequiresOneOf([ - RequiresAllOf([APIVersion(V1_3)]), - RequiresAllOf([DeviceExtension(ext_subgroup_size_control)]), - ]), - */ -} - /// The value to provide for a specialization constant, when creating a pipeline. #[derive(Clone, Copy, Debug, PartialEq)] pub enum SpecializationConstant { From 5619a709bfbe1d49f35f8329b4c1c5f341b21fab Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 25 Jun 2023 17:47:55 +0200 Subject: [PATCH 5/6] Update vulkano/src/lib.rs Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> --- vulkano/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulkano/src/lib.rs b/vulkano/src/lib.rs index 61b093d5cb..0c85272c5d 100644 --- a/vulkano/src/lib.rs +++ b/vulkano/src/lib.rs @@ -427,7 +427,7 @@ impl Display for ValidationError { if self.problem.is_empty() { write!(f, "requires one of: {}", self.requires_one_of)?; } else { - write!(f, " -- requires one of: {}", self.requires_one_of)?; + write!(f, " -- {}", self.requires_one_of)?; } } From 44eab254d16382c49ed7cbd29c865d2177208a71 Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 25 Jun 2023 17:48:40 +0200 Subject: [PATCH 6/6] Update vulkano/src/lib.rs Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> --- vulkano/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulkano/src/lib.rs b/vulkano/src/lib.rs index 0c85272c5d..1982f5c117 100644 --- a/vulkano/src/lib.rs +++ b/vulkano/src/lib.rs @@ -425,7 +425,7 @@ impl Display for ValidationError { if !self.requires_one_of.is_empty() { if self.problem.is_empty() { - write!(f, "requires one of: {}", self.requires_one_of)?; + write!(f, "{}", self.requires_one_of)?; } else { write!(f, " -- {}", self.requires_one_of)?; }