From cc3c5043769362a9e78d6f342026fed30f3ce7c7 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Tue, 5 Dec 2023 09:55:49 +0100 Subject: [PATCH] device,instance: Provide `load_with()` constructor for get_proc_addr closure While working on a GStreamer Vulkan interop example (where GStreamer-Vulkan opens the ICD and creates most objects for us, which need to be imported in an `ash::Instance` and `ash::Device`), it wasn't feasible to construct a `vk::EntryFnV1_0` and `vk::InstanceFnV1_0` with `extern` functions while keeping object data in some global static, especially `vk::InstanceFnV1_0` which contains many more functions that are not consumed by `Instance::load()`. GStreamer provides function loaders directly on its `GstVulkanInstance` and `GstVulkanDevice` which are desired to be used rather than attempting to open the same ICD and loading the same functions by hand. The original `Device::load()` and `Instance::load()` already create a closure internally, which is exactly what we need to expose to have a single callback that can hold the `&gst_vulkan::VulkanInstance/Device` state, and respond to a char-pointer name with a function pointer. Note that this doesn't map very clearly to `Entry`, where the `load()` constructor is named `from_static_fn()` and a closure signature is equally lacking. This is due `Entry` also storing `StaticFn` for various uses, which any constructor with just a closure won't (easily) be able to replicate. --- Changelog.md | 1 + ash/src/device.rs | 28 ++++++++++++++++++---------- ash/src/instance.rs | 22 ++++++++++++++-------- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Changelog.md b/Changelog.md index 7240e397..440f26dd 100644 --- a/Changelog.md +++ b/Changelog.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `descriptor_count()` setter on `ash::vk::WriteDescriptorSet` (#809) - Added `*_as_c_str()` getters for `c_char` pointers and `c_char` arrays (#831) - Added `#[must_use]` to Vulkan structs to make it more clear that they are moved by the builder pattern (#845) +- Added `load_with()` function on `Device` and `Instance` for providing custom `get_xxx_proc_addr()` implementations (#846) - Added `Send`/`Sync` to all Vulkan structs (#869) ### Changed diff --git a/ash/src/device.rs b/ash/src/device.rs index f35788a6..ae21dab0 100644 --- a/ash/src/device.rs +++ b/ash/src/device.rs @@ -2,8 +2,8 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; +use core::ffi; use std::mem; -use std::os::raw::c_void; use std::ptr; /// @@ -19,16 +19,24 @@ pub struct Device { impl Device { pub unsafe fn load(instance_fn: &vk::InstanceFnV1_0, device: vk::Device) -> Self { - let load_fn = |name: &std::ffi::CStr| { - mem::transmute((instance_fn.get_device_proc_addr)(device, name.as_ptr())) - }; + Self::load_with( + |name: &std::ffi::CStr| { + mem::transmute((instance_fn.get_device_proc_addr)(device, name.as_ptr())) + }, + device, + ) + } + pub unsafe fn load_with( + mut load_fn: impl FnMut(&ffi::CStr) -> *const ffi::c_void, + device: vk::Device, + ) -> Self { Self::from_parts_1_3( device, - vk::DeviceFnV1_0::load(load_fn), - vk::DeviceFnV1_1::load(load_fn), - vk::DeviceFnV1_2::load(load_fn), - vk::DeviceFnV1_3::load(load_fn), + vk::DeviceFnV1_0::load(&mut load_fn), + vk::DeviceFnV1_1::load(&mut load_fn), + vk::DeviceFnV1_2::load(&mut load_fn), + vk::DeviceFnV1_3::load(&mut load_fn), ) } @@ -951,7 +959,7 @@ impl Device { &self, descriptor_set: vk::DescriptorSet, descriptor_update_template: vk::DescriptorUpdateTemplate, - data: *const c_void, + data: *const ffi::c_void, ) { (self.device_fn_1_1.update_descriptor_set_with_template)( self.handle(), @@ -2273,7 +2281,7 @@ impl Device { offset: vk::DeviceSize, size: vk::DeviceSize, flags: vk::MemoryMapFlags, - ) -> VkResult<*mut c_void> { + ) -> VkResult<*mut ffi::c_void> { let mut data = mem::MaybeUninit::uninit(); (self.device_fn_1_0.map_memory)( self.handle(), diff --git a/ash/src/instance.rs b/ash/src/instance.rs index abb5c572..a4aca79d 100644 --- a/ash/src/instance.rs +++ b/ash/src/instance.rs @@ -4,8 +4,8 @@ use crate::device::Device; use crate::prelude::*; use crate::vk; use crate::RawPtr; +use core::ffi; use std::mem; -use std::os::raw::c_char; use std::ptr; /// @@ -20,15 +20,21 @@ pub struct Instance { impl Instance { pub unsafe fn load(static_fn: &vk::StaticFn, instance: vk::Instance) -> Self { - let load_fn = |name: &std::ffi::CStr| { - mem::transmute((static_fn.get_instance_proc_addr)(instance, name.as_ptr())) - }; + Self::load_with( + |name| mem::transmute((static_fn.get_instance_proc_addr)(instance, name.as_ptr())), + instance, + ) + } + pub unsafe fn load_with( + mut load_fn: impl FnMut(&ffi::CStr) -> *const ffi::c_void, + instance: vk::Instance, + ) -> Self { Self::from_parts_1_3( instance, - vk::InstanceFnV1_0::load(load_fn), - vk::InstanceFnV1_1::load(load_fn), - vk::InstanceFnV1_3::load(load_fn), + vk::InstanceFnV1_0::load(&mut load_fn), + vk::InstanceFnV1_1::load(&mut load_fn), + vk::InstanceFnV1_3::load(&mut load_fn), ) } @@ -374,7 +380,7 @@ impl Instance { pub unsafe fn get_device_proc_addr( &self, device: vk::Device, - p_name: *const c_char, + p_name: *const ffi::c_char, ) -> vk::PFN_vkVoidFunction { (self.instance_fn_1_0.get_device_proc_addr)(device, p_name) }