]> git.eshelyaron.com Git - emacs.git/commitdiff
Implement extended frame synchronization
authorPo Lu <luangruo@yahoo.com>
Fri, 29 Jul 2022 02:13:54 +0000 (10:13 +0800)
committerPo Lu <luangruo@yahoo.com>
Fri, 29 Jul 2022 02:14:04 +0000 (10:14 +0800)
* src/xterm.c (x_atom_refs): New atom _NET_WM_FRAME_TIMINGS.
(x_sync_update_finish, x_sync_update_begin): New frame.
(x_update_begin, x_update_end, XTframe_up_to_date): Begin and
end frames accordingly if extended frame synchronization is
enabled.
(handle_one_xevent): Ignore timing and frame drawn events.

* src/xterm.h (struct x_display_info): New atom.
(FRAME_X_COUNTER_VALUE): New macro.

src/xterm.c
src/xterm.h

index e7222d35b3a23711a5f8b349c6b8b9fa5ecc7c15..acdac92d94a784bae655d6ef52b81d4c3e05831b 100644 (file)
@@ -998,6 +998,7 @@ static const struct x_atom_ref x_atom_refs[] =
     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_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)
     ATOM_REFS_INIT ("_NET_WM_USER_TIME_WINDOW", Xatom_net_wm_user_time_window)
     ATOM_REFS_INIT ("_NET_CLIENT_LIST_STACKING", Xatom_net_client_list_stacking)
@@ -6595,6 +6596,82 @@ x_set_frame_alpha (struct frame *f)
                    Starting and ending an update
  ***********************************************************************/
 
+#if defined HAVE_XSYNC && !defined USE_GTK
+/* Tell the compositing manager to postpone updates of F until a frame
+   has finished drawing.  */
+
+static void
+x_sync_update_begin (struct frame *f)
+{
+  XSyncValue value, add;
+  Bool overflow;
+
+  if (FRAME_X_EXTENDED_COUNTER (f) == None)
+    return;
+
+  value = FRAME_X_COUNTER_VALUE (f);
+
+  /* Since a frame is already in progress, there is no point in
+     continuing.  */
+  if (XSyncValueLow32 (value) % 2)
+    return;
+
+  /* Since Emacs needs a non-urgent redraw, ensure that value % 4 ==
+     0.  */
+  if (XSyncValueLow32 (value) % 4 == 2)
+    XSyncIntToValue (&add, 3);
+  else
+    XSyncIntToValue (&add, 1);
+
+  XSyncValueAdd (&FRAME_X_COUNTER_VALUE (f),
+                value, add, &overflow);
+
+  if (XSyncValueLow32 (FRAME_X_COUNTER_VALUE (f)) % 4 != 1)
+    emacs_abort ();
+
+  if (overflow)
+    XSyncIntToValue (&FRAME_X_COUNTER_VALUE (f), 1);
+
+  XSyncSetCounter (FRAME_X_DISPLAY (f),
+                  FRAME_X_EXTENDED_COUNTER (f),
+                  FRAME_X_COUNTER_VALUE (f));
+}
+
+/* Tell the compositing manager that FRAME has been drawn and can be
+   updated.  */
+
+static void
+x_sync_update_finish (struct frame *f)
+{
+  XSyncValue value, add;
+  Bool overflow;
+
+  if (FRAME_X_EXTENDED_COUNTER (f) == None)
+    return;
+
+  if (FRAME_X_OUTPUT (f)->ext_sync_end_pending_p)
+    return;
+
+  value = FRAME_X_COUNTER_VALUE (f);
+
+  if (!(XSyncValueLow32 (value) % 2))
+    return;
+
+  XSyncIntToValue (&add, 1);
+  XSyncValueAdd (&FRAME_X_COUNTER_VALUE (f),
+                value, add, &overflow);
+
+  if (overflow)
+    XSyncIntToValue (&FRAME_X_COUNTER_VALUE (f), 0);
+
+  XSyncSetCounter (FRAME_X_DISPLAY (f),
+                  FRAME_X_EXTENDED_COUNTER (f),
+                  FRAME_X_COUNTER_VALUE (f));
+
+  /* TODO: implement sync fences.  */
+}
+#endif
+
 /* Start an update of frame F.  This function is installed as a hook
    for update_begin, i.e. it is called when update_begin is called.
    This function is called prior to calls to gui_update_window_begin for
@@ -6604,7 +6681,11 @@ x_set_frame_alpha (struct frame *f)
 static void
 x_update_begin (struct frame *f)
 {
+#if defined HAVE_XSYNC && !defined USE_GTK
+  x_sync_update_begin (f);
+#else
   /* Nothing to do.  */
+#endif
 }
 
 /* Draw a vertical window border from (x,y0) to (x,y1)  */
@@ -6750,17 +6831,17 @@ x_update_end (struct frame *f)
 
 #ifdef USE_CAIRO
   if (!FRAME_X_DOUBLE_BUFFERED_P (f) && FRAME_CR_CONTEXT (f))
