Skip to content

Conversation

@MarijnS95
Copy link
Collaborator

@MarijnS95 MarijnS95 commented Nov 21, 2025

Fixes #974

Even though create_surface() is typically off the hot path, we're repeatedly loading all platform-specific surface function pointers each time a new surface has to be created (sometimes for multiple windows, and on Android after every suspend-resume cycle when the app becomes invisible). In a subsequent patch these loaded extensions can be used to call their respective get_present_support() without reloading the entire function-pointer struct too.

Additionally some users seem to be confused about object lifetimes when seeing this Instance::new() being dropped inside the implementation. This patch only marginally addresses that and users are more than free to just drop their SurfaceFactory object if no longer used (or recreate it later) without having any impact on the "parent/child relationship" mentioned in the fn create_surface() documentation.

For now the choice has been made to store the passed DisplayHandle field with the enum variant when used in create_surface() to reduce ambiguity by not requiring it to be passed again. The user might still pass an incompatible WindowHandle in which case this returns ERROR_EXTENSION_NOT_PRESENT.

Copy link

@StarLederer StarLederer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coming from #974, I looked at the source code and figured that it probably doesn't matter if ash::khr::Surface::Instance instance is the same or not whenever it is being used to destroy surfaces, but I think it would be better if create_surface() returned both the vk::SurfaceKHR and ash::khr::Surface::Instance. This would be a very obvious clue that we can use the loader that is returned to destroy the surface later. This would also let us avoid executing redundant init code when creating the loader again right before or after one is already created inside create_surface().

I think that is very close to what this PR is doing but the PR also adds the ability to reuse the same extension/loader instance to create more surfaces later, if I understood correctly, so I think it is a good change.

Btw, I don't want to make any false impressions, I am very new to Vulkan and my experience with Rust is also limited so consider my comments with this in mind

Copy link
Collaborator

@Ralith Ralith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice design!

@MarijnS95 MarijnS95 force-pushed the ash-window-store-loaded-extension branch from 9b92e12 to 1d26882 Compare November 23, 2025 22:01
@MarijnS95 MarijnS95 changed the title ash-window: Keep loaded fns around via new SurfaceExtension object ash-window: Keep loaded fns around via new SurfaceFactory object Nov 23, 2025
Even though `create_surface()` is typically off the hot path, we're
repeatedly loading all platform-specific surface function pointers each
time a new surface has to be created (sometimes for multiple windows,
and on Android after every suspend-resume cycle when the app becomes
invisible).  In a subsequent patch these loaded extensions can be used
to call their respective `get_present_support()` without reloading the
entire function-pointer struct too.

Additionally some users seem to be confused about object lifetimes when
seeing this `Instance::new()` being dropped inside the implementation.
This patch only marginally addresses that and users are more than
free to just drop their `SurfaceFactory` object if no longer used
(or recreate it later) without having any impact on the "parent/child
relationship" mentioned in the `fn create_surface()` documentation.

For now the choice has been made to store the passed `DisplayHandle`
field with the enum variant when used in `create_surface()` to reduce
ambiguity by not requiring it to be passed again.  The user might
still pass an incompatible `WindowHandle` in which case this returns
`ERROR_EXTENSION_NOT_PRESENT`.
@MarijnS95 MarijnS95 force-pushed the ash-window-store-loaded-extension branch from 1d26882 to 989eb03 Compare November 25, 2025 09:33
impl SurfaceFactory {
/// Load the relevant surface extension for a given [`RawDisplayHandle`].
///
// TODO: Safety docs about Entry/Instance lifetime?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because neither new nor drop traverse display_handle, I don't think we need a formal safety comment here. The safety comment on create_surface is sufficient.

pub fn new(
entry: &Entry,
instance: &Instance,
// TODO: Return "lifetimed" on DisplayHandle?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea, but it might give users a false sense of security if we don't also track the lifetime of the window handle, which would require bundling a lifetime with the SurfaceKHR somehow. I'd leave this for future work -- updating ash-window should be much less disruptive than updating ash, anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ash_window loses access to Surface Instance

4 participants