diff --git a/src/Makefile.am b/src/Makefile.am index b4f22de0d..1afc1204d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,6 +52,8 @@ mutter_built_sources = \ meta/meta-enum-types.h \ meta-enum-types.c \ meta-default-modes.h \ + meta-marshal.c \ + meta-marshal.h \ $(NULL) if HAVE_REMOTE_DESKTOP @@ -680,8 +682,9 @@ pkgconfig_DATA = libmutter-$(LIBMUTTER_API_VERSION).pc EXTRA_DIST += \ $(wayland_protocols) \ libmutter.pc.in \ - meta/meta-enum-types.h.in \ - meta/meta-enum-types.c.in \ + meta/meta-enum-types.h.in \ + meta/meta-enum-types.c.in \ + meta-marshal.list \ org.freedesktop.login1.xml \ org.gnome.Mutter.DisplayConfig.xml \ org.gnome.Mutter.IdleMonitor.xml \ @@ -695,7 +698,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 @@ -791,3 +797,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 0f6ae87d3..974f8f425 100644 --- a/src/backends/native/meta-gpu-kms.c +++ b/src/backends/native/meta-gpu-kms.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,7 @@ typedef struct _MetaGpuKmsFlipClosureContainer { GClosure *flip_closure; MetaGpuKms *gpu_kms; + MetaCrtc *crtc; } MetaGpuKmsFlipClosureContainer; struct _MetaGpuKms @@ -64,6 +66,8 @@ struct _MetaGpuKms char *file_path; GSource *source; + clockid_t clock_id; + drmModeConnector **connectors; unsigned int n_connectors; @@ -173,18 +177,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); } @@ -224,6 +236,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; @@ -231,7 +244,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; @@ -273,6 +287,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, @@ -306,6 +321,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, @@ -316,8 +348,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); } @@ -396,6 +432,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) @@ -695,6 +742,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) @@ -823,6 +881,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 349db2990..21fb04605 100644 --- a/src/backends/native/meta-gpu-kms.h +++ b/src/backends/native/meta-gpu-kms.h @@ -76,6 +76,8 @@ uint32_t meta_gpu_kms_get_id (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); @@ -92,6 +94,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 6277dda20..768c70e1c 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -62,6 +62,7 @@ #include "backends/native/meta-monitor-manager-kms.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" @@ -1160,6 +1161,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); @@ -1170,6 +1173,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) { @@ -1300,7 +1321,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, @@ -1543,7 +1566,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. @@ -2765,6 +2788,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) { @@ -2793,6 +2825,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/meson.build b/src/meson.build index 4ea30b06d..11669e974 100644 --- a/src/meson.build +++ b/src/meson.build @@ -711,6 +711,13 @@ endif subdir('meta') +mutter_marshal = gnome.genmarshal('meta-marshal', + sources: ['meta-marshal.list'], + prefix: 'meta_marshal', + internal: true, +) +mutter_built_sources += mutter_marshal + mutter_built_sources += mutter_enum_types mutter_built_sources += mutter_version diff --git a/src/meta-marshal.list b/src/meta-marshal.list new file mode 100644 index 000000000..c1f4781d2 --- /dev/null +++ b/src/meta-marshal.list @@ -0,0 +1 @@ +VOID:OBJECT,OBJECT,INT64