[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 9a9634dc72: Add preparations for animation frame timing support,
Po Lu <=