KhronosGroup / Vulkan-Tools

Vulkan Development Tools
Apache License 2.0
361 stars 153 forks source link

vkcube-wayland does not read from the wayland socket if un-paused #976

Closed mahkoh closed 5 months ago

mahkoh commented 5 months ago

Here is the outer loop of vkcube-wayland:

static void demo_run(struct demo *demo) {
    while (!demo->quit) {
        if (demo->pause) {
            wl_display_dispatch(demo->display);  // block and wait for input
        } else {
            wl_display_dispatch_pending(demo->display);  // don't block
            demo_draw(demo);
            demo->curFrame++;
            if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) demo->quit = true;
        }
    }
}

As long as the demo is not paused, vkcube-wayland only invokes wl_display_dispatch_pending which will not read any data from the wayland socket. This has worked so far because the WSI would read from the wayland socket in vkAcquireNextImageKHR.

However, in the next mesa release, and if the wayland compositor supports it, mesa will no longer read from the wayland socket in vkAcquireNextImageKHR. This will cause no messages (keyboard input, resize events, etc.) to be read and dispatched.

I've used the following patch for testing, but you might come up with a more elegant solution:

diff --git a/cube/cube.c b/cube/cube.c
index e319ee8b..84ea6906 100644
--- a/cube/cube.c
+++ b/cube/cube.c
@@ -2815,12 +2815,18 @@ static void demo_create_xcb_window(struct demo *demo) {
 }
 // VK_USE_PLATFORM_XCB_KHR
 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
+#include <poll.h>
 static void demo_run(struct demo *demo) {
     while (!demo->quit) {
         if (demo->pause) {
             wl_display_dispatch(demo->display);  // block and wait for input
         } else {
-            wl_display_dispatch_pending(demo->display);  // don't block
+            struct pollfd pollfd = { .fd = wl_display_get_fd(demo->display), .events = POLLIN };
+            if (poll(&pollfd, 1, 0) > 0) {
+                wl_display_dispatch(demo->display);
+            } else {
+                wl_display_dispatch_pending(demo->display);  // don't block
+            }
             demo_draw(demo);
             demo->curFrame++;
             if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) demo->quit = true;
charles-lunarg commented 5 months ago

Changes seem reasonable, happy to take this as a PR.

Since I'm a wayland newbie, I needed to look up the docs for the wl_display_dispatch and wl_display_dispatch_pending functions, and they make sense with the explanation given, so I very much appreciate the details added.

My understanding is that wl_display_dispatch_pending only dispatches "pending" events, whereas wl_display_dispatch will also poll for events (blocking in the process) before dispatching events. Mesa no longer polling in acquire indeed is a departure in behavior, but an understandable one.