Skip to content

Commit

Permalink
extensions: Separate wrappers between instance and device functions
Browse files Browse the repository at this point in the history
Not only is it more efficient to load specialized device functions via
`get_device_proc_addr()` instead of `get_instance_proc_addr()` (saves a
device-based jump in the ICD), loading instance functions via
`get_device_proc_addr()` (which was the case in `VK_KHR_swapchain`,
`VK_KHR_device_group` and `VK_EXT_full_screen_exclusive`) always results
in a `NULL` causing their instance functions panic no matter what.

Low-level `*Fn` structs are separated out between instance and device
pointers for every extension that contains both, forcing users
(typically high-level extension writers) to explicitly account for this.
  • Loading branch information
MarijnS95 committed Aug 28, 2023
1 parent 38c203b commit cc1c114
Show file tree
Hide file tree
Showing 11 changed files with 369 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ pub struct ExternalMemoryAndroidHardwareBuffer {
impl ExternalMemoryAndroidHardwareBuffer {
pub fn new(instance: &Instance, device: &Device) -> Self {
let handle = device.handle();
let fp = vk::android_external_memory_android_hardware_buffer::DeviceFn::load(|name| unsafe {
mem::transmute(instance.get_device_proc_addr(handle, name.as_ptr()))
});
let fp =
vk::android_external_memory_android_hardware_buffer::DeviceFn::load(|name| unsafe {
mem::transmute(instance.get_device_proc_addr(handle, name.as_ptr()))
});
Self { handle, fp }
}

Expand All @@ -42,7 +43,8 @@ impl ExternalMemoryAndroidHardwareBuffer {
.result_with_success(buffer)
}

pub const NAME: &'static CStr = vk::android_external_memory_android_hardware_buffer::DeviceFn::NAME;
pub const NAME: &'static CStr =
vk::android_external_memory_android_hardware_buffer::DeviceFn::NAME;

#[inline]
pub fn fp(&self) -> &vk::android_external_memory_android_hardware_buffer::DeviceFn {
Expand Down
77 changes: 50 additions & 27 deletions ash/src/extensions/ext/calibrated_timestamps.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,40 @@
use crate::prelude::*;
use crate::vk;
use crate::{Entry, Instance};
use crate::{Device, Entry, Instance};
use std::ffi::CStr;
use std::mem;

pub const NAME: &CStr = vk::ext_calibrated_timestamps::InstanceFn::NAME;

/// High-level device function wrapper for
/// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_calibrated_timestamps.html>
#[derive(Clone)]
pub struct CalibratedTimestamps {
handle: vk::Instance,
pub struct CalibratedTimestampsDevice {
handle: vk::Device,
fp: vk::ext_calibrated_timestamps::DeviceFn,
}

impl CalibratedTimestamps {
pub fn new(entry: &Entry, instance: &Instance) -> Self {
let handle = instance.handle();
impl CalibratedTimestampsDevice {
pub fn new(instance: &Instance, device: &Device) -> Self {
let handle = device.handle();
let fp = vk::ext_calibrated_timestamps::DeviceFn::load(|name| unsafe {
mem::transmute(entry.get_instance_proc_addr(handle, name.as_ptr()))
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/vkGetPhysicalDeviceCalibrateableTimeDomainsEXT.html>
#[inline]
pub unsafe fn get_physical_device_calibrateable_time_domains(
&self,
physical_device: vk::PhysicalDevice,
) -> VkResult<Vec<vk::TimeDomainEXT>> {
read_into_uninitialized_vector(|count, data| {
(self.fp.get_physical_device_calibrateable_time_domains_ext)(
physical_device,
count,
data,
)
})
}

/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetCalibratedTimestampsEXT.html>
///
/// Returns a tuple containing `(timestamps, max_deviation)`
#[inline]
pub unsafe fn get_calibrated_timestamps(
&self,
device: vk::Device,
info: &[vk::CalibratedTimestampInfoEXT],
) -> VkResult<(Vec<u64>, u64)> {
let mut timestamps = vec![0u64; info.len()];
let mut max_deviation = 0u64;
(self.fp.get_calibrated_timestamps_ext)(
device,
self.handle,
info.len() as u32,
info.as_ptr(),
timestamps.as_mut_ptr(),
Expand All @@ -55,15 +43,50 @@ impl CalibratedTimestamps {
.result_with_success((timestamps, max_deviation))
}

pub const NAME: &'static CStr = vk::ext_calibrated_timestamps::DeviceFn::NAME;

#[inline]
pub fn fp(&self) -> &vk::ext_calibrated_timestamps::DeviceFn {
&self.fp
}

#[inline]
pub fn instance(&self) -> vk::Instance {
pub fn device(&self) -> vk::Device {
self.handle
}
}

/// High-level instance function wrapper for
/// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_calibrated_timestamps.html>
#[derive(Clone)]
pub struct CalibratedTimestampsInstance {
fp: vk::ext_calibrated_timestamps::InstanceFn,
}

impl CalibratedTimestampsInstance {
pub fn new(entry: &Entry, instance: &Instance) -> Self {
let handle = instance.handle();
let fp = vk::ext_calibrated_timestamps::InstanceFn::load(|name| unsafe {
mem::transmute(entry.get_instance_proc_addr(handle, name.as_ptr()))
});
Self { fp }
}

/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetPhysicalDeviceCalibrateableTimeDomainsEXT.html>
#[inline]
pub unsafe fn get_physical_device_calibrateable_time_domains(
&self,
physical_device: vk::PhysicalDevice,
) -> VkResult<Vec<vk::TimeDomainEXT>> {
read_into_uninitialized_vector(|count, data| {
(self.fp.get_physical_device_calibrateable_time_domains_ext)(
physical_device,
count,
data,
)
})
}

#[inline]
pub fn fp(&self) -> &vk::ext_calibrated_timestamps::InstanceFn {
&self.fp
}
}
54 changes: 41 additions & 13 deletions ash/src/extensions/ext/debug_utils.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
use crate::prelude::*;
use crate::{vk, RawPtr};
use crate::{Entry, Instance};
use crate::{Device, Entry, Instance};
use std::ffi::CStr;
use std::mem;

pub const NAME: &CStr = vk::ext_debug_utils::NAME;

/// High-level device function wrapper for
/// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_debug_utils.html>
#[derive(Clone)]
pub struct DebugUtils {
handle: vk::Instance,
pub struct DebugUtilsDevice {
handle: vk::Device,
fp: vk::ext_debug_utils::DeviceFn,
}

impl DebugUtils {
pub fn new(entry: &Entry, instance: &Instance) -> Self {
let handle = instance.handle();
impl DebugUtilsDevice {
pub fn new(instance: &Instance, device: &Device) -> Self {
let handle = device.handle();
let fp = vk::ext_debug_utils::DeviceFn::load(|name| unsafe {
mem::transmute(entry.get_instance_proc_addr(handle, name.as_ptr()))
mem::transmute(instance.get_device_proc_addr(handle, name.as_ptr()))
});
Self { handle, fp }
}
Expand All @@ -23,20 +27,18 @@ impl DebugUtils {
#[inline]
pub unsafe fn set_debug_utils_object_name(
&self,
device: vk::Device,
name_info: &vk::DebugUtilsObjectNameInfoEXT,
) -> VkResult<()> {
(self.fp.set_debug_utils_object_name_ext)(device, name_info).result()
(self.fp.set_debug_utils_object_name_ext)(self.handle, name_info).result()
}

/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkSetDebugUtilsObjectTagEXT.html>
#[inline]
pub unsafe fn set_debug_utils_object_tag(
&self,
device: vk::Device,
tag_info: &vk::DebugUtilsObjectTagInfoEXT,
) -> VkResult<()> {
(self.fp.set_debug_utils_object_tag_ext)(device, tag_info).result()
(self.fp.set_debug_utils_object_tag_ext)(self.handle, tag_info).result()
}

/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkCmdBeginDebugUtilsLabelEXT.html>
Expand Down Expand Up @@ -91,6 +93,34 @@ impl DebugUtils {
(self.fp.queue_insert_debug_utils_label_ext)(queue, label);
}

#[inline]
pub fn fp(&self) -> &vk::ext_debug_utils::DeviceFn {
&self.fp
}

#[inline]
pub fn device(&self) -> vk::Device {
self.handle
}
}

/// High-level instance function wrapper for
/// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_debug_utils.html>
#[derive(Clone)]
pub struct DebugUtilsInstance {
handle: vk::Instance,
fp: vk::ext_debug_utils::InstanceFn,
}

impl DebugUtilsInstance {
pub fn new(entry: &Entry, instance: &Instance) -> Self {
let handle = instance.handle();
let fp = vk::ext_debug_utils::InstanceFn::load(|name| unsafe {
mem::transmute(entry.get_instance_proc_addr(handle, name.as_ptr()))
});
Self { handle, fp }
}

/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkCreateDebugUtilsMessengerEXT.html>
#[inline]
pub unsafe fn create_debug_utils_messenger(
Expand Down Expand Up @@ -134,8 +164,6 @@ impl DebugUtils {
);
}

pub const NAME: &'static CStr = vk::ext_debug_utils::DeviceFn::NAME;

#[inline]
pub fn fp(&self) -> &vk::ext_debug_utils::DeviceFn {
&self.fp
Expand Down
68 changes: 46 additions & 22 deletions ash/src/extensions/ext/full_screen_exclusive.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
use crate::prelude::*;
use crate::vk;
use crate::{Device, Instance};
use crate::{Device, Entry, Instance};
use std::ffi::CStr;
use std::mem;

pub const NAME: &CStr = vk::ext_full_screen_exclusive::NAME;

/// High-level device function wrapper for
/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_EXT_full_screen_exclusive.html>
#[derive(Clone)]
pub struct FullScreenExclusive {
pub struct FullScreenExclusiveDevice {
handle: vk::Device,
fp: vk::ext_full_screen_exclusive::DeviceFn,
}

impl FullScreenExclusive {
impl FullScreenExclusiveDevice {
pub fn new(instance: &Instance, device: &Device) -> Self {
let handle = device.handle();
let fp = vk::ext_full_screen_exclusive::DeviceFn::load(|name| unsafe {
Expand All @@ -28,23 +32,6 @@ impl FullScreenExclusive {
(self.fp.acquire_full_screen_exclusive_mode_ext)(self.handle, swapchain).result()
}

/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetPhysicalDeviceSurfacePresentModes2EXT.html>
#[inline]
pub unsafe fn get_physical_device_surface_present_modes2(
&self,
physical_device: vk::PhysicalDevice,
surface_info: &vk::PhysicalDeviceSurfaceInfo2KHR,
) -> VkResult<Vec<vk::PresentModeKHR>> {
read_into_uninitialized_vector(|count, data| {
(self.fp.get_physical_device_surface_present_modes2_ext)(
physical_device,
surface_info,
count,
data,
)
})
}

/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkReleaseFullScreenExclusiveModeEXT.html>
#[inline]
pub unsafe fn release_full_screen_exclusive_mode(
Expand All @@ -69,8 +56,6 @@ impl FullScreenExclusive {
.result_with_success(present_modes)
}

pub const NAME: &'static CStr = vk::ext_full_screen_exclusive::DeviceFn::NAME;

#[inline]
pub fn fp(&self) -> &vk::ext_full_screen_exclusive::DeviceFn {
&self.fp
Expand All @@ -81,3 +66,42 @@ impl FullScreenExclusive {
self.handle
}
}

/// High-level instance function wrapper for
/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_EXT_full_screen_exclusive.html>
#[derive(Clone)]
pub struct FullScreenExclusiveInstance {
fp: vk::ext_full_screen_exclusive::InstanceFn,
}

impl FullScreenExclusiveInstance {
pub fn new(entry: &Entry, instance: &Instance) -> Self {
let handle = instance.handle();
let fp = vk::ext_full_screen_exclusive::InstanceFn::load(|name| unsafe {
mem::transmute(entry.get_instance_proc_addr(handle, name.as_ptr()))
});
Self { fp }
}

/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetPhysicalDeviceSurfacePresentModes2EXT.html>
#[inline]
pub unsafe fn get_physical_device_surface_present_modes2(
&self,
physical_device: vk::PhysicalDevice,
surface_info: &vk::PhysicalDeviceSurfaceInfo2KHR,
) -> VkResult<Vec<vk::PresentModeKHR>> {
read_into_uninitialized_vector(|count, data| {
(self.fp.get_physical_device_surface_present_modes2_ext)(
physical_device,
surface_info,
count,
data,
)
})
}

#[inline]
pub fn fp(&self) -> &vk::ext_full_screen_exclusive::InstanceFn {
&self.fp
}
}
8 changes: 4 additions & 4 deletions ash/src/extensions/ext/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
pub use self::acquire_drm_display::AcquireDrmDisplay;
pub use self::buffer_device_address::BufferDeviceAddress;
pub use self::calibrated_timestamps::CalibratedTimestamps;
pub use self::calibrated_timestamps::{CalibratedTimestampsDevice, CalibratedTimestampsInstance};
#[allow(deprecated)]
pub use self::debug_marker::DebugMarker;
#[allow(deprecated)]
pub use self::debug_report::DebugReport;
pub use self::debug_utils::DebugUtils;
pub use self::debug_utils::{DebugUtilsDevice, DebugUtilsInstance};
pub use self::descriptor_buffer::DescriptorBuffer;
pub use self::extended_dynamic_state::ExtendedDynamicState;
pub use self::extended_dynamic_state2::ExtendedDynamicState2;
pub use self::extended_dynamic_state3::ExtendedDynamicState3;
pub use self::full_screen_exclusive::FullScreenExclusive;
pub use self::full_screen_exclusive::{FullScreenExclusiveDevice, FullScreenExclusiveInstance};
pub use self::headless_surface::HeadlessSurface;
pub use self::host_image_copy::HostImageCopy;
pub use self::image_compression_control::ImageCompressionControl;
Expand All @@ -19,7 +19,7 @@ pub use self::mesh_shader::MeshShader;
pub use self::metal_surface::MetalSurface;
pub use self::pipeline_properties::PipelineProperties;
pub use self::private_data::PrivateData;
pub use self::sample_locations::SampleLocations;
pub use self::sample_locations::{SampleLocationsDevice, SampleLocationsInstance};
pub use self::shader_object::ShaderObject;
pub use self::swapchain_maintenance1::SwapchainMaintenance1;
pub use self::tooling_info::ToolingInfo;
Expand Down
Loading

0 comments on commit cc1c114

Please sign in to comment.