error(vk_validation): vkDestroyImage(): cant be called on VkImage 0x1050000000105 that is currently in use by VkCommandBuffer 0x11555840.
The Vulkan spec states: All submitted commands that refer to image, either directly or via a VkImageView, must have completed execution (https://docs.vulkan.org/spec/latest/chapters/resources.html#VUID-vkDestroyImage-image-01000)
error(vk_validation): vkResetCommandPool(): (VkCommandBuffer 0x11555840) is in use.
The Vulkan spec states: All VkCommandBuffer objects allocated from commandPool must not be in the pending state (https://docs.vulkan.org/spec/latest/chapters/cmdbuffers.html#VUID-vkResetCommandPool-commandPool-00040)
error(vk_validation): vkBeginCommandBuffer(): on active VkCommandBuffer 0x11555840 before it has completed. You must check command buffer fence before this call.
The Vulkan spec states: commandBuffer must not be in the recording or pending state (https://docs.vulkan.org/spec/latest/chapters/cmdbuffers.html#VUID-vkBeginCommandBuffer-commandBuffer-00049)
error(vk_validation): vkQueueSubmit(): pSubmits[0].pCommandBuffers[0] VkCommandBuffer 0x11555840 is already in use and is not marked for simultaneous use.
The Vulkan spec states: If any element of the pCommandBuffers member of any element of pSubmits was not recorded with the VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, it must not be in the pending state (https://docs.vulkan.org/spec/latest/chapters/cmdbuffers.html#VUID-vkQueueSubmit-pCommandBuffers-00071)
Conceptually I love what your saying, and I too would love to adopt this style where possible. If it is possible to simplify things one should do so in general, to me atleast.
Me being a bit naive, do you reckon this loader for any generic library could possibly be automated by e.g. a zig library one could fetch? Or even as a step in build.zig? Or do you foresee this always being a bespoke approach?
I can easily imagine this being something I would like to do. However what you describe sounds like it would either require the technical skill or at the very be somewhat time intensive to implement.
Just want to tie a bow on this, now that I’ve had some time.
I’ve added implicit synchronization as a fallback if the explicit sync setup fails, which means it now works with Nvidia GPUs (at least from my testing).
Thanks to the issues raised in this thread and in the repo, I was able to iron out a lot of little quirks. A couple of the more interesting things I learned along the way:
DRM formats and Vulkan formats are in opposite byte-order on little endian systems. For example, DRM_FORMAT_RGBA8888 -> [4]u8{a, b, g, r}, but VK_FORMAT_R8G8B8A8_UNORM -> [4]u8{r, g, b, a}, unless it’s a _pack format, in which case it’s the opposite VK_FORMAT_A8B8G8R8_UNORM_PACK32 -> [4]u8{r, g, b, a}.
Every compositor seems to send the DMA-BUF feedback events in a slightly different order. You really need to be able to handle these events no matter what order they come in, at least relative to each tranche.
At this point, I have directly tested that this works with all of the following compositors across Arch, Debian, and Fedora:
Cosmic
Hyprland
KWin
Labwc
Mutter
Niri
River (classic)
Sway
It does not work with Muffin (Cinnamon, Linux Mint), as its Wayland support is currently only experimental and lacks the necessary DMA-BUF extension version (has 3, needs 4).
I will continue to update the repo as I learn, or if any new issues come in. Hopefully others may find this as educational as I have
Finally, here’s a little benchmark of the uncapped FPS by number of swap images. Reminder that the only work the GPU is doing is a single, different-per-frame vkCmdClearColorImage(), and I made the window as small as I could, so this is essentially just timing the synchronization overhead (KWin, CachyOS, two frames in flight, ReleaseFast):
Swap Images
Approx. FPS
2
23,000
3
40,000
4
42,000
I would have expected 3 images to be faster than 2, but twice as fast was surprising. And just 25 microseconds for all of the syscalls and plumbing was pleasant to see as well.
I am currently working on pure-Zig implementations of Wayland and D-Bus, and I noticed that there was currently no way to send control/ancillary data (which is required for passing file descriptors) within the confines of net.Stream.
From the examples I see here, it appears that everybody reached for the std.os.linux syscall APIs for sending/receiving Wayland messages. I didn’t want to do that for my implementation, so I took some time and wrote a PR that lets you send and receive control data with net.Stream: https://codeberg.org/ziglang/zig/pulls/36277
With this change, you should be able to talk with Wayland on other POSIX-compliant platforms, such as FreeBSD.
receiving messages is actually possible with Io.Operation.NetReceive, you put the control data direcly into the Io net.IncomingMessage. I just chose the syscall approach because I couldn’t use Io for send anyways and wanted a vectored receive (for putting data in two parts of a ring buffer) which Io.Operation.NetReceive doesn’t support
Edit: I actually looked at your PR and know that you are aware of this.