-    {
-      block_input ();
-      cairo_surface_flush (cairo_get_target (FRAME_CR_CONTEXT (f)));
-      unblock_input ();
-    }
+    cairo_surface_flush (cairo_get_target (FRAME_CR_CONTEXT (f)));
 #endif
 
-#ifndef XFlush
-  block_input ();
-  XFlush (FRAME_X_DISPLAY (f));
-  unblock_input ();
+  /* If double buffering is disabled, finish the update here.
+     Otherwise, finish the update when the back buffer is next
+     displayed.  */
+#if defined HAVE_XSYNC && !defined USE_GTK
+#ifdef HAVE_XDBE
+  if (!FRAME_X_DOUBLE_BUFFERED_P (f))
+#endif
+    x_sync_update_finish (f);
 #endif
 }
 
@@ -6788,6 +6869,11 @@ XTframe_up_to_date (struct frame *f)
   if (!buffer_flipping_blocked_p ()
       && FRAME_X_NEED_BUFFER_FLIP (f))
     show_back_buffer (f);
+
+#if defined HAVE_XSYNC && !defined USE_GTK
+  if (FRAME_X_DOUBLE_BUFFERED_P (f))
+    x_sync_update_finish (f);
+#endif
 #endif
 
 #ifdef HAVE_XSYNC
@@ -6804,14 +6890,14 @@ XTframe_up_to_date (struct frame *f)
   if (FRAME_X_OUTPUT (f)->ext_sync_end_pending_p
       && FRAME_X_EXTENDED_COUNTER (f) != None)
     {
-      current = FRAME_X_OUTPUT (f)->current_extended_counter_value;
+      current = FRAME_X_COUNTER_VALUE (f);
 
       if (XSyncValueLow32 (current) % 2)
        XSyncIntToValue (&add, 1);
       else
        XSyncIntToValue (&add, 2);
 
-      XSyncValueAdd (&FRAME_X_OUTPUT (f)->current_extended_counter_value,
+      XSyncValueAdd (&FRAME_X_COUNTER_VALUE (f),
                     current, add, &overflow_p);
 
       if (overflow_p)
@@ -6819,7 +6905,7 @@ XTframe_up_to_date (struct frame *f)
 
       XSyncSetCounter (FRAME_X_DISPLAY (f),
                       FRAME_X_EXTENDED_COUNTER (f),
-                      FRAME_X_OUTPUT (f)->current_extended_counter_value);
+                      FRAME_X_COUNTER_VALUE (f));
 
       FRAME_X_OUTPUT (f)->ext_sync_end_pending_p = false;
     }
@@ -16861,8 +16947,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                      }
                    else if (event->xclient.data.l[4] == 1)
                      {
-                       XSyncIntsToValue (&FRAME_X_OUTPUT (f)->current_extended_counter_value,
-                                         event->xclient.data.l[2], event->xclient.data.l[3]);
+                       XSyncIntsToValue (&FRAME_X_COUNTER_VALUE (f),
+                                         event->xclient.data.l[2],
+                                         event->xclient.data.l[3]);
                        FRAME_X_OUTPUT (f)->ext_sync_end_pending_p = true;
                      }
 
@@ -16979,6 +17066,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
             goto done;
           }
 
+#if defined HAVE_XSYNC && !defined USE_GTK
+       /* These messages are sent by the compositing manager after a
+          frame is drawn under extended synchronization.  */
+       if (event->xclient.message_type == dpyinfo->Xatom_net_wm_frame_drawn
+           || event->xclient.message_type == dpyinfo->Xatom_net_wm_frame_timings)
+         goto done;
+#endif
+
         xft_settings_event (dpyinfo, event);
 
        f = any;
index b9e7b094e31df6c91a65c89934d6e7930e996c39..3e237158e7e2461bb63e3c125d4aa4cc718f4782 100644 (file)
@@ -614,7 +614,7 @@ 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_user_time,
+    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;
 
@@ -1211,8 +1211,12 @@ extern void x_mark_frame_dirty (struct frame *f);
 #endif
 
 #ifdef HAVE_XSYNC
-#define FRAME_X_BASIC_COUNTER(f) FRAME_X_OUTPUT (f)->basic_frame_counter
-#define FRAME_X_EXTENDED_COUNTER(f) FRAME_X_OUTPUT (f)->extended_frame_counter
+#define FRAME_X_BASIC_COUNTER(f)               \
+  FRAME_X_OUTPUT (f)->basic_frame_counter
+#define FRAME_X_EXTENDED_COUNTER(f)            \
+  FRAME_X_OUTPUT (f)->extended_frame_counter
+#define FRAME_X_COUNTER_VALUE(f)               \
+  FRAME_X_OUTPUT (f)->current_extended_counter_value
 #endif
 
 /* This is the Colormap which frame F uses.  */