diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h index 758cfade6..9c4abfe53 100644 --- a/clutter/clutter/clutter-stage.h +++ b/clutter/clutter/clutter-stage.h @@ -127,7 +127,7 @@ typedef enum struct _ClutterFrameInfo { int64_t frame_counter; - int64_t presentation_time; + int64_t presentation_time; /* microseconds; CLOCK_MONOTONIC */ float refresh_rate; ClutterFrameInfoFlag flags; diff --git a/cogl/cogl/cogl-frame-info-private.h b/cogl/cogl/cogl-frame-info-private.h index 35d2bd97f..debeb5dff 100644 --- a/cogl/cogl/cogl-frame-info-private.h +++ b/cogl/cogl/cogl-frame-info-private.h @@ -47,7 +47,7 @@ struct _CoglFrameInfo CoglObject _parent; int64_t frame_counter; - int64_t presentation_time_us; + int64_t presentation_time_us; /* CLOCK_MONOTONIC */ float refresh_rate; int64_t global_frame_counter; diff --git a/cogl/cogl/cogl-frame-info.h b/cogl/cogl/cogl-frame-info.h index 97f0d7c14..c128bf820 100644 --- a/cogl/cogl/cogl-frame-info.h +++ b/cogl/cogl/cogl-frame-info.h @@ -97,11 +97,9 @@ int64_t cogl_frame_info_get_frame_counter (CoglFrameInfo *info); * the frame became visible to the user. * * The presentation time measured in microseconds, is based on - * cogl_get_clock_time(). + * CLOCK_MONOTONIC. * - * Linux kernel version less that 3.8 can result in - * non-monotonic timestamps being reported when using a drm based - * OpenGL driver. Also some buggy Mesa drivers up to 9.0.1 may also + * Some buggy Mesa drivers up to 9.0.1 may * incorrectly report non-monotonic timestamps. * * Return value: the presentation time for the frame diff --git a/cogl/cogl/winsys/cogl-onscreen-glx.c b/cogl/cogl/winsys/cogl-onscreen-glx.c index 19aca8cf7..6526ae799 100644 --- a/cogl/cogl/winsys/cogl-onscreen-glx.c +++ b/cogl/cogl/winsys/cogl-onscreen-glx.c @@ -454,6 +454,17 @@ ust_to_microseconds (CoglRenderer *renderer, return 0; } +static gboolean +is_ust_monotonic (CoglRenderer *renderer, + GLXDrawable drawable) +{ + CoglGLXRenderer *glx_renderer = renderer->winsys; + + ensure_ust_type (renderer, drawable); + + return (glx_renderer->ust_type == COGL_GLX_UST_IS_MONOTONIC_TIME); +} + static void _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen) { @@ -482,10 +493,19 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen) glx_renderer->glXWaitForMsc (xlib_renderer->xdpy, drawable, 0, 1, 0, &ust, &msc, &sbc); - info->presentation_time_us = ust_to_microseconds (ctx->display->renderer, - drawable, - ust); - info->flags |= COGL_FRAME_INFO_FLAG_HW_CLOCK; + + if (is_ust_monotonic (ctx->display->renderer, drawable)) + { + info->presentation_time_us = + ust_to_microseconds (ctx->display->renderer, + drawable, + ust); + info->flags |= COGL_FRAME_INFO_FLAG_HW_CLOCK; + } + else + { + info->presentation_time_us = g_get_monotonic_time (); + } } else { @@ -962,16 +982,20 @@ cogl_onscreen_glx_notify_swap_buffers (CoglOnscreen *onscreen, GLXBufferSwapComplete *swap_event) { CoglOnscreenGlx *onscreen_glx = COGL_ONSCREEN_GLX (onscreen); + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + CoglContext *context = cogl_framebuffer_get_context (framebuffer); + gboolean ust_is_monotonic; /* We only want to notify that the swap is complete when the application calls cogl_context_dispatch so instead of immediately notifying we'll set a flag to remember to notify later */ set_sync_pending (onscreen); - if (swap_event->ust != 0) + ust_is_monotonic = is_ust_monotonic (context->display->renderer, + onscreen_glx->glxwin); + + if (swap_event->ust != 0 && ust_is_monotonic) { - CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); - CoglContext *context = cogl_framebuffer_get_context (framebuffer); CoglFrameInfo *info; info = cogl_onscreen_peek_head_frame_info (onscreen); diff --git a/src/backends/native/meta-gpu-kms.c b/src/backends/native/meta-gpu-kms.c index 643c25882..7cec11325 100644 --- a/src/backends/native/meta-gpu-kms.c +++ b/src/backends/native/meta-gpu-kms.c @@ -143,6 +143,12 @@ meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms) return timespec_to_nanoseconds (&ts); } +gboolean +meta_gpu_kms_is_clock_monotonic (MetaGpuKms *gpu_kms) +{ + return gpu_kms->clock_id == CLOCK_MONOTONIC; +} + gboolean meta_gpu_kms_is_boot_vga (MetaGpuKms *gpu_kms) { diff --git a/src/backends/native/meta-gpu-kms.h b/src/backends/native/meta-gpu-kms.h index d75c8a40f..8af89b0ce 100644 --- a/src/backends/native/meta-gpu-kms.h +++ b/src/backends/native/meta-gpu-kms.h @@ -59,6 +59,8 @@ const char * meta_gpu_kms_get_file_path (MetaGpuKms *gpu_kms); int64_t meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms); +gboolean meta_gpu_kms_is_clock_monotonic (MetaGpuKms *gpu_kms); + void meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms, uint64_t state, MetaKmsUpdate *kms_update); diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c index 0fd6e237e..3c81c9601 100644 --- a/src/backends/native/meta-onscreen-native.c +++ b/src/backends/native/meta-onscreen-native.c @@ -259,15 +259,35 @@ page_flip_feedback_flipped (MetaKmsCrtc *kms_crtc, { MetaRendererView *view = user_data; struct timeval page_flip_time; + MetaCrtc *crtc; + MetaGpuKms *gpu_kms; + int64_t presentation_time_us; + CoglFrameInfoFlag flags = COGL_FRAME_INFO_FLAG_NONE; page_flip_time = (struct timeval) { .tv_sec = tv_sec, .tv_usec = tv_usec, }; + crtc = META_CRTC (meta_crtc_kms_from_kms_crtc (kms_crtc)); + gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); + if (meta_gpu_kms_is_clock_monotonic (gpu_kms)) + { + presentation_time_us = timeval_to_microseconds (&page_flip_time); + flags |= COGL_FRAME_INFO_FLAG_HW_CLOCK; + } + else + { + /* + * Other parts of the code assume MONOTONIC timestamps. So, if the device + * timestamp isn't MONOTONIC, don't use it. + */ + presentation_time_us = g_get_monotonic_time (); + } + notify_view_crtc_presented (view, kms_crtc, - timeval_to_microseconds (&page_flip_time), - COGL_FRAME_INFO_FLAG_HW_CLOCK); + presentation_time_us, + flags); } static void @@ -291,22 +311,18 @@ page_flip_feedback_mode_set_fallback (MetaKmsCrtc *kms_crtc, gpointer user_data) { MetaRendererView *view = user_data; - MetaCrtc *crtc; - MetaGpuKms *gpu_kms; - int64_t now_ns; + int64_t now_us; /* * We ended up not page flipping, thus we don't have a presentation time to * use. Lets use the next best thing: the current time. */ - crtc = META_CRTC (meta_crtc_kms_from_kms_crtc (kms_crtc)); - gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); - now_ns = meta_gpu_kms_get_current_time_ns (gpu_kms); + now_us = g_get_monotonic_time (); notify_view_crtc_presented (view, kms_crtc, - ns2us (now_ns), + now_us, COGL_FRAME_INFO_FLAG_NONE); } @@ -316,9 +332,7 @@ page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc, const GError *error) { MetaRendererView *view = user_data; - MetaCrtc *crtc; - MetaGpuKms *gpu_kms; - int64_t now_ns; + int64_t now_us; /* * Page flipping failed, but we want to fail gracefully, so to avoid freezing @@ -331,13 +345,11 @@ page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc, G_IO_ERROR_PERMISSION_DENIED)) g_warning ("Page flip discarded: %s", error->message); - crtc = META_CRTC (meta_crtc_kms_from_kms_crtc (kms_crtc)); - gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); - now_ns = meta_gpu_kms_get_current_time_ns (gpu_kms); + now_us = g_get_monotonic_time (); notify_view_crtc_presented (view, kms_crtc, - ns2us (now_ns), + now_us, COGL_FRAME_INFO_FLAG_NONE); } diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 639d6225c..1770550d4 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -1033,36 +1033,9 @@ on_presented (ClutterStage *stage, { MetaCompositorPrivate *priv = meta_compositor_get_instance_private (compositor); - int64_t presentation_time_cogl = frame_info->presentation_time; - int64_t presentation_time; + int64_t presentation_time = frame_info->presentation_time; GList *l; - if (presentation_time_cogl != 0) - { - int64_t current_cogl_time; - int64_t current_monotonic_time; - - /* Cogl reports presentation in terms of its own clock, which is - * guaranteed to be in nanoseconds but with no specified base. The - * normal case with the open source GPU drivers on Linux 3.8 and - * newer is that the base of cogl_get_clock_time() is that of - * clock_gettime(CLOCK_MONOTONIC), so the same as g_get_monotonic_time), - * but there's no exposure of that through the API. clock_gettime() - * is fairly fast, so calling it twice and subtracting to get a - * nearly-zero number is acceptable, if a little ugly. - */ - current_cogl_time = cogl_get_clock_time (priv->context); - current_monotonic_time = g_get_monotonic_time (); - - presentation_time = - current_monotonic_time + - (presentation_time_cogl - current_cogl_time) / 1000; - } - else - { - presentation_time = 0; - } - for (l = priv->windows; l; l = l->next) { ClutterActor *actor = l->data;