[Bf-blender-cvs] [deb8ae6bd1e] blender-v3.4-release: GHOST/Wayland: replace roundtrip with dispatch_pending

Campbell Barton noreply at git.blender.org
Sat Nov 12 05:14:56 CET 2022


Commit: deb8ae6bd1edb0983d9ac972b2c95090f4c5e642
Author: Campbell Barton
Date:   Thu Nov 10 18:03:32 2022 +1100
Branches: blender-v3.4-release
https://developer.blender.org/rBdeb8ae6bd1edb0983d9ac972b2c95090f4c5e642

GHOST/Wayland: replace roundtrip with dispatch_pending

Add a non-blocking version wrapper for wl_display_dispatch_pending.
This uses roughly the same logic as Wayland_PumpEvents in SDL.
Noticed this when investigating T100855.

Note that performing a round-trip doesn't seem necessary from looking
into QT/GTK & SDL event handling loops.

===================================================================

M	intern/ghost/CMakeLists.txt
M	intern/ghost/intern/GHOST_SystemWayland.cpp
M	intern/wayland_dynload/extern/wayland_dynload_client.h

===================================================================

diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index ea21d831b0c..5c559072625 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -310,6 +310,11 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
       add_definitions(-DHAVE_MEMFD_CREATE)
     endif()
 
+    check_symbol_exists(poll "poll.h" HAVE_POLL)
+    if(HAVE_POLL)
+      add_definitions(-DHAVE_POLL)
+    endif()
+
     list(APPEND SRC
       intern/GHOST_SystemWayland.cpp
       intern/GHOST_WindowWayland.cpp
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 528aa6e1884..7948112c53c 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -69,6 +69,10 @@
 #include <cstring>
 #include <mutex>
 
+#ifdef HAVE_POLL
+#  include <poll.h>
+#endif
+
 /* Logging, use `ghost.wl.*` prefix. */
 #include "CLG_log.h"
 
@@ -1456,6 +1460,85 @@ static int memfd_create_sealed(const char *name)
 #endif /* !HAVE_MEMFD_CREATE */
 }
 
