From: Po Lu Date: Thu, 4 Aug 2022 07:37:54 +0000 (+0800) Subject: Correctly implement refresh synchronization fences X-Git-Tag: emacs-29.0.90~1447^2~483 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=78129dcf53ab2b1ce49eab28dba89dea9f687284;p=emacs.git 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'. --- diff --git a/configure.ac b/configure.ac index 87c126ecbbf..1a264275bd4 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 614a5b34551..672097c0d80 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 7e304bcd6e1..33e90603f80 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 fb099e92ea0..c1a944d3cd6 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);