renderer-native: Add hardware presentation timing

Add support for getting hardware presentation times from KMS (Wayland
sessions). Also implement cogl_get_clock_time which is required to compare
and judge the age of presentation timestamps.

For single monitor systems this is straightforward. For multi-monitor
systems though we have to choose a display to sync to. The compositor
already partially solves this for us in the case of only one display
updating because it will only use the subset of monitors that are
changing. In the case of multiple monitors consuming the same frame
concurrently however, we choose the fastest one (in use at the time).
Note however that we also need !73 to land in order to fully realize
multiple monitors running at full speed.
This commit is contained in:
Daniel van Vugt 2018-06-27 17:19:27 +08:00 committed by Jonas Ådahl
parent 6834bedb95
commit e9e4b2b72e
6 changed files with 137 additions and 10 deletions

View File

@ -52,6 +52,8 @@ mutter_built_sources = \
meta/meta-enum-types.h \ meta/meta-enum-types.h \
meta-enum-types.c \ meta-enum-types.c \
meta-default-modes.h \ meta-default-modes.h \
meta-marshal.c \
meta-marshal.h \
$(NULL) $(NULL)
if HAVE_REMOTE_DESKTOP if HAVE_REMOTE_DESKTOP
@ -682,6 +684,7 @@ EXTRA_DIST += \
libmutter.pc.in \ libmutter.pc.in \
meta/meta-enum-types.h.in \ meta/meta-enum-types.h.in \
meta/meta-enum-types.c.in \ meta/meta-enum-types.c.in \
meta-marshal.list \
org.freedesktop.login1.xml \ org.freedesktop.login1.xml \
org.gnome.Mutter.DisplayConfig.xml \ org.gnome.Mutter.DisplayConfig.xml \
org.gnome.Mutter.IdleMonitor.xml \ org.gnome.Mutter.IdleMonitor.xml \
@ -695,7 +698,10 @@ BUILT_SOURCES = \
$(libmutterinclude_built_headers) $(libmutterinclude_built_headers)
MUTTER_STAMP_FILES = stamp-meta-enum-types.h 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 meta/meta-enum-types.h: stamp-meta-enum-types.h Makefile
@true @true
@ -791,3 +797,20 @@ endef
$(AM_V_GEN)$(WAYLAND_SCANNER) server-header $< $@ $(AM_V_GEN)$(WAYLAND_SCANNER) server-header $< $@
%-server-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/%.xml %-server-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/%.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) server-header $< $@ $(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=$@ \
$<

View File

@ -28,6 +28,7 @@
#include <errno.h> #include <errno.h>
#include <poll.h> #include <poll.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <xf86drm.h> #include <xf86drm.h>
#include <xf86drmMode.h> #include <xf86drmMode.h>
@ -53,6 +54,7 @@ typedef struct _MetaGpuKmsFlipClosureContainer
{ {
GClosure *flip_closure; GClosure *flip_closure;
MetaGpuKms *gpu_kms; MetaGpuKms *gpu_kms;
MetaCrtc *crtc;
} MetaGpuKmsFlipClosureContainer; } MetaGpuKmsFlipClosureContainer;
struct _MetaGpuKms struct _MetaGpuKms
@ -64,6 +66,8 @@ struct _MetaGpuKms
char *file_path; char *file_path;
GSource *source; GSource *source;
clockid_t clock_id;
drmModeConnector **connectors; drmModeConnector **connectors;
unsigned int n_connectors; unsigned int n_connectors;
@ -173,18 +177,26 @@ meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms,
static void static void
invoke_flip_closure (GClosure *flip_closure, invoke_flip_closure (GClosure *flip_closure,
MetaGpuKms *gpu_kms) MetaGpuKms *gpu_kms,
MetaCrtc *crtc,
int64_t page_flip_time_ns)
{ {
GValue params[] = { GValue params[] = {
G_VALUE_INIT, G_VALUE_INIT,
G_VALUE_INIT G_VALUE_INIT,
G_VALUE_INIT,
G_VALUE_INIT,
}; };
g_value_init (&params[0], G_TYPE_POINTER); g_value_init (&params[0], G_TYPE_POINTER);
g_value_set_pointer (&params[0], flip_closure); g_value_set_pointer (&params[0], flip_closure);
g_value_init (&params[1], G_TYPE_OBJECT); g_value_init (&params[1], G_TYPE_OBJECT);
g_value_set_object (&params[1], gpu_kms); g_value_set_object (&params[1], gpu_kms);
g_closure_invoke (flip_closure, NULL, 2, params, NULL); g_value_init (&params[2], G_TYPE_OBJECT);
g_value_set_object (&params[2], crtc);
g_value_init (&params[3], G_TYPE_INT64);
g_value_set_int64 (&params[3], page_flip_time_ns);
g_closure_invoke (flip_closure, NULL, 4, params, NULL);
g_closure_unref (flip_closure); g_closure_unref (flip_closure);
} }
@ -224,6 +236,7 @@ meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
MetaGpuKmsFlipClosureContainer * MetaGpuKmsFlipClosureContainer *
meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms, meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms,
MetaCrtc *crtc,
GClosure *flip_closure) GClosure *flip_closure)
{ {
MetaGpuKmsFlipClosureContainer *closure_container; MetaGpuKmsFlipClosureContainer *closure_container;
@ -231,7 +244,8 @@ meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms,
closure_container = g_new0 (MetaGpuKmsFlipClosureContainer, 1); closure_container = g_new0 (MetaGpuKmsFlipClosureContainer, 1);
*closure_container = (MetaGpuKmsFlipClosureContainer) { *closure_container = (MetaGpuKmsFlipClosureContainer) {
.flip_closure = flip_closure, .flip_closure = flip_closure,
.gpu_kms = gpu_kms .gpu_kms = gpu_kms,
.crtc = crtc
}; };
return closure_container; 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); int kms_fd = meta_gpu_kms_get_fd (gpu_kms);
closure_container = meta_gpu_kms_wrap_flip_closure (gpu_kms, closure_container = meta_gpu_kms_wrap_flip_closure (gpu_kms,
crtc,
flip_closure); flip_closure);
ret = drmModePageFlip (kms_fd, ret = drmModePageFlip (kms_fd,
@ -306,6 +321,23 @@ meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms,
return TRUE; 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 static void
page_flip_handler (int fd, page_flip_handler (int fd,
unsigned int frame, unsigned int frame,
@ -316,8 +348,12 @@ page_flip_handler (int fd,
MetaGpuKmsFlipClosureContainer *closure_container = user_data; MetaGpuKmsFlipClosureContainer *closure_container = user_data;
GClosure *flip_closure = closure_container->flip_closure; GClosure *flip_closure = closure_container->flip_closure;
MetaGpuKms *gpu_kms = closure_container->gpu_kms; 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); 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; 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 void
meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms, meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
uint64_t state) uint64_t state)
@ -695,6 +742,17 @@ init_crtcs (MetaGpuKms *gpu_kms,
meta_gpu_take_crtcs (gpu, crtcs); 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 static void
init_outputs (MetaGpuKms *gpu_kms, init_outputs (MetaGpuKms *gpu_kms,
MetaKmsResources *resources) MetaKmsResources *resources)
@ -823,6 +881,7 @@ meta_gpu_kms_read_current (MetaGpu *gpu,
init_modes (gpu_kms, resources.resources); init_modes (gpu_kms, resources.resources);
init_crtcs (gpu_kms, &resources); init_crtcs (gpu_kms, &resources);
init_outputs (gpu_kms, &resources); init_outputs (gpu_kms, &resources);
init_frame_clock (gpu_kms);
meta_kms_resources_release (&resources); meta_kms_resources_release (&resources);

View File

@ -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); 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, void meta_gpu_kms_get_max_buffer_size (MetaGpuKms *gpu_kms,
int *max_width, int *max_width,
int *max_height); 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); float meta_calculate_drm_mode_refresh_rate (const drmModeModeInfo *mode);
MetaGpuKmsFlipClosureContainer * meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms, MetaGpuKmsFlipClosureContainer * meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms,
MetaCrtc *crtc,
GClosure *flip_closure); GClosure *flip_closure);
void meta_gpu_kms_flip_closure_container_free (MetaGpuKmsFlipClosureContainer *closure_container); void meta_gpu_kms_flip_closure_container_free (MetaGpuKmsFlipClosureContainer *closure_container);

View File

@ -62,6 +62,7 @@
#include "backends/native/meta-monitor-manager-kms.h" #include "backends/native/meta-monitor-manager-kms.h"
#include "backends/native/meta-renderer-native-gles3.h" #include "backends/native/meta-renderer-native-gles3.h"
#include "backends/native/meta-renderer-native.h" #include "backends/native/meta-renderer-native.h"
#include "meta-marshal.h"
#include "cogl/cogl.h" #include "cogl/cogl.h"
#include "core/boxes-private.h" #include "core/boxes-private.h"
@ -1160,6 +1161,8 @@ meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen)
static void static void
on_crtc_flipped (GClosure *closure, on_crtc_flipped (GClosure *closure,
MetaGpuKms *gpu_kms, MetaGpuKms *gpu_kms,
MetaCrtc *crtc,
int64_t page_flip_time_ns,
MetaRendererView *view) MetaRendererView *view)
{ {
ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view); ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
@ -1170,6 +1173,24 @@ on_crtc_flipped (GClosure *closure,
MetaOnscreenNative *onscreen_native = onscreen_egl->platform; MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
MetaRendererNative *renderer_native = onscreen_native->renderer_native; MetaRendererNative *renderer_native = onscreen_native->renderer_native;
MetaGpuKms *render_gpu = onscreen_native->render_gpu; 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) if (gpu_kms != render_gpu)
{ {
@ -1300,7 +1321,9 @@ flip_egl_stream (MetaOnscreenNative *onscreen_native,
return FALSE; return FALSE;
closure_container = 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[]) { acquire_attribs = (EGLAttrib[]) {
EGL_DRM_FLIP_EVENT_DATA_NV, 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), flip_closure = g_cclosure_new (G_CALLBACK (on_crtc_flipped),
g_object_ref (view), g_object_ref (view),
(GClosureNotify) flip_closure_destroyed); (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 /* 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. * 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; 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 * static const CoglWinsysVtable *
get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer) 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 = vtable.onscreen_swap_buffers_with_damage =
meta_onscreen_native_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; vtable_inited = TRUE;
} }

View File

@ -711,6 +711,13 @@ endif
subdir('meta') 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_enum_types
mutter_built_sources += mutter_version mutter_built_sources += mutter_version

1
src/meta-marshal.list Normal file
View File

@ -0,0 +1 @@
VOID:OBJECT,OBJECT,INT64