diff options
author | Daniel van Vugt <daniel.van.vugt@canonical.com> | 2018-06-27 17:19:27 +0800 |
---|---|---|
committer | Jonas Ã…dahl <jadahl@gmail.com> | 2018-11-23 11:01:30 +0000 |
commit | e9e4b2b72ef63890c4225dc641da38482b2b13b5 (patch) | |
tree | 50771c195a733f448054768561711602aa52d957 /src/backends/native/meta-gpu-kms.c | |
parent | 6834bedb957477527f1efcbc11df09f283523d3a (diff) | |
download | mutter-e9e4b2b72ef63890c4225dc641da38482b2b13b5.tar.gz |
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.
Diffstat (limited to 'src/backends/native/meta-gpu-kms.c')
-rw-r--r-- | src/backends/native/meta-gpu-kms.c | 69 |
1 files changed, 64 insertions, 5 deletions
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 <errno.h> #include <poll.h> #include <string.h> +#include <time.h> #include <xf86drm.h> #include <xf86drmMode.h> @@ -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) @@ -696,6 +743,17 @@ init_crtcs (MetaGpuKms *gpu_kms, } 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); |