From: Daniel van Vugt Date: Thu, 29 Nov 2018 16:31:58 +0000 (+0000) Subject: Sync to the hardware refresh rate, not just 60.00Hz X-Git-Tag: archive/raspbian/3.30.2-7+rpi1~1^2^2^2^2~2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=3c405bb63755ed639d77ed8d80b3558f94bfd8f8;p=mutter.git Sync to the hardware refresh rate, not just 60.00Hz The Clutter master clock supports three synchronization methods in order of preference: (a) Hardware presentation times (b) Swap throttling (c) Fake vsync at 60.00Hz X11 already supports all three but Wayland only has (c). This patch implements both (a) and (b) for Wayland bringing it in line with X11. Origin: https://gitlab.gnome.org/GNOME/mutter/merge_requests/171 via backport https://gitlab.gnome.org/GNOME/mutter/merge_requests/318 Bug: https://bugzilla.gnome.org/show_bug.cgi?id=781296 Bug-Ubuntu: https://bugs.launchpad.net/bugs/1763892 Forwarded: yes Last-Update: 2018-11-23 Gbp-Pq: Name Sync-to-the-hardware-refresh-rate-not-just-60.00Hz.patch --- diff --git a/src/Makefile.am b/src/Makefile.am index 811e2b8..56d5398 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,6 +51,8 @@ mutter_built_sources = \ $(dbus_login1_built_sources) \ meta/meta-enum-types.h \ meta-enum-types.c \ + meta-marshal.c \ + meta-marshal.h \ $(NULL) if HAVE_REMOTE_DESKTOP @@ -677,6 +679,7 @@ EXTRA_DIST += \ libmutter.pc.in \ meta-enum-types.h.in \ meta-enum-types.c.in \ + meta-marshal.list \ org.freedesktop.login1.xml \ org.gnome.Mutter.DisplayConfig.xml \ org.gnome.Mutter.IdleMonitor.xml \ @@ -690,7 +693,10 @@ BUILT_SOURCES = \ $(libmutterinclude_built_headers) MUTTER_STAMP_FILES = stamp-meta-enum-types.h -CLEANFILES += $(MUTTER_STAMP_FILES) +CLEANFILES += \ + $(MUTTER_STAMP_FILES) \ + meta-marshal.c \ + meta-marshal.h meta/meta-enum-types.h: stamp-meta-enum-types.h Makefile @true @@ -786,3 +792,20 @@ endef $(AM_V_GEN)$(WAYLAND_SCANNER) server-header $< $@ %-server-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/%.xml $(AM_V_GEN)$(WAYLAND_SCANNER) server-header $< $@ + +meta_marshal_opts = --prefix=meta_marshal --internal + +meta-marshal.h: meta-marshal.list + $(AM_V_GEN)$(GLIB_GENMARSHAL) \ + --header \ + $(meta_marshal_opts) \ + --output=$@ \ + $< + +meta-marshal.c: meta-marshal.list meta-marshal.h + $(AM_V_GEN)$(GLIB_GENMARSHAL) \ + --include-header=meta-marshal.h \ + $(meta_marshal_opts) \ + --body \ + --output=$@ \ + $< diff --git a/src/backends/native/meta-gpu-kms.c b/src/backends/native/meta-gpu-kms.c index c3c5d0d..26c7590 100644 --- a/src/backends/native/meta-gpu-kms.c +++ b/src/backends/native/meta-gpu-kms.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -51,6 +52,7 @@ typedef struct _MetaGpuKmsFlipClosureContainer { GClosure *flip_closure; MetaGpuKms *gpu_kms; + MetaCrtc *crtc; } MetaGpuKmsFlipClosureContainer; struct _MetaGpuKms @@ -61,6 +63,8 @@ struct _MetaGpuKms char *file_path; GSource *source; + clockid_t clock_id; + drmModeConnector **connectors; unsigned int n_connectors; @@ -165,18 +169,26 @@ meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms, static void invoke_flip_closure (GClosure *flip_closure, - MetaGpuKms *gpu_kms) + MetaGpuKms *gpu_kms, + MetaCrtc *crtc, + int64_t page_flip_time_ns) { GValue params[] = { G_VALUE_INIT, - G_VALUE_INIT + G_VALUE_INIT, + G_VALUE_INIT, + G_VALUE_INIT, }; g_value_init (¶ms[0], G_TYPE_POINTER); g_value_set_pointer (¶ms[0], flip_closure); g_value_init (¶ms[1], G_TYPE_OBJECT); g_value_set_object (¶ms[1], gpu_kms); - g_closure_invoke (flip_closure, NULL, 2, params, NULL); + g_value_init (¶ms[2], G_TYPE_OBJECT); + g_value_set_object (¶ms[2], crtc); + g_value_init (¶ms[3], G_TYPE_INT64); + g_value_set_int64 (¶ms[3], page_flip_time_ns); + g_closure_invoke (flip_closure, NULL, 4, params, NULL); g_closure_unref (flip_closure); } @@ -216,6 +228,7 @@ meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms, MetaGpuKmsFlipClosureContainer * meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms, + MetaCrtc *crtc, GClosure *flip_closure) { MetaGpuKmsFlipClosureContainer *closure_container; @@ -223,7 +236,8 @@ meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms, closure_container = g_new0 (MetaGpuKmsFlipClosureContainer, 1); *closure_container = (MetaGpuKmsFlipClosureContainer) { .flip_closure = flip_closure, - .gpu_kms = gpu_kms + .gpu_kms = gpu_kms, + .crtc = crtc }; return closure_container; @@ -263,6 +277,7 @@ meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms, int kms_fd = meta_gpu_kms_get_fd (gpu_kms); closure_container = meta_gpu_kms_wrap_flip_closure (gpu_kms, + crtc, flip_closure); ret = drmModePageFlip (kms_fd, @@ -296,6 +311,23 @@ meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms, return TRUE; } +static int64_t +timespec_to_nanoseconds (const struct timespec *ts) +{ + const int64_t one_billion = 1000000000; + + return ((int64_t) ts->tv_sec) * one_billion + ts->tv_nsec; +} + +static int64_t +timeval_to_nanoseconds (const struct timeval *tv) +{ + int64_t usec = ((int64_t) tv->tv_sec) * G_USEC_PER_SEC + tv->tv_usec; + int64_t nsec = usec * 1000; + + return nsec; +} + static void page_flip_handler (int fd, unsigned int frame, @@ -306,8 +338,12 @@ page_flip_handler (int fd, MetaGpuKmsFlipClosureContainer *closure_container = user_data; GClosure *flip_closure = closure_container->flip_closure; MetaGpuKms *gpu_kms = closure_container->gpu_kms; + struct timeval page_flip_time = {sec, usec}; - invoke_flip_closure (flip_closure, gpu_kms); + invoke_flip_closure (flip_closure, + gpu_kms, + closure_container->crtc, + timeval_to_nanoseconds (&page_flip_time)); meta_gpu_kms_flip_closure_container_free (closure_container); } @@ -380,6 +416,17 @@ meta_gpu_kms_get_file_path (MetaGpuKms *gpu_kms) return gpu_kms->file_path; } +int64_t +meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms) +{ + struct timespec ts; + + if (clock_gettime (gpu_kms->clock_id, &ts)) + return 0; + + return timespec_to_nanoseconds (&ts); +} + void meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms, uint64_t state) @@ -679,6 +726,17 @@ init_crtcs (MetaGpuKms *gpu_kms, meta_gpu_take_crtcs (gpu, crtcs); } +static void +init_frame_clock (MetaGpuKms *gpu_kms) +{ + uint64_t uses_monotonic; + + if (drmGetCap (gpu_kms->fd, DRM_CAP_TIMESTAMP_MONOTONIC, &uses_monotonic) != 0) + uses_monotonic = 0; + + gpu_kms->clock_id = uses_monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME; +} + static void init_outputs (MetaGpuKms *gpu_kms, MetaKmsResources *resources) @@ -806,6 +864,7 @@ meta_gpu_kms_read_current (MetaGpu *gpu, init_modes (gpu_kms, resources.resources); init_crtcs (gpu_kms, &resources); init_outputs (gpu_kms, &resources); + init_frame_clock (gpu_kms); meta_kms_resources_release (&resources); diff --git a/src/backends/native/meta-gpu-kms.h b/src/backends/native/meta-gpu-kms.h index 5f77f19..3e3f45c 100644 --- a/src/backends/native/meta-gpu-kms.h +++ b/src/backends/native/meta-gpu-kms.h @@ -73,6 +73,8 @@ int meta_gpu_kms_get_fd (MetaGpuKms *gpu_kms); const char * meta_gpu_kms_get_file_path (MetaGpuKms *gpu_kms); +int64_t meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms); + void meta_gpu_kms_get_max_buffer_size (MetaGpuKms *gpu_kms, int *max_width, int *max_height); @@ -89,6 +91,7 @@ gboolean meta_drm_mode_equal (const drmModeModeInfo *one, float meta_calculate_drm_mode_refresh_rate (const drmModeModeInfo *mode); MetaGpuKmsFlipClosureContainer * meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms, + MetaCrtc *crtc, GClosure *flip_closure); void meta_gpu_kms_flip_closure_container_free (MetaGpuKmsFlipClosureContainer *closure_container); diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index f58e6b3..24d6b8b 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -60,8 +60,9 @@ #include "backends/native/meta-crtc-kms.h" #include "backends/native/meta-gpu-kms.h" #include "backends/native/meta-monitor-manager-kms.h" -#include "backends/native/meta-renderer-native.h" #include "backends/native/meta-renderer-native-gles3.h" +#include "backends/native/meta-renderer-native.h" +#include "meta-marshal.h" #include "cogl/cogl.h" #include "core/boxes-private.h" @@ -1159,6 +1160,8 @@ meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen) static void on_crtc_flipped (GClosure *closure, MetaGpuKms *gpu_kms, + MetaCrtc *crtc, + int64_t page_flip_time_ns, MetaRendererView *view) { ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view); @@ -1169,6 +1172,24 @@ on_crtc_flipped (GClosure *closure, MetaOnscreenNative *onscreen_native = onscreen_egl->platform; MetaRendererNative *renderer_native = onscreen_native->renderer_native; MetaGpuKms *render_gpu = onscreen_native->render_gpu; + CoglFrameInfo *frame_info; + float refresh_rate; + + frame_info = g_queue_peek_tail (&onscreen->pending_frame_infos); + refresh_rate = crtc && crtc->current_mode ? + crtc->current_mode->refresh_rate : + 0.0f; + + /* Only keep the frame info for the fastest CRTC in use, which may not be + * the first one to complete a flip. By only telling the compositor about the + * fastest monitor(s) we direct it to produce new frames fast enough to + * satisfy all monitors. + */ + if (refresh_rate >= frame_info->refresh_rate) + { + frame_info->presentation_time = page_flip_time_ns; + frame_info->refresh_rate = refresh_rate; + } if (gpu_kms != render_gpu) { @@ -1299,7 +1320,9 @@ flip_egl_stream (MetaOnscreenNative *onscreen_native, return FALSE; closure_container = - meta_gpu_kms_wrap_flip_closure (onscreen_native->render_gpu, flip_closure); + meta_gpu_kms_wrap_flip_closure (onscreen_native->render_gpu, + NULL, + flip_closure); acquire_attribs = (EGLAttrib[]) { EGL_DRM_FLIP_EVENT_DATA_NV, @@ -1542,7 +1565,7 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen) flip_closure = g_cclosure_new (G_CALLBACK (on_crtc_flipped), g_object_ref (view), (GClosureNotify) flip_closure_destroyed); - g_closure_set_marshal (flip_closure, g_cclosure_marshal_VOID__OBJECT); + g_closure_set_marshal (flip_closure, meta_marshal_VOID__OBJECT_OBJECT_INT64); /* Either flip the CRTC's of the monitor info, if we are drawing just part * of the stage, or all of the CRTC's if we are drawing the whole stage. @@ -1982,6 +2005,13 @@ meta_renderer_native_init_egl_context (CoglContext *cogl_context, COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN, TRUE); + /* COGL_WINSYS_FEATURE_SWAP_THROTTLE is always true for this renderer + * because we have the call to wait_for_pending_flips on every frame. + */ + COGL_FLAGS_SET (cogl_context->winsys_features, + COGL_WINSYS_FEATURE_SWAP_THROTTLE, + TRUE); + #ifdef HAVE_EGL_DEVICE if (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_EGL_DEVICE) COGL_FLAGS_SET (cogl_context->features, @@ -2616,8 +2646,12 @@ meta_renderer_native_create_onscreen (MetaRendererNative *renderer_native, } onscreen = cogl_onscreen_new (context, width, height); - cogl_onscreen_set_swap_throttled (onscreen, - _clutter_get_sync_to_vblank ()); + + /* We have wait_for_pending_flips hardcoded, so throttling always. */ + cogl_onscreen_set_swap_throttled (onscreen, TRUE); + if (!_clutter_get_sync_to_vblank ()) + g_warning ("Request to disable sync-to-vblank is being ignored. " + "MetaRendererNative does not support disabling it."); if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (onscreen), error)) { @@ -2687,6 +2721,15 @@ meta_renderer_native_create_offscreen (MetaRendererNative *renderer, return fb; } +static int64_t +meta_renderer_native_get_clock_time (CoglContext *context) +{ + CoglRenderer *cogl_renderer = cogl_context_get_renderer (context); + MetaGpuKms *gpu_kms = cogl_renderer->custom_winsys_user_data; + + return meta_gpu_kms_get_current_time_ns (gpu_kms); +} + static const CoglWinsysVtable * get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer) { @@ -2715,6 +2758,8 @@ get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer) vtable.onscreen_swap_buffers_with_damage = meta_onscreen_native_swap_buffers_with_damage; + vtable.context_get_clock_time = meta_renderer_native_get_clock_time; + vtable_inited = TRUE; } diff --git a/src/meta-marshal.list b/src/meta-marshal.list new file mode 100644 index 0000000..c1f4781 --- /dev/null +++ b/src/meta-marshal.list @@ -0,0 +1 @@ +VOID:OBJECT,OBJECT,INT64