diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c index 7d5e72198..10d344e62 100644 --- a/src/backends/native/meta-crtc-kms.c +++ b/src/backends/native/meta-crtc-kms.c @@ -25,9 +25,12 @@ #include "backends/native/meta-crtc-kms.h" #include "backends/meta-backend-private.h" +#include "backends/meta-logical-monitor.h" #include "backends/native/meta-gpu-kms.h" +#include "backends/native/meta-output-kms.h" #include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms-plane.h" +#include "backends/native/meta-kms-update.h" #define ALL_TRANSFORMS_MASK ((1 << META_MONITOR_N_TRANSFORMS) - 1) @@ -35,12 +38,11 @@ typedef struct _MetaCrtcKms { MetaKmsCrtc *kms_crtc; - uint32_t rotation_prop_id; - uint32_t rotation_map[META_MONITOR_N_TRANSFORMS]; - MetaKmsPlane *primary_plane; } MetaCrtcKms; +static GQuark kms_crtc_crtc_kms_quark; + gboolean meta_crtc_kms_is_transform_handled (MetaCrtc *crtc, MetaMonitorTransform transform) @@ -55,60 +57,123 @@ meta_crtc_kms_is_transform_handled (MetaCrtc *crtc, } void -meta_crtc_kms_apply_transform (MetaCrtc *crtc) +meta_crtc_kms_apply_transform (MetaCrtc *crtc, + MetaKmsPlaneAssignment *kms_plane_assignment) { MetaCrtcKms *crtc_kms = crtc->driver_private; - MetaGpu *gpu = meta_crtc_get_gpu (crtc); - MetaGpuKms *gpu_kms = META_GPU_KMS (gpu); - int kms_fd; MetaMonitorTransform hw_transform; - kms_fd = meta_gpu_kms_get_fd (gpu_kms); - hw_transform = crtc->transform; if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform)) hw_transform = META_MONITOR_TRANSFORM_NORMAL; if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform)) return; - if (drmModeObjectSetProperty (kms_fd, - meta_kms_plane_get_id (crtc_kms->primary_plane), - DRM_MODE_OBJECT_PLANE, - crtc_kms->rotation_prop_id, - crtc_kms->rotation_map[hw_transform]) != 0) - g_warning ("Failed to apply DRM plane transform %d: %m", hw_transform); + meta_kms_plane_update_set_rotation (crtc_kms->primary_plane, + kms_plane_assignment, + hw_transform); } -static int -find_property_index (MetaGpu *gpu, - drmModeObjectPropertiesPtr props, - const char *prop_name, - drmModePropertyPtr *out_prop) +void +meta_crtc_kms_assign_primary_plane (MetaCrtc *crtc, + uint32_t fb_id, + MetaKmsUpdate *kms_update) { - MetaGpuKms *gpu_kms = META_GPU_KMS (gpu); - int kms_fd; - unsigned int i; + MetaRectangle logical_monitor_rect; + int x, y; + MetaFixed16Rectangle src_rect; + MetaFixed16Rectangle dst_rect; + MetaKmsCrtc *kms_crtc; + MetaKmsDevice *kms_device; + MetaKmsPlane *primary_kms_plane; + MetaKmsPlaneAssignment *plane_assignment; - kms_fd = meta_gpu_kms_get_fd (gpu_kms); + logical_monitor_rect = + meta_logical_monitor_get_layout (crtc->logical_monitor); + x = crtc->rect.x - logical_monitor_rect.x; + y = crtc->rect.y - logical_monitor_rect.y; + src_rect = (MetaFixed16Rectangle) { + .x = meta_fixed_16_from_int (x), + .y = meta_fixed_16_from_int (y), + .width = meta_fixed_16_from_int (crtc->rect.width), + .height = meta_fixed_16_from_int (crtc->rect.height), + }; + dst_rect = (MetaFixed16Rectangle) { + .x = meta_fixed_16_from_int (0), + .y = meta_fixed_16_from_int (0), + .width = meta_fixed_16_from_int (crtc->rect.width), + .height = meta_fixed_16_from_int (crtc->rect.height), + }; - for (i = 0; i < props->count_props; i++) + kms_crtc = meta_crtc_kms_get_kms_crtc (crtc); + kms_device = meta_kms_crtc_get_device (kms_crtc); + primary_kms_plane = meta_kms_device_get_primary_plane_for (kms_device, + kms_crtc); + plane_assignment = meta_kms_update_assign_plane (kms_update, + kms_crtc, + primary_kms_plane, + fb_id, + src_rect, + dst_rect); + meta_crtc_kms_apply_transform (crtc, plane_assignment); +} + +static GList * +generate_crtc_connector_list (MetaGpu *gpu, + MetaCrtc *crtc) +{ + GList *connectors = NULL; + GList *l; + + for (l = meta_gpu_get_outputs (gpu); l; l = l->next) { - drmModePropertyPtr prop; + MetaOutput *output = l->data; + MetaCrtc *assigned_crtc; - prop = drmModeGetProperty (kms_fd, props->props[i]); - if (!prop) - continue; - - if (strcmp (prop->name, prop_name) == 0) + assigned_crtc = meta_output_get_assigned_crtc (output); + if (assigned_crtc == crtc) { - *out_prop = prop; - return i; - } + MetaKmsConnector *kms_connector = + meta_output_kms_get_kms_connector (output); - drmModeFreeProperty (prop); + connectors = g_list_prepend (connectors, kms_connector); + } } - return -1; + return connectors; +} + +void +meta_crtc_kms_set_mode (MetaCrtc *crtc, + MetaKmsUpdate *kms_update) +{ + MetaGpu *gpu = meta_crtc_get_gpu (crtc); + GList *connectors; + drmModeModeInfo *mode; + + connectors = generate_crtc_connector_list (gpu, crtc); + + if (connectors) + mode = crtc->current_mode->driver_private; + else + mode = NULL; + + meta_kms_update_mode_set (kms_update, + meta_crtc_kms_get_kms_crtc (crtc), + g_steal_pointer (&connectors), + mode); +} + +void +meta_crtc_kms_page_flip (MetaCrtc *crtc, + const MetaKmsPageFlipFeedback *page_flip_feedback, + gpointer user_data, + MetaKmsUpdate *kms_update) +{ + meta_kms_update_page_flip (kms_update, + meta_crtc_kms_get_kms_crtc (crtc), + page_flip_feedback, + user_data); } MetaKmsCrtc * @@ -176,62 +241,10 @@ meta_crtc_kms_supports_format (MetaCrtc *crtc, drm_format); } -static void -parse_transforms (MetaCrtc *crtc, - drmModePropertyPtr prop) +MetaCrtc * +meta_crtc_kms_from_kms_crtc (MetaKmsCrtc *kms_crtc) { - MetaCrtcKms *crtc_kms = crtc->driver_private; - int i; - - for (i = 0; i < prop->count_enums; i++) - { - int transform = -1; - - if (strcmp (prop->enums[i].name, "rotate-0") == 0) - transform = META_MONITOR_TRANSFORM_NORMAL; - else if (strcmp (prop->enums[i].name, "rotate-90") == 0) - transform = META_MONITOR_TRANSFORM_90; - else if (strcmp (prop->enums[i].name, "rotate-180") == 0) - transform = META_MONITOR_TRANSFORM_180; - else if (strcmp (prop->enums[i].name, "rotate-270") == 0) - transform = META_MONITOR_TRANSFORM_270; - - if (transform != -1) - crtc_kms->rotation_map[transform] = 1 << prop->enums[i].value; - } -} - -static void -init_crtc_rotations (MetaCrtc *crtc, - MetaGpu *gpu) -{ - MetaCrtcKms *crtc_kms = crtc->driver_private; - MetaGpuKms *gpu_kms = META_GPU_KMS (gpu); - int kms_fd; - uint32_t primary_plane_id; - drmModePlane *drm_plane; - drmModeObjectPropertiesPtr props; - drmModePropertyPtr prop; - int rotation_idx; - - kms_fd = meta_gpu_kms_get_fd (gpu_kms); - primary_plane_id = meta_kms_plane_get_id (crtc_kms->primary_plane); - drm_plane = drmModeGetPlane (kms_fd, primary_plane_id); - props = drmModeObjectGetProperties (kms_fd, - primary_plane_id, - DRM_MODE_OBJECT_PLANE); - - rotation_idx = find_property_index (gpu, props, - "rotation", &prop); - if (rotation_idx >= 0) - { - crtc_kms->rotation_prop_id = props->props[rotation_idx]; - parse_transforms (crtc, prop); - drmModeFreeProperty (prop); - } - - drmModeFreeObjectProperties (props); - drmModeFreePlane (drm_plane); + return g_object_get_qdata (G_OBJECT (kms_crtc), kms_crtc_crtc_kms_quark); } static void @@ -287,7 +300,13 @@ meta_create_kms_crtc (MetaGpuKms *gpu_kms, crtc->driver_private = crtc_kms; crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify; - init_crtc_rotations (crtc, gpu); + if (!kms_crtc_crtc_kms_quark) + { + kms_crtc_crtc_kms_quark = + g_quark_from_static_string ("meta-kms-crtc-crtc-kms-quark"); + } + + g_object_set_qdata (G_OBJECT (kms_crtc), kms_crtc_crtc_kms_quark, crtc); return crtc; } diff --git a/src/backends/native/meta-crtc-kms.h b/src/backends/native/meta-crtc-kms.h index 178c282c3..898622478 100644 --- a/src/backends/native/meta-crtc-kms.h +++ b/src/backends/native/meta-crtc-kms.h @@ -34,7 +34,23 @@ gboolean meta_crtc_kms_is_transform_handled (MetaCrtc *crtc, MetaMonitorTransform transform); -void meta_crtc_kms_apply_transform (MetaCrtc *crtc); +void meta_crtc_kms_apply_transform (MetaCrtc *crtc, + MetaKmsPlaneAssignment *kms_plane_assignment); + +void meta_crtc_kms_assign_primary_plane (MetaCrtc *crtc, + uint32_t fb_id, + MetaKmsUpdate *kms_update); + +void meta_crtc_kms_set_mode (MetaCrtc *crtc, + MetaKmsUpdate *kms_update); + +void meta_crtc_kms_page_flip (MetaCrtc *crtc, + const MetaKmsPageFlipFeedback *page_flip_feedback, + gpointer user_data, + MetaKmsUpdate *kms_update); + +void meta_crtc_kms_set_is_underscanning (MetaCrtc *crtc, + gboolean is_underscanning); MetaKmsCrtc * meta_crtc_kms_get_kms_crtc (MetaCrtc *crtc); @@ -48,6 +64,8 @@ gboolean meta_crtc_kms_supports_format (MetaCrtc *crtc, uint32_t drm_format); +MetaCrtc * meta_crtc_kms_from_kms_crtc (MetaKmsCrtc *kms_crtc); + MetaCrtc * meta_create_kms_crtc (MetaGpuKms *gpu_kms, MetaKmsCrtc *kms_crtc); diff --git a/src/backends/native/meta-gpu-kms.c b/src/backends/native/meta-gpu-kms.c index 596a775f3..ea937ba3e 100644 --- a/src/backends/native/meta-gpu-kms.c +++ b/src/backends/native/meta-gpu-kms.c @@ -39,6 +39,7 @@ #include "backends/native/meta-crtc-kms.h" #include "backends/native/meta-kms-connector.h" #include "backends/native/meta-kms-device.h" +#include "backends/native/meta-kms-update.h" #include "backends/native/meta-kms-utils.h" #include "backends/native/meta-kms.h" #include "backends/native/meta-launcher.h" @@ -46,21 +47,6 @@ #include "meta-default-modes.h" -typedef struct _MetaKmsSource -{ - GSource source; - - gpointer fd_tag; - MetaGpuKms *gpu_kms; -} MetaKmsSource; - -typedef struct _MetaGpuKmsFlipClosureContainer -{ - GClosure *flip_closure; - MetaGpuKms *gpu_kms; - MetaCrtc *crtc; -} MetaGpuKmsFlipClosureContainer; - struct _MetaGpuKms { MetaGpu parent; @@ -69,7 +55,6 @@ struct _MetaGpuKms uint32_t id; int fd; - GSource *source; clockid_t clock_id; @@ -78,124 +63,6 @@ struct _MetaGpuKms G_DEFINE_TYPE (MetaGpuKms, meta_gpu_kms, META_TYPE_GPU) -static gboolean -kms_event_check (GSource *source) -{ - MetaKmsSource *kms_source = (MetaKmsSource *) source; - - return g_source_query_unix_fd (source, kms_source->fd_tag) & G_IO_IN; -} - -static gboolean -kms_event_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - MetaKmsSource *kms_source = (MetaKmsSource *) source; - - meta_gpu_kms_wait_for_flip (kms_source->gpu_kms, NULL); - - return G_SOURCE_CONTINUE; -} - -static GSourceFuncs kms_event_funcs = { - NULL, - kms_event_check, - kms_event_dispatch -}; - -static void -get_crtc_drm_connectors (MetaGpu *gpu, - MetaCrtc *crtc, - uint32_t **connectors, - unsigned int *n_connectors) -{ - GArray *connectors_array = g_array_new (FALSE, FALSE, sizeof (uint32_t)); - GList *l; - - for (l = meta_gpu_get_outputs (gpu); l; l = l->next) - { - MetaOutput *output = l->data; - MetaCrtc *assigned_crtc; - - assigned_crtc = meta_output_get_assigned_crtc (output); - if (assigned_crtc == crtc) - { - uint32_t connector_id; - - connector_id = meta_output_kms_get_connector_id (output); - g_array_append_val (connectors_array, connector_id); - } - } - - *n_connectors = connectors_array->len; - *connectors = (uint32_t *) g_array_free (connectors_array, FALSE); -} - -gboolean -meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms, - MetaCrtc *crtc, - int x, - int y, - uint32_t fb_id) -{ - MetaGpu *gpu = meta_crtc_get_gpu (crtc); - int kms_fd = meta_gpu_kms_get_fd (gpu_kms); - uint32_t *connectors; - unsigned int n_connectors; - drmModeModeInfo *mode; - - get_crtc_drm_connectors (gpu, crtc, &connectors, &n_connectors); - - if (connectors) - mode = crtc->current_mode->driver_private; - else - mode = NULL; - - if (drmModeSetCrtc (kms_fd, - crtc->crtc_id, - fb_id, - x, y, - connectors, n_connectors, - mode) != 0) - { - if (mode) - g_warning ("Failed to set CRTC mode %s: %m", crtc->current_mode->name); - else - g_warning ("Failed to disable CRTC"); - g_free (connectors); - return FALSE; - } - - g_free (connectors); - - return TRUE; -} - -static void -invoke_flip_closure (GClosure *flip_closure, - 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 (¶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_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); -} - gboolean meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms, MetaCrtc *crtc) @@ -232,79 +99,6 @@ meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms, return TRUE; } -MetaGpuKmsFlipClosureContainer * -meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms, - MetaCrtc *crtc, - GClosure *flip_closure) -{ - MetaGpuKmsFlipClosureContainer *closure_container; - - closure_container = g_new0 (MetaGpuKmsFlipClosureContainer, 1); - *closure_container = (MetaGpuKmsFlipClosureContainer) { - .flip_closure = g_closure_ref (flip_closure), - .gpu_kms = gpu_kms, - .crtc = crtc - }; - - return closure_container; -} - -void -meta_gpu_kms_flip_closure_container_free (MetaGpuKmsFlipClosureContainer *closure_container) -{ - g_closure_unref (closure_container->flip_closure); - g_free (closure_container); -} - -gboolean -meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms, - MetaCrtc *crtc, - uint32_t fb_id, - GClosure *flip_closure, - GError **error) -{ - MetaGpu *gpu = META_GPU (gpu_kms); - MetaBackend *backend = meta_gpu_get_backend (gpu); - MetaMonitorManager *monitor_manager = - meta_backend_get_monitor_manager (backend); - MetaGpuKmsFlipClosureContainer *closure_container; - int kms_fd = meta_gpu_kms_get_fd (gpu_kms); - uint32_t *connectors; - unsigned int n_connectors; - int ret = -1; - - g_assert (meta_crtc_get_gpu (crtc) == gpu); - g_assert (monitor_manager); - g_assert (meta_monitor_manager_get_power_save_mode (monitor_manager) == - META_POWER_SAVE_ON); - - get_crtc_drm_connectors (gpu, crtc, &connectors, &n_connectors); - g_assert (n_connectors > 0); - g_free (connectors); - - g_assert (fb_id != 0); - - closure_container = meta_gpu_kms_wrap_flip_closure (gpu_kms, - crtc, - flip_closure); - - ret = drmModePageFlip (kms_fd, - crtc->crtc_id, - fb_id, - DRM_MODE_PAGE_FLIP_EVENT, - closure_container); - if (ret != 0) - { - meta_gpu_kms_flip_closure_container_free (closure_container); - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (-ret), - "drmModePageFlip failed: %s", g_strerror (-ret)); - return FALSE; - } - - return TRUE; -} - static int64_t timespec_to_nanoseconds (const struct timespec *ts) { @@ -313,71 +107,12 @@ timespec_to_nanoseconds (const struct timespec *ts) 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, - unsigned int sec, - unsigned int usec, - void *user_data) -{ - 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, - closure_container->crtc, - timeval_to_nanoseconds (&page_flip_time)); - meta_gpu_kms_flip_closure_container_free (closure_container); -} - gboolean meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms, GError **error) { - drmEventContext evctx; - - memset (&evctx, 0, sizeof evctx); - evctx.version = 2; - evctx.page_flip_handler = page_flip_handler; - - while (TRUE) - { - if (drmHandleEvent (gpu_kms->fd, &evctx) != 0) - { - struct pollfd pfd; - int ret; - - if (errno != EAGAIN) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - strerror (errno)); - return FALSE; - } - - pfd.fd = gpu_kms->fd; - pfd.events = POLL_IN | POLL_ERR; - do - { - ret = poll (&pfd, 1, -1); - } - while (ret == -1 && errno == EINTR); - } - else - { - break; - } - } + if (meta_kms_device_dispatch_sync (gpu_kms->kms_device, error) < 0) + return FALSE; return TRUE; } @@ -418,8 +153,9 @@ meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms) } void -meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms, - uint64_t state) +meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms, + uint64_t state, + MetaKmsUpdate *kms_update) { GList *l; @@ -427,7 +163,7 @@ meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms, { MetaOutput *output = l->data; - meta_output_kms_set_power_save_mode (output, state); + meta_output_kms_set_power_save_mode (output, state, kms_update); } } @@ -707,16 +443,13 @@ init_outputs (MetaGpuKms *gpu_kms) for (l = meta_kms_device_get_connectors (gpu_kms->kms_device); l; l = l->next) { MetaKmsConnector *kms_connector = l->data; + const MetaKmsConnectorState *connector_state; MetaOutput *output; MetaOutput *old_output; GError *error = NULL; - uint32_t connector_id; - drmModeConnector *connector; - connector_id = meta_kms_connector_get_id (kms_connector); - connector = drmModeGetConnector (gpu_kms->fd, connector_id); - - if (!connector || connector->connection != DRM_MODE_CONNECTED) + connector_state = meta_kms_connector_get_current_state (kms_connector); + if (!connector_state) continue; old_output = @@ -724,7 +457,6 @@ init_outputs (MetaGpuKms *gpu_kms) meta_kms_connector_get_id (kms_connector)); output = meta_create_kms_output (gpu_kms, kms_connector, - connector, old_output, &error); if (!output) @@ -787,8 +519,6 @@ meta_gpu_kms_new (MetaBackendNative *backend_native, MetaKmsDevice *kms_device, GError **error) { - GSource *source; - MetaKmsSource *kms_source; MetaGpuKms *gpu_kms; int kms_fd; @@ -803,29 +533,9 @@ meta_gpu_kms_new (MetaBackendNative *backend_native, meta_gpu_kms_read_current (META_GPU (gpu_kms), NULL); - source = g_source_new (&kms_event_funcs, sizeof (MetaKmsSource)); - kms_source = (MetaKmsSource *) source; - kms_source->fd_tag = g_source_add_unix_fd (source, - gpu_kms->fd, - G_IO_IN | G_IO_ERR); - kms_source->gpu_kms = gpu_kms; - - gpu_kms->source = source; - g_source_attach (gpu_kms->source, NULL); - return gpu_kms; } -static void -meta_gpu_kms_finalize (GObject *object) -{ - MetaGpuKms *gpu_kms = META_GPU_KMS (object); - - g_source_destroy (gpu_kms->source); - - G_OBJECT_CLASS (meta_gpu_kms_parent_class)->finalize (object); -} - static void meta_gpu_kms_init (MetaGpuKms *gpu_kms) { @@ -838,10 +548,7 @@ meta_gpu_kms_init (MetaGpuKms *gpu_kms) static void meta_gpu_kms_class_init (MetaGpuKmsClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); MetaGpuClass *gpu_class = META_GPU_CLASS (klass); - object_class->finalize = meta_gpu_kms_finalize; - gpu_class->read_current = meta_gpu_kms_read_current; } diff --git a/src/backends/native/meta-gpu-kms.h b/src/backends/native/meta-gpu-kms.h index 1dcdc50aa..6646ead93 100644 --- a/src/backends/native/meta-gpu-kms.h +++ b/src/backends/native/meta-gpu-kms.h @@ -29,6 +29,7 @@ #include "backends/meta-gpu.h" #include "backends/native/meta-backend-native.h" +#include "backends/native/meta-kms-types.h" #define META_TYPE_GPU_KMS (meta_gpu_kms_get_type ()) G_DECLARE_FINAL_TYPE (MetaGpuKms, meta_gpu_kms, META, GPU_KMS, MetaGpu) @@ -39,12 +40,6 @@ MetaGpuKms * meta_gpu_kms_new (MetaBackendNative *backend_native, MetaKmsDevice *kms_device, GError **error); -gboolean meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms, - MetaCrtc *crtc, - int x, - int y, - uint32_t fb_id); - gboolean meta_gpu_kms_can_have_outputs (MetaGpuKms *gpu_kms); gboolean meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms, @@ -53,12 +48,6 @@ gboolean meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms, gboolean meta_gpu_kms_is_boot_vga (MetaGpuKms *gpu_kms); gboolean meta_gpu_kms_is_platform_device (MetaGpuKms *gpu_kms); -gboolean meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms, - MetaCrtc *crtc, - uint32_t fb_id, - GClosure *flip_closure, - GError **error); - gboolean meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms, GError **error); @@ -72,8 +61,9 @@ 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_set_power_save_mode (MetaGpuKms *gpu_kms, - uint64_t state); +void meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms, + uint64_t state, + MetaKmsUpdate *kms_update); MetaCrtcMode * meta_gpu_kms_get_mode_from_drm_mode (MetaGpuKms *gpu_kms, const drmModeModeInfo *drm_mode); diff --git a/src/backends/native/meta-kms-connector.c b/src/backends/native/meta-kms-connector.c index bcd97e1c3..70d3336d3 100644 --- a/src/backends/native/meta-kms-connector.c +++ b/src/backends/native/meta-kms-connector.c @@ -26,6 +26,7 @@ #include "backends/native/meta-kms-device-private.h" #include "backends/native/meta-kms-impl-device.h" +#include "backends/native/meta-kms-update-private.h" struct _MetaKmsConnector { @@ -38,6 +39,13 @@ struct _MetaKmsConnector char *name; MetaKmsConnectorState *current_state; + + uint32_t dpms_prop_id; + uint32_t underscan_prop_id; + uint32_t underscan_hborder_prop_id; + uint32_t underscan_vborder_prop_id; + uint32_t edid_blob_id; + uint32_t tile_blob_id; }; G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT) @@ -48,6 +56,47 @@ meta_kms_connector_get_device (MetaKmsConnector *connector) return connector->device; } +void +meta_kms_connector_update_set_dpms_state (MetaKmsConnector *connector, + MetaKmsUpdate *update, + uint64_t state) +{ + meta_kms_update_set_connector_property (update, + connector, + connector->dpms_prop_id, + state); +} + +void +meta_kms_connector_set_underscanning (MetaKmsConnector *connector, + MetaKmsUpdate *update, + uint64_t hborder, + uint64_t vborder) +{ + meta_kms_update_set_connector_property (update, + connector, + connector->underscan_prop_id, + 1); + meta_kms_update_set_connector_property (update, + connector, + connector->underscan_hborder_prop_id, + hborder); + meta_kms_update_set_connector_property (update, + connector, + connector->underscan_vborder_prop_id, + vborder); +} + +void +meta_kms_connector_unset_underscanning (MetaKmsConnector *connector, + MetaKmsUpdate *update) +{ + meta_kms_update_set_connector_property (update, + connector, + connector->underscan_prop_id, + 0); +} + MetaConnectorType meta_kms_connector_get_connector_type (MetaKmsConnector *connector) { @@ -89,6 +138,12 @@ meta_kms_connector_get_current_state (MetaKmsConnector *connector) return connector->current_state; } +gboolean +meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector) +{ + return connector->underscan_prop_id != 0; +} + static void set_panel_orientation (MetaKmsConnectorState *state, drmModePropertyPtr prop, @@ -437,6 +492,41 @@ meta_kms_connector_update_state (MetaKmsConnector *connector, drm_resources); } +static void +find_property_ids (MetaKmsConnector *connector, + MetaKmsImplDevice *impl_device, + drmModeConnector *drm_connector) +{ + int fd; + int i; + + fd = meta_kms_impl_device_get_fd (impl_device); + + for (i = 0; i < drm_connector->count_props; i++) + { + drmModePropertyPtr prop; + + prop = drmModeGetProperty (fd, drm_connector->props[i]); + if (!prop) + continue; + + if ((prop->flags & DRM_MODE_PROP_ENUM) && + strcmp (prop->name, "DPMS") == 0) + connector->dpms_prop_id = prop->prop_id; + else if ((prop->flags & DRM_MODE_PROP_ENUM) && + strcmp (prop->name, "underscan") == 0) + connector->underscan_prop_id = prop->prop_id; + else if ((prop->flags & DRM_MODE_PROP_RANGE) && + strcmp (prop->name, "underscan hborder") == 0) + connector->underscan_hborder_prop_id = prop->prop_id; + else if ((prop->flags & DRM_MODE_PROP_RANGE) && + strcmp (prop->name, "underscan vborder") == 0) + connector->underscan_vborder_prop_id = prop->prop_id; + + drmModeFreeProperty (prop); + } +} + static char * make_connector_name (drmModeConnector *drm_connector) { @@ -483,6 +573,8 @@ meta_kms_connector_new (MetaKmsImplDevice *impl_device, connector->type = (MetaConnectorType) drm_connector->connector_type; connector->name = make_connector_name (drm_connector); + find_property_ids (connector, impl_device, drm_connector); + meta_kms_connector_read_state (connector, impl_device, drm_connector, drm_resources); diff --git a/src/backends/native/meta-kms-connector.h b/src/backends/native/meta-kms-connector.h index d536608e1..b6198b467 100644 --- a/src/backends/native/meta-kms-connector.h +++ b/src/backends/native/meta-kms-connector.h @@ -61,6 +61,18 @@ typedef struct _MetaKmsConnectorState MetaKmsDevice * meta_kms_connector_get_device (MetaKmsConnector *connector); +void meta_kms_connector_update_set_dpms_state (MetaKmsConnector *connector, + MetaKmsUpdate *update, + uint64_t state); + +void meta_kms_connector_set_underscanning (MetaKmsConnector *connector, + MetaKmsUpdate *update, + uint64_t hborder, + uint64_t vborder); + +void meta_kms_connector_unset_underscanning (MetaKmsConnector *connector, + MetaKmsUpdate *update); + MetaConnectorType meta_kms_connector_get_connector_type (MetaKmsConnector *connector); uint32_t meta_kms_connector_get_id (MetaKmsConnector *connector); @@ -72,4 +84,6 @@ gboolean meta_kms_connector_can_clone (MetaKmsConnector *connector, const MetaKmsConnectorState * meta_kms_connector_get_current_state (MetaKmsConnector *connector); +gboolean meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector); + #endif /* META_KMS_CONNECTOR_H */ diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c index 910a5a84a..5006a1816 100644 --- a/src/backends/native/meta-kms-crtc.c +++ b/src/backends/native/meta-kms-crtc.c @@ -24,6 +24,7 @@ #include "backends/native/meta-kms-device-private.h" #include "backends/native/meta-kms-impl-device.h" +#include "backends/native/meta-kms-update-private.h" struct _MetaKmsCrtc { diff --git a/src/backends/native/meta-kms-device.c b/src/backends/native/meta-kms-device.c index a4dd0006d..3a626c58c 100644 --- a/src/backends/native/meta-kms-device.c +++ b/src/backends/native/meta-kms-device.c @@ -108,6 +108,35 @@ meta_kms_device_get_primary_plane_for (MetaKmsDevice *device, return NULL; } +static gboolean +dispatch_in_impl (MetaKmsImpl *impl, + gpointer user_data, + GError **error) +{ + MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (user_data); + + return meta_kms_impl_device_dispatch (impl_device, error); +} + +int +meta_kms_device_dispatch_sync (MetaKmsDevice *device, + GError **error) +{ + int callback_count; + + callback_count = meta_kms_flush_callbacks (device->kms); + if (callback_count > 0) + return TRUE; + + if (!meta_kms_run_impl_task_sync (device->kms, + dispatch_in_impl, + device->impl_device, + error)) + return -1; + + return meta_kms_flush_callbacks (device->kms); +} + typedef struct _CreateImplDeviceData { MetaKmsDevice *device; diff --git a/src/backends/native/meta-kms-device.h b/src/backends/native/meta-kms-device.h index c4ec034c3..ea0f9aab5 100644 --- a/src/backends/native/meta-kms-device.h +++ b/src/backends/native/meta-kms-device.h @@ -42,6 +42,9 @@ GList * meta_kms_device_get_crtcs (MetaKmsDevice *device); MetaKmsPlane * meta_kms_device_get_primary_plane_for (MetaKmsDevice *device, MetaKmsCrtc *crtc); +int meta_kms_device_dispatch_sync (MetaKmsDevice *device, + GError **error); + MetaKmsDevice * meta_kms_device_new (MetaKms *kms, const char *path, MetaKmsDeviceFlag flags, diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index 6593f2aee..5f7a43daf 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -21,6 +21,7 @@ #include "backends/native/meta-kms-impl-device.h" +#include #include #include "backends/native/meta-kms-connector-private.h" @@ -28,8 +29,10 @@ #include "backends/native/meta-kms-crtc-private.h" #include "backends/native/meta-kms-crtc.h" #include "backends/native/meta-kms-impl.h" +#include "backends/native/meta-kms-page-flip-private.h" #include "backends/native/meta-kms-plane.h" #include "backends/native/meta-kms-private.h" +#include "backends/native/meta-kms-update.h" struct _MetaKmsImplDevice { @@ -39,6 +42,7 @@ struct _MetaKmsImplDevice MetaKmsImpl *impl; int fd; + GSource *fd_source; GList *crtcs; GList *connectors; @@ -71,6 +75,77 @@ meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device) return g_list_copy (impl_device->planes); } +static void +page_flip_handler (int fd, + unsigned int sequence, + unsigned int sec, + unsigned int usec, + void *user_data) +{ + MetaKmsPageFlipData *page_flip_data = user_data; + MetaKmsImpl *impl; + + meta_kms_page_flip_data_set_timings_in_impl (page_flip_data, + sequence, sec, usec); + + impl = meta_kms_page_flip_data_get_kms_impl (page_flip_data); + meta_kms_impl_handle_page_flip_callback (impl, page_flip_data); +} + +gboolean +meta_kms_impl_device_dispatch (MetaKmsImplDevice *impl_device, + GError **error) +{ + drmEventContext drm_event_context; + + meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl)); + + drm_event_context = (drmEventContext) { 0 }; + drm_event_context.version = 2; + drm_event_context.page_flip_handler = page_flip_handler; + + while (TRUE) + { + if (drmHandleEvent (impl_device->fd, &drm_event_context) != 0) + { + struct pollfd pfd; + int ret; + + if (errno != EAGAIN) + { + g_set_error_literal (error, G_IO_ERROR, + g_io_error_from_errno (errno), + strerror (errno)); + return FALSE; + } + + pfd.fd = impl_device->fd; + pfd.events = POLL_IN | POLL_ERR; + do + { + ret = poll (&pfd, 1, -1); + } + while (ret == -1 && errno == EINTR); + } + else + { + break; + } + } + + return TRUE; +} + +static gboolean +kms_event_dispatch_in_impl (MetaKmsImpl *impl, + gpointer user_data, + GError **error) +{ + MetaKmsImplDevice *impl_device = user_data; + + return meta_kms_impl_device_dispatch (impl_device, error); +} + drmModePropertyPtr meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device, drmModeObjectProperties *props, @@ -236,10 +311,11 @@ meta_kms_impl_device_new (MetaKmsDevice *device, MetaKmsImpl *impl, int fd) { + MetaKms *kms = meta_kms_impl_get_kms (impl); MetaKmsImplDevice *impl_device; drmModeRes *drm_resources; - meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl)); + meta_assert_in_kms_impl (kms); impl_device = g_object_new (META_TYPE_KMS_IMPL_DEVICE, NULL); impl_device->device = device; @@ -256,6 +332,11 @@ meta_kms_impl_device_new (MetaKmsDevice *device, drmModeFreeResources (drm_resources); + impl_device->fd_source = + meta_kms_register_fd_in_impl (kms, fd, + kms_event_dispatch_in_impl, + impl_device); + return impl_device; } @@ -280,6 +361,7 @@ meta_kms_impl_device_close (MetaKmsImplDevice *impl_device) meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl)); + g_clear_pointer (&impl_device->fd_source, g_source_destroy); fd = impl_device->fd; impl_device->fd = -1; diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h index 974915c3d..6c4b4e540 100644 --- a/src/backends/native/meta-kms-impl-device.h +++ b/src/backends/native/meta-kms-impl-device.h @@ -26,6 +26,7 @@ #include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms-types.h" +#include "backends/native/meta-kms-update.h" #define META_TYPE_KMS_IMPL_DEVICE (meta_kms_impl_device_get_type ()) G_DECLARE_FINAL_TYPE (MetaKmsImplDevice, meta_kms_impl_device, @@ -40,6 +41,9 @@ GList * meta_kms_impl_device_copy_crtcs (MetaKmsImplDevice *impl_device); GList * meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device); +gboolean meta_kms_impl_device_dispatch (MetaKmsImplDevice *impl_device, + GError **error); + drmModePropertyPtr meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device, drmModeObjectProperties *props, const char *prop_name, diff --git a/src/backends/native/meta-kms-impl-simple.c b/src/backends/native/meta-kms-impl-simple.c index 6432cbb7a..ddbee6b81 100644 --- a/src/backends/native/meta-kms-impl-simple.c +++ b/src/backends/native/meta-kms-impl-simple.c @@ -21,16 +21,47 @@ #include "backends/native/meta-kms-impl-simple.h" +#include #include +#include + +#include "backends/native/meta-kms-connector.h" +#include "backends/native/meta-kms-crtc.h" +#include "backends/native/meta-kms-device-private.h" +#include "backends/native/meta-kms-page-flip-private.h" +#include "backends/native/meta-kms-plane.h" +#include "backends/native/meta-kms-private.h" +#include "backends/native/meta-kms-update-private.h" +#include "backends/native/meta-kms-utils.h" + +typedef struct _CachedModeSet +{ + GList *connectors; + drmModeModeInfo *drm_mode; +} CachedModeSet; struct _MetaKmsImplSimple { MetaKmsImpl parent; + + GSource *mode_set_fallback_feedback_source; + GList *mode_set_fallback_page_flip_datas; + + GList *pending_page_flip_retries; + GSource *retry_page_flips_source; + + GList *postponed_page_flip_datas; + GList *postponed_mode_set_fallback_datas; + + GHashTable *cached_mode_sets; }; G_DEFINE_TYPE (MetaKmsImplSimple, meta_kms_impl_simple, META_TYPE_KMS_IMPL) +static void +flush_postponed_page_flip_datas (MetaKmsImplSimple *impl_simple); + MetaKmsImplSimple * meta_kms_impl_simple_new (MetaKms *kms, GError **error) @@ -40,12 +71,755 @@ meta_kms_impl_simple_new (MetaKms *kms, NULL); } +static gboolean +process_connector_property (MetaKmsImpl *impl, + MetaKmsUpdate *update, + MetaKmsConnectorProperty *connector_property, + GError **error) +{ + MetaKmsConnector *connector = connector_property->connector; + MetaKmsDevice *device = meta_kms_connector_get_device (connector); + MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device); + int fd; + int ret; + + fd = meta_kms_impl_device_get_fd (impl_device); + + ret = drmModeObjectSetProperty (fd, + meta_kms_connector_get_id (connector), + DRM_MODE_OBJECT_CONNECTOR, + connector_property->prop_id, + connector_property->value); + if (ret != 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret), + "Failed to set connector %u property %u: %s", + meta_kms_connector_get_id (connector), + connector_property->prop_id, + g_strerror (-ret)); + return FALSE; + } + + return TRUE; +} + +static gboolean +process_plane_property (MetaKmsImpl *impl, + MetaKmsPlane *plane, + MetaKmsProperty *prop, + GError **error) +{ + MetaKmsDevice *device = meta_kms_plane_get_device (plane); + MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device); + int fd; + int ret; + + fd = meta_kms_impl_device_get_fd (impl_device); + + ret = drmModeObjectSetProperty (fd, + meta_kms_plane_get_id (plane), + DRM_MODE_OBJECT_PLANE, + prop->prop_id, + prop->value); + if (ret != 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret), + "Failed to set plane %u property %u: %s", + meta_kms_plane_get_id (plane), + prop->prop_id, + g_strerror (-ret)); + return FALSE; + } + + return TRUE; +} + +static MetaKmsPlaneAssignment * +get_primary_plane_assignment (MetaKmsImpl *impl, + MetaKmsUpdate *update, + MetaKmsCrtc *crtc) +{ + GList *l; + + for (l = meta_kms_update_get_plane_assignments (update); l; l = l->next) + { + MetaKmsPlaneAssignment *plane_assignment = l->data; + + if (plane_assignment->crtc == crtc) + return plane_assignment; + } + + return NULL; +} + +static CachedModeSet * +cached_mode_set_new (GList *connectors, + const drmModeModeInfo *drm_mode) +{ + CachedModeSet *cached_mode_set; + + cached_mode_set = g_new0 (CachedModeSet, 1); + *cached_mode_set = (CachedModeSet) { + .connectors = g_list_copy (connectors), + .drm_mode = g_memdup (drm_mode, sizeof *drm_mode), + }; + + return cached_mode_set; +} + +static void +cached_mode_set_free (CachedModeSet *cached_mode_set) +{ + g_list_free (cached_mode_set->connectors); + g_free (cached_mode_set->drm_mode); + g_free (cached_mode_set); +} + +static void +fill_connector_ids_array (GList *connectors, + uint32_t **out_connectors, + int *out_n_connectors) +{ + GList *l; + int i; + + *out_n_connectors = g_list_length (connectors); + *out_connectors = g_new0 (uint32_t, *out_n_connectors); + i = 0; + for (l = connectors; l; l = l->next) + { + MetaKmsConnector *connector = l->data; + + (*out_connectors)[i++] = meta_kms_connector_get_id (connector); + } +} + +static gboolean +process_mode_set (MetaKmsImpl *impl, + MetaKmsUpdate *update, + MetaKmsModeSet *mode_set, + GError **error) +{ + MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl); + MetaKmsCrtc *crtc = mode_set->crtc;; + MetaKmsDevice *device = meta_kms_crtc_get_device (crtc); + MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device); + g_autofree uint32_t *connectors = NULL; + int n_connectors; + MetaKmsPlaneAssignment *plane_assignment; + uint32_t x, y; + uint32_t fb_id; + int fd; + int ret; + + crtc = mode_set->crtc; + + if (mode_set->drm_mode) + { + GList *l; + + fill_connector_ids_array (mode_set->connectors, + &connectors, + &n_connectors); + + plane_assignment = get_primary_plane_assignment (impl, update, crtc); + if (!plane_assignment) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing primary plane assignment for legacy mode set on CRTC %u", + meta_kms_crtc_get_id (crtc)); + return FALSE; + } + + x = meta_fixed_16_to_int (plane_assignment->src_rect.x); + y = meta_fixed_16_to_int (plane_assignment->src_rect.y); + + for (l = plane_assignment->plane_properties; l; l = l->next) + { + MetaKmsProperty *prop = l->data; + + if (!process_plane_property (impl, plane_assignment->plane, + prop, error)) + return FALSE; + } + + fb_id = plane_assignment->fb_id; + } + else + { + x = y = 0; + n_connectors = 0; + connectors = NULL; + fb_id = 0; + } + + fd = meta_kms_impl_device_get_fd (impl_device); + ret = drmModeSetCrtc (fd, + meta_kms_crtc_get_id (crtc), + fb_id, + x, y, + connectors, n_connectors, + mode_set->drm_mode); + if (ret != 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret), + "Failed to set mode on CRTC %u: %s", + meta_kms_crtc_get_id (crtc), + g_strerror (-ret)); + return FALSE; + } + + if (mode_set->drm_mode) + { + g_hash_table_replace (impl_simple->cached_mode_sets, + crtc, + cached_mode_set_new (mode_set->connectors, + mode_set->drm_mode)); + } + else + { + g_hash_table_remove (impl_simple->cached_mode_sets, crtc); + } + + return TRUE; +} + +static gboolean +is_timestamp_earlier_than (uint64_t ts1, + uint64_t ts2) +{ + if (ts1 == ts2) + return FALSE; + else + return ts2 - ts1 < UINT64_MAX / 2; +} + +typedef struct _RetryPageFlipData +{ + MetaKmsCrtc *crtc; + uint32_t fb_id; + MetaKmsPageFlipData *page_flip_data; + float refresh_rate; + uint64_t retry_time_us; +} RetryPageFlipData; + +static void +retry_page_flip_data_free (RetryPageFlipData *retry_page_flip_data) +{ + g_assert (!retry_page_flip_data->page_flip_data); + g_free (retry_page_flip_data); +} + +static float +get_cached_crtc_refresh_rate (MetaKmsImplSimple *impl_simple, + MetaKmsCrtc *crtc) +{ + CachedModeSet *cached_mode_set; + + cached_mode_set = g_hash_table_lookup (impl_simple->cached_mode_sets, + crtc); + g_assert (cached_mode_set); + + return meta_calculate_drm_mode_refresh_rate (cached_mode_set->drm_mode); +} + +static gboolean +retry_page_flips (gpointer user_data) +{ + MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (user_data); + uint64_t now_us; + GList *l; + + meta_assert_in_kms_impl (meta_kms_impl_get_kms (META_KMS_IMPL (impl_simple))); + + now_us = g_source_get_time (impl_simple->retry_page_flips_source); + + l = impl_simple->pending_page_flip_retries; + while (l) + { + RetryPageFlipData *retry_page_flip_data = l->data; + MetaKmsCrtc *crtc = retry_page_flip_data->crtc; + MetaKmsDevice *device = meta_kms_crtc_get_device (crtc); + MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device); + GList *l_next = l->next; + int fd; + int ret; + MetaKmsPageFlipData *page_flip_data; + + if (is_timestamp_earlier_than (now_us, + retry_page_flip_data->retry_time_us)) + { + l = l_next; + continue; + } + + fd = meta_kms_impl_device_get_fd (impl_device); + ret = drmModePageFlip (fd, + meta_kms_crtc_get_id (crtc), + retry_page_flip_data->fb_id, + DRM_MODE_PAGE_FLIP_EVENT, + retry_page_flip_data->page_flip_data); + if (ret == -EBUSY) + { + float refresh_rate; + + refresh_rate = get_cached_crtc_refresh_rate (impl_simple, crtc); + retry_page_flip_data->retry_time_us += + (uint64_t) (G_USEC_PER_SEC / refresh_rate); + l = l_next; + continue; + } + + impl_simple->pending_page_flip_retries = + g_list_remove_link (impl_simple->pending_page_flip_retries, l); + + page_flip_data = g_steal_pointer (&retry_page_flip_data->page_flip_data); + if (ret != 0) + { + g_autoptr (GError) error = NULL; + + g_set_error (&error, G_IO_ERROR, g_io_error_from_errno (-ret), + "drmModePageFlip on CRTC %u failed: %s", + meta_kms_crtc_get_id (crtc), + g_strerror (-ret)); + if (!g_error_matches (error, + G_IO_ERROR, + G_IO_ERROR_PERMISSION_DENIED)) + g_critical ("Failed to page flip: %s", error->message); + + meta_kms_page_flip_data_discard_in_impl (page_flip_data, error); + } + + retry_page_flip_data_free (retry_page_flip_data); + + l = l_next; + } + + if (impl_simple->pending_page_flip_retries) + { + GList *l; + uint64_t earliest_retry_time_us = 0; + + for (l = impl_simple->pending_page_flip_retries; l; l = l->next) + { + RetryPageFlipData *retry_page_flip_data = l->data; + + if (l == impl_simple->pending_page_flip_retries || + is_timestamp_earlier_than (retry_page_flip_data->retry_time_us, + earliest_retry_time_us)) + earliest_retry_time_us = retry_page_flip_data->retry_time_us; + } + + g_source_set_ready_time (impl_simple->retry_page_flips_source, + earliest_retry_time_us); + return G_SOURCE_CONTINUE; + } + else + { + g_clear_pointer (&impl_simple->retry_page_flips_source, + g_source_unref); + + flush_postponed_page_flip_datas (impl_simple); + + return G_SOURCE_REMOVE; + } +} + +static void +schedule_retry_page_flip (MetaKmsImplSimple *impl_simple, + MetaKmsCrtc *crtc, + uint32_t fb_id, + float refresh_rate, + MetaKmsPageFlipData *page_flip_data) +{ + RetryPageFlipData *retry_page_flip_data; + uint64_t now_us; + uint64_t retry_time_us; + + now_us = g_get_monotonic_time (); + retry_time_us = now_us + (uint64_t) (G_USEC_PER_SEC / refresh_rate); + + retry_page_flip_data = g_new0 (RetryPageFlipData, 1); + *retry_page_flip_data = (RetryPageFlipData) { + .crtc = crtc, + .fb_id = fb_id, + .page_flip_data = meta_kms_page_flip_data_ref (page_flip_data), + .refresh_rate = refresh_rate, + .retry_time_us = retry_time_us, + }; + + if (!impl_simple->retry_page_flips_source) + { + MetaKms *kms = meta_kms_impl_get_kms (META_KMS_IMPL (impl_simple)); + GSource *source; + + source = meta_kms_add_source_in_impl (kms, retry_page_flips, + impl_simple, NULL); + g_source_set_ready_time (source, retry_time_us); + + impl_simple->retry_page_flips_source = source; + } + else + { + GList *l; + + for (l = impl_simple->pending_page_flip_retries; l; l = l->next) + { + RetryPageFlipData *pending_retry_page_flip_data = l->data; + uint64_t pending_retry_time_us = + pending_retry_page_flip_data->retry_time_us; + + if (is_timestamp_earlier_than (retry_time_us, pending_retry_time_us)) + { + g_source_set_ready_time (impl_simple->retry_page_flips_source, + retry_time_us); + break; + } + } + } + + impl_simple->pending_page_flip_retries = + g_list_append (impl_simple->pending_page_flip_retries, + retry_page_flip_data); +} + +static void +invoke_page_flip_datas (GList *page_flip_datas, + MetaPageFlipDataFeedbackFunc func) +{ + g_list_foreach (page_flip_datas, (GFunc) func, NULL); +} + +static void +clear_page_flip_datas (GList **page_flip_datas) +{ + g_list_free_full (*page_flip_datas, + (GDestroyNotify) meta_kms_page_flip_data_unref); + *page_flip_datas = NULL; +} + +static gboolean +mode_set_fallback_feedback_idle (gpointer user_data) +{ + MetaKmsImplSimple *impl_simple = user_data; + + g_clear_pointer (&impl_simple->mode_set_fallback_feedback_source, + g_source_unref); + + if (!impl_simple->pending_page_flip_retries) + { + impl_simple->postponed_mode_set_fallback_datas = + g_steal_pointer (&impl_simple->mode_set_fallback_page_flip_datas); + } + else + { + invoke_page_flip_datas (impl_simple->mode_set_fallback_page_flip_datas, + meta_kms_page_flip_data_mode_set_fallback_in_impl); + clear_page_flip_datas (&impl_simple->mode_set_fallback_page_flip_datas); + } + + return G_SOURCE_REMOVE; +} + +static gboolean +mode_set_fallback (MetaKmsImplSimple *impl_simple, + MetaKmsUpdate *update, + MetaKmsPageFlip *page_flip, + MetaKmsPlaneAssignment *plane_assignment, + MetaKmsPageFlipData *page_flip_data, + GError **error) +{ + MetaKms *kms = meta_kms_impl_get_kms (META_KMS_IMPL (impl_simple)); + MetaKmsCrtc *crtc = page_flip->crtc; + MetaKmsDevice *device = meta_kms_crtc_get_device (crtc); + MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device); + CachedModeSet *cached_mode_set; + g_autofree uint32_t *connectors = NULL; + int n_connectors; + uint32_t x, y; + int fd; + int ret; + + cached_mode_set = g_hash_table_lookup (impl_simple->cached_mode_sets, + crtc); + g_assert (cached_mode_set); + + fill_connector_ids_array (cached_mode_set->connectors, + &connectors, + &n_connectors); + + x = meta_fixed_16_to_int (plane_assignment->src_rect.x); + y = meta_fixed_16_to_int (plane_assignment->src_rect.y); + + fd = meta_kms_impl_device_get_fd (impl_device); + ret = drmModeSetCrtc (fd, + meta_kms_crtc_get_id (crtc), + plane_assignment->fb_id, + x, y, + connectors, n_connectors, + cached_mode_set->drm_mode); + if (ret != 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret), + "drmModeSetCrtc mode '%s' on CRTC %u failed: %s", + cached_mode_set->drm_mode->name, + meta_kms_crtc_get_id (crtc), + g_strerror (-ret)); + return FALSE; + } + + if (!impl_simple->mode_set_fallback_feedback_source) + { + GSource *source; + + source = meta_kms_add_source_in_impl (kms, + mode_set_fallback_feedback_idle, + impl_simple, + NULL); + impl_simple->mode_set_fallback_feedback_source = source; + } + + impl_simple->mode_set_fallback_page_flip_datas = + g_list_prepend (impl_simple->mode_set_fallback_page_flip_datas, + meta_kms_page_flip_data_ref (page_flip_data)); + + return TRUE; +} + +static gboolean +process_page_flip (MetaKmsImpl *impl, + MetaKmsUpdate *update, + MetaKmsPageFlip *page_flip, + GError **error) +{ + MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl); + MetaKmsCrtc *crtc; + MetaKmsDevice *device; + MetaKmsImplDevice *impl_device; + MetaKmsPlaneAssignment *plane_assignment; + MetaKmsPageFlipData *page_flip_data; + MetaKmsCustomPageFlipFunc custom_page_flip_func; + int fd; + int ret; + + crtc = page_flip->crtc; + plane_assignment = get_primary_plane_assignment (impl, update, crtc); + + page_flip_data = meta_kms_page_flip_data_new (impl, + crtc, + page_flip->feedback, + page_flip->user_data); + + device = meta_kms_crtc_get_device (crtc); + impl_device = meta_kms_device_get_impl_device (device); + fd = meta_kms_impl_device_get_fd (impl_device); + custom_page_flip_func = page_flip->custom_page_flip_func; + if (custom_page_flip_func) + { + ret = custom_page_flip_func (page_flip->custom_page_flip_user_data, + meta_kms_page_flip_data_ref (page_flip_data)); + } + else + { + ret = drmModePageFlip (fd, + meta_kms_crtc_get_id (crtc), + plane_assignment->fb_id, + DRM_MODE_PAGE_FLIP_EVENT, + meta_kms_page_flip_data_ref (page_flip_data)); + } + + if (ret == -EBUSY) + { + float refresh_rate; + + refresh_rate = get_cached_crtc_refresh_rate (impl_simple, crtc); + schedule_retry_page_flip (impl_simple, + crtc, + plane_assignment->fb_id, + refresh_rate, + page_flip_data); + } + else if (ret == -EINVAL) + { + if (!mode_set_fallback (impl_simple, + update, + page_flip, + plane_assignment, + page_flip_data, + error)) + { + meta_kms_page_flip_data_unref (page_flip_data); + return FALSE; + } + } + else if (ret != 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret), + "drmModePageFlip on CRTC %u failed: %s", + meta_kms_crtc_get_id (crtc), + g_strerror (-ret)); + meta_kms_page_flip_data_unref (page_flip_data); + return FALSE; + } + + meta_kms_page_flip_data_unref (page_flip_data); + return TRUE; +} + +static void +discard_page_flip (MetaKmsImpl *impl, + MetaKmsUpdate *update, + MetaKmsPageFlip *page_flip) +{ + MetaKmsCrtc *crtc; + MetaKmsPageFlipData *page_flip_data; + + crtc = page_flip->crtc; + page_flip_data = meta_kms_page_flip_data_new (impl, + crtc, + page_flip->feedback, + page_flip->user_data); + meta_kms_page_flip_data_discard_in_impl (page_flip_data, NULL); + meta_kms_page_flip_data_unref (page_flip_data); +} + +static gboolean +meta_kms_impl_simple_process_update (MetaKmsImpl *impl, + MetaKmsUpdate *update, + GError **error) +{ + GList *l; + + meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl)); + + for (l = meta_kms_update_get_connector_properties (update); l; l = l->next) + { + MetaKmsConnectorProperty *connector_property = l->data; + + if (!process_connector_property (impl, update, connector_property, error)) + goto discard_page_flips; + } + + for (l = meta_kms_update_get_mode_sets (update); l; l = l->next) + { + MetaKmsModeSet *mode_set = l->data; + + if (!process_mode_set (impl, update, mode_set, error)) + goto discard_page_flips; + } + + for (l = meta_kms_update_get_page_flips (update); l; l = l->next) + { + MetaKmsPageFlip *page_flip = l->data; + + if (!process_page_flip (impl, update, page_flip, error)) + goto discard_page_flips; + } + + return TRUE; + +discard_page_flips: + for (l = meta_kms_update_get_page_flips (update); l; l = l->next) + { + MetaKmsPageFlip *page_flip = l->data; + + discard_page_flip (impl, update, page_flip); + } + + return FALSE; +} + +static void +flush_postponed_page_flip_datas (MetaKmsImplSimple *impl_simple) +{ + invoke_page_flip_datas (impl_simple->postponed_page_flip_datas, + meta_kms_page_flip_data_flipped_in_impl); + clear_page_flip_datas (&impl_simple->postponed_page_flip_datas); + + invoke_page_flip_datas (impl_simple->postponed_mode_set_fallback_datas, + meta_kms_page_flip_data_mode_set_fallback_in_impl); + clear_page_flip_datas (&impl_simple->postponed_mode_set_fallback_datas); +} + +static void +meta_kms_impl_simple_handle_page_flip_callback (MetaKmsImpl *impl, + MetaKmsPageFlipData *page_flip_data) +{ + MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl); + + if (impl_simple->pending_page_flip_retries) + { + impl_simple->postponed_page_flip_datas = + g_list_append (impl_simple->postponed_page_flip_datas, + page_flip_data); + } + else + { + meta_kms_page_flip_data_flipped_in_impl (page_flip_data); + } +} + +static void +meta_kms_impl_simple_discard_pending_page_flips (MetaKmsImpl *impl) +{ + MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl); + GList *l; + + if (!impl_simple->pending_page_flip_retries) + return; + + for (l = impl_simple->pending_page_flip_retries; l; l = l->next) + { + RetryPageFlipData *retry_page_flip_data = l->data; + MetaKmsPageFlipData *page_flip_data; + + page_flip_data = g_steal_pointer (&retry_page_flip_data->page_flip_data); + meta_kms_page_flip_data_discard_in_impl (page_flip_data, NULL); + retry_page_flip_data_free (retry_page_flip_data); + } + g_clear_pointer (&impl_simple->pending_page_flip_retries, g_list_free); + + g_clear_pointer (&impl_simple->retry_page_flips_source, + g_source_destroy); +} + +static void +meta_kms_impl_simple_finalize (GObject *object) +{ + MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (object); + + g_list_free_full (impl_simple->pending_page_flip_retries, + (GDestroyNotify) retry_page_flip_data_free); + g_list_free_full (impl_simple->postponed_page_flip_datas, + (GDestroyNotify) meta_kms_page_flip_data_unref); + g_list_free_full (impl_simple->postponed_mode_set_fallback_datas, + (GDestroyNotify) meta_kms_page_flip_data_unref); + g_clear_pointer (&impl_simple->mode_set_fallback_feedback_source, + g_source_destroy); + g_hash_table_destroy (impl_simple->cached_mode_sets); + + G_OBJECT_CLASS (meta_kms_impl_simple_parent_class)->finalize (object); +} + static void meta_kms_impl_simple_init (MetaKmsImplSimple *impl_simple) { + impl_simple->cached_mode_sets = + g_hash_table_new_full (NULL, + NULL, + NULL, + (GDestroyNotify) cached_mode_set_free); } static void meta_kms_impl_simple_class_init (MetaKmsImplSimpleClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaKmsImplClass *impl_class = META_KMS_IMPL_CLASS (klass); + + object_class->finalize = meta_kms_impl_simple_finalize; + + impl_class->process_update = meta_kms_impl_simple_process_update; + impl_class->handle_page_flip_callback = meta_kms_impl_simple_handle_page_flip_callback; + impl_class->discard_pending_page_flips = meta_kms_impl_simple_discard_pending_page_flips; } diff --git a/src/backends/native/meta-kms-impl.c b/src/backends/native/meta-kms-impl.c index b6f9c2509..1934d21ae 100644 --- a/src/backends/native/meta-kms-impl.c +++ b/src/backends/native/meta-kms-impl.c @@ -43,6 +43,28 @@ meta_kms_impl_get_kms (MetaKmsImpl *impl) return priv->kms; } +gboolean +meta_kms_impl_process_update (MetaKmsImpl *impl, + MetaKmsUpdate *update, + GError **error) +{ + return META_KMS_IMPL_GET_CLASS (impl)->process_update (impl, update, error); +} + +void +meta_kms_impl_handle_page_flip_callback (MetaKmsImpl *impl, + MetaKmsPageFlipData *page_flip_data) +{ + META_KMS_IMPL_GET_CLASS (impl)->handle_page_flip_callback (impl, + page_flip_data); +} + +void +meta_kms_impl_discard_pending_page_flips (MetaKmsImpl *impl) +{ + META_KMS_IMPL_GET_CLASS (impl)->discard_pending_page_flips (impl); +} + static void meta_kms_impl_set_property (GObject *object, guint prop_id, diff --git a/src/backends/native/meta-kms-impl.h b/src/backends/native/meta-kms-impl.h index fa774af17..7816253d9 100644 --- a/src/backends/native/meta-kms-impl.h +++ b/src/backends/native/meta-kms-impl.h @@ -21,6 +21,7 @@ #define META_KMS_IMPL_H #include "backends/native/meta-kms-impl-device.h" +#include "backends/native/meta-kms-page-flip-private.h" #include "backends/native/meta-kms.h" #define META_TYPE_KMS_IMPL (meta_kms_impl_get_type ()) @@ -30,8 +31,24 @@ G_DECLARE_DERIVABLE_TYPE (MetaKmsImpl, meta_kms_impl, struct _MetaKmsImplClass { GObjectClass parent_class; + + gboolean (* process_update) (MetaKmsImpl *impl, + MetaKmsUpdate *update, + GError **error); + void (* handle_page_flip_callback) (MetaKmsImpl *impl, + MetaKmsPageFlipData *page_flip_data); + void (* discard_pending_page_flips) (MetaKmsImpl *impl); }; MetaKms * meta_kms_impl_get_kms (MetaKmsImpl *impl); +gboolean meta_kms_impl_process_update (MetaKmsImpl *impl, + MetaKmsUpdate *update, + GError **error); + +void meta_kms_impl_handle_page_flip_callback (MetaKmsImpl *impl, + MetaKmsPageFlipData *page_flip_data); + +void meta_kms_impl_discard_pending_page_flips (MetaKmsImpl *impl); + #endif /* META_KMS_IMPL_H */ diff --git a/src/backends/native/meta-kms-page-flip-private.h b/src/backends/native/meta-kms-page-flip-private.h new file mode 100644 index 000000000..ef8faf7ad --- /dev/null +++ b/src/backends/native/meta-kms-page-flip-private.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_KMS_PAGE_FLIP_H +#define META_KMS_PAGE_FLIP_H + +#include + +#include "backends/native/meta-kms-types.h" + +typedef struct _MetaKmsPageFlipData MetaKmsPageFlipData; + +typedef void (* MetaPageFlipDataFeedbackFunc) (MetaKmsPageFlipData *page_flip_data); + +MetaKmsPageFlipData * meta_kms_page_flip_data_new (MetaKmsImpl *impl, + MetaKmsCrtc *crtc, + const MetaKmsPageFlipFeedback *feedback, + gpointer user_data); + +MetaKmsPageFlipData * meta_kms_page_flip_data_ref (MetaKmsPageFlipData *page_flip_data); + +void meta_kms_page_flip_data_unref (MetaKmsPageFlipData *page_flip_data); + +MetaKmsImpl * meta_kms_page_flip_data_get_kms_impl (MetaKmsPageFlipData *page_flip_data); + +void meta_kms_page_flip_data_set_timings_in_impl (MetaKmsPageFlipData *page_flip_data, + unsigned int sequence, + unsigned int sec, + unsigned int usec); + +void meta_kms_page_flip_data_flipped_in_impl (MetaKmsPageFlipData *page_flip_data); + +void meta_kms_page_flip_data_mode_set_fallback_in_impl (MetaKmsPageFlipData *page_flip_data); + +void meta_kms_page_flip_data_discard_in_impl (MetaKmsPageFlipData *page_flip_data, + const GError *error); + +void meta_kms_page_flip_data_take_error (MetaKmsPageFlipData *page_flip_data, + GError *error); + +#endif /* META_KMS_PAGE_FLIP_H */ diff --git a/src/backends/native/meta-kms-page-flip.c b/src/backends/native/meta-kms-page-flip.c new file mode 100644 index 000000000..997c3fca5 --- /dev/null +++ b/src/backends/native/meta-kms-page-flip.c @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2019 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/native/meta-kms-page-flip-private.h" + +#include "backends/native/meta-kms-impl.h" +#include "backends/native/meta-kms-private.h" +#include "backends/native/meta-kms-update.h" + +struct _MetaKmsPageFlipData +{ + int ref_count; + + MetaKmsImpl *impl; + MetaKmsCrtc *crtc; + + const MetaKmsPageFlipFeedback *feedback; + gpointer user_data; + + unsigned int sequence; + unsigned int sec; + unsigned int usec; + + GError *error; +}; + +MetaKmsPageFlipData * +meta_kms_page_flip_data_new (MetaKmsImpl *impl, + MetaKmsCrtc *crtc, + const MetaKmsPageFlipFeedback *feedback, + gpointer user_data) +{ + MetaKmsPageFlipData *page_flip_data; + + page_flip_data = g_new0 (MetaKmsPageFlipData , 1); + *page_flip_data = (MetaKmsPageFlipData) { + .ref_count = 1, + .impl = impl, + .crtc = crtc, + .feedback = feedback, + .user_data = user_data, + }; + + return page_flip_data; +} + +MetaKmsPageFlipData * +meta_kms_page_flip_data_ref (MetaKmsPageFlipData *page_flip_data) +{ + page_flip_data->ref_count++; + + return page_flip_data; +} + +void +meta_kms_page_flip_data_unref (MetaKmsPageFlipData *page_flip_data) +{ + page_flip_data->ref_count--; + + if (page_flip_data->ref_count == 0) + { + g_clear_error (&page_flip_data->error); + g_free (page_flip_data); + } +} + +MetaKmsImpl * +meta_kms_page_flip_data_get_kms_impl (MetaKmsPageFlipData *page_flip_data) +{ + return page_flip_data->impl; +} + +static void +meta_kms_page_flip_data_flipped (MetaKms *kms, + gpointer user_data) +{ + MetaKmsPageFlipData *page_flip_data = user_data; + + meta_assert_not_in_kms_impl (kms); + + page_flip_data->feedback->flipped (page_flip_data->crtc, + page_flip_data->sequence, + page_flip_data->sec, + page_flip_data->usec, + page_flip_data->user_data); +} + +void +meta_kms_page_flip_data_set_timings_in_impl (MetaKmsPageFlipData *page_flip_data, + unsigned int sequence, + unsigned int sec, + unsigned int usec) +{ + MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl); + + meta_assert_in_kms_impl (kms); + + page_flip_data->sequence = sequence; + page_flip_data->sec = sec; + page_flip_data->usec = usec; +} + +void +meta_kms_page_flip_data_flipped_in_impl (MetaKmsPageFlipData *page_flip_data) +{ + MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl); + + meta_assert_in_kms_impl (kms); + + meta_kms_queue_callback (kms, + meta_kms_page_flip_data_flipped, + meta_kms_page_flip_data_ref (page_flip_data), + (GDestroyNotify) meta_kms_page_flip_data_unref); +} + +static void +meta_kms_page_flip_data_mode_set_fallback (MetaKms *kms, + gpointer user_data) +{ + MetaKmsPageFlipData *page_flip_data = user_data; + + meta_assert_not_in_kms_impl (kms); + + page_flip_data->feedback->mode_set_fallback (page_flip_data->crtc, + page_flip_data->user_data); +} + +void +meta_kms_page_flip_data_mode_set_fallback_in_impl (MetaKmsPageFlipData *page_flip_data) +{ + MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl); + + meta_assert_in_kms_impl (kms); + + meta_kms_queue_callback (kms, + meta_kms_page_flip_data_mode_set_fallback, + meta_kms_page_flip_data_ref (page_flip_data), + (GDestroyNotify) meta_kms_page_flip_data_unref); +} + +static void +meta_kms_page_flip_data_discard (MetaKms *kms, + gpointer user_data) +{ + MetaKmsPageFlipData *page_flip_data = user_data; + + meta_assert_not_in_kms_impl (kms); + + page_flip_data->feedback->discarded (page_flip_data->crtc, + page_flip_data->user_data, + page_flip_data->error); +} + +void +meta_kms_page_flip_data_take_error (MetaKmsPageFlipData *page_flip_data, + GError *error) +{ + g_assert (!page_flip_data->error); + + page_flip_data->error = error; +} + +void +meta_kms_page_flip_data_discard_in_impl (MetaKmsPageFlipData *page_flip_data, + const GError *error) +{ + MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl); + + meta_assert_in_kms_impl (kms); + + if (error) + meta_kms_page_flip_data_take_error (page_flip_data, g_error_copy (error)); + + meta_kms_queue_callback (kms, + meta_kms_page_flip_data_discard, + meta_kms_page_flip_data_ref (page_flip_data), + (GDestroyNotify) meta_kms_page_flip_data_unref); +} diff --git a/src/backends/native/meta-kms-plane.c b/src/backends/native/meta-kms-plane.c index 94a407bd8..d34d8c194 100644 --- a/src/backends/native/meta-kms-plane.c +++ b/src/backends/native/meta-kms-plane.c @@ -27,6 +27,7 @@ #include "backends/meta-monitor-transform.h" #include "backends/native/meta-kms-crtc.h" #include "backends/native/meta-kms-impl-device.h" +#include "backends/native/meta-kms-update-private.h" struct _MetaKmsPlane { @@ -53,6 +54,12 @@ struct _MetaKmsPlane G_DEFINE_TYPE (MetaKmsPlane, meta_kms_plane, G_TYPE_OBJECT) +MetaKmsDevice * +meta_kms_plane_get_device (MetaKmsPlane *plane) +{ + return plane->device; +} + uint32_t meta_kms_plane_get_id (MetaKmsPlane *plane) { @@ -65,6 +72,18 @@ meta_kms_plane_get_plane_type (MetaKmsPlane *plane) return plane->type; } +void +meta_kms_plane_update_set_rotation (MetaKmsPlane *plane, + MetaKmsPlaneAssignment *plane_assignment, + MetaMonitorTransform transform) +{ + g_return_if_fail (meta_kms_plane_is_transform_handled (plane, transform)); + + meta_kms_plane_assignment_set_plane_property (plane_assignment, + plane->rotation_prop_id, + plane->rotation_map[transform]); +} + gboolean meta_kms_plane_is_transform_handled (MetaKmsPlane *plane, MetaMonitorTransform transform) diff --git a/src/backends/native/meta-kms-plane.h b/src/backends/native/meta-kms-plane.h index 11cb3ad2f..e360f83ca 100644 --- a/src/backends/native/meta-kms-plane.h +++ b/src/backends/native/meta-kms-plane.h @@ -43,6 +43,8 @@ MetaKmsPlane * meta_kms_plane_new (MetaKmsPlaneType type, drmModePlane *drm_plane, drmModeObjectProperties *drm_plane_props); +MetaKmsDevice * meta_kms_plane_get_device (MetaKmsPlane *plane); + uint32_t meta_kms_plane_get_id (MetaKmsPlane *plane); MetaKmsPlaneType meta_kms_plane_get_plane_type (MetaKmsPlane *plane); @@ -61,4 +63,8 @@ gboolean meta_kms_plane_is_format_supported (MetaKmsPlane *plane, gboolean meta_kms_plane_is_usable_with (MetaKmsPlane *plane, MetaKmsCrtc *crtc); +void meta_kms_plane_update_set_rotation (MetaKmsPlane *plane, + MetaKmsPlaneAssignment *plane_assignment, + MetaMonitorTransform transform); + #endif /* META_KMS_PLANE_H */ diff --git a/src/backends/native/meta-kms-private.h b/src/backends/native/meta-kms-private.h index 910779ea7..fa632e1f7 100644 --- a/src/backends/native/meta-kms-private.h +++ b/src/backends/native/meta-kms-private.h @@ -36,14 +36,17 @@ void meta_kms_queue_callback (MetaKms *kms, gpointer user_data, GDestroyNotify user_data_destroy); +int meta_kms_flush_callbacks (MetaKms *kms); + gboolean meta_kms_run_impl_task_sync (MetaKms *kms, MetaKmsImplTaskFunc func, gpointer user_data, GError **error); -GSource * meta_kms_add_source_in_impl (MetaKms *kms, - GSourceFunc func, - gpointer user_data); +GSource * meta_kms_add_source_in_impl (MetaKms *kms, + GSourceFunc func, + gpointer user_data, + GDestroyNotify user_data_destroy); GSource * meta_kms_register_fd_in_impl (MetaKms *kms, int fd, diff --git a/src/backends/native/meta-kms-types.h b/src/backends/native/meta-kms-types.h index 7a9264934..dd14a7be7 100644 --- a/src/backends/native/meta-kms-types.h +++ b/src/backends/native/meta-kms-types.h @@ -20,6 +20,8 @@ #ifndef META_KMS_IMPL_TYPES_H #define META_KMS_IMPL_TYPES_H +#include + typedef struct _MetaKms MetaKms; typedef struct _MetaKmsDevice MetaKmsDevice; @@ -27,9 +29,26 @@ typedef struct _MetaKmsPlane MetaKmsPlane; typedef struct _MetaKmsCrtc MetaKmsCrtc; typedef struct _MetaKmsConnector MetaKmsConnector; +typedef struct _MetaKmsUpdate MetaKmsUpdate; +typedef struct _MetaKmsPlaneAssignment MetaKmsPlaneAssignment; +typedef struct _MetaKmsModeSet MetaKmsModeSet; + +typedef struct _MetaKmsPageFlipFeedback MetaKmsPageFlipFeedback; + typedef struct _MetaKmsImpl MetaKmsImpl; typedef struct _MetaKmsImplDevice MetaKmsImplDevice; +/* 16:16 fixed point */ +typedef int32_t MetaFixed16; + +typedef struct _MetaFixed16Rectangle +{ + MetaFixed16 x; + MetaFixed16 y; + MetaFixed16 width; + MetaFixed16 height; +} MetaFixed16Rectangle; + typedef enum _MetaKmsDeviceFlag { META_KMS_DEVICE_FLAG_NONE = 0, diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h new file mode 100644 index 000000000..bf3326ac4 --- /dev/null +++ b/src/backends/native/meta-kms-update-private.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_KMS_UPDATE_PRIVATE_H +#define META_KMS_UPDATE_PRIVATE_H + +#include +#include + +#include "backends/native/meta-kms-types.h" +#include "backends/native/meta-kms-update.h" + +typedef struct _MetaKmsProperty +{ + uint32_t prop_id; + uint64_t value; +} MetaKmsProperty; + +typedef struct _MetaKmsPlaneAssignment +{ + MetaKmsCrtc *crtc; + MetaKmsPlane *plane; + uint32_t fb_id; + MetaFixed16Rectangle src_rect; + MetaFixed16Rectangle dst_rect; + + GList *plane_properties; +} MetaKmsPlaneAssignment; + +typedef struct _MetaKmsModeSet +{ + MetaKmsCrtc *crtc; + GList *connectors; + drmModeModeInfo *drm_mode; +} MetaKmsModeSet; + +typedef struct _MetaKmsConnectorProperty +{ + MetaKmsDevice *device; + MetaKmsConnector *connector; + uint32_t prop_id; + uint64_t value; +} MetaKmsConnectorProperty; + +typedef struct _MetaKmsPageFlip +{ + MetaKmsCrtc *crtc; + const MetaKmsPageFlipFeedback *feedback; + gpointer user_data; + MetaKmsCustomPageFlipFunc custom_page_flip_func; + gpointer custom_page_flip_user_data; +} MetaKmsPageFlip; + +void meta_kms_update_set_connector_property (MetaKmsUpdate *update, + MetaKmsConnector *connector, + uint32_t prop_id, + uint64_t value); + +void meta_kms_plane_assignment_set_plane_property (MetaKmsPlaneAssignment *plane_assignment, + uint32_t prop_id, + uint64_t value); + +GList * meta_kms_update_get_plane_assignments (MetaKmsUpdate *update); + +GList * meta_kms_update_get_mode_sets (MetaKmsUpdate *update); + +GList * meta_kms_update_get_page_flips (MetaKmsUpdate *update); + +GList * meta_kms_update_get_connector_properties (MetaKmsUpdate *update); + +gboolean meta_kms_update_has_mode_set (MetaKmsUpdate *update); + +#endif /* META_KMS_UPDATE_PRIVATE_H */ diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c new file mode 100644 index 000000000..439e917ba --- /dev/null +++ b/src/backends/native/meta-kms-update.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2018 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/native/meta-kms-update.h" +#include "backends/native/meta-kms-update-private.h" + +#include "backends/meta-display-config-shared.h" +#include "backends/native/meta-kms-plane.h" + +struct _MetaKmsUpdate +{ + MetaPowerSave power_save; + GList *mode_sets; + GList *plane_assignments; + GList *page_flips; + GList *connector_properties; +}; + +static MetaKmsProperty * +meta_kms_property_new (uint32_t prop_id, + uint64_t value) +{ + MetaKmsProperty *prop; + + prop = g_new0 (MetaKmsProperty, 1); + *prop = (MetaKmsProperty) { + .prop_id = prop_id, + .value = value, + }; + + return prop; +} + +static void +meta_kms_property_free (MetaKmsProperty *prop) +{ + g_free (prop); +} + +static void +meta_kms_plane_assignment_free (MetaKmsPlaneAssignment *plane_assignment) +{ + g_list_free_full (plane_assignment->plane_properties, + (GDestroyNotify) meta_kms_property_free); + g_free (plane_assignment); +} + +static void +meta_kms_mode_set_free (MetaKmsModeSet *mode_set) +{ + g_free (mode_set->drm_mode); + g_list_free (mode_set->connectors); + g_free (mode_set); +} + +MetaKmsPlaneAssignment * +meta_kms_update_assign_plane (MetaKmsUpdate *update, + MetaKmsCrtc *crtc, + MetaKmsPlane *plane, + uint32_t fb_id, + MetaFixed16Rectangle src_rect, + MetaFixed16Rectangle dst_rect) +{ + MetaKmsPlaneAssignment *plane_assignment; + + plane_assignment = g_new0 (MetaKmsPlaneAssignment, 1); + *plane_assignment = (MetaKmsPlaneAssignment) { + .crtc = crtc, + .plane = plane, + .fb_id = fb_id, + .src_rect = src_rect, + .dst_rect = dst_rect, + }; + + update->plane_assignments = g_list_prepend (update->plane_assignments, + plane_assignment); + + return plane_assignment; +} + +void +meta_kms_update_mode_set (MetaKmsUpdate *update, + MetaKmsCrtc *crtc, + GList *connectors, + drmModeModeInfo *drm_mode) +{ + MetaKmsModeSet *mode_set; + + mode_set = g_new0 (MetaKmsModeSet, 1); + *mode_set = (MetaKmsModeSet) { + .crtc = crtc, + .connectors = connectors, + .drm_mode = drm_mode ? g_memdup (drm_mode, sizeof *drm_mode) : NULL, + }; + + update->mode_sets = g_list_prepend (update->mode_sets, mode_set); +} + +void +meta_kms_update_set_connector_property (MetaKmsUpdate *update, + MetaKmsConnector *connector, + uint32_t prop_id, + uint64_t value) +{ + MetaKmsConnectorProperty *prop; + + prop = g_new0 (MetaKmsConnectorProperty, 1); + *prop = (MetaKmsConnectorProperty) { + .connector = connector, + .prop_id = prop_id, + .value = value, + }; + + update->connector_properties = g_list_prepend (update->connector_properties, + prop); +} + +void +meta_kms_update_page_flip (MetaKmsUpdate *update, + MetaKmsCrtc *crtc, + const MetaKmsPageFlipFeedback *feedback, + gpointer user_data) +{ + MetaKmsPageFlip *page_flip; + + page_flip = g_new0 (MetaKmsPageFlip, 1); + *page_flip = (MetaKmsPageFlip) { + .crtc = crtc, + .feedback = feedback, + .user_data = user_data, + }; + + update->page_flips = g_list_prepend (update->page_flips, page_flip); +} + +void +meta_kms_update_custom_page_flip (MetaKmsUpdate *update, + MetaKmsCrtc *crtc, + const MetaKmsPageFlipFeedback *feedback, + gpointer user_data, + MetaKmsCustomPageFlipFunc custom_page_flip_func, + gpointer custom_page_flip_user_data) +{ + MetaKmsPageFlip *page_flip; + + page_flip = g_new0 (MetaKmsPageFlip, 1); + *page_flip = (MetaKmsPageFlip) { + .crtc = crtc, + .feedback = feedback, + .user_data = user_data, + .custom_page_flip_func = custom_page_flip_func, + .custom_page_flip_user_data = custom_page_flip_user_data, + }; + + update->page_flips = g_list_prepend (update->page_flips, page_flip); +} + +void +meta_kms_plane_assignment_set_plane_property (MetaKmsPlaneAssignment *plane_assignment, + uint32_t prop_id, + uint64_t value) +{ + MetaKmsProperty *plane_prop; + + plane_prop = meta_kms_property_new (prop_id, value); + + plane_assignment->plane_properties = + g_list_prepend (plane_assignment->plane_properties, plane_prop); +} + +GList * +meta_kms_update_get_plane_assignments (MetaKmsUpdate *update) +{ + return update->plane_assignments; +} + +GList * +meta_kms_update_get_mode_sets (MetaKmsUpdate *update) +{ + return update->mode_sets; +} + +GList * +meta_kms_update_get_page_flips (MetaKmsUpdate *update) +{ + return update->page_flips; +} + +GList * +meta_kms_update_get_connector_properties (MetaKmsUpdate *update) +{ + return update->connector_properties; +} + +gboolean +meta_kms_update_has_mode_set (MetaKmsUpdate *update) +{ + return !!update->mode_sets; +} + +MetaKmsUpdate * +meta_kms_update_new (void) +{ + return g_new0 (MetaKmsUpdate, 1); +} + +void +meta_kms_update_free (MetaKmsUpdate *update) +{ + g_list_free_full (update->plane_assignments, + (GDestroyNotify) meta_kms_plane_assignment_free); + g_list_free_full (update->mode_sets, + (GDestroyNotify) meta_kms_mode_set_free); + g_list_free_full (update->page_flips, g_free); + g_list_free_full (update->connector_properties, g_free); + + g_free (update); +} diff --git a/src/backends/native/meta-kms-update.h b/src/backends/native/meta-kms-update.h new file mode 100644 index 000000000..fc7d83f33 --- /dev/null +++ b/src/backends/native/meta-kms-update.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_KMS_UPDATE_H +#define META_KMS_UPDATE_H + +#include +#include +#include +#include + +#include "backends/meta-monitor-transform.h" +#include "backends/native/meta-kms-types.h" + +struct _MetaKmsPageFlipFeedback +{ + void (* flipped) (MetaKmsCrtc *crtc, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + gpointer user_data); + + void (* mode_set_fallback) (MetaKmsCrtc *crtc, + gpointer user_data); + + void (* discarded) (MetaKmsCrtc *crtc, + gpointer user_data, + const GError *error); +}; + +typedef int (* MetaKmsCustomPageFlipFunc) (gpointer custom_page_flip_data, + gpointer user_data); + +MetaKmsUpdate * meta_kms_update_new (void); + +void meta_kms_update_free (MetaKmsUpdate *update); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaKmsUpdate, meta_kms_update_free) + +void meta_kms_update_mode_set (MetaKmsUpdate *update, + MetaKmsCrtc *crtc, + GList *connectors, + drmModeModeInfo *drm_mode); + +MetaKmsPlaneAssignment * meta_kms_update_assign_plane (MetaKmsUpdate *update, + MetaKmsCrtc *crtc, + MetaKmsPlane *plane, + uint32_t fb_id, + MetaFixed16Rectangle src_rect, + MetaFixed16Rectangle dst_rect); + +void meta_kms_update_page_flip (MetaKmsUpdate *update, + MetaKmsCrtc *crtc, + const MetaKmsPageFlipFeedback *feedback, + gpointer user_data); + +void meta_kms_update_custom_page_flip (MetaKmsUpdate *update, + MetaKmsCrtc *crtc, + const MetaKmsPageFlipFeedback *feedback, + gpointer user_data, + MetaKmsCustomPageFlipFunc custom_page_flip_func, + gpointer custom_page_flip_user_data); + +static inline MetaFixed16 +meta_fixed_16_from_int (int16_t d) +{ + return d * 65536; +} + +static inline int16_t +meta_fixed_16_to_int (MetaFixed16 fixed) +{ + return fixed / 65536; +} + +#endif /* META_KMS_UPDATE_H */ diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c index 31bafd53b..c13360a1d 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c @@ -25,6 +25,7 @@ #include "backends/native/meta-kms-device-private.h" #include "backends/native/meta-kms-impl.h" #include "backends/native/meta-kms-impl-simple.h" +#include "backends/native/meta-kms-update-private.h" #include "backends/native/meta-udev.h" typedef struct _MetaKmsCallbackData @@ -64,12 +65,86 @@ struct _MetaKms GList *devices; + MetaKmsUpdate *pending_update; + GList *pending_callbacks; guint callback_source_id; }; G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT) +static void +meta_kms_update_states_in_impl (MetaKms *kms); + +MetaKmsUpdate * +meta_kms_ensure_pending_update (MetaKms *kms) +{ + if (!kms->pending_update) + kms->pending_update = meta_kms_update_new (); + + return meta_kms_get_pending_update (kms); +} + +MetaKmsUpdate * +meta_kms_get_pending_update (MetaKms *kms) +{ + return kms->pending_update; +} + +static gboolean +meta_kms_update_process_in_impl (MetaKmsImpl *impl, + gpointer user_data, + GError **error) +{ + g_autoptr (MetaKmsUpdate) update = user_data; + gboolean ret; + + ret = meta_kms_impl_process_update (impl, update, error); + + if (meta_kms_update_has_mode_set (update)) + meta_kms_update_states_in_impl (meta_kms_impl_get_kms (impl)); + + return ret; +} + +static gboolean +meta_kms_post_update_sync (MetaKms *kms, + MetaKmsUpdate *update, + GError **error) +{ + return meta_kms_run_impl_task_sync (kms, + meta_kms_update_process_in_impl, + update, + error); +} + +gboolean +meta_kms_post_pending_update_sync (MetaKms *kms, + GError **error) +{ + return meta_kms_post_update_sync (kms, + g_steal_pointer (&kms->pending_update), + error); +} + +static gboolean +meta_kms_discard_pending_page_flips_in_impl (MetaKmsImpl *impl, + gpointer user_data, + GError **error) +{ + meta_kms_impl_discard_pending_page_flips (impl); + return TRUE; +} + +void +meta_kms_discard_pending_page_flips (MetaKms *kms) +{ + meta_kms_run_impl_task_sync (kms, + meta_kms_discard_pending_page_flips_in_impl, + NULL, + NULL); +} + static void meta_kms_callback_data_free (MetaKmsCallbackData *callback_data) { @@ -78,11 +153,11 @@ meta_kms_callback_data_free (MetaKmsCallbackData *callback_data) g_slice_free (MetaKmsCallbackData, callback_data); } -static gboolean -callback_idle (gpointer user_data) +static int +flush_callbacks (MetaKms *kms) { - MetaKms *kms = user_data; GList *l; + int callback_count = 0; for (l = kms->pending_callbacks; l; l = l->next) { @@ -90,11 +165,22 @@ callback_idle (gpointer user_data) callback_data->callback (kms, callback_data->user_data); meta_kms_callback_data_free (callback_data); + callback_count++; } g_list_free (kms->pending_callbacks); kms->pending_callbacks = NULL; + return callback_count; +} + +static gboolean +callback_idle (gpointer user_data) +{ + MetaKms *kms = user_data; + + flush_callbacks (kms); + kms->callback_source_id = 0; return G_SOURCE_REMOVE; } @@ -119,6 +205,17 @@ meta_kms_queue_callback (MetaKms *kms, kms->callback_source_id = g_idle_add (callback_idle, kms); } +int +meta_kms_flush_callbacks (MetaKms *kms) +{ + int callback_count; + + callback_count = flush_callbacks (kms); + g_clear_handle_id (&kms->callback_source_id, g_source_remove); + + return callback_count; +} + gboolean meta_kms_run_impl_task_sync (MetaKms *kms, MetaKmsImplTaskFunc func, @@ -156,9 +253,10 @@ static GSourceFuncs simple_impl_source_funcs = { }; GSource * -meta_kms_add_source_in_impl (MetaKms *kms, - GSourceFunc func, - gpointer user_data) +meta_kms_add_source_in_impl (MetaKms *kms, + GSourceFunc func, + gpointer user_data, + GDestroyNotify user_data_destroy) { GSource *source; MetaKmsSimpleImplSource *simple_impl_source; @@ -170,7 +268,7 @@ meta_kms_add_source_in_impl (MetaKms *kms, simple_impl_source = (MetaKmsSimpleImplSource *) source; simple_impl_source->kms = kms; - g_source_set_callback (source, func, user_data, NULL); + g_source_set_callback (source, func, user_data, user_data_destroy); g_source_attach (source, g_main_context_get_thread_default ()); return source; @@ -245,14 +343,13 @@ meta_kms_in_impl_task (MetaKms *kms) return kms->in_impl_task; } -static gboolean -update_states_in_impl (MetaKmsImpl *impl, - gpointer user_data, - GError **error) +static void +meta_kms_update_states_in_impl (MetaKms *kms) { - MetaKms *kms = user_data; GList *l; + meta_assert_in_kms_impl (kms); + for (l = kms->devices; l; l = l->next) { MetaKmsDevice *device = l->data; @@ -260,6 +357,16 @@ update_states_in_impl (MetaKmsImpl *impl, meta_kms_impl_device_update_states (impl_device); } +} + +static gboolean +update_states_in_impl (MetaKmsImpl *impl, + gpointer user_data, + GError **error) +{ + MetaKms *kms = user_data; + + meta_kms_update_states_in_impl (kms); return TRUE; } diff --git a/src/backends/native/meta-kms.h b/src/backends/native/meta-kms.h index 7c4073256..cfe4e9105 100644 --- a/src/backends/native/meta-kms.h +++ b/src/backends/native/meta-kms.h @@ -28,6 +28,15 @@ #define META_TYPE_KMS (meta_kms_get_type ()) G_DECLARE_FINAL_TYPE (MetaKms, meta_kms, META, KMS, GObject) +MetaKmsUpdate * meta_kms_ensure_pending_update (MetaKms *kms); + +MetaKmsUpdate * meta_kms_get_pending_update (MetaKms *kms); + +gboolean meta_kms_post_pending_update_sync (MetaKms *kms, + GError **error); + +void meta_kms_discard_pending_page_flips (MetaKms *kms); + MetaBackend * meta_kms_get_backend (MetaKms *kms); MetaKmsDevice * meta_kms_create_device (MetaKms *kms, diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c index 6fa230020..58fd93fcc 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -54,6 +54,8 @@ #include "backends/native/meta-backend-native.h" #include "backends/native/meta-crtc-kms.h" #include "backends/native/meta-gpu-kms.h" +#include "backends/native/meta-kms-update.h" +#include "backends/native/meta-kms.h" #include "backends/native/meta-launcher.h" #include "backends/native/meta-output-kms.h" #include "backends/native/meta-renderer-native.h" @@ -115,6 +117,11 @@ static void meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, MetaPowerSave mode) { + MetaBackend *backend = meta_monitor_manager_get_backend (manager); + MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); + MetaKms *kms = meta_backend_native_get_kms (backend_native); + MetaKmsUpdate *kms_update; + g_autoptr (GError) error = NULL; uint64_t state; GList *l; @@ -135,12 +142,16 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, return; } - for (l = meta_backend_get_gpus (manager->backend); l; l = l->next) + kms_update = meta_kms_ensure_pending_update (kms); + for (l = meta_backend_get_gpus (backend); l; l = l->next) { MetaGpuKms *gpu_kms = l->data; - meta_gpu_kms_set_power_save_mode (gpu_kms, state); + meta_gpu_kms_set_power_save_mode (gpu_kms, state, kms_update); } + + if (!meta_kms_post_pending_update_sync (kms, &error)) + g_warning ("Failed to DPMS: %s", error->message); } static void @@ -214,8 +225,6 @@ apply_crtc_assignments (MetaMonitorManager *manager, meta_output_assign_crtc (output, crtc); } } - - meta_crtc_kms_apply_transform (crtc); } /* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE, because they weren't seen in the first loop) */ @@ -253,8 +262,6 @@ apply_crtc_assignments (MetaMonitorManager *manager, output->is_primary = output_info->is_primary; output->is_presentation = output_info->is_presentation; output->is_underscanning = output_info->is_underscanning; - - meta_output_kms_set_underscan (output); } /* Disable outputs not mentioned in the list */ diff --git a/src/backends/native/meta-output-kms.c b/src/backends/native/meta-output-kms.c index 1d3386387..42633702c 100644 --- a/src/backends/native/meta-output-kms.c +++ b/src/backends/native/meta-output-kms.c @@ -42,67 +42,42 @@ typedef struct _MetaOutputKms MetaOutput parent; MetaKmsConnector *kms_connector; - - drmModeConnector *connector; - - uint32_t dpms_prop_id; - - uint32_t underscan_prop_id; - uint32_t underscan_hborder_prop_id; - uint32_t underscan_vborder_prop_id; } MetaOutputKms; -void -meta_output_kms_set_underscan (MetaOutput *output) +MetaKmsConnector * +meta_output_kms_get_kms_connector (MetaOutput *output) { MetaOutputKms *output_kms = output->driver_private; - MetaGpu *gpu = meta_output_get_gpu (output); - MetaGpuKms *gpu_kms = META_GPU_KMS (gpu); - MetaCrtc *crtc; - int kms_fd; - uint32_t connector_id; - if (!output_kms->underscan_prop_id) + return output_kms->kms_connector; +} + +void +meta_output_kms_set_underscan (MetaOutput *output, + MetaKmsUpdate *kms_update) +{ + MetaOutputKms *output_kms = output->driver_private; + + if (!output->supports_underscanning) return; - crtc = meta_output_get_assigned_crtc (output); - kms_fd = meta_gpu_kms_get_fd (gpu_kms); - connector_id = output_kms->connector->connector_id; - - if (output->is_underscanning && crtc && crtc->current_mode) + if (output->is_underscanning) { - drmModeObjectSetProperty (kms_fd, connector_id, - DRM_MODE_OBJECT_CONNECTOR, - output_kms->underscan_prop_id, - (uint64_t) 1); + MetaCrtc *crtc; + uint64_t hborder, vborder; - if (output_kms->underscan_hborder_prop_id) - { - uint64_t value; - - value = MIN (128, crtc->current_mode->width * 0.05); - drmModeObjectSetProperty (kms_fd, connector_id, - DRM_MODE_OBJECT_CONNECTOR, - output_kms->underscan_hborder_prop_id, - value); - } - if (output_kms->underscan_vborder_prop_id) - { - uint64_t value; - - value = MIN (128, crtc->current_mode->height * 0.05); - drmModeObjectSetProperty (kms_fd, connector_id, - DRM_MODE_OBJECT_CONNECTOR, - output_kms->underscan_vborder_prop_id, - value); - } + crtc = meta_output_get_assigned_crtc (output); + hborder = MIN (128, (uint64_t) round (crtc->current_mode->width * 0.05)); + vborder = MIN (128, (uint64_t) round (crtc->current_mode->height * 0.05)); + meta_kms_connector_set_underscanning (output_kms->kms_connector, + kms_update, + hborder, + vborder); } else { - drmModeObjectSetProperty (kms_fd, connector_id, - DRM_MODE_OBJECT_CONNECTOR, - output_kms->underscan_prop_id, - (uint64_t) 0); + meta_kms_connector_unset_underscanning (output_kms->kms_connector, + kms_update); } } @@ -115,24 +90,15 @@ meta_output_kms_get_connector_id (MetaOutput *output) } void -meta_output_kms_set_power_save_mode (MetaOutput *output, - uint64_t state) +meta_output_kms_set_power_save_mode (MetaOutput *output, + uint64_t dpms_state, + MetaKmsUpdate *kms_update) { MetaOutputKms *output_kms = output->driver_private; - MetaGpu *gpu = meta_output_get_gpu (output); - MetaGpuKms *gpu_kms = META_GPU_KMS (gpu); - if (output_kms->dpms_prop_id != 0) - { - int fd; - - fd = meta_gpu_kms_get_fd (gpu_kms); - if (drmModeObjectSetProperty (fd, output_kms->connector->connector_id, - DRM_MODE_OBJECT_CONNECTOR, - output_kms->dpms_prop_id, state) < 0) - g_warning ("Failed to set power save mode for output %s: %s", - output->name, strerror (errno)); - } + meta_kms_connector_update_set_dpms_state (output_kms->kms_connector, + kms_update, + dpms_state); } gboolean @@ -162,40 +128,6 @@ meta_output_kms_read_edid (MetaOutput *output) return g_bytes_new_from_bytes (edid_data, 0, g_bytes_get_size (edid_data)); } -static void -find_connector_properties (MetaGpuKms *gpu_kms, - MetaOutput *output, - drmModeConnector *connector) -{ - MetaOutputKms *output_kms = output->driver_private; - int fd; - int i; - - fd = meta_gpu_kms_get_fd (gpu_kms); - - for (i = 0; i < connector->count_props; i++) - { - drmModePropertyPtr prop = drmModeGetProperty (fd, connector->props[i]); - if (!prop) - continue; - - if ((prop->flags & DRM_MODE_PROP_ENUM) && - strcmp (prop->name, "DPMS") == 0) - output_kms->dpms_prop_id = prop->prop_id; - else if ((prop->flags & DRM_MODE_PROP_ENUM) && - strcmp (prop->name, "underscan") == 0) - output_kms->underscan_prop_id = prop->prop_id; - else if ((prop->flags & DRM_MODE_PROP_RANGE) && - strcmp (prop->name, "underscan hborder") == 0) - output_kms->underscan_hborder_prop_id = prop->prop_id; - else if ((prop->flags & DRM_MODE_PROP_RANGE) && - strcmp (prop->name, "underscan vborder") == 0) - output_kms->underscan_vborder_prop_id = prop->prop_id; - - drmModeFreeProperty (prop); - } -} - static void meta_output_destroy_notify (MetaOutput *output) { @@ -344,7 +276,6 @@ init_output_modes (MetaOutput *output, MetaOutput * meta_create_kms_output (MetaGpuKms *gpu_kms, MetaKmsConnector *kms_connector, - drmModeConnector *connector, MetaOutput *old_output, GError **error) { @@ -373,8 +304,6 @@ meta_create_kms_output (MetaGpuKms *gpu_kms, output_kms->kms_connector = kms_connector; - find_connector_properties (gpu_kms, output, connector); - connector_state = meta_kms_connector_get_current_state (kms_connector); panel_orientation_transform = connector_state->panel_orientation_transform; @@ -443,7 +372,8 @@ meta_create_kms_output (MetaGpuKms *gpu_kms, output->suggested_x = connector_state->suggested_x; output->suggested_y = connector_state->suggested_y; output->hotplug_mode_update = connector_state->hotplug_mode_update; - output->supports_underscanning = output_kms->underscan_prop_id != 0; + output->supports_underscanning = + meta_kms_connector_is_underscanning_supported (kms_connector); meta_output_parse_edid (output, connector_state->edid_data); diff --git a/src/backends/native/meta-output-kms.h b/src/backends/native/meta-output-kms.h index f35aa130f..47ce68a3c 100644 --- a/src/backends/native/meta-output-kms.h +++ b/src/backends/native/meta-output-kms.h @@ -27,21 +27,24 @@ #include "backends/native/meta-gpu-kms.h" #include "backends/native/meta-kms-types.h" -void meta_output_kms_set_underscan (MetaOutput *output); +void meta_output_kms_set_power_save_mode (MetaOutput *output, + uint64_t dpms_state, + MetaKmsUpdate *kms_update); -void meta_output_kms_set_power_save_mode (MetaOutput *output, - uint64_t state); +void meta_output_kms_set_underscan (MetaOutput *output, + MetaKmsUpdate *kms_update); gboolean meta_output_kms_can_clone (MetaOutput *output, MetaOutput *other_output); +MetaKmsConnector * meta_output_kms_get_kms_connector (MetaOutput *output); + uint32_t meta_output_kms_get_connector_id (MetaOutput *output); GBytes * meta_output_kms_read_edid (MetaOutput *output); MetaOutput * meta_create_kms_output (MetaGpuKms *gpu_kms, MetaKmsConnector *kms_connector, - drmModeConnector *connector, MetaOutput *old_output, GError **error); diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 2cb3f1cf7..5228310fc 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -62,11 +62,12 @@ #include "backends/native/meta-drm-buffer-gbm.h" #include "backends/native/meta-drm-buffer.h" #include "backends/native/meta-gpu-kms.h" +#include "backends/native/meta-kms-update.h" #include "backends/native/meta-kms-utils.h" -#include "backends/native/meta-monitor-manager-kms.h" +#include "backends/native/meta-kms.h" +#include "backends/native/meta-output-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" @@ -182,7 +183,6 @@ typedef struct _MetaOnscreenNative } egl; #endif - gboolean pending_queue_swap_notify; gboolean pending_swap_notify; gboolean pending_set_crtc; @@ -190,9 +190,6 @@ typedef struct _MetaOnscreenNative int64_t pending_queue_swap_notify_frame_count; int64_t pending_swap_notify_frame_count; - GList *pending_page_flip_retries; - GSource *retry_page_flips_source; - MetaRendererView *view; int total_pending_flips; } MetaOnscreenNative; @@ -215,7 +212,7 @@ struct _MetaRendererNative int64_t frame_counter; gboolean pending_unset_disabled_crtcs; - GList *power_save_page_flip_closures; + GList *power_save_page_flip_onscreens; guint power_save_page_flip_source_id; }; @@ -1292,11 +1289,9 @@ 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) +notify_view_crtc_presented (MetaRendererView *view, + MetaKmsCrtc *kms_crtc, + int64_t time_ns) { ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view); CoglFramebuffer *framebuffer = @@ -1307,24 +1302,28 @@ on_crtc_flipped (GClosure *closure, MetaRendererNative *renderer_native = onscreen_native->renderer_native; MetaGpuKms *render_gpu = onscreen_native->render_gpu; CoglFrameInfo *frame_info; + MetaCrtc *crtc; 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; + MetaGpuKms *gpu_kms; /* 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. */ + frame_info = g_queue_peek_tail (&onscreen->pending_frame_infos); + + crtc = meta_crtc_kms_from_kms_crtc (kms_crtc); + refresh_rate = crtc && crtc->current_mode ? + crtc->current_mode->refresh_rate : + 0.0f; if (refresh_rate >= frame_info->refresh_rate) { - frame_info->presentation_time = page_flip_time_ns; + frame_info->presentation_time = time_ns; frame_info->refresh_rate = refresh_rate; } + gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); if (gpu_kms != render_gpu) { MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; @@ -1338,8 +1337,6 @@ on_crtc_flipped (GClosure *closure, { MetaRendererNativeGpuData *renderer_gpu_data; - onscreen_native->pending_queue_swap_notify = FALSE; - meta_onscreen_native_queue_swap_notify (onscreen); renderer_gpu_data = @@ -1358,6 +1355,92 @@ on_crtc_flipped (GClosure *closure, } } +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_feedback_flipped (MetaKmsCrtc *kms_crtc, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + gpointer user_data) +{ + MetaRendererView *view = user_data; + struct timeval page_flip_time; + + page_flip_time = (struct timeval) { + .tv_sec = tv_sec, + .tv_usec = tv_usec, + }; + + notify_view_crtc_presented (view, kms_crtc, + timeval_to_nanoseconds (&page_flip_time)); + + g_object_unref (view); +} + +static void +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; + + /* + * 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_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); + + notify_view_crtc_presented (view, kms_crtc, now_ns); + + g_object_unref (view); +} + +static void +page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc, + gpointer user_data, + const GError *error) +{ + MetaRendererView *view = user_data; + MetaCrtc *crtc; + MetaGpuKms *gpu_kms; + int64_t now_ns; + + /* + * Page flipping failed, but we want to fail gracefully, so to avoid freezing + * the frame clack, pretend we flipped. + */ + + if (error) + g_warning ("Page flip discarded: %s", error->message); + + 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); + + notify_view_crtc_presented (view, kms_crtc, now_ns); + + g_object_unref (view); +} + +static const MetaKmsPageFlipFeedback page_flip_feedback = { + .flipped = page_flip_feedback_flipped, + .mode_set_fallback = page_flip_feedback_mode_set_fallback, + .discarded = page_flip_feedback_discarded, +}; + static void free_next_secondary_bo (MetaGpuKms *gpu_kms, MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state) @@ -1375,73 +1458,29 @@ free_next_secondary_bo (MetaGpuKms *gpu_kms, } } -static void -flip_closure_destroyed (MetaRendererView *view) -{ - ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view); - CoglFramebuffer *framebuffer = - clutter_stage_view_get_onscreen (stage_view); - CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); - CoglOnscreenEGL *onscreen_egl = onscreen->winsys; - MetaOnscreenNative *onscreen_native = onscreen_egl->platform; - MetaRendererNative *renderer_native = onscreen_native->renderer_native; - MetaGpuKms *render_gpu = onscreen_native->render_gpu; - MetaRendererNativeGpuData *renderer_gpu_data; - - renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, - render_gpu); - switch (renderer_gpu_data->mode) - { - case META_RENDERER_NATIVE_MODE_GBM: - g_clear_object (&onscreen_native->gbm.next_fb); - - g_hash_table_foreach (onscreen_native->secondary_gpu_states, - (GHFunc) free_next_secondary_bo, - NULL); - - break; #ifdef HAVE_EGL_DEVICE - case META_RENDERER_NATIVE_MODE_EGL_DEVICE: - break; -#endif - } - - if (onscreen_native->pending_queue_swap_notify) - { - meta_onscreen_native_queue_swap_notify (onscreen); - onscreen_native->pending_queue_swap_notify = FALSE; - } - - g_object_unref (view); -} - -#ifdef HAVE_EGL_DEVICE -static gboolean -flip_egl_stream (MetaOnscreenNative *onscreen_native, - GClosure *flip_closure) +static int +custom_egl_stream_page_flip (gpointer custom_page_flip_data, + gpointer user_data) { + MetaOnscreenNative *onscreen_native = custom_page_flip_data; + MetaRendererView *view = user_data; + MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native); MetaRendererNativeGpuData *renderer_gpu_data; EGLDisplay *egl_display; - MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native); - MetaGpuKmsFlipClosureContainer *closure_container; EGLAttrib *acquire_attribs; - GError *error = NULL; + g_autoptr (GError) error = NULL; + + acquire_attribs = (EGLAttrib[]) { + EGL_DRM_FLIP_EVENT_DATA_NV, + (EGLAttrib) view, + EGL_NONE + }; renderer_gpu_data = meta_renderer_native_get_gpu_data (onscreen_native->renderer_native, onscreen_native->render_gpu); - closure_container = - meta_gpu_kms_wrap_flip_closure (onscreen_native->render_gpu, - NULL, - flip_closure); - - acquire_attribs = (EGLAttrib[]) { - EGL_DRM_FLIP_EVENT_DATA_NV, - (EGLAttrib) closure_container, - EGL_NONE - }; - egl_display = renderer_gpu_data->egl_display; if (!meta_egl_stream_consumer_acquire_attrib (egl, egl_display, @@ -1449,28 +1488,21 @@ flip_egl_stream (MetaOnscreenNative *onscreen_native, acquire_attribs, &error)) { - if (error->domain != META_EGL_ERROR || - error->code != EGL_RESOURCE_BUSY_EXT) - { - g_warning ("Failed to flip EGL stream: %s", error->message); - } - g_error_free (error); - meta_gpu_kms_flip_closure_container_free (closure_container); - return FALSE; + if (g_error_matches (error, META_EGL_ERROR, EGL_RESOURCE_BUSY_EXT)) + return -EBUSY; + else + return -EINVAL; } - return TRUE; + return 0; } #endif /* HAVE_EGL_DEVICE */ -static gboolean -is_timestamp_earlier_than (uint64_t ts1, - uint64_t ts2) +static void +dummy_power_save_page_flip (CoglOnscreen *onscreen) { - if (ts1 == ts2) - return FALSE; - else - return ts2 - ts1 < UINT64_MAX / 2; + meta_onscreen_native_swap_drm_fb (onscreen); + meta_onscreen_native_queue_swap_notify (onscreen); } static gboolean @@ -1478,18 +1510,22 @@ dummy_power_save_page_flip_cb (gpointer user_data) { MetaRendererNative *renderer_native = user_data; - g_list_free_full (renderer_native->power_save_page_flip_closures, - (GDestroyNotify) g_closure_unref); - renderer_native->power_save_page_flip_closures = NULL; + g_list_foreach (renderer_native->power_save_page_flip_onscreens, + (GFunc) dummy_power_save_page_flip, NULL); + g_list_free_full (renderer_native->power_save_page_flip_onscreens, + (GDestroyNotify) cogl_object_unref); + renderer_native->power_save_page_flip_onscreens = NULL; renderer_native->power_save_page_flip_source_id = 0; return G_SOURCE_REMOVE; } static void -queue_dummy_power_save_page_flip (MetaRendererNative *renderer_native, - GClosure *flip_closure) +queue_dummy_power_save_page_flip (CoglOnscreen *onscreen) { + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + MetaRendererNative *renderer_native = onscreen_native->renderer_native; const unsigned int timeout_ms = 100; if (!renderer_native->power_save_page_flip_source_id) @@ -1500,225 +1536,16 @@ queue_dummy_power_save_page_flip (MetaRendererNative *renderer_native, renderer_native); } - renderer_native->power_save_page_flip_closures = - g_list_prepend (renderer_native->power_save_page_flip_closures, - g_closure_ref (flip_closure)); -} - -typedef struct _RetryPageFlipData -{ - MetaCrtc *crtc; - uint32_t fb_id; - GClosure *flip_closure; - uint64_t retry_time_us; -} RetryPageFlipData; - -static void -retry_page_flip_data_free (RetryPageFlipData *retry_page_flip_data) -{ - g_closure_unref (retry_page_flip_data->flip_closure); - g_free (retry_page_flip_data); + renderer_native->power_save_page_flip_onscreens = + g_list_prepend (renderer_native->power_save_page_flip_onscreens, + cogl_object_ref (onscreen)); } static void -retry_page_flip_data_fake_flipped (RetryPageFlipData *retry_page_flip_data, - MetaOnscreenNative *onscreen_native) -{ - MetaCrtc *crtc = retry_page_flip_data->crtc; - MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); - - if (gpu_kms != onscreen_native->render_gpu) - { - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; - - secondary_gpu_state = - meta_onscreen_native_get_secondary_gpu_state (onscreen_native, - gpu_kms); - secondary_gpu_state->pending_flips--; - } - - onscreen_native->total_pending_flips--; -} - -static gboolean -retry_page_flips (gpointer user_data) -{ - MetaOnscreenNative *onscreen_native = user_data; - MetaRendererNative *renderer_native = onscreen_native->renderer_native; - MetaMonitorManager *monitor_manager = - meta_backend_get_monitor_manager (renderer_native->backend); - uint64_t now_us; - MetaPowerSave power_save_mode; - GList *l; - - now_us = g_source_get_time (onscreen_native->retry_page_flips_source); - power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); - - l = onscreen_native->pending_page_flip_retries; - while (l) - { - RetryPageFlipData *retry_page_flip_data = l->data; - MetaCrtc *crtc = retry_page_flip_data->crtc; - MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); - GList *l_next = l->next; - g_autoptr (GError) error = NULL; - gboolean did_flip; - - if (power_save_mode != META_POWER_SAVE_ON) - { - onscreen_native->pending_page_flip_retries = - g_list_remove_link (onscreen_native->pending_page_flip_retries, l); - - retry_page_flip_data_fake_flipped (retry_page_flip_data, - onscreen_native); - retry_page_flip_data_free (retry_page_flip_data); - - l = l_next; - continue; - } - - if (is_timestamp_earlier_than (now_us, - retry_page_flip_data->retry_time_us)) - { - l = l_next; - continue; - } - - did_flip = meta_gpu_kms_flip_crtc (gpu_kms, - crtc, - retry_page_flip_data->fb_id, - retry_page_flip_data->flip_closure, - &error); - if (!did_flip && - g_error_matches (error, G_IO_ERROR, G_IO_ERROR_BUSY)) - { - retry_page_flip_data->retry_time_us += - (uint64_t) (G_USEC_PER_SEC / crtc->current_mode->refresh_rate); - l = l_next; - continue; - } - - onscreen_native->pending_page_flip_retries = - g_list_remove_link (onscreen_native->pending_page_flip_retries, l); - - if (!did_flip) - { - if (!g_error_matches (error, - G_IO_ERROR, - G_IO_ERROR_PERMISSION_DENIED)) - g_critical ("Failed to page flip: %s", error->message); - - retry_page_flip_data_fake_flipped (retry_page_flip_data, - onscreen_native); - } - - retry_page_flip_data_free (retry_page_flip_data); - - l = l_next; - } - - if (onscreen_native->pending_page_flip_retries) - { - GList *l; - uint64_t earliest_retry_time_us = 0; - - for (l = onscreen_native->pending_page_flip_retries; l; l = l->next) - { - RetryPageFlipData *retry_page_flip_data = l->data; - - if (l == onscreen_native->pending_page_flip_retries || - is_timestamp_earlier_than (retry_page_flip_data->retry_time_us, - earliest_retry_time_us)) - earliest_retry_time_us = retry_page_flip_data->retry_time_us; - } - - g_source_set_ready_time (onscreen_native->retry_page_flips_source, - earliest_retry_time_us); - return G_SOURCE_CONTINUE; - } - else - { - meta_backend_thaw_updates (renderer_native->backend); - g_clear_pointer (&onscreen_native->retry_page_flips_source, - g_source_unref); - return G_SOURCE_REMOVE; - } -} - -static gboolean -retry_page_flips_source_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - return callback (user_data); -} - -static GSourceFuncs retry_page_flips_source_funcs = { - .dispatch = retry_page_flips_source_dispatch, -}; - -static void -schedule_retry_page_flip (MetaOnscreenNative *onscreen_native, - MetaCrtc *crtc, - uint32_t fb_id, - GClosure *flip_closure) -{ - MetaRendererNative *renderer_native = onscreen_native->renderer_native; - RetryPageFlipData *retry_page_flip_data; - uint64_t now_us; - uint64_t retry_time_us; - - now_us = g_get_monotonic_time (); - retry_time_us = - now_us + (uint64_t) (G_USEC_PER_SEC / crtc->current_mode->refresh_rate); - - retry_page_flip_data = g_new0 (RetryPageFlipData, 1); - retry_page_flip_data->crtc = crtc; - retry_page_flip_data->fb_id = fb_id; - retry_page_flip_data->flip_closure = g_closure_ref (flip_closure); - retry_page_flip_data->retry_time_us = retry_time_us; - - if (!onscreen_native->retry_page_flips_source) - { - GSource *source; - - source = g_source_new (&retry_page_flips_source_funcs, sizeof (GSource)); - g_source_set_callback (source, retry_page_flips, onscreen_native, NULL); - g_source_set_ready_time (source, retry_time_us); - g_source_attach (source, NULL); - - onscreen_native->retry_page_flips_source = source; - meta_backend_freeze_updates (renderer_native->backend); - } - else - { - GList *l; - - for (l = onscreen_native->pending_page_flip_retries; l; l = l->next) - { - RetryPageFlipData *pending_retry_page_flip_data = l->data; - uint64_t pending_retry_time_us = - pending_retry_page_flip_data->retry_time_us; - - if (is_timestamp_earlier_than (retry_time_us, pending_retry_time_us)) - { - g_source_set_ready_time (onscreen_native->retry_page_flips_source, - retry_time_us); - break; - } - } - } - - onscreen_native->pending_page_flip_retries = - g_list_append (onscreen_native->pending_page_flip_retries, - retry_page_flip_data); -} - -static gboolean -meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - GClosure *flip_closure, - MetaCrtc *crtc, - GError **error) +meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, + MetaRendererView *view, + MetaCrtc *crtc, + MetaKmsUpdate *kms_update) { CoglOnscreenEGL *onscreen_egl = onscreen->winsys; MetaOnscreenNative *onscreen_native = onscreen_egl->platform; @@ -1748,25 +1575,11 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, fb_id = meta_drm_buffer_get_fb_id (secondary_gpu_state->gbm.next_fb); } - if (!meta_gpu_kms_flip_crtc (gpu_kms, - crtc, - fb_id, - flip_closure, - error)) - { - if (g_error_matches (*error, - G_IO_ERROR, - G_IO_ERROR_BUSY)) - { - g_clear_error (error); - schedule_retry_page_flip (onscreen_native, crtc, - fb_id, flip_closure); - } - else - { - return FALSE; - } - } + meta_crtc_kms_assign_primary_plane (crtc, fb_id, kms_update); + meta_crtc_kms_page_flip (crtc, + &page_flip_feedback, + g_object_ref (view), + kms_update); onscreen_native->total_pending_flips++; if (secondary_gpu_state) @@ -1775,166 +1588,78 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: - if (flip_egl_stream (onscreen_native, - flip_closure)) - onscreen_native->total_pending_flips++; + meta_kms_update_custom_page_flip (kms_update, + meta_crtc_kms_get_kms_crtc (crtc), + &page_flip_feedback, + g_object_ref (view), + custom_egl_stream_page_flip, + onscreen_native); + onscreen_native->total_pending_flips++; break; #endif } - - return TRUE; } -static void -set_crtc_fb (CoglOnscreen *onscreen, - MetaLogicalMonitor *logical_monitor, - MetaCrtc *crtc, - uint32_t render_fb_id) +typedef struct _SetCrtcModeData { - CoglOnscreenEGL *onscreen_egl = onscreen->winsys; - MetaOnscreenNative *onscreen_native = onscreen_egl->platform; - MetaGpuKms *render_gpu = onscreen_native->render_gpu; - MetaGpuKms *gpu_kms; - int x, y; - uint32_t fb_id; - - gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); - if (gpu_kms == render_gpu) - { - fb_id = render_fb_id; - } - else - { - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; - - secondary_gpu_state = get_secondary_gpu_state (onscreen, gpu_kms); - if (!secondary_gpu_state) - return; - - fb_id = meta_drm_buffer_get_fb_id (secondary_gpu_state->gbm.next_fb); - } - - x = crtc->rect.x - logical_monitor->rect.x; - y = crtc->rect.y - logical_monitor->rect.y; - - meta_gpu_kms_apply_crtc_mode (gpu_kms, crtc, x, y, fb_id); -} - -typedef struct _SetCrtcFbData -{ - CoglOnscreen *onscreen; - uint32_t fb_id; -} SetCrtcFbData; - -static void -set_crtc_fb_cb (MetaLogicalMonitor *logical_monitor, - MetaOutput *output, - MetaCrtc *crtc, - gpointer user_data) -{ - SetCrtcFbData *data = user_data; - CoglOnscreen *onscreen = data->onscreen; - - set_crtc_fb (onscreen, logical_monitor, crtc, data->fb_id); -} - -static void -meta_onscreen_native_set_crtc_modes (CoglOnscreen *onscreen) -{ - CoglOnscreenEGL *onscreen_egl = onscreen->winsys; - MetaOnscreenNative *onscreen_native = onscreen_egl->platform; - MetaRendererNative *renderer_native = onscreen_native->renderer_native; - MetaGpuKms *render_gpu = onscreen_native->render_gpu; MetaRendererNativeGpuData *renderer_gpu_data; - MetaRendererView *view = onscreen_native->view; - uint32_t fb_id = 0; - MetaLogicalMonitor *logical_monitor; + MetaOnscreenNative *onscreen_native; + MetaKmsUpdate *kms_update; +} SetCrtcModeData; - renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, - render_gpu); - switch (renderer_gpu_data->mode) +static void +set_crtc_mode (MetaLogicalMonitor *logical_monitor, + MetaOutput *output, + MetaCrtc *crtc, + gpointer user_data) +{ + SetCrtcModeData *data = user_data; + + switch (data->renderer_gpu_data->mode) { case META_RENDERER_NATIVE_MODE_GBM: - fb_id = meta_drm_buffer_get_fb_id (onscreen_native->gbm.next_fb); break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: - fb_id = onscreen_native->egl.dumb_fb.fb_id; - break; + { + uint32_t fb_id; + + fb_id = data->onscreen_native->egl.dumb_fb.fb_id; + meta_crtc_kms_assign_primary_plane (crtc, fb_id, data->kms_update); + break; + } #endif } - g_assert (fb_id != 0); - - logical_monitor = meta_renderer_view_get_logical_monitor (view); - if (logical_monitor) - { - SetCrtcFbData data = { - .onscreen = onscreen, - .fb_id = fb_id - }; - - meta_logical_monitor_foreach_crtc (logical_monitor, - set_crtc_fb_cb, - &data); - } - else - { - GList *l; - - for (l = meta_gpu_get_crtcs (META_GPU (render_gpu)); l; l = l->next) - { - MetaCrtc *crtc = l->data; - - meta_gpu_kms_apply_crtc_mode (render_gpu, - crtc, - crtc->rect.x, crtc->rect.y, - fb_id); - } - } + meta_crtc_kms_set_mode (crtc, data->kms_update); + meta_output_kms_set_underscan (output, data->kms_update); } -static gboolean -crtc_mode_set_fallback (CoglOnscreen *onscreen, - MetaLogicalMonitor *logical_monitor, - MetaCrtc *crtc) +static void +meta_onscreen_native_set_crtc_modes (CoglOnscreen *onscreen, + MetaRendererNativeGpuData *renderer_gpu_data, + MetaKmsUpdate *kms_update) { CoglOnscreenEGL *onscreen_egl = onscreen->winsys; MetaOnscreenNative *onscreen_native = onscreen_egl->platform; - MetaGpuKms *render_gpu = onscreen_native->render_gpu; - MetaRendererNative *renderer_native; - MetaRendererNativeGpuData *renderer_gpu_data; - uint32_t fb_id; - static gboolean warned_once = FALSE; + MetaRendererView *view = onscreen_native->view; + MetaLogicalMonitor *logical_monitor; + SetCrtcModeData data; - if (!warned_once) - { - g_warning ("Page flipping not supported by driver, " - "relying on the clock from now on"); - warned_once = TRUE; - } - - renderer_native = meta_renderer_native_from_gpu (render_gpu); - renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, - render_gpu); - if (renderer_gpu_data->mode != META_RENDERER_NATIVE_MODE_GBM) - { - g_warning ("Mode set fallback not handled for EGLStreams"); - return FALSE; - } - - fb_id = meta_drm_buffer_get_fb_id (onscreen_native->gbm.next_fb); - set_crtc_fb (onscreen, logical_monitor, crtc, fb_id); - return TRUE; + logical_monitor = meta_renderer_view_get_logical_monitor (view); + data = (SetCrtcModeData) { + .renderer_gpu_data = renderer_gpu_data, + .onscreen_native = onscreen_native, + .kms_update = kms_update, + }; + meta_logical_monitor_foreach_crtc (logical_monitor, set_crtc_mode, &data); } typedef struct _FlipCrtcData { + MetaRendererView *view; CoglOnscreen *onscreen; - GClosure *flip_closure; - - gboolean did_flip; - gboolean did_mode_set; + MetaKmsUpdate *kms_update; } FlipCrtcData; static void @@ -1944,32 +1669,16 @@ flip_crtc (MetaLogicalMonitor *logical_monitor, gpointer user_data) { FlipCrtcData *data = user_data; - GError *error = NULL; - if (!meta_onscreen_native_flip_crtc (data->onscreen, - data->flip_closure, - crtc, - &error)) - { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) - { - if (crtc_mode_set_fallback (data->onscreen, logical_monitor, crtc)) - data->did_mode_set = TRUE; - } - else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED)) - { - g_warning ("Failed to flip onscreen: %s", error->message); - } - g_error_free (error); - } - else - { - data->did_flip = TRUE; - } + meta_onscreen_native_flip_crtc (data->onscreen, + data->view, + crtc, + data->kms_update); } static void -meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen) +meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen, + MetaKmsUpdate *kms_update) { CoglOnscreenEGL *onscreen_egl = onscreen->winsys; MetaOnscreenNative *onscreen_native = onscreen_egl->platform; @@ -1977,51 +1686,24 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen) MetaRendererNative *renderer_native = onscreen_native->renderer_native; MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (renderer_native->backend); - GClosure *flip_closure; MetaPowerSave power_save_mode; MetaLogicalMonitor *logical_monitor; - /* - * Create a closure that either will be invoked or destructed. - * Invoking the closure represents a completed flip. If the closure - * is destructed before being invoked, the framebuffer references will be - * cleaned up accordingly. - * - * Each successful flip will each own one reference to the closure, thus keep - * it alive until either invoked or destructed. If flipping failed, the - * closure will be destructed before this function goes out of scope. - */ - flip_closure = g_cclosure_new (G_CALLBACK (on_crtc_flipped), - g_object_ref (view), - (GClosureNotify) flip_closure_destroyed); - g_closure_set_marshal (flip_closure, meta_marshal_VOID__OBJECT_OBJECT_INT64); - power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); if (power_save_mode == META_POWER_SAVE_ON) { FlipCrtcData data = { .onscreen = onscreen, - .flip_closure = flip_closure, + .view = view, + .kms_update = kms_update, }; logical_monitor = meta_renderer_view_get_logical_monitor (view); meta_logical_monitor_foreach_crtc (logical_monitor, flip_crtc, &data); - - /* - * If we didn't queue a page flip, but instead directly changed the mode - * due to the driver not supporting mode setting, we must swap the - * buffers directly as we won't get a page flip callback. - */ - if (!data.did_flip && data.did_mode_set) - meta_onscreen_native_swap_drm_fb (onscreen); } else { - queue_dummy_power_save_page_flip (renderer_native, flip_closure); + queue_dummy_power_save_page_flip (onscreen); } - - onscreen_native->pending_queue_swap_notify = TRUE; - - g_closure_unref (flip_closure); } static void @@ -2031,6 +1713,7 @@ wait_for_pending_flips (CoglOnscreen *onscreen) MetaOnscreenNative *onscreen_native = onscreen_egl->platform; MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; GHashTableIter iter; + GError *error = NULL; g_hash_table_iter_init (&iter, onscreen_native->secondary_gpu_states); while (g_hash_table_iter_next (&iter, @@ -2038,11 +1721,26 @@ wait_for_pending_flips (CoglOnscreen *onscreen) (gpointer *) &secondary_gpu_state)) { while (secondary_gpu_state->pending_flips) - meta_gpu_kms_wait_for_flip (secondary_gpu_state->gpu_kms, NULL); + { + if (!meta_gpu_kms_wait_for_flip (secondary_gpu_state->gpu_kms, &error)) + { + g_warning ("Failed to wait for flip on secondary GPU: %s", + error->message); + g_clear_error (&error); + break; + } + } } while (onscreen_native->total_pending_flips) - meta_gpu_kms_wait_for_flip (onscreen_native->render_gpu, NULL); + { + if (!meta_gpu_kms_wait_for_flip (onscreen_native->render_gpu, &error)) + { + g_warning ("Failed to wait for flip: %s", error->message); + g_clear_error (&error); + break; + } + } } static void @@ -2305,17 +2003,23 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; + MetaBackend *backend = renderer_native->backend; MetaMonitorManager *monitor_manager = - meta_backend_get_monitor_manager (renderer_native->backend); + meta_backend_get_monitor_manager (backend); + MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); + MetaKms *kms = meta_backend_native_get_kms (backend_native); CoglOnscreenEGL *onscreen_egl = onscreen->winsys; MetaOnscreenNative *onscreen_native = onscreen_egl->platform; MetaGpuKms *render_gpu = onscreen_native->render_gpu; CoglFrameInfo *frame_info; gboolean egl_context_changed = FALSE; + MetaKmsUpdate *kms_update; MetaPowerSave power_save_mode; g_autoptr (GError) error = NULL; MetaDrmBufferGbm *buffer_gbm; + kms_update = meta_kms_ensure_pending_update (kms); + /* * Wait for the flip callback before continuing, as we might have started the * animation earlier due to the animation being driven by some other monitor. @@ -2367,12 +2071,14 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, if (onscreen_native->pending_set_crtc && power_save_mode == META_POWER_SAVE_ON) { - meta_onscreen_native_set_crtc_modes (onscreen); + meta_onscreen_native_set_crtc_modes (onscreen, + renderer_gpu_data, + kms_update); onscreen_native->pending_set_crtc = FALSE; } onscreen_native->pending_queue_swap_notify_frame_count = renderer_native->frame_counter; - meta_onscreen_native_flip_crtcs (onscreen); + meta_onscreen_native_flip_crtcs (onscreen, kms_update); /* * If we changed EGL context, cogl will have the wrong idea about what is @@ -2382,6 +2088,12 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, */ if (egl_context_changed) _cogl_winsys_egl_ensure_current (cogl_display); + + if (!meta_kms_post_pending_update_sync (kms, &error)) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED)) + g_warning ("Failed to post KMS update: %s", error->message); + } } static gboolean @@ -2946,15 +2658,6 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen) g_warning ("Failed to clear current context"); } - g_list_free_full (onscreen_native->pending_page_flip_retries, - (GDestroyNotify) retry_page_flip_data_free); - if (onscreen_native->retry_page_flips_source) - { - meta_backend_thaw_updates (renderer_native->backend); - g_clear_pointer (&onscreen_native->retry_page_flips_source, - g_source_destroy); - } - renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, onscreen_native->render_gpu); @@ -3410,6 +3113,12 @@ meta_renderer_native_create_view (MetaRenderer *renderer, void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native) { + MetaBackend *backend = renderer_native->backend; + MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); + MetaKms *kms = meta_backend_native_get_kms (backend_native); + MetaKmsUpdate *kms_update = NULL; + GError *error = NULL; + renderer_native->frame_counter++; if (renderer_native->pending_unset_disabled_crtcs) @@ -3419,7 +3128,6 @@ meta_renderer_native_finish_frame (MetaRendererNative *renderer_native) for (l = meta_backend_get_gpus (renderer_native->backend); l; l = l->next) { MetaGpu *gpu = l->data; - MetaGpuKms *gpu_kms = META_GPU_KMS (gpu); GList *k; for (k = meta_gpu_get_crtcs (gpu); k; k = k->next) @@ -3429,12 +3137,23 @@ meta_renderer_native_finish_frame (MetaRendererNative *renderer_native) if (crtc->current_mode) continue; - meta_gpu_kms_apply_crtc_mode (gpu_kms, crtc, 0, 0, 0); + kms_update = meta_kms_ensure_pending_update (kms); + meta_crtc_kms_set_mode (crtc, kms_update); } } renderer_native->pending_unset_disabled_crtcs = FALSE; } + + if (kms_update) + { + if (!meta_kms_post_pending_update_sync (kms, &error)) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED)) + g_warning ("Failed to post KMS update: %s", error->message); + g_error_free (error); + } + } } int64_t @@ -4031,6 +3750,22 @@ on_gpu_added (MetaBackendNative *backend_native, _cogl_winsys_egl_ensure_current (cogl_display); } +static void +on_power_save_mode_changed (MetaMonitorManager *monitor_manager, + MetaRendererNative *renderer_native) +{ + MetaBackendNative *backend_native = + META_BACKEND_NATIVE (renderer_native->backend); + MetaKms *kms = meta_backend_native_get_kms (backend_native); + MetaPowerSave power_save_mode; + + power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); + if (power_save_mode == META_POWER_SAVE_ON) + meta_renderer_native_queue_modes_reset (renderer_native); + else + meta_kms_discard_pending_page_flips (kms); +} + static MetaGpuKms * choose_primary_gpu_unchecked (MetaBackend *backend, MetaRendererNative *renderer_native) @@ -4143,10 +3878,10 @@ meta_renderer_native_finalize (GObject *object) { MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object); - if (renderer_native->power_save_page_flip_closures) + if (renderer_native->power_save_page_flip_onscreens) { - g_list_free_full (renderer_native->power_save_page_flip_closures, - (GDestroyNotify) g_closure_unref); + g_list_free_full (renderer_native->power_save_page_flip_onscreens, + (GDestroyNotify) cogl_object_unref); g_source_remove (renderer_native->power_save_page_flip_source_id); } @@ -4162,6 +3897,8 @@ meta_renderer_native_constructed (GObject *object) MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object); MetaBackend *backend = renderer_native->backend; MetaSettings *settings = meta_backend_get_settings (backend); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); if (meta_settings_is_experimental_feature_enabled ( settings, META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS)) @@ -4169,6 +3906,8 @@ meta_renderer_native_constructed (GObject *object) g_signal_connect (backend, "gpu-added", G_CALLBACK (on_gpu_added), renderer_native); + g_signal_connect (monitor_manager, "power-save-mode-changed", + G_CALLBACK (on_power_save_mode_changed), renderer_native); G_OBJECT_CLASS (meta_renderer_native_parent_class)->constructed (object); } diff --git a/src/meson.build b/src/meson.build index acfd879ef..515638fe5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -610,10 +610,15 @@ if have_native_backend 'backends/native/meta-kms-impl-simple.h', 'backends/native/meta-kms-impl.c', 'backends/native/meta-kms-impl.h', + 'backends/native/meta-kms-page-flip.c', + 'backends/native/meta-kms-page-flip-private.h', 'backends/native/meta-kms-plane.c', 'backends/native/meta-kms-plane.h', 'backends/native/meta-kms-private.h', 'backends/native/meta-kms-types.h', + 'backends/native/meta-kms-update-private.h', + 'backends/native/meta-kms-update.c', + 'backends/native/meta-kms-update.h', 'backends/native/meta-kms-utils.c', 'backends/native/meta-kms-utils.h', 'backends/native/meta-kms.c', @@ -801,14 +806,6 @@ endif subdir('meta') -mutter_marshal = gnome.genmarshal('meta-marshal', - sources: ['meta-marshal.list'], - prefix: 'meta_marshal', - extra_args: ['--quiet'], - 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 deleted file mode 100644 index c1f4781d2..000000000 --- a/src/meta-marshal.list +++ /dev/null @@ -1 +0,0 @@ -VOID:OBJECT,OBJECT,INT64