Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <campbell@blender.org>2022-11-10 10:03:32 +0300
committerCampbell Barton <campbell@blender.org>2022-11-12 07:11:43 +0300
commitdeb8ae6bd1edb0983d9ac972b2c95090f4c5e642 (patch)
tree702b1b072c067a580958a4f33b6ad559b02f3ab9
parentc5b36aa9404be6859fee7c3d212e484ea9b1d1dc (diff)
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.
-rw-r--r--intern/ghost/CMakeLists.txt5
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp85
-rw-r--r--intern/wayland_dynload/extern/wayland_dynload_client.h19
3 files changed, 108 insertions, 1 deletions
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__)