I recently started to learn vulkan api and it contains synchronization primitives such as fences and semaphores. Is it possible to somehow integrate them with zig Io primitives? For example if i want to wait for a fence but maybe do some work at the same time on another thread (green thread).
In practice i feel like it won’t be such a big issue since game is highly likely to use Io.Threaded which will be able to integrate nicely with any type of uncooperative blocking. Or maybe anything related to graphics works with Io.Threaded and anything related to networking used Io.Evented. But maybe someone has ideas about it.
Tbh I would be conservative and keep those things completely separated, especially for games where all timing is strictly dictated by the frame tick. E.g. at most use std.Io as interface to the OS for doing async file IO and networking, but even there it’s a bit unclear to me how that would work in a ‘game runtime environment’, since all async operations would either need to be polled or use a completion callback (can’t use await in ‘per-frame-code’ because it would block the frame loop).
Also in a typical Vulkan render loop you’d want to move all the heavy CPU work in a frame in front of any wait operations on Vulkan fences (e.g. the swapchain or queue-submit fences), e.g. there should be nothing left to do on the CPU for that frame anyway while waiting for the fence so that this fence is either used to throttle the frame rate to vsync, or with vsync off ideally the fence is already signalled and the wait is a no-op.
I would also try to avoid green-threading in a game because a long-running background task that doesn’t yield can completely disrupt your carefully arranged frame time budgets.
But even with proper threading you can’t await anything in the frame loop anyway since that would ‘freeze’ rendering until the await resolves, and without await, async is only half as useful (is it even possible to poll a std.Io.Future for completion or attach a completion callback?).
Maybe it makes sense thinking about a custom ‘frame-aware’ std.Io runtime specialized for games, where the traditional ‘per-frame function’ is disolved into many small per-frame-tasks with dependencies which need to complete within the same frame (allowing await to be used to schedule other such ‘micro-tasks’ within the same frame), or long-running background tasks (like file IO) which may take many frames to complete. But this could just as well be done by a relatively simple task scheduler, and trying to fit this into the std.Io interface sounds just wrong to me.
What i do currently is pass a queue to async task and use std.Io.Queue.get which allows to get nonblocking completion results. And tasks themselfs are spawned in Group so i can cancel or await them when app exits
you cant poll a future, but you can implement your own polling on top of futures through some other mechanism, like a queue or even just an atomic bool