Skip to content

Commit 52cb83d

Browse files
committed
extensions: Provide new_from_instance() fallback for Instance functions
This is a minimal, semver-compatible backport of #734 to the `0.37-stable` branch, warning Ash users of the problem outlined below while the issue is properly being solved in the next breaking Ash release (by separating `Instance` and `Device` functions in the generator to avert this problem entirely while also always providing optimal `Device`-specific functions for extension wrappers that are currently already loading _everything_ via `Instance` to forgo the problem). As discovered and detailed in #727 a few extension wrappers were loading and calling `Instance` functions via `Device` and `get_device_proc_addr()` which is [defined] to only return non-`NULL` function pointers for `Device` functions. Those wrapper functions will always call into Ash's panicking NULL-stub functions as the desired `Instance` function could not be loaded. Deprecate the `new()` functions for extension wrappers that were doing this, while pointing the reader to `new_from_instance()` and explaining in the docs what function will always `panic!()` when the struct was loaded using `new()` instead. This function always takes a raw `vk::Device` directly to fill `handle` (rather than `ash::Device` to retrieve `handle()` from), allowing users to pass `vk::Device::null()` when they do intend to load this extension wrapper just for calling the `Instance` function. [defined]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetDeviceProcAddr.html#_description
1 parent a2d17fe commit 52cb83d

File tree

5 files changed

+95
-8
lines changed

5 files changed

+95
-8
lines changed

Changelog.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased] - ReleaseDate
99