+enum {
+  GWL_IOR_READ = 1 << 0,
+  GWL_IOR_WRITE = 1 << 1,
+  GWL_IOR_NO_RETRY = 1 << 2,
+};
+
+static int file_descriptor_is_io_ready(int fd, const int flags, const int timeout_ms)
+{
+  int result;
+
+  GHOST_ASSERT(flags & (GWL_IOR_READ | GWL_IOR_WRITE), "X");
+
+  /* Note: We don't bother to account for elapsed time if we get EINTR */
+  do {
+#ifdef HAVE_POLL
+    struct pollfd info;
+
+    info.fd = fd;
+    info.events = 0;
+    if (flags & GWL_IOR_READ) {
+      info.events |= POLLIN | POLLPRI;
+    }
+    if (flags & GWL_IOR_WRITE) {
+      info.events |= POLLOUT;
+    }
+    result = poll(&info, 1, timeout_ms);
+#else
+    fd_set rfdset, *rfdp = nullptr;
+    fd_set wfdset, *wfdp = nullptr;
+    struct timeval tv, *tvp = nullptr;
+
+    /* If this assert triggers we'll corrupt memory here */
+    GHOST_ASSERT(fd >= 0 && fd < FD_SETSIZE, "X");
+
+    if (flags & GWL_IOR_READ) {
+      FD_ZERO(&rfdset);
+      FD_SET(fd, &rfdset);
+      rfdp = &rfdset;
+    }
+    if (flags & GWL_IOR_WRITE) {
+      FD_ZERO(&wfdset);
+      FD_SET(fd, &wfdset);
+      wfdp = &wfdset;
+    }
+
+    if (timeout_ms >= 0) {
+      tv.tv_sec = timeout_ms / 1000;
+      tv.tv_usec = (timeout_ms % 1000) * 1000;
+      tvp = &tv;
+    }
+
+    result = select(fd + 1, rfdp, wfdp, nullptr, tvp);
+#endif /* !HAVE_POLL */
+  } while (result < 0 && errno == EINTR && !(flags & GWL_IOR_NO_RETRY));
+
+  return result;
+}
+
+static int ghost_wl_display_event_pump(struct wl_display *wl_display)
+{
+  /* Based on SDL's `Wayland_PumpEvents`. */
+  int err;
+  if (wl_display_prepare_read(wl_display) == 0) {
+    /* Use #GWL_IOR_NO_RETRY to ensure #SIGINT will break us out of our wait. */
+    if (file_descriptor_is_io_ready(
+            wl_display_get_fd(wl_display), GWL_IOR_READ | GWL_IOR_NO_RETRY, 0) > 0) {
+      err = wl_display_read_events(wl_display);
+    }
+    else {
+      wl_display_cancel_read(wl_display);
+      err = 0;
+    }
+  }
+  else {
+    err = wl_display_dispatch_pending(wl_display);
+  }
+  return err;
+}
+
 static size_t ghost_wl_shm_format_as_size(enum wl_shm_format format)
 {
   switch (format) {
@@ -5169,7 +5252,7 @@ bool GHOST_SystemWayland::processEvents(bool waitForEvent)
     }
   }
   else {
-    if (wl_display_roundtrip(display_->wl_display) == -1) {
+    if (ghost_wl_display_event_pump(display_->wl_display) == -1) {
       ghost_wl_display_report_error(display_->wl_display);
     }
   }
diff --git a/intern/wayland_dynload/extern/wayland_dynload_client.h b/intern/wayland_dynload/extern/wayland_dynload_client.h
index bf1e2f89c18..22ec33b1ef2 100644
--- a/intern/wayland_dynload/extern/wayland_dynload_client.h
+++ b/intern/wayland_dynload/extern/wayland_dynload_client.h
@@ -14,6 +14,11 @@ extern "C" {
 WAYLAND_DYNLOAD_FN(wl_display_connect)
 WAYLAND_DYNLOAD_FN(wl_display_disconnect)
 WAYLAND_DYNLOAD_FN(wl_display_dispatch)
+WAYLAND_DYNLOAD_FN(wl_display_dispatch_pending)
+WAYLAND_DYNLOAD_FN(wl_display_get_fd)
+WAYLAND_DYNLOAD_FN(wl_display_prepare_read)
+WAYLAND_DYNLOAD_FN(wl_display_read_events)
+WAYLAND_DYNLOAD_FN(wl_display_cancel_read)
 WAYLAND_DYNLOAD_FN(wl_display_roundtrip)
 WAYLAND_DYNLOAD_FN(wl_display_flush)
 WAYLAND_DYNLOAD_FN(wl_display_get_error)
@@ -68,6 +73,11 @@ struct WaylandDynload_Client {
   void WL_DYN_FN(wl_display_disconnect)(struct wl_display *display);
   int WL_DYN_FN(wl_display_dispatch)(struct wl_display *display);
   int WL_DYN_FN(wl_display_roundtrip)(struct wl_display *display);
+  int WL_DYN_FN(wl_display_dispatch_pending)(struct wl_display *display);
+  int WL_DYN_FN(wl_display_get_fd)(struct wl_display *display);
+  int WL_DYN_FN(wl_display_prepare_read)(struct wl_display *display);
+  int WL_DYN_FN(wl_display_read_events)(struct wl_display *display);
+  void WL_DYN_FN(wl_display_cancel_read)(struct wl_display *display);
   int WL_DYN_FN(wl_display_flush)(struct wl_display *display);
   int WL_DYN_FN(wl_display_get_error)(struct wl_display *display);
   void WL_DYN_FN(wl_log_set_handler_client)(wl_log_func_t);
@@ -103,6 +113,15 @@ struct WaylandDynload_Client {
 #      define wl_display_disconnect(...) \
         (*wayland_dynload_client.wl_display_disconnect)(__VA_ARGS__)
 #      define wl_display_dispatch(...) (*wayland_dynload_client.wl_display_dispatch)(__VA_ARGS__)
+#      define wl_display_dispatch_pending(...) \
+        (*wayland_dynload_client.wl_display_dispatch)(__VA_ARGS__)
+#      define wl_display_get_fd(...) (*wayland_dynload_client.wl_display_get_fd)(__VA_ARGS__)
+#      define wl_display_prepare_read(...) \
+        (*wayland_dynload_client.wl_display_prepare_read)(__VA_ARGS__)
+#      define wl_display_read_events(...) \
+        (*wayland_dynload_client.wl_display_read_events)(__VA_ARGS__)
+#      define wl_display_cancel_read(...) \
+        (*wayland_dynload_client.wl_display_cancel_read)(__VA_ARGS__)
 #      define wl_display_roundtrip(...) (*wayland_dynload_client.wl_display_roundtrip)(__VA_ARGS__)
 #      define wl_display_flush(...) (*wayland_dynload_client.wl_display_flush)(__VA_ARGS__)
 #      define wl_display_get_error(...) (*wayland_dynload_client.wl_display_get_error)(__VA_ARGS__)



More information about the Bf-blender-cvs mailing list