From 0243736003cbe3396d6469cd66d186c5e0a53169 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Mon, 27 Jul 2020 12:49:57 -0700 Subject: [PATCH] macos: support ARM/PowerPC time conversion for DisplayLink times When converting DisplayLink frame presentation times, we need to take into account the arch-specific types. This tracks changes in GNOME/GLib!1566 so that precision is not lost. --- gdk/macos/gdkdisplaylinksource.c | 74 +++++++++++++------------------- meson.build | 11 +++++ 2 files changed, 42 insertions(+), 43 deletions(-) diff --git a/gdk/macos/gdkdisplaylinksource.c b/gdk/macos/gdkdisplaylinksource.c index 36decbbaad..76c57feaeb 100644 --- a/gdk/macos/gdkdisplaylinksource.c +++ b/gdk/macos/gdkdisplaylinksource.c @@ -28,7 +28,7 @@ #include "gdkmacoseventsource-private.h" -static gint64 host_to_frame_clock_time (gint64 host_time); +static gint64 host_to_frame_clock_time (gint64 val); static gboolean gdk_display_link_source_prepare (GSource *source, @@ -203,52 +203,40 @@ gdk_display_link_source_new (void) } static gint64 -host_to_frame_clock_time (gint64 host_time) +host_to_frame_clock_time (gint64 val) { - static mach_timebase_info_data_t timebase_info; + /* NOTE: Code adapted from GLib's g_get_monotonic_time(). */ - /* - * NOTE: - * - * This code is taken from GLib to match g_get_monotonic_time(). - */ - if (G_UNLIKELY (timebase_info.denom == 0)) + mach_timebase_info_data_t timebase_info; + + /* we get nanoseconds from mach_absolute_time() using timebase_info */ + mach_timebase_info (&timebase_info); + + if (timebase_info.numer != timebase_info.denom) { - /* This is a fraction that we must use to scale - * mach_absolute_time() by in order to reach nanoseconds. - * - * We've only ever observed this to be 1/1, but maybe it could be - * 1000/1 if mach time is microseconds already, or 1/1000 if - * picoseconds. Try to deal nicely with that. - */ - mach_timebase_info (&timebase_info); +#ifdef HAVE_UINT128_T + val = ((__uint128_t) val * (__uint128_t) timebase_info.numer) / timebase_info.denom / 1000; +#else + guint64 t_high, t_low; + guint64 result_high, result_low; - /* We actually want microseconds... */ - if (timebase_info.numer % 1000 == 0) - timebase_info.numer /= 1000; - else - timebase_info.denom *= 1000; - - /* We want to make the numer 1 to avoid having to multiply... */ - if (timebase_info.denom % timebase_info.numer == 0) - { - timebase_info.denom /= timebase_info.numer; - timebase_info.numer = 1; - } - else - { - /* We could just multiply by timebase_info.numer below, but why - * bother for a case that may never actually exist... - * - * Plus -- performing the multiplication would risk integer - * overflow. If we ever actually end up in this situation, we - * should more carefully evaluate the correct course of action. - */ - mach_timebase_info (&timebase_info); /* Get a fresh copy for a better message */ - g_error ("Got weird mach timebase info of %d/%d. Please file a bug against GLib.", - timebase_info.numer, timebase_info.denom); - } + /* 64 bit x 32 bit / 32 bit with 96-bit intermediate + * algorithm lifted from qemu */ + t_low = (val & 0xffffffffLL) * (guint64) timebase_info.numer; + t_high = (val >> 32) * (guint64) timebase_info.numer; + t_high += (t_low >> 32); + result_high = t_high / (guint64) timebase_info.denom; + result_low = (((t_high % (guint64) timebase_info.denom) << 32) + + (t_low & 0xffffffff)) / + (guint64) timebase_info.denom; + val = ((result_high << 32) | result_low) / 1000; +#endif + } + else + { + /* nanoseconds to microseconds */ + val = val / 1000; } - return host_time / timebase_info.denom; + return val; } diff --git a/meson.build b/meson.build index 43208bc669..3ab900eb06 100644 --- a/meson.build +++ b/meson.build @@ -207,6 +207,17 @@ foreach func : check_functions endif endforeach +# Check for __uint128_t (gcc) by checking for 128-bit division +uint128_t_src = '''int main() { +static __uint128_t v1 = 100; +static __uint128_t v2 = 10; +static __uint128_t u; +u = v1 / v2; +}''' +if cc.compiles(uint128_t_src, name : '__uint128_t available') + cdata.set('HAVE_UINT128_T', 1) +endif + # Disable deprecation checks for all libraries we depend on on stable branches. # This is so newer versions of those libraries don't cause more warnings with # a stable GTK version.