10+
### Changed
11+
12+
- `VK_KHR_device_group_creation`: Replaced `device()` with `instance()` (via deprecation) because it is returning `vk::Instance` (#744)
13+
1014
### Added
1115

1216
- Added `VK_EXT_pipeline_properties` device extension (#622)
1317
- Update Vulkan-Headers to 1.3.246 (#697, #723)
1418
- Added `VK_KHR_performance_query` device extension (#726)
1519
- Added `VK_EXT_shader_object` device extension (#732)
1620
- Added missing `Device::get_device_queue2()` wrapper (#736)
21+
- Added with `new_with_instance()` on the following extensions to allow loading the listed `Instance` functions: (#744)
22+
- `VK_KHR_swapchain`: `get_physical_device_present_rectangles()`
23+
- `VK_KHR_device_group`: `get_physical_device_present_rectangles()`
24+
- `VK_EXT_full_screen_exclusive`: `get_physical_device_surface_present_modes2()`
1725
- Exposed `FramebufferCreateInfoBuilder::attachment_count()` builder for `vk::FramebufferCreateFlags::IMAGELESS` (#747)
1826

1927
## [0.37.2] - 2022-01-11
@@ -52,7 +60,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5260
- Added `VK_EXT_extended_dynamic_state3` device extension (#671)
5361
- Added `VK_EXT_descriptor_buffer` instance extension (#679)
5462

55-
5663
### Fixed
5764

5865
- `VK_KHR_ray_tracing_pipeline`: Set the buffer length in `get_ray_tracing_capture_replay_shader_group_handles` so it no longer always returns an empty `Vec` (#658)
@@ -296,7 +303,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
296303

297304
### 0.29.0
298305

299-
- -Breaking-: Removed Display impl for flags. The Debug impl now reports flags by name.
306+
- _Breaking_: Removed Display impl for flags. The Debug impl now reports flags by name.
300307
- Functions now have a doc comment that links to the Vulkan spec
301308
- Entry has a new method called `try_enumerate_instance_version` which can be used in a 1.0 context.
302309
- The generator now uses `BTreeMap` for better diffs.
@@ -305,9 +312,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
305312

306313
- Switched to a new [changelog](https://keepachangelog.com/en/1.0.0/) format
307314
- Fixed a build issue on ARM.
308-
- -Breaking- Arrays are now passed by reference.
315+
- _Breaking_: Arrays are now passed by reference.
309316
- Builders are now marked as `#[transparent]`.
310-
- -Breaking- Renamed `.next(..)` to `push_next`. `push_next` is only available on structs that are passed directly. Additionally `push_next` only accepts structs that can be inserted into the pointer chain. Read the readme for more information.
317+
- _Breaking_: Renamed `.next(..)` to `push_next`. `push_next` is only available on structs that are passed directly. Additionally `push_next` only accepts structs that can be inserted into the pointer chain. Read the readme for more information.
311318
- New -experimental- extensions. Those do not follow the semver rules and can be removed at any time.
312319
- Added `AmdGpaInterface` extension.
313320

@@ -372,7 +379,7 @@ flags: vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER_BIT,
372379
- `map_memory` now returns a void ptr
373380

374381
- `ash::util::Align` is a helper struct that
375-
can write to aligned memory.
382+
can write to aligned memory.
376383

377384
[Unreleased]: https://github.com/MaikKlein/ash/compare/0.37.2...HEAD
378385
[0.37.2]: https://github.com/MaikKlein/ash/releases/tag/0.37.2

ash/src/extensions/ext/full_screen_exclusive.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
use crate::prelude::*;
22
use crate::vk;
3-
use crate::{Device, Instance};
3+
use crate::{Device, Entry, Instance};
44
use std::ffi::CStr;
55
use std::mem;
66

7+
/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_EXT_full_screen_exclusive.html>
78
#[derive(Clone)]
89
pub struct FullScreenExclusive {
910
handle: vk::Device,
1011
fp: vk::ExtFullScreenExclusiveFn,
1112
}
1213

1314
impl FullScreenExclusive {
15+
/// # Warning
16+
/// [`Instance`] functions cannot be loaded from a [`Device`] and will always panic when called:
17+
/// - [`Self::get_physical_device_surface_present_modes2()`]
18+
///
19+
/// Load this struct using an [`Instance`] instead via [`Self::new_from_instance()`] if the
20+
/// above [`Instance`] function is called. This will be solved in the next breaking `ash`
21+
/// release: <https://github.com/ash-rs/ash/issues/727>.
1422
pub fn new(instance: &Instance, device: &Device) -> Self {
1523
let handle = device.handle();
1624
let fp = vk::ExtFullScreenExclusiveFn::load(|name| unsafe {
@@ -19,6 +27,19 @@ impl FullScreenExclusive {
1927
Self { handle, fp }
2028
}
2129

30+
/// Loads all functions on the [`Instance`] instead of [`Device`]. This incurs an extra
31+
/// dispatch table for [`Device`] functions but also allows the [`Instance`] function to be
32+
/// loaded instead of always panicking. See also [`Self::new()`] for more details.
33+
///
34+
/// It is okay to pass [`vk::Device::null()`] when this struct is only used to call the
35+
/// [`Instance`] function.
36+
pub fn new_from_instance(entry: &Entry, instance: &Instance, device: vk::Device) -> Self {
37+
let fp = vk::ExtFullScreenExclusiveFn::load(|name| unsafe {
38+
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
39+
});
40+
Self { handle: device, fp }
41+
}
42+
2243
/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkAcquireFullScreenExclusiveModeEXT.html>
2344
#[inline]
2445
pub unsafe fn acquire_full_screen_exclusive_mode(
@@ -29,6 +50,10 @@ impl FullScreenExclusive {
2950
}
3051

3152
/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetPhysicalDeviceSurfacePresentModes2EXT.html>
53+
///
54+
/// # Warning
55+
///
56+
/// Function will always panic unless this struct is loaded via [`Self::new_from_instance()`].
3257
#[inline]
3358
pub unsafe fn get_physical_device_surface_present_modes2(
3459
&self,

ash/src/extensions/khr/device_group.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use super::Swapchain;
33
use crate::prelude::*;
44
use crate::vk;
5-
use crate::{Device, Instance};
5+
use crate::{Device, Entry, Instance};
66
use std::ffi::CStr;
77
use std::mem;
88

@@ -14,6 +14,13 @@ pub struct DeviceGroup {
1414
}
1515

1616
impl DeviceGroup {
17+
/// # Warning
18+
/// [`Instance`] functions cannot be loaded from a [`Device`] and will always panic when called:
19+
/// - [`Self::get_physical_device_present_rectangles()`]
20+
///
21+
/// Load this struct using an [`Instance`] instead via [`Self::new_from_instance()`] if the
22+
/// above [`Instance`] function is called. This will be solved in the next breaking `ash`
23+
/// release: <https://github.com/ash-rs/ash/issues/727>.
1724
pub fn new(instance: &Instance, device: &Device) -> Self {
1825
let handle = device.handle();
1926
let fp = vk::KhrDeviceGroupFn::load(|name| unsafe {
@@ -22,6 +29,19 @@ impl DeviceGroup {
2229
Self { handle, fp }
2330
}
2431

32+
/// Loads all functions on the [`Instance`] instead of [`Device`]. This incurs an extra
33+
/// dispatch table for [`Device`] functions but also allows the [`Instance`] function to be
34+
/// loaded instead of always panicking. See also [`Self::new()`] for more details.
35+
///
36+
/// It is okay to pass [`vk::Device::null()`] when this struct is only used to call the
37+
/// [`Instance`] function.
38+
pub fn new_from_instance(entry: &Entry, instance: &Instance, device: vk::Device) -> Self {
39+
let fp = vk::KhrDeviceGroupFn::load(|name| unsafe {
40+
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
41+
});
42+
Self { handle: device, fp }
43+
}
44+
2545
/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetDeviceGroupPeerMemoryFeaturesKHR.html>
2646
#[inline]
2747
pub unsafe fn get_device_group_peer_memory_features(
@@ -112,6 +132,10 @@ impl DeviceGroup {
112132
///
113133
/// [Vulkan 1.1]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_VERSION_1_1.html
114134
/// [`VK_KHR_surface`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_KHR_surface.html
135+
///
136+
/// # Warning
137+
///
138+
/// Function will always panic unless this struct is loaded via [`Self::new_from_instance()`].
115139
#[inline]
116140
pub unsafe fn get_physical_device_present_rectangles(
117141
&self,

ash/src/extensions/khr/device_group_creation.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,14 @@ impl DeviceGroupCreation {
5959
&self.fp
6060
}
6161

62+
#[deprecated = "typo: this function is called `device()`, but returns an `Instance`."]
6263
#[inline]
6364
pub fn device(&self) -> vk::Instance {
6465
self.handle
6566
}
67+
68+
#[inline]
69+
pub fn instance(&self) -> vk::Instance {
70+
self.handle
71+
}
6672
}

ash/src/extensions/khr/swapchain.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@ use super::DeviceGroup;
33
use crate::prelude::*;
44
use crate::vk;
55
use crate::RawPtr;
6-
use crate::{Device, Instance};
6+
use crate::{Device, Entry, Instance};
77
use std::ffi::CStr;
88
use std::mem;
99

10+
/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_KHR_swapchain.html>
1011
#[derive(Clone)]
1112
pub struct Swapchain {
1213
handle: vk::Device,
1314
fp: vk::KhrSwapchainFn,
1415
}
1516

1617
impl Swapchain {
18+
/// # Warning
19+
/// [`Instance`] functions cannot be loaded from a [`Device`] and will always panic when called:
20+
/// - [`Self::get_physical_device_present_rectangles()`]
21+
///
22+
/// Load this struct using an [`Instance`] instead via [`Self::new_from_instance()`] if the
23+
/// above [`Instance`] function is called. This will be solved in the next breaking `ash`
24+
/// release: <https://github.com/ash-rs/ash/issues/727>.
1725
pub fn new(instance: &Instance, device: &Device) -> Self {
1826
let handle = device.handle();
1927
let fp = vk::KhrSwapchainFn::load(|name| unsafe {
@@ -22,6 +30,19 @@ impl Swapchain {
2230
Self { handle, fp }
2331
}
2432

33+
/// Loads all functions on the [`Instance`] instead of [`Device`]. This incurs an extra
34+
/// dispatch table for [`Device`] functions but also allows the [`Instance`] function to be
35+
/// loaded instead of always panicking. See also [`Self::new()`] for more details.
36+
///
37+
/// It is okay to pass [`vk::Device::null()`] when this struct is only used to call the
38+
/// [`Instance`] function.
39+
pub fn new_from_instance(entry: &Entry, instance: &Instance, device: vk::Device) -> Self {
40+
let fp = vk::KhrSwapchainFn::load(|name| unsafe {
41+
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
42+
});
43+
Self { handle: device, fp }
44+
}
45+
2546
/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkCreateSwapchainKHR.html>
2647
#[inline]
2748
pub unsafe fn create_swapchain(
@@ -153,6 +174,10 @@ impl Swapchain {
153174
///
154175
/// [Vulkan 1.1]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_VERSION_1_1.html
155176
/// [`VK_KHR_surface`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_KHR_surface.html
177+
///
178+
/// # Warning
179+
///
180+
/// Function will always panic unless this struct is loaded via [`Self::new_from_instance()`].
156181
#[inline]
157182
pub unsafe fn get_physical_device_present_rectangles(
158183
&self,

0 commit comments

Comments
 (0)