extensions/ext: Add VK_EXT_pipeline_properties device extension (#622)

* extensions/ext: Add VK_EXT_pipeline_properties device extension

* Generate traits and impls for all `validstructs` on command parameters
This commit is contained in:
Marijn Suijten 2023-05-06 20:30:46 +02:00
parent 33bc042e9c
commit a2d17fe5ba
No known key found for this signature in database
GPG key ID: 449FC1DE031665DA
6 changed files with 118 additions and 12 deletions

View file

@ -36,7 +36,7 @@ jobs:
- name: Run generator - name: Run generator
run: cargo run -p generator run: cargo run -p generator
- name: Diff autogen result - name: Diff autogen result
run: git diff --quiet || (echo "::error::Generated files are different, please regenerate with cargo run -p generator!"; git diff; false) run: test -z "$(git status --porcelain)" || (echo "::error::Generated files are different, please regenerate with cargo run -p generator!"; git diff; false)
test: test:
name: Test Suite name: Test Suite

View file

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Added `VK_EXT_pipeline_properties` device extension (#622)
- Update Vulkan-Headers to 1.3.246 (#697, #723) - Update Vulkan-Headers to 1.3.246 (#697, #723)
- Added `VK_KHR_performance_query` device extension (#726) - Added `VK_KHR_performance_query` device extension (#726)
- Added `VK_EXT_shader_object` device extension (#732) - Added `VK_EXT_shader_object` device extension (#732)

View file

@ -17,6 +17,7 @@ pub use self::image_drm_format_modifier::ImageDrmFormatModifier;
pub use self::mesh_shader::MeshShader; pub use self::mesh_shader::MeshShader;
pub use self::metal_surface::MetalSurface; pub use self::metal_surface::MetalSurface;
pub use self::physical_device_drm::PhysicalDeviceDrm; pub use self::physical_device_drm::PhysicalDeviceDrm;
pub use self::pipeline_properties::PipelineProperties;
pub use self::private_data::PrivateData; pub use self::private_data::PrivateData;
pub use self::sample_locations::SampleLocations; pub use self::sample_locations::SampleLocations;
pub use self::shader_object::ShaderObject; pub use self::shader_object::ShaderObject;
@ -41,6 +42,7 @@ mod image_drm_format_modifier;
mod mesh_shader; mod mesh_shader;
mod metal_surface; mod metal_surface;
mod physical_device_drm; mod physical_device_drm;
mod pipeline_properties;
mod private_data; mod private_data;
mod sample_locations; mod sample_locations;
mod shader_object; mod shader_object;

View file

@ -0,0 +1,52 @@
use crate::prelude::*;
use crate::vk;
use crate::{Device, Instance};
use std::ffi::CStr;
use std::mem;
/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_EXT_pipeline_properties.html>
#[derive(Clone)]
pub struct PipelineProperties {
handle: vk::Device,
fp: vk::ExtPipelinePropertiesFn,
}
impl PipelineProperties {
pub fn new(instance: &Instance, device: &Device) -> Self {
let handle = device.handle();
let fp = vk::ExtPipelinePropertiesFn::load(|name| unsafe {
mem::transmute(instance.get_device_proc_addr(handle, name.as_ptr()))
});
Self { handle, fp }
}
/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetPipelinePropertiesEXT.html>
#[inline]
pub unsafe fn get_pipeline_properties(
&self,
pipeline_info: &vk::PipelineInfoEXT,
pipeline_properties: &mut impl vk::GetPipelinePropertiesEXTParamPipelineProperties,
) -> VkResult<()> {
(self.fp.get_pipeline_properties_ext)(
self.handle,
pipeline_info,
<*mut _>::cast(pipeline_properties),
)
.result()
}
#[inline]
pub const fn name() -> &'static CStr {
vk::ExtPipelinePropertiesFn::name()
}
#[inline]
pub fn fp(&self) -> &vk::ExtPipelinePropertiesFn {
&self.fp
}
#[inline]
pub fn device(&self) -> vk::Device {
self.handle
}
}

View file

@ -20233,6 +20233,10 @@ impl ExtPipelinePropertiesFn {
pub const SPEC_VERSION: u32 = 1u32; pub const SPEC_VERSION: u32 = 1u32;
} }
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[doc = "Implemented for all types that can be passed as argument to `pipeline_properties` in [`PFN_vkGetPipelinePropertiesEXT`]"]
pub unsafe trait GetPipelinePropertiesEXTParamPipelineProperties {}
unsafe impl GetPipelinePropertiesEXTParamPipelineProperties for PipelinePropertiesIdentifierEXT {}
#[allow(non_camel_case_types)]
pub type PFN_vkGetPipelinePropertiesEXT = unsafe extern "system" fn( pub type PFN_vkGetPipelinePropertiesEXT = unsafe extern "system" fn(
device: Device, device: Device,
p_pipeline_info: *const PipelineInfoEXT, p_pipeline_info: *const PipelineInfoEXT,

View file

@ -906,32 +906,36 @@ fn generate_function_pointers<'a>(
struct Command<'a> { struct Command<'a> {
type_needs_defining: bool, type_needs_defining: bool,
type_name: Ident, type_name: Ident,
pfn_type_name: Ident,
function_name_c: &'a str, function_name_c: &'a str,
function_name_rust: Ident, function_name_rust: Ident,
parameters: TokenStream, parameters: TokenStream,
parameters_unused: TokenStream, parameters_unused: TokenStream,
returns: TokenStream, returns: TokenStream,
parameter_validstructs: Vec<(Ident, Vec<String>)>,
} }
let commands = commands let commands = commands
.iter() .iter()
.map(|cmd| { .map(|cmd| {
let name = &cmd.proto.name; let name = &cmd.proto.name;
let type_name = format_ident!("PFN_{}", name); let pfn_type_name = format_ident!("PFN_{}", name);
// We might need to generate a function pointer for an extension, where we are given the original // We might need to generate a function pointer for an extension, where we are given the original
// `cmd` and a rename back to the extension alias (typically with vendor suffix) in `rename_commands`: // `cmd` and a rename back to the extension alias (typically with vendor suffix) in `rename_commands`:
let function_name_c = rename_commands.get(name.as_str()).cloned().unwrap_or(name); let function_name_c = rename_commands.get(name.as_str()).cloned().unwrap_or(name);
let function_name_rust = format_ident!( let type_name = function_name_c.strip_prefix("vk").unwrap();
"{}", let function_name_rust = format_ident!("{}", type_name.to_snake_case());
function_name_c.strip_prefix("vk").unwrap().to_snake_case() let type_name = format_ident!("{}", type_name);
);
let params: Vec<_> = cmd let params = cmd
.params .params
.iter() .iter()
.filter(|param| matches!(param.api.as_deref(), None | Some(DESIRED_API))) .filter(|param| matches!(param.api.as_deref(), None | Some(DESIRED_API)));
let params_tokens: Vec<_> = params
.clone()
.map(|param| { .map(|param| {
let name = param.param_ident(); let name = param.param_ident();
let ty = param.type_tokens(true); let ty = param.type_tokens(true);
@ -939,17 +943,22 @@ fn generate_function_pointers<'a>(
}) })
.collect(); .collect();
let params_iter = params let params_iter = params_tokens
.iter() .iter()
.map(|(param_name, param_ty)| quote!(#param_name: #param_ty)); .map(|(param_name, param_ty)| quote!(#param_name: #param_ty));
let parameters = quote!(#(#params_iter,)*); let parameters = quote!(#(#params_iter,)*);
let params_iter = params.iter().map(|(param_name, param_ty)| { let params_iter = params_tokens.iter().map(|(param_name, param_ty)| {
let unused_name = format_ident!("_{}", param_name); let unused_name = format_ident!("_{}", param_name);
quote!(#unused_name: #param_ty) quote!(#unused_name: #param_ty)
}); });
let parameters_unused = quote!(#(#params_iter,)*); let parameters_unused = quote!(#(#params_iter,)*);
let parameter_validstructs: Vec<_> = params
.filter(|param| !param.validstructs.is_empty())
.map(|param| (param.param_ident(), param.validstructs.clone()))
.collect();
let ret = cmd let ret = cmd
.proto .proto
.type_name .type_name
@ -961,6 +970,7 @@ fn generate_function_pointers<'a>(
// This can happen because there are aliases to commands // This can happen because there are aliases to commands
type_needs_defining: fn_cache.insert(name), type_needs_defining: fn_cache.insert(name),
type_name, type_name,
pfn_type_name,
function_name_c, function_name_c,
function_name_rust, function_name_rust,
parameters, parameters,
@ -971,14 +981,49 @@ fn generate_function_pointers<'a>(
let ret_ty_tokens = name_to_tokens(ret); let ret_ty_tokens = name_to_tokens(ret);
quote!(-> #ret_ty_tokens) quote!(-> #ret_ty_tokens)
}, },
parameter_validstructs,
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
struct CommandToParamTraits<'a>(&'a Command<'a>);
impl<'a> quote::ToTokens for CommandToParamTraits<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
for (param_ident, validstructs) in &self.0.parameter_validstructs {
let param_ident = param_ident.to_string();
let param_ident = param_ident
.strip_prefix("pp_")
.or_else(|| param_ident.strip_prefix("p_"))
.unwrap_or(&param_ident);
let doc_string = format!(
"Implemented for all types that can be passed as argument to `{}` in [`{}`]",
param_ident, self.0.pfn_type_name
);
let param_trait_name = format_ident!(
"{}Param{}",
self.0.type_name,
param_ident.to_upper_camel_case()
);
quote! {
#[allow(non_camel_case_types)]
#[doc = #doc_string]
pub unsafe trait #param_trait_name {}
}
.to_tokens(tokens);
for validstruct in validstructs {
let structname = name_to_tokens(validstruct);
quote!(unsafe impl #param_trait_name for #structname {}).to_tokens(tokens);
}
}
}
}
struct CommandToType<'a>(&'a Command<'a>); struct CommandToType<'a>(&'a Command<'a>);
impl<'a> quote::ToTokens for CommandToType<'a> { impl<'a> quote::ToTokens for CommandToType<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let type_name = &self.0.type_name; let type_name = &self.0.pfn_type_name;
let parameters = &self.0.parameters; let parameters = &self.0.parameters;
let returns = &self.0.returns; let returns = &self.0.returns;
quote!( quote!(
@ -992,7 +1037,7 @@ fn generate_function_pointers<'a>(
struct CommandToMember<'a>(&'a Command<'a>); struct CommandToMember<'a>(&'a Command<'a>);
impl<'a> quote::ToTokens for CommandToMember<'a> { impl<'a> quote::ToTokens for CommandToMember<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let type_name = &self.0.type_name; let type_name = &self.0.pfn_type_name;
let type_name = if self.0.type_needs_defining { let type_name = if self.0.type_needs_defining {
// Type is defined in local scope // Type is defined in local scope
quote!(#type_name) quote!(#type_name)
@ -1033,6 +1078,7 @@ fn generate_function_pointers<'a>(
} }
} }
let param_traits = commands.iter().map(CommandToParamTraits);
let pfn_typedefs = commands let pfn_typedefs = commands
.iter() .iter()
.filter(|pfn| pfn.type_needs_defining) .filter(|pfn| pfn.type_needs_defining)
@ -1041,6 +1087,7 @@ fn generate_function_pointers<'a>(
let loaders = commands.iter().map(CommandToLoader); let loaders = commands.iter().map(CommandToLoader);
quote! { quote! {
#(#param_traits)*
#(#pfn_typedefs)* #(#pfn_typedefs)*
#[derive(Clone)] #[derive(Clone)]