Skip to content

Introduce ash-swapchain helper crate#506

Open
Ralith wants to merge 2 commits into
ash-rs:masterfrom
Ralith:swapchain
Open

Introduce ash-swapchain helper crate#506
Ralith wants to merge 2 commits into
ash-rs:masterfrom
Ralith:swapchain

Conversation

@Ralith

@Ralith Ralith commented Dec 5, 2021

Copy link
Copy Markdown
Collaborator

This implements a reusable, lightly-opinionated helper for typical resizable windowed swapchain operation, which is otherwise error-prone.

Comment on lines +270 to +291
&[vk::SubmitInfo::builder()
.wait_semaphores(&[acq.ready])
.wait_dst_stage_mask(&[vk::PipelineStageFlags::TRANSFER])
.signal_semaphores(&[self.frames[acq.frame_index].complete])
.command_buffers(&[cmd])
.build()],

@MarijnS95 MarijnS95 Dec 5, 2021

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

When needing a slice of a single element that is created by a builder, I typically use std::slice::as_ref() which allows the builder to Deref without calling .build().

Edit: Same for a few other single-element slice constructs in this PR.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

That seems like extraneous ceremony to me, since this build call is lexically within the statement that consumes it and therefore sound regardless.

Comment thread ash-swapchain/src/lib.rs Outdated
@Ralith Ralith marked this pull request as ready for review December 11, 2021 19:04
@Ralith Ralith force-pushed the swapchain branch 2 times, most recently from 678186d to b5d68ce Compare December 11, 2021 19:22
@Ralith

Ralith commented Dec 11, 2021

Copy link
Copy Markdown
Collaborator Author

I'm now confident the resize handling here is as well-behaved as the presentation API permits. Expanded the doc comments a good bit too.

@Ralith Ralith force-pushed the swapchain branch 3 times, most recently from f303def to fcbaa31 Compare December 11, 2021 21:20
Comment thread ash-swapchain/src/lib.rs Outdated
MarijnS95 added a commit that referenced this pull request Dec 19, 2021
As per the readme `.build()` should only be called as late as possible,
and only if absolutely necessary; such cases include slices that are
passed directly to functions.  More precisely, such build calls and the
creation of temporary slices should happen inside the same expression as
the function call to be sound and completely lifetime-checked.

This pattern of `&[my_builder.build()]` is however not possible when
constructing intermediary Vulkan objects that reference the slice.  In
the first place this slice goes out of scope after the expression that
creates the Vulkan object, which is caught and disallowed by rustc
(unless this expression itself ends in `.build()`, which is completely
 unsound as it makes rustc unable to validate this lifetime dependency).

In the second place - and as is most relevant for this patch that
removes `.build()` calls that were not surrounded by temporary slice
constructors - said expression drops the lifetime checks on anything
held by `my_builder` which _could_ go out of scope before the newly
constructed Vulkan object is used, resulting yet again in Undefined
Behaviour.

Fortunately, for slices of size 1 which are typical in Vulkan,
`std::slice::as_ref` exists which is analogous to taking a pointer to an
object and considering it an array of length 1 in C(++).  This maintains
the lifetime through `Deref` and makes rustc able to fully check all
lifetimes and prevent unsound code.

Albeit improving overall consistency, the `&[my_builder.build()]`
pattern is not substituted in aforementioned Vulkan function-call
expressions as that is considered "extraneous" [1] and demonstrates the
various ways to safely construct Vulkan objects for the observant reader.

[1]: #506 (comment)
Ralith pushed a commit that referenced this pull request Dec 20, 2021
As per the readme `.build()` should only be called as late as possible,
and only if absolutely necessary; such cases include slices that are
passed directly to functions.  More precisely, such build calls and the
creation of temporary slices should happen inside the same expression as
the function call to be sound and completely lifetime-checked.

This pattern of `&[my_builder.build()]` is however not possible when
constructing intermediary Vulkan objects that reference the slice.  In
the first place this slice goes out of scope after the expression that
creates the Vulkan object, which is caught and disallowed by rustc
(unless this expression itself ends in `.build()`, which is completely
 unsound as it makes rustc unable to validate this lifetime dependency).

In the second place - and as is most relevant for this patch that
removes `.build()` calls that were not surrounded by temporary slice
constructors - said expression drops the lifetime checks on anything
held by `my_builder` which _could_ go out of scope before the newly
constructed Vulkan object is used, resulting yet again in Undefined
Behaviour.

Fortunately, for slices of size 1 which are typical in Vulkan,
`std::slice::as_ref` exists which is analogous to taking a pointer to an
object and considering it an array of length 1 in C(++).  This maintains
the lifetime through `Deref` and makes rustc able to fully check all
lifetimes and prevent unsound code.

Albeit improving overall consistency, the `&[my_builder.build()]`
pattern is not substituted in aforementioned Vulkan function-call
expressions as that is considered "extraneous" [1] and demonstrates the
various ways to safely construct Vulkan objects for the observant reader.

[1]: #506 (comment)
@MaikKlein

Copy link
Copy Markdown
Member

A few high level comments:

This would need a readme that quickly explains the purpose of this library (The why and how). Similar to what ash-window has. We should probably also promote our helper crates in the main readme

On another note, should we use this in the ash examples as well?

@Ralith

Ralith commented Dec 24, 2021

Copy link
Copy Markdown
Collaborator Author

Added a brief README.

On another note, should we use this in the ash examples as well?

I'm kinda tempted to drop ash's current example entirely in favor of something like this demo.rs; if we don't try to teach Vulkan in general and focus on maximal simplicity, the (currently empirically unsustainable) maintenance effort required to keep the example in good shape will be much reduced.

@Ralith

Ralith commented Dec 24, 2021

Copy link
Copy Markdown
Collaborator Author

Replaced the AcquiredFramge::generation: u64 with a AcquiredFrame::invalidate_images: bool to make things a little less opinionated.

@Ralith Ralith force-pushed the swapchain branch 5 times, most recently from 4304185 to 36d99ec Compare December 24, 2021 19:43
Comment thread ash-swapchain/src/lib.rs
Comment thread ash-swapchain/src/lib.rs
};
self.needs_rebuild = true;

// Rebuild swapchain

This comment was marked as off-topic.

Comment thread ash-swapchain/src/lib.rs
impl Swapchain {
/// Construct a new [`Swapchain`] for rendering at most `frames_in_flight` frames
/// concurrently. `extent` should be the current dimensions of `surface`.
pub fn new(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this needs to be unsafe:

VUID-VkSwapchainCreateInfoKHR-surface-01270 states the device must be compatible with the surface. This function arguably has no way to test for that

brandonpollack23 pushed a commit to brandonpollack23/ash-bootstrap that referenced this pull request Dec 1, 2022
Swapchain support courtesy of Ralith
ash-rs/ash#506 - thanks!
@Ralith

Ralith commented Sep 18, 2023

Copy link
Copy Markdown
Collaborator Author

This should be heavily revised to take advantage of VK_EXT_swapchain_maintenance1, which resolves some key ambiguities in the base extension.

@Ralith

Ralith commented Nov 26, 2025

Copy link
Copy Markdown
Collaborator Author

I think this should draw inspiration from #1019 to load and cache the function pointer tables internally rather than requiring the user to awkwardly pass them in. Storing some redundant function pointers isn't a big deal.

VK_EXT_swapchain_maintenance1

AFAIK this is still not implemented by all major vendors on desktop, so maybe not a good target :(

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants