From 4bceaf550574ac793f8c6e6e4ddd0c69e3e53271 Mon Sep 17 00:00:00 2001
From: Tudor Brindus <me@tbrindus.ca>
Date: Sun, 3 Jan 2021 21:09:55 -0500
Subject: [PATCH] [client] fix hang in eglSwapBuffers when exiting while not
 visible

eglSwapBuffers is allowed to block when called with a nonzero interval
parameter. On Wayland, Mesa will block until a frame callback arrives.
If an application is not visible, a compositor is free to not schedule
frame callbacks (in order to save CPU time rendering something that is
entirely invisible).

Currently, starting Looking Glass from a terminal, hiding it
entirely, and sending ^C will cause Looking Glass to hang joining the
render thread until the window is made visible again.

Calling eglDestroySurface is insufficient to unblock eglSwapBuffers, as
it attempts to grab the same underlying mutex.

Instead, this commit makes it so that we pass a 0 interval to
eglSwapBuffers when running on Wayland, such that we don't block waiting
for a frame callback. This is not entirely ideal as it *does* mean
Looking Glass submits buffers while hidden, but it seems better than
hanging on exit.

It also forces opengl:vsync and egl:vsync flags to off when running on
Wayland, as they are meaningless there.
---
 client/renderers/EGL/egl.c       | 13 ++++++++++++-
 client/renderers/OpenGL/opengl.c | 14 +++++++++++++-
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c
index d194f566..36b888bd 100644
--- a/client/renderers/EGL/egl.c
+++ b/client/renderers/EGL/egl.c
@@ -97,6 +97,16 @@ struct Inst
   LG_FontObj        fontObj;
 };
 
+static bool egl_vsync_option_validator(struct Option * opt, const char ** error)
+{
+  if (opt->value.x_bool && getenv("WAYLAND_DISPLAY"))
+  {
+    DEBUG_WARN("Cannot disable vsync on Wayland, forcing egl:vsync=off");
+    opt->value.x_bool = false;
+  }
+
+  return true;
+}
 
 static struct Option egl_options[] =
 {
@@ -105,7 +115,8 @@ static struct Option egl_options[] =
     .name         = "vsync",
     .description  = "Enable vsync",
     .type         = OPTION_TYPE_BOOL,
-    .value.x_bool = false
+    .value.x_bool = false,
+    .validator    = &vsync_option_validator
   },
   {
     .module       = "egl",
diff --git a/client/renderers/OpenGL/opengl.c b/client/renderers/OpenGL/opengl.c
index a00f46ae..f99fbf8d 100644
--- a/client/renderers/OpenGL/opengl.c
+++ b/client/renderers/OpenGL/opengl.c
@@ -48,6 +48,17 @@ Place, Suite 330, Boston, MA 02111-1307 USA
 
 #define FADE_TIME 1000000
 
+static bool opengl_vsync_option_validator(struct Option * opt, const char ** error)
+{
+  if (opt->value.x_bool && getenv("WAYLAND_DISPLAY"))
+  {
+    DEBUG_WARN("Cannot disable vsync on Wayland, forcing opengl:vsync=off");
+    opt->value.x_bool = false;
+  }
+
+  return true;
+}
+
 static struct Option opengl_options[] =
 {
   {
@@ -62,7 +73,8 @@ static struct Option opengl_options[] =
     .name         = "vsync",
     .description  = "Enable vsync",
     .type         = OPTION_TYPE_BOOL,
-    .value.x_bool = false
+    .value.x_bool = false,
+    .validator    = &vsync_option_validator
   },
   {
     .module       = "opengl",