emacs-diffs
[Top][All Lists]
Advanced

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

master 9a9634dc72: Add preparations for animation frame timing support


From: Po Lu
Subject: master 9a9634dc72: Add preparations for animation frame timing support
Date: Tue, 2 Aug 2022 23:38:49 -0400 (EDT)

branch: master
commit 9a9634dc725278a6a676fa4590f53543cada34b2
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Add preparations for animation frame timing support
    
    * src/xterm.c (x_sync_get_monotonic_time)
    (x_sync_current_monotonic_time, x_sync_note_frame_times): New
    functions.
    (x_sync_wait_for_frame_drawn_event, x_sync_update_begin)
    (x_sync_handle_frame_drawn): Note frame times.
    (x_display_set_last_user_time): Check if the X server time is
    probably the same as CLOCK_MONOTONIC.
    
    * src/xterm.h (struct x_display_info, struct x_output): New
    fields and flags for clock handling and frame times.
---
 src/xterm.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/xterm.h | 12 ++++++++++
 2 files changed, 89 insertions(+)

diff --git a/src/xterm.c b/src/xterm.c
index 2455b205bd..2239b9fa4e 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -6634,6 +6634,57 @@ x_if_event (Display *dpy, XEvent *event_return,
     }
 }
 
+/* Return the monotonic time corresponding to the high-resolution
+   server timestamp TIMESTAMP.  Return 0 if the necessary information
+   is not available.  */
+
+static uint64_t
+x_sync_get_monotonic_time (struct x_display_info *dpyinfo,
+                          uint64_t timestamp)
+{
+  if (dpyinfo->server_time_monotonic_p)
+    return timestamp;
+
+  return 0;
+}
+
+/* Return the current monotonic time in the same format as a
+   high-resolution server timestamp.  */
+
+static uint64_t
+x_sync_current_monotonic_time (void)
+{
+  struct timespec time;
+
+  clock_gettime (CLOCK_MONOTONIC, &time);
+  return time.tv_sec * 1000000 + time.tv_nsec / 1000;
+}
+
+/* Decode a _NET_WM_FRAME_DRAWN message and calculate the time it took
+   to draw the last frame.  */
+
+static void
+x_sync_note_frame_times (struct x_display_info *dpyinfo,
+                        struct frame *f, XEvent *event)
+{
+  uint64_t low, high, time;
+  struct x_output *output;
+
+  low = event->xclient.data.l[2];
+  high = event->xclient.data.l[3];
+  output = FRAME_X_OUTPUT (f);
+
+  time = x_sync_get_monotonic_time (dpyinfo, low | (high << 32));
+
+  if (time)
+    output->last_frame_time = time - output->temp_frame_time;
+
+#ifdef FRAME_DEBUG
+  fprintf (stderr, "Drawing the last frame took: %lu ms (%lu)\n",
+          output->last_frame_time / 1000, time);
+#endif
+}
+
 static Bool
 x_sync_is_frame_drawn_event (Display *dpy, XEvent *event,
                             XPointer user_data)
@@ -6681,6 +6732,8 @@ x_sync_wait_for_frame_drawn_event (struct frame *f)
       /* Also change the frame parameter to reflect the new state.  */
       store_frame_param (f, Quse_frame_synchronization, Qnil);
     }
+  else
+    x_sync_note_frame_times (FRAME_DISPLAY_INFO (f), f, &event);
 
   FRAME_X_WAITING_FOR_DRAW (f) = false;
 }
@@ -6726,6 +6779,10 @@ x_sync_update_begin (struct frame *f)
   /* Wait for the last frame to be drawn before drawing this one.  */
   x_sync_wait_for_frame_drawn_event (f);
 
+  /* Make a note of the time at which we started to draw this
+     frame.  */
+  FRAME_X_OUTPUT (f)->temp_frame_time = x_sync_current_monotonic_time ();
+
   /* Since Emacs needs a non-urgent redraw, ensure that value % 4 ==
      1.  Later, add 3 to create the even counter value.  */
   if (XSyncValueLow32 (value) % 4 == 2)
@@ -6796,6 +6853,8 @@ x_sync_handle_frame_drawn (struct x_display_info *dpyinfo,
 {
   if (FRAME_OUTER_WINDOW (f) == message->xclient.window)
     FRAME_X_WAITING_FOR_DRAW (f) = false;
+
+  x_sync_note_frame_times (dpyinfo, f, message);
 }
 #endif
 
@@ -7379,6 +7438,9 @@ x_display_set_last_user_time (struct x_display_info 
*dpyinfo, Time time,
 #ifndef USE_GTK
   struct frame *focus_frame;
   Time old_time;
+#if defined HAVE_XSYNC
+  uint64_t monotonic_time;
+#endif
 
   focus_frame = dpyinfo->x_focus_frame;
   old_time = dpyinfo->last_user_time;
@@ -7391,6 +7453,21 @@ x_display_set_last_user_time (struct x_display_info 
*dpyinfo, Time time,
   if (!send_event || time > dpyinfo->last_user_time)
     dpyinfo->last_user_time = time;
 
+#if defined HAVE_XSYNC && !defined USE_GTK
+  if (!send_event)
+    {
+      /* See if the current CLOCK_MONOTONIC time is reasonably close
+        to the X server time.  */
+      monotonic_time = x_sync_current_monotonic_time ();
+
+      if (time * 1000 > monotonic_time - 500 * 1000
+         && time * 1000 < monotonic_time + 500 * 1000)
+       dpyinfo->server_time_monotonic_p = true;
+      else
+       dpyinfo->server_time_monotonic_p = false;
+    }
+#endif
+
 #ifndef USE_GTK
   /* Don't waste bandwidth if the time hasn't actually changed.  */
   if (focus_frame && old_time != dpyinfo->last_user_time)
diff --git a/src/xterm.h b/src/xterm.h
index 2b8a2e5da4..b656c8dcb2 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -769,6 +769,12 @@ struct x_display_info
   /* The pending drag-and-drop time for middle-click based
      drag-and-drop emulation.  */
   Time pending_dnd_time;
+
+#if defined HAVE_XSYNC && !defined USE_GTK
+  /* Whether or not the server time is probably the same as
+     "clock_gettime (CLOCK_MONOTONIC, ...)".  */
+  bool server_time_monotonic_p;
+#endif
 };
 
 #ifdef HAVE_X_I18N
@@ -1061,6 +1067,12 @@ struct x_output
   /* Whether or not Emacs should wait for the compositing manager to
      draw frames before starting a new frame.  */
   bool_bf use_vsync_p : 1;
+
+  /* The time (in microseconds) it took to draw the last frame.  */
+  uint64_t last_frame_time;
+
+  /* A temporary time used to calculate that value.  */
+  uint64_t temp_frame_time;
 #endif
 #endif
 



reply via email to

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