vulkano-rs/vulkano

Async GPUFuture API

nshyrei opened this issue · 2 comments

Hello, I see that there is a Future (https://doc.rust-lang.org/std/future/trait.Future.html) implementation for
FenceSignalFuture

pub struct FenceSignalFuture<F>
which allows to use Rust async/await with said type. However I don't fully understand how can this be used in conjunction with functions that allow to execute commands on the gpu like
then_execute
fn then_execute(
or
then_swapchain_present
fn then_swapchain_present(

It seems like there is an additional functional layer missing to make this work and I don't fully understand if it is a complicated feature to add or no. My main question here is: how is GPU future different than the one that does file or networking I/O ?

GpuFuture does in fact have nothing at all to do with Rust Futures.

Vulkan is an async API by default; there's no way around it. When you submit a batch of work to a queue, it gets sent off to the kernel driver and then the function returns. At no point in time are you waiting on the work to complete when submitting work, only on the submission itself. The only ways you can wait for completion is by waiting on the fence (or checking its status repeatedly until it is complete). Or waiting for idle which does the same thing but on a queue-wide or device-wide level. There's timeline semaphores as well as of late which you can wait for on the host.

Rust futures on the other hand are meant for async I/O. They allow you to suspend a future while it is waiting on some event (such as a file read becoming available or a socket getting new data) and run other Rust code in the meantime (other futures and the executor itself). Notice how Rust futures are not useful at all for CPU-bound work, only for I/O. Notice also how the operations that you mentioned, such as then_execute and such, are only doing CPU-bound work. Same goes for submitting work to a queue, it's CPU-bound. There's nothing to wait on in order to run other Rust code in the meantime because the code never suspends. Rust sync code is the only sensible option. When it comes to waiting on a fence, that's a bit more murky. Clearly we are waiting on some external event and can run other Rust code in the meantime. But at the same time, this event is not sent to us as part of the Rust async executor's event loop. So the best we can do is what's called a "spin future" which is exactly what it sounds like. It's scuffed either way.

TL;DR: Vulkan is 100% async, but 0% in the Rust sense.

Thanks for explanation.