emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 78129dcf53: Correctly implement refresh synchronization fences


From: Po Lu
Subject: master 78129dcf53: Correctly implement refresh synchronization fences
Date: Thu, 4 Aug 2022 03:38:36 -0400 (EDT)

branch: master
commit 78129dcf53ab2b1ce49eab28dba89dea9f687284
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Correctly implement refresh synchronization fences
    
    * configure.ac (HAVE_XSYNC): Also check for XSyncTriggerFence.
    
    * src/xfns.c (Fx_create_frame): Create fences.
    * src/xterm.c (x_atom_refs): New atom.
    (x_sync_trigger_fence, x_sync_init_fences, x_sync_free_fences):
    New functions.
    (x_sync_update_finish): Trigger the appropriate fence.
    (x_free_frame_resources): Free fences.
    * src/xterm.h (struct x_display_info): New atom
    `_NET_WM_SYNC_FENCES'.
    (struct x_output): New field `sync_fences'.
---
 configure.ac |  4 +++
 src/xfns.c   |  4 +++
 src/xterm.c  | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/xterm.h  | 16 +++++++++--
 4 files changed, 111 insertions(+), 5 deletions(-)

diff --git a/configure.ac b/configure.ac
index 87c126ecbb..1a264275bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4675,6 +4675,10 @@ if test "${HAVE_X11}" = "yes"; then
     AC_DEFINE([HAVE_XSYNC], [1],
       [Define to 1 if the X Synchronization Extension is available.])
     XSYNC_LIBS="-lXext"
+    OLDLIBS="$LIBS"
+    LIBS="-lXext $LIBS" # Set this temporarily for AC_CHECK_FUNC
+    AC_CHECK_FUNCS([XSyncTriggerFence]) # Check for version 3.1
+    LIBS="$OLDLIBS"
   fi
 fi
 AC_SUBST([XSYNC_LIBS])
diff --git a/src/xfns.c b/src/xfns.c
index 614a5b3455..672097c0d8 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -5157,6 +5157,10 @@ This function is an internal primitive--use `make-frame' 
instead.  */)
                       (unsigned char *) &counters,
                       ((STRINGP (value)
                         && !strcmp (SSDATA (value), "extended")) ? 2 : 1));
+
+#if defined HAVE_XSYNCTRIGGERFENCE && !defined USE_GTK
+      x_sync_init_fences (f);
+#endif
 #endif
     }
 #endif
diff --git a/src/xterm.c b/src/xterm.c
index 7e304bcd6e..33e90603f8 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -997,6 +997,7 @@ static const struct x_atom_ref x_atom_refs[] =
     ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea)
     ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST", Xatom_net_wm_sync_request)
     ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST_COUNTER", 
Xatom_net_wm_sync_request_counter)
+    ATOM_REFS_INIT ("_NET_WM_SYNC_FENCES", Xatom_net_wm_sync_fences)
     ATOM_REFS_INIT ("_NET_WM_FRAME_DRAWN", Xatom_net_wm_frame_drawn)
     ATOM_REFS_INIT ("_NET_WM_FRAME_TIMINGS", Xatom_net_wm_frame_timings)
     ATOM_REFS_INIT ("_NET_WM_USER_TIME", Xatom_net_wm_user_time)
@@ -6812,6 +6813,85 @@ x_sync_update_begin (struct frame *f)
                   FRAME_X_COUNTER_VALUE (f));
 }
 
+#ifdef HAVE_XSYNCTRIGGERFENCE
+
+/* Trigger the sync fence for counter VALUE immediately before a frame
+   finishes.  */
+
+static void
+x_sync_trigger_fence (struct frame *f, XSyncValue value)
+{
+  uint64_t n, low, high, idx;
+
+  /* Sync fences aren't supported by the X server.  */
+  if (FRAME_DISPLAY_INFO (f)->xsync_major < 3
+      || (FRAME_DISPLAY_INFO (f)->xsync_major == 3
+         && FRAME_DISPLAY_INFO (f)->xsync_minor < 1))
+    return;
+
+  low = XSyncValueLow32 (value);
+  high = XSyncValueHigh32 (value);
+
+  n = low | (high << 32);
+  idx = (n / 4) % 2;
+
+#ifdef FRAME_DEBUG
+  fprintf (stderr, "Triggering synchonization fence: %lu\n", idx);
+#endif
+
+  XSyncTriggerFence (FRAME_X_DISPLAY (f),
+                    FRAME_X_OUTPUT (f)->sync_fences[idx]);
+}
+
+/* Initialize the sync fences on F.  */
+
+void
+x_sync_init_fences (struct frame *f)
+{
+  struct x_output *output;
+  struct x_display_info *dpyinfo;
+
+  output = FRAME_X_OUTPUT (f);
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
+  /* Sync fences aren't supported by the X server.  */
+  if (dpyinfo->xsync_major < 3
+      || (dpyinfo->xsync_major == 3
+         && dpyinfo->xsync_minor < 1))
+    return;
+
+  output->sync_fences[0]
+    = XSyncCreateFence (FRAME_X_DISPLAY (f),
+                       /* The drawable given below is only used to
+                          determine the screen on which the fence is
+                          created.  */
+                       FRAME_X_WINDOW (f),
+                       False);
+  output->sync_fences[1]
+    = XSyncCreateFence (FRAME_X_DISPLAY (f),
+                       FRAME_X_WINDOW (f),
+                       False);
+
+  XChangeProperty (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+                  dpyinfo->Xatom_net_wm_sync_fences, XA_CARDINAL,
+                  32, PropModeReplace,
+                  (unsigned char *) &output->sync_fences, 1);
+}
+
+static void
+x_sync_free_fences (struct frame *f)
+{
+  if (FRAME_X_OUTPUT (f)->sync_fences[0] != None)
+    XSyncDestroyFence (FRAME_X_DISPLAY (f),
+                      FRAME_X_OUTPUT (f)->sync_fences[0]);
+
+  if (FRAME_X_OUTPUT (f)->sync_fences[1] != None)
+    XSyncDestroyFence (FRAME_X_DISPLAY (f),
+                      FRAME_X_OUTPUT (f)->sync_fences[1]);
+}
+
+#endif
+
 /* Tell the compositing manager that FRAME has been drawn and can be
    updated.  */
 
@@ -6844,12 +6924,15 @@ x_sync_update_finish (struct frame *f)
   if (overflow)
     XSyncIntToValue (&FRAME_X_COUNTER_VALUE (f), 0);
 
+  /* Trigger any sync fences if necessary.  */
+#ifdef HAVE_XSYNCTRIGGERFENCE
+  x_sync_trigger_fence (f, FRAME_X_COUNTER_VALUE (f));
+#endif
+
   XSyncSetCounter (FRAME_X_DISPLAY (f),
                   FRAME_X_EXTENDED_COUNTER (f),
                   FRAME_X_COUNTER_VALUE (f));
 
-  /* FIXME: this leads to freezes if the compositing manager crashes
-     in the meantime.  */
   if (FRAME_OUTPUT_DATA (f)->use_vsync_p)
     FRAME_X_WAITING_FOR_DRAW (f) = true;
 }
@@ -26282,6 +26365,11 @@ x_free_frame_resources (struct frame *f)
        XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_edge_cursor);
       if (f->output_data.x->bottom_left_corner_cursor != 0)
        XFreeCursor (FRAME_X_DISPLAY (f), 
f->output_data.x->bottom_left_corner_cursor);
+
+      /* Free sync fences.  */
+#if defined HAVE_XSYNCTRIGGERFENCE && !defined USE_GTK
+      x_sync_free_fences (f);
+#endif
     }
 
 #ifdef HAVE_GTK3
diff --git a/src/xterm.h b/src/xterm.h
index fb099e92ea..c1a944d3cd 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -614,9 +614,9 @@ struct x_display_info
     Xatom_net_wm_state_shaded, Xatom_net_frame_extents, 
Xatom_net_current_desktop,
     Xatom_net_workarea, Xatom_net_wm_opaque_region, Xatom_net_wm_ping,
     Xatom_net_wm_sync_request, Xatom_net_wm_sync_request_counter,
-    Xatom_net_wm_frame_drawn, Xatom_net_wm_frame_timings, 
Xatom_net_wm_user_time,
-    Xatom_net_wm_user_time_window, Xatom_net_client_list_stacking,
-    Xatom_net_wm_pid;
+    Xatom_net_wm_sync_fences, Xatom_net_wm_frame_drawn, 
Xatom_net_wm_frame_timings,
+    Xatom_net_wm_user_time, Xatom_net_wm_user_time_window,
+    Xatom_net_client_list_stacking, Xatom_net_wm_pid;
 
   /* XSettings atoms and windows.  */
   Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;
@@ -1077,6 +1077,13 @@ struct x_output
 
   /* A temporary time used to calculate that value.  */
   uint64_t temp_frame_time;
+
+#ifdef HAVE_XSYNCTRIGGERFENCE
+  /* An array of two sync fences that are triggered in order after a
+     frame completes.  Not initialized if the XSync extension is too
+     old to support sync fences.  */
+  XSyncFence sync_fences[2];
+#endif
 #endif
 #endif
 
@@ -1516,6 +1523,9 @@ extern void x_make_frame_invisible (struct frame *);
 extern void x_iconify_frame (struct frame *);
 extern void x_free_frame_resources (struct frame *);
 extern void x_wm_set_size_hint (struct frame *, long, bool);
+#if defined HAVE_XSYNCTRIGGERFENCE && !defined USE_GTK
+extern void x_sync_init_fences (struct frame *);
+#endif
 
 extern void x_delete_terminal (struct terminal *);
 extern Cursor x_create_font_cursor (struct x_display_info *, int);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]