From 9e6f8a250f428984f06dc87f8d14b3d66af2303d Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 16 Jan 2024 16:41:39 +0100 Subject: [PATCH 01/18] monitor-config-manager: Use autoptr in more cases Part-of: --- src/backends/meta-monitor-config-manager.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c index 358b01f15d3..e8294a66043 100644 --- a/src/backends/meta-monitor-config-manager.c +++ b/src/backends/meta-monitor-config-manager.c @@ -383,9 +383,9 @@ meta_monitor_config_manager_assign (MetaMonitorManager *manager, GPtrArray **out_output_assignments, GError **error) { - GPtrArray *crtc_assignments; - GPtrArray *output_assignments; - GArray *reserved_crtcs; + g_autoptr (GPtrArray) crtc_assignments = NULL; + g_autoptr (GPtrArray) output_assignments = NULL; + g_autoptr (GArray) reserved_crtcs = NULL; GList *l; crtc_assignments = @@ -432,18 +432,11 @@ meta_monitor_config_manager_assign (MetaMonitorManager *manager, config, logical_monitor_config, crtc_assignments, output_assignments, reserved_crtcs, error)) - { - g_ptr_array_free (crtc_assignments, TRUE); - g_ptr_array_free (output_assignments, TRUE); - g_array_free (reserved_crtcs, TRUE); - return FALSE; - } + return FALSE; } - g_array_free (reserved_crtcs, TRUE); - - *out_crtc_assignments = crtc_assignments; - *out_output_assignments = output_assignments; + *out_crtc_assignments = g_steal_pointer (&crtc_assignments); + *out_output_assignments = g_steal_pointer (&output_assignments); return TRUE; } -- GitLab From 9da43a34200626486595854ce27a4be01d469b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 7 Jul 2021 16:54:16 +0200 Subject: [PATCH 02/18] kms/connector: Add 'for-lease' getter This is intended to be used to filter out what connectors will be available for lease, i.e. non-desktop ones. Co-authored-by: Sebastian Wick Part-of: --- src/backends/native/meta-gpu-kms.c | 7 ++++--- src/backends/native/meta-kms-connector.c | 6 ++++++ src/backends/native/meta-kms-connector.h | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/backends/native/meta-gpu-kms.c b/src/backends/native/meta-gpu-kms.c index 3e0ad99c56e..3b4356ca6b5 100644 --- a/src/backends/native/meta-gpu-kms.c +++ b/src/backends/native/meta-gpu-kms.c @@ -348,13 +348,14 @@ 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; MetaOutputKms *output_kms; MetaOutput *old_output; GError *error = NULL; - connector_state = meta_kms_connector_get_current_state (kms_connector); - if (!connector_state || connector_state->non_desktop) + if (!meta_kms_connector_get_current_state (kms_connector)) + continue; + + if (meta_kms_connector_is_for_lease (kms_connector)) continue; old_output = diff --git a/src/backends/native/meta-kms-connector.c b/src/backends/native/meta-kms-connector.c index 8acc58f26ca..590b5869ac6 100644 --- a/src/backends/native/meta-kms-connector.c +++ b/src/backends/native/meta-kms-connector.c @@ -164,6 +164,12 @@ meta_kms_connector_get_current_state (MetaKmsConnector *connector) return connector->current_state; } +gboolean +meta_kms_connector_is_for_lease (MetaKmsConnector *connector) +{ + return connector->current_state && connector->current_state->non_desktop; +} + static gboolean has_privacy_screen_software_toggle (MetaKmsConnector *connector) { diff --git a/src/backends/native/meta-kms-connector.h b/src/backends/native/meta-kms-connector.h index dcf303bca60..f54ef16b9bc 100644 --- a/src/backends/native/meta-kms-connector.h +++ b/src/backends/native/meta-kms-connector.h @@ -101,3 +101,5 @@ MetaKmsMode * meta_kms_connector_get_preferred_mode (MetaKmsConnector *connector META_EXPORT_TEST const MetaKmsConnectorState * meta_kms_connector_get_current_state (MetaKmsConnector *connector); + +gboolean meta_kms_connector_is_for_lease (MetaKmsConnector *connector); -- GitLab From 7784c0d0aa32f7d3a565f915c86a25d453e03328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 9 May 2024 11:06:38 +0200 Subject: [PATCH 03/18] kms/connector: Allow to force connectors for lease Add an environment variable (MUTTER_DEBUG_LEASE_CONNECTORS) that allows set a ":" separated list of connector names as available for lease. The names of the connectors can be found in "/sys/class/drm". To illustrate it with an example, the names of the connectors and its status can be fetched with this command: $ for p in /sys/class/drm/*/status; do con=${p%/status}; echo -n "${con#*/card?-}: "; cat $p; done DP-1: disconnected DP-2: disconnected DP-3: disconnected DP-4: disconnected DP-5: connected DP-6: connected DP-7: disconnected eDP-1: connected HDMI-A-1: disconnected And, to set "DP-5" and "DP-6" available for lease, the environment variable can be set like: MUTTER_DEBUG_LEASE_CONNECTORS=DP-5:DP-6 Part-of: --- src/backends/native/meta-kms-connector.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/backends/native/meta-kms-connector.c b/src/backends/native/meta-kms-connector.c index 590b5869ac6..437eef11f88 100644 --- a/src/backends/native/meta-kms-connector.c +++ b/src/backends/native/meta-kms-connector.c @@ -167,7 +167,26 @@ meta_kms_connector_get_current_state (MetaKmsConnector *connector) gboolean meta_kms_connector_is_for_lease (MetaKmsConnector *connector) { - return connector->current_state && connector->current_state->non_desktop; + const char *lease_connectors_str; + + if (!connector->current_state) + return FALSE; + + lease_connectors_str = getenv ("MUTTER_DEBUG_LEASE_CONNECTORS"); + if (lease_connectors_str && *lease_connectors_str != '\0') + { + int n; + g_auto (GStrv) names; + + names = g_strsplit (lease_connectors_str, ":", -1); + for (n = 0; n < g_strv_length (names); n++) + { + if (g_str_equal (meta_kms_connector_get_name (connector), names[n])) + return TRUE; + } + } + + return connector->current_state->non_desktop; } static gboolean -- GitLab From a001dbae590d13a3d6e75db75f34c80260468446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 7 Jul 2021 16:54:53 +0200 Subject: [PATCH 04/18] kms: Add 'device-added' signal This signals when there was a mode setting device added. Part-of: --- src/backends/native/meta-kms.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c index d41fcefb5a6..47702c556ef 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c @@ -34,6 +34,7 @@ enum { RESOURCES_CHANGED, + DEVICE_ADDED, N_SIGNALS }; @@ -336,6 +337,8 @@ meta_kms_create_device (MetaKms *kms, kms->devices = g_list_append (kms->devices, device); + g_signal_emit (kms, signals[DEVICE_ADDED], 0, device); + return device; } @@ -452,6 +455,15 @@ meta_kms_class_init (MetaKmsClass *klass) G_TYPE_NONE, 1, META_TYPE_KMS_RESOURCE_CHANGES); + signals[DEVICE_ADDED] = + g_signal_new ("device-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 1, + META_TYPE_KMS_DEVICE); + meta_thread_class_register_impl_type (thread_class, META_TYPE_KMS_IMPL); } -- GitLab From 498310ec7c0c9fd4969cb5edcca55dc969399992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 3 Jan 2022 17:24:12 +0100 Subject: [PATCH 05/18] monitor-config-manager: Consider leased CRTCs assigned With leasing, we will give another client control over connectors but they also need a CRTC to drive them. Those CRTCs won't be available to the desktop/monitor-manager. Co-authored-by: Sebastian Wick Part-of: --- src/backends/meta-crtc.c | 11 +++++++++++ src/backends/meta-crtc.h | 4 ++++ src/backends/meta-monitor-config-manager.c | 3 +++ src/backends/native/meta-crtc-kms.c | 10 ++++++++++ src/backends/native/meta-kms-crtc.c | 8 ++++++++ src/backends/native/meta-kms-crtc.h | 2 ++ 6 files changed, 38 insertions(+) diff --git a/src/backends/meta-crtc.c b/src/backends/meta-crtc.c index 646a508b9af..bca008ea9b4 100644 --- a/src/backends/meta-crtc.c +++ b/src/backends/meta-crtc.c @@ -470,3 +470,14 @@ meta_crtc_config_new (graphene_rect_t *layout, return config; } + +gboolean +meta_crtc_is_leased (MetaCrtc *crtc) +{ + MetaCrtcClass *klass = META_CRTC_GET_CLASS (crtc); + + if (klass->is_leased) + return klass->is_leased (crtc); + else + return FALSE; +} diff --git a/src/backends/meta-crtc.h b/src/backends/meta-crtc.h index 0b1eb8b671a..68ff58ea84e 100644 --- a/src/backends/meta-crtc.h +++ b/src/backends/meta-crtc.h @@ -55,6 +55,8 @@ struct _MetaCrtcClass void (* set_config) (MetaCrtc *crtc, const MetaCrtcConfig *config, gpointer backend_private); + + gboolean (* is_leased) (MetaCrtc *crtc); }; META_EXPORT_TEST @@ -132,4 +134,6 @@ MetaCrtcConfig * meta_crtc_config_new (graphene_rect_t *layout, MetaCrtcMode *mode, MetaMonitorTransform transform); +gboolean meta_crtc_is_leased (MetaCrtc *crtc); + G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaGammaLut, meta_gamma_lut_free) diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c index e8294a66043..efc48d45e54 100644 --- a/src/backends/meta-monitor-config-manager.c +++ b/src/backends/meta-monitor-config-manager.c @@ -99,6 +99,9 @@ is_crtc_assigned (MetaCrtc *crtc, { unsigned int i; + if (meta_crtc_is_leased (crtc)) + return TRUE; + for (i = 0; i < crtc_assignments->len; i++) { MetaCrtcAssignment *assigned_crtc_assignment = diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c index 3498f922a30..1b426d76d10 100644 --- a/src/backends/native/meta-crtc-kms.c +++ b/src/backends/native/meta-crtc-kms.c @@ -326,6 +326,15 @@ meta_crtc_kms_set_config (MetaCrtc *crtc, crtc_kms->assigned_cursor_plane = kms_assignment->cursor_plane; } +static gboolean +meta_crtc_kms_is_leased (MetaCrtc *crtc) +{ + MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc); + MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); + + return meta_kms_crtc_is_leased (kms_crtc); +} + static gboolean meta_crtc_kms_is_transform_handled (MetaCrtcNative *crtc_native, MetaMonitorTransform transform) @@ -476,6 +485,7 @@ meta_crtc_kms_class_init (MetaCrtcKmsClass *klass) crtc_class->set_gamma_lut = meta_crtc_kms_set_gamma_lut; crtc_class->assign_extra = meta_crtc_kms_assign_extra; crtc_class->set_config = meta_crtc_kms_set_config; + crtc_class->is_leased = meta_crtc_kms_is_leased; crtc_native_class->is_transform_handled = meta_crtc_kms_is_transform_handled; crtc_native_class->is_hw_cursor_supported = meta_crtc_kms_is_hw_cursor_supported; diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c index a0872089a0c..6ca1c08d318 100644 --- a/src/backends/native/meta-kms-crtc.c +++ b/src/backends/native/meta-kms-crtc.c @@ -50,6 +50,8 @@ struct _MetaKmsCrtc MetaKmsCrtcState current_state; MetaKmsCrtcPropTable prop_table; + + gboolean is_leased; }; G_DEFINE_TYPE (MetaKmsCrtc, meta_kms_crtc, G_TYPE_OBJECT) @@ -107,6 +109,12 @@ meta_kms_crtc_is_active (MetaKmsCrtc *crtc) return crtc->current_state.is_active; } +gboolean +meta_kms_crtc_is_leased (MetaKmsCrtc *crtc) +{ + return crtc->is_leased; +} + static void read_crtc_gamma (MetaKmsCrtc *crtc, MetaKmsCrtcState *crtc_state, diff --git a/src/backends/native/meta-kms-crtc.h b/src/backends/native/meta-kms-crtc.h index 580ee9a89c1..af6538cd39a 100644 --- a/src/backends/native/meta-kms-crtc.h +++ b/src/backends/native/meta-kms-crtc.h @@ -65,3 +65,5 @@ int meta_kms_crtc_get_idx (MetaKmsCrtc *crtc); META_EXPORT_TEST gboolean meta_kms_crtc_is_active (MetaKmsCrtc *crtc); + +gboolean meta_kms_crtc_is_leased (MetaKmsCrtc *crtc); -- GitLab From aaa8cefc2549556d6faed4c9d08962d5e7ca25b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 3 Jan 2022 17:24:12 +0100 Subject: [PATCH 06/18] kms-device-impl: Implement leasing, revoking and listing leases The lease_objects function takes connectors, CRTCs and planes which are turned into a drm lease. The resulting lease can be revoked with revoke_lease. With list_lessees the currently active leases can be queried. Co-authored-by: Sebastian Wick Part-of: --- src/backends/native/meta-kms-device.c | 139 ++++++++++++ src/backends/native/meta-kms-device.h | 17 ++ src/backends/native/meta-kms-impl-device.c | 238 ++++++++++++++++----- src/backends/native/meta-kms-impl-device.h | 17 ++ 4 files changed, 355 insertions(+), 56 deletions(-) diff --git a/src/backends/native/meta-kms-device.c b/src/backends/native/meta-kms-device.c index 127a05de793..b3fcc71bdc1 100644 --- a/src/backends/native/meta-kms-device.c +++ b/src/backends/native/meta-kms-device.c @@ -423,6 +423,145 @@ meta_kms_device_handle_flush (MetaKmsDevice *device, return needs_flush; } +typedef struct +{ + MetaKmsDevice *device; + GList *connectors; + GList *crtcs; + GList *planes; + + int fd; + uint32_t lessee_id; +} LeaseRequestData; + +static gpointer +lease_objects_in_impl (MetaThreadImpl *thread_impl, + gpointer user_data, + GError **error) +{ + LeaseRequestData *data = user_data; + MetaKmsImplDevice *impl_device = + meta_kms_device_get_impl_device (data->device); + uint32_t lessee_id; + int fd; + + if (!meta_kms_impl_device_lease_objects (impl_device, + data->connectors, + data->crtcs, + data->planes, + &fd, + &lessee_id, + error)) + return GINT_TO_POINTER (FALSE); + + data->fd = fd; + data->lessee_id = lessee_id; + + return GINT_TO_POINTER (TRUE); +} + +gboolean +meta_kms_device_lease_objects (MetaKmsDevice *device, + GList *connectors, + GList *crtcs, + GList *planes, + int *out_fd, + uint32_t *out_lessee_id, + GError **error) +{ + LeaseRequestData data = {}; + + data.device = device; + data.connectors = connectors; + data.crtcs = crtcs; + data.planes = planes; + + if (!meta_kms_run_impl_task_sync (device->kms, lease_objects_in_impl, &data, + error)) + return FALSE; + + *out_fd = data.fd; + *out_lessee_id = data.lessee_id; + return TRUE; +} + +typedef struct +{ + MetaKmsDevice *device; + uint32_t lessee_id; +} RevokeLeaseData; + +static gpointer +revoke_lease_in_impl (MetaThreadImpl *thread_impl, + gpointer user_data, + GError **error) +{ + LeaseRequestData *data = user_data; + MetaKmsImplDevice *impl_device = + meta_kms_device_get_impl_device (data->device); + + if (!meta_kms_impl_device_revoke_lease (impl_device, data->lessee_id, error)) + return GINT_TO_POINTER (FALSE); + else + return GINT_TO_POINTER (TRUE); +} + +gboolean +meta_kms_device_revoke_lease (MetaKmsDevice *device, + uint32_t lessee_id, + GError **error) +{ + LeaseRequestData data = {}; + + data.device = device; + data.lessee_id = lessee_id; + + return !!meta_kms_run_impl_task_sync (device->kms, revoke_lease_in_impl, &data, + error); +} + +typedef struct +{ + MetaKmsDevice *device; + uint32_t **out_lessee_ids; + int *out_num_lessee_ids; +} ListLesseesData; + +static gpointer +list_lessees_in_impl (MetaThreadImpl *thread_impl, + gpointer user_data, + GError **error) +{ + ListLesseesData *data = user_data; + MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (data->device); + + if (!meta_kms_impl_device_list_lessees (impl_device, + data->out_lessee_ids, + data->out_num_lessee_ids, + error)) + return GINT_TO_POINTER (FALSE); + else + return GINT_TO_POINTER (TRUE); +} + +gboolean +meta_kms_device_list_lessees (MetaKmsDevice *device, + uint32_t **out_lessee_ids, + int *out_num_lessee_ids, + GError **error) +{ + ListLesseesData data = {}; + + data.device = device; + data.out_lessee_ids = out_lessee_ids; + data.out_num_lessee_ids = out_num_lessee_ids; + + return !!meta_kms_run_impl_task_sync (device->kms, + list_lessees_in_impl, + &data, + error); +} + typedef struct _CreateImplDeviceData { MetaKmsDevice *device; diff --git a/src/backends/native/meta-kms-device.h b/src/backends/native/meta-kms-device.h index 00dafb16c4c..0b39f7df522 100644 --- a/src/backends/native/meta-kms-device.h +++ b/src/backends/native/meta-kms-device.h @@ -86,6 +86,23 @@ gboolean meta_kms_device_handle_flush (MetaKmsDevice *device, META_EXPORT_TEST void meta_kms_device_disable (MetaKmsDevice *device); +gboolean meta_kms_device_lease_objects (MetaKmsDevice *device, + GList *connectors, + GList *crtcs, + GList *planes, + int *out_fd, + uint32_t *out_lessee_id, + GError **error); + +gboolean meta_kms_device_revoke_lease (MetaKmsDevice *device, + uint32_t lessee_id, + GError **error); + +gboolean meta_kms_device_list_lessees (MetaKmsDevice *device, + uint32_t **out_lessee_ids, + int *out_num_lessee_ids, + 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 1bff6be33c6..3465857fea5 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -264,6 +264,188 @@ meta_kms_impl_device_get_path (MetaKmsImplDevice *impl_device) return priv->path; } +static MetaDeviceFile * +meta_kms_impl_device_open_device_file (MetaKmsImplDevice *impl_device, + const char *path, + GError **error) +{ + MetaKmsImplDevicePrivate *priv = + meta_kms_impl_device_get_instance_private (impl_device); + MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device); + + return klass->open_device_file (impl_device, priv->path, error); +} + +static gpointer +kms_event_dispatch_in_impl (MetaThreadImpl *impl, + gpointer user_data, + GError **error) +{ + MetaKmsImplDevice *impl_device = user_data; + gboolean ret; + + ret = meta_kms_impl_device_dispatch (impl_device, error); + return GINT_TO_POINTER (ret); +} + +static gboolean +ensure_device_file (MetaKmsImplDevice *impl_device, + GError **error) +{ + MetaKmsImplDevicePrivate *priv = + meta_kms_impl_device_get_instance_private (impl_device); + MetaDeviceFile *device_file; + + if (priv->device_file) + return TRUE; + + device_file = meta_kms_impl_device_open_device_file (impl_device, + priv->path, + error); + if (!device_file) + return FALSE; + + priv->device_file = device_file; + + if (!(priv->flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING)) + { + priv->fd_source = + meta_thread_impl_register_fd (META_THREAD_IMPL (priv->impl), + meta_device_file_get_fd (device_file), + kms_event_dispatch_in_impl, + impl_device); + g_source_set_priority (priv->fd_source, G_PRIORITY_HIGH); + } + + return TRUE; +} + +gboolean +meta_kms_impl_device_lease_objects (MetaKmsImplDevice *impl_device, + GList *connectors, + GList *crtcs, + GList *planes, + int *out_fd, + uint32_t *out_lessee_id, + GError **error) +{ + MetaKmsImplDevicePrivate *priv = + meta_kms_impl_device_get_instance_private (impl_device); + uint32_t *object_ids; + int n_object_ids; + GList *l; + int retval; + uint32_t lessee_id; + int i = 0; + + meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl)); + + if (!ensure_device_file (impl_device, error)) + return FALSE; + + meta_kms_impl_device_hold_fd (impl_device); + + n_object_ids = (g_list_length (connectors) + + g_list_length (crtcs) + + g_list_length (planes)); + object_ids = g_alloca (sizeof (uint32_t) * n_object_ids); + + for (l = connectors; l; l = l->next) + { + MetaKmsConnector *connector = l->data; + + object_ids[i++] = meta_kms_connector_get_id (connector); + } + + for (l = crtcs; l; l = l->next) + { + MetaKmsCrtc *crtc = l->data; + + object_ids[i++] = meta_kms_crtc_get_id (crtc); + } + + for (l = planes; l; l = l->next) + { + MetaKmsPlane *plane = l->data; + + object_ids[i++] = meta_kms_plane_get_id (plane); + } + + retval = drmModeCreateLease (meta_kms_impl_device_get_fd (impl_device), + object_ids, n_object_ids, 0, + &lessee_id); + + if (retval < 0) + { + meta_kms_impl_device_unhold_fd (impl_device); + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-retval), + "Failed to create lease: %s", g_strerror (-retval)); + return FALSE; + } + + *out_fd = retval; + *out_lessee_id = lessee_id; + + return TRUE; +} + +gboolean +meta_kms_impl_device_revoke_lease (MetaKmsImplDevice *impl_device, + uint32_t lessee_id, + GError **error) +{ + MetaKmsImplDevicePrivate *priv = + meta_kms_impl_device_get_instance_private (impl_device); + int retval; + + meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl)); + + retval = drmModeRevokeLease (meta_kms_impl_device_get_fd (impl_device), + lessee_id); + meta_kms_impl_device_unhold_fd (impl_device); + + if (retval != 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-retval), + "Failed to revoke lease: %s", g_strerror (-retval)); + return FALSE; + } + + return TRUE; +} + +gboolean +meta_kms_impl_device_list_lessees (MetaKmsImplDevice *impl_device, + uint32_t **out_lessee_ids, + int *out_num_lessee_ids, + GError **error) +{ + MetaKmsImplDevicePrivate *priv = + meta_kms_impl_device_get_instance_private (impl_device); + drmModeLesseeListRes *list; + int i; + uint32_t *lessee_ids; + + meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl)); + + list = drmModeListLessees (meta_kms_impl_device_get_fd (impl_device)); + + if (!list) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to list lessees"); + return FALSE; + } + + lessee_ids = g_new0 (uint32_t, list->count); + for (i = 0; i < list->count; i++) + lessee_ids[i] = list->lessees[i]; + + *out_lessee_ids = lessee_ids; + *out_num_lessee_ids = list->count; + return TRUE; +} + gboolean meta_kms_impl_device_dispatch (MetaKmsImplDevice *impl_device, GError **error) @@ -314,18 +496,6 @@ meta_kms_impl_device_dispatch (MetaKmsImplDevice *impl_device, return TRUE; } -static gpointer -kms_event_dispatch_in_impl (MetaThreadImpl *impl, - gpointer user_data, - GError **error) -{ - MetaKmsImplDevice *impl_device = user_data; - gboolean ret; - - ret = meta_kms_impl_device_dispatch (impl_device, error); - return GINT_TO_POINTER (ret); -} - drmModePropertyPtr meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device, drmModeObjectProperties *props, @@ -890,50 +1060,6 @@ init_fallback_modes (MetaKmsImplDevice *impl_device) priv->fallback_modes = g_list_reverse (modes); } -static MetaDeviceFile * -meta_kms_impl_device_open_device_file (MetaKmsImplDevice *impl_device, - const char *path, - GError **error) -{ - MetaKmsImplDevicePrivate *priv = - meta_kms_impl_device_get_instance_private (impl_device); - MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device); - - return klass->open_device_file (impl_device, priv->path, error); -} - -static gboolean -ensure_device_file (MetaKmsImplDevice *impl_device, - GError **error) -{ - MetaKmsImplDevicePrivate *priv = - meta_kms_impl_device_get_instance_private (impl_device); - MetaDeviceFile *device_file; - - if (priv->device_file) - return TRUE; - - device_file = meta_kms_impl_device_open_device_file (impl_device, - priv->path, - error); - if (!device_file) - return FALSE; - - priv->device_file = device_file; - - if (!(priv->flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING)) - { - priv->fd_source = - meta_thread_impl_register_fd (META_THREAD_IMPL (priv->impl), - meta_device_file_get_fd (device_file), - kms_event_dispatch_in_impl, - impl_device); - g_source_set_priority (priv->fd_source, G_PRIORITY_HIGH); - } - - return TRUE; -} - static void ensure_latched_fd_hold (MetaKmsImplDevice *impl_device) { diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h index d32e0663012..dd6a224ed0f 100644 --- a/src/backends/native/meta-kms-impl-device.h +++ b/src/backends/native/meta-kms-impl-device.h @@ -132,6 +132,23 @@ const char * meta_kms_impl_device_get_driver_description (MetaKmsImplDevice *imp const char * meta_kms_impl_device_get_path (MetaKmsImplDevice *impl_device); +gboolean meta_kms_impl_device_lease_objects (MetaKmsImplDevice *impl_device, + GList *connectors, + GList *crtcs, + GList *planes, + int *out_fd, + uint32_t *out_lessee_id, + GError **error); + +gboolean meta_kms_impl_device_revoke_lease (MetaKmsImplDevice *impl_device, + uint32_t lessee_id, + GError **error); + +gboolean meta_kms_impl_device_list_lessees (MetaKmsImplDevice *impl_device, + uint32_t **out_lessee_ids, + int *out_num_lessee_ids, + GError **error); + gboolean meta_kms_impl_device_dispatch (MetaKmsImplDevice *impl_device, GError **error); -- GitLab From 46493a986ba5e1c9c3e3cf58f783424ce86ce2d3 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 17 Oct 2023 18:25:45 +0200 Subject: [PATCH 07/18] udev: Listen for lease events Lease events are sent when drm leases disappear. This event will help us track leased out drm resources. Part-of: --- src/backends/native/meta-kms.c | 21 +++++++++++++++++++++ src/backends/native/meta-udev.c | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c index 47702c556ef..32f3a0088e7 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c @@ -35,6 +35,7 @@ enum { RESOURCES_CHANGED, DEVICE_ADDED, + LEASE_CHANGED, N_SIGNALS }; @@ -48,6 +49,7 @@ struct _MetaKms MetaKmsFlags flags; gulong hotplug_handler_id; + gulong lease_handler_id; gulong removed_handler_id; MetaKmsImpl *impl; @@ -308,6 +310,14 @@ on_udev_device_removed (MetaUdev *udev, handle_hotplug_event (kms, NULL, META_KMS_RESOURCE_CHANGE_NONE); } +static void +on_udev_lease (MetaUdev *udev, + GUdevDevice *udev_device, + MetaKms *kms) +{ + g_signal_emit (kms, signals[LEASE_CHANGED], 0); +} + MetaBackend * meta_kms_get_backend (MetaKms *kms) { @@ -403,6 +413,8 @@ meta_kms_new (MetaBackend *backend, { kms->hotplug_handler_id = g_signal_connect (udev, "hotplug", G_CALLBACK (on_udev_hotplug), kms); + kms->lease_handler_id = + g_signal_connect (udev, "lease", G_CALLBACK (on_udev_lease), kms); } kms->removed_handler_id = @@ -427,6 +439,7 @@ meta_kms_finalize (GObject *object) g_list_free_full (kms->devices, g_object_unref); g_clear_signal_handler (&kms->hotplug_handler_id, udev); + g_clear_signal_handler (&kms->lease_handler_id, udev); g_clear_signal_handler (&kms->removed_handler_id, udev); G_OBJECT_CLASS (meta_kms_parent_class)->finalize (object); @@ -464,6 +477,14 @@ meta_kms_class_init (MetaKmsClass *klass) G_TYPE_NONE, 1, META_TYPE_KMS_DEVICE); + signals[LEASE_CHANGED] = + g_signal_new ("lease-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); + meta_thread_class_register_impl_type (thread_class, META_TYPE_KMS_IMPL); } diff --git a/src/backends/native/meta-udev.c b/src/backends/native/meta-udev.c index 712e642a2e2..f3cd06ee719 100644 --- a/src/backends/native/meta-udev.c +++ b/src/backends/native/meta-udev.c @@ -28,6 +28,7 @@ enum { HOTPLUG, + LEASE, DEVICE_ADDED, DEVICE_REMOVED, @@ -230,6 +231,9 @@ on_uevent (GUdevClient *client, if (g_udev_device_get_property_as_boolean (device, "HOTPLUG")) g_signal_emit (udev, signals[HOTPLUG], 0, device); + + if (g_udev_device_get_property_as_boolean (device, "LEASE")) + g_signal_emit (udev, signals[LEASE], 0, device); } MetaUdev * @@ -291,6 +295,13 @@ meta_udev_class_init (MetaUdevClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_UDEV_TYPE_DEVICE); + signals[LEASE] = + g_signal_new ("lease", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_UDEV_TYPE_DEVICE); signals[DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (object_class), -- GitLab From af8ef6cf02dd421cc4efda56e8974d7929c7fad4 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 16 Jan 2024 16:37:49 +0100 Subject: [PATCH 08/18] native/crtc-kms: Unset config of CRTCs which are not part of a modeset This allows us to keep track when primary and cursor plane assignments on a CRTC are unassigned. With this commit, all planes which are assigned are actually in use and can't be assigned to anything else. We'll make use of that fact when we search for a leasable primary plane. Part-of: --- src/backends/meta-crtc.c | 4 ++++ src/backends/meta-crtc.h | 2 ++ src/backends/native/meta-crtc-kms.c | 21 +++++++++++++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/backends/meta-crtc.c b/src/backends/meta-crtc.c index bca008ea9b4..71b9bcbe9b6 100644 --- a/src/backends/meta-crtc.c +++ b/src/backends/meta-crtc.c @@ -130,6 +130,10 @@ void meta_crtc_unset_config (MetaCrtc *crtc) { MetaCrtcPrivate *priv = meta_crtc_get_instance_private (crtc); + MetaCrtcClass *klass = META_CRTC_GET_CLASS (crtc); + + if (klass->unset_config) + klass->unset_config (crtc); g_clear_pointer (&priv->config, g_free); } diff --git a/src/backends/meta-crtc.h b/src/backends/meta-crtc.h index 68ff58ea84e..3c6abfe3571 100644 --- a/src/backends/meta-crtc.h +++ b/src/backends/meta-crtc.h @@ -56,6 +56,8 @@ struct _MetaCrtcClass const MetaCrtcConfig *config, gpointer backend_private); + void (* unset_config) (MetaCrtc *crtc); + gboolean (* is_leased) (MetaCrtc *crtc); }; diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c index 1b426d76d10..2d2deab1b1e 100644 --- a/src/backends/native/meta-crtc-kms.c +++ b/src/backends/native/meta-crtc-kms.c @@ -206,6 +206,15 @@ meta_crtc_kms_set_gamma_lut (MetaCrtc *crtc, clutter_stage_schedule_update (CLUTTER_STAGE (stage)); } +static gboolean +meta_crtc_kms_is_leased (MetaCrtc *crtc) +{ + MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc); + MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); + + return meta_kms_crtc_is_leased (kms_crtc); +} + typedef struct _CrtcKmsAssignment { MetaKmsPlane *primary_plane; @@ -326,13 +335,16 @@ meta_crtc_kms_set_config (MetaCrtc *crtc, crtc_kms->assigned_cursor_plane = kms_assignment->cursor_plane; } -static gboolean -meta_crtc_kms_is_leased (MetaCrtc *crtc) +static void +meta_crtc_kms_unset_config (MetaCrtc *crtc) { MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc); - MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); - return meta_kms_crtc_is_leased (kms_crtc); + if (meta_crtc_kms_is_leased (crtc)) + return; + + crtc_kms->assigned_primary_plane = NULL; + crtc_kms->assigned_cursor_plane = NULL; } static gboolean @@ -485,6 +497,7 @@ meta_crtc_kms_class_init (MetaCrtcKmsClass *klass) crtc_class->set_gamma_lut = meta_crtc_kms_set_gamma_lut; crtc_class->assign_extra = meta_crtc_kms_assign_extra; crtc_class->set_config = meta_crtc_kms_set_config; + crtc_class->unset_config = meta_crtc_kms_unset_config; crtc_class->is_leased = meta_crtc_kms_is_leased; crtc_native_class->is_transform_handled = meta_crtc_kms_is_transform_handled; -- GitLab From 647f45bfa644f7be1b1520f8c19e30fbe08fde05 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 16 Jan 2024 16:47:16 +0100 Subject: [PATCH 09/18] native/crtc-kms: Don't assign leased primary planes to CRTCs When a plane is leased, it is assigned to a CRTC which is leased. When trying to find a primary plane for a modeset, skip the assigned planes on leased CRTCs to avoid sharing the resources with the leased process. Part-of: --- src/backends/native/meta-crtc-kms.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c index 2d2deab1b1e..90c539196ec 100644 --- a/src/backends/native/meta-crtc-kms.c +++ b/src/backends/native/meta-crtc-kms.c @@ -256,6 +256,25 @@ is_plane_assigned (MetaKmsPlane *plane, return FALSE; } +static gboolean +is_plane_leased (MetaKmsDevice *kms_device, + MetaKmsPlane *kms_plane) +{ + GList *l; + + for (l = meta_kms_device_get_crtcs (kms_device); l; l = l->next) + { + MetaKmsCrtc *kms_crtc = l->data; + MetaCrtcKms *crtc_kms = meta_crtc_kms_from_kms_crtc (kms_crtc); + + if (meta_kms_crtc_is_leased (kms_crtc) && + crtc_kms->assigned_primary_plane == kms_plane) + return TRUE; + } + + return FALSE; +} + static MetaKmsPlane * find_unassigned_plane (MetaCrtcKms *crtc_kms, MetaKmsPlaneType kms_plane_type, @@ -279,6 +298,9 @@ find_unassigned_plane (MetaCrtcKms *crtc_kms, crtc_assignments)) continue; + if (is_plane_leased (kms_device, kms_plane)) + continue; + return kms_plane; } -- GitLab From 4a5fcef38de7f052465bf620c0844c8ec83b8020 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 17 Oct 2023 18:30:25 +0200 Subject: [PATCH 10/18] native/kms-lease: Implement leasing out a set of connectors The manager keeps track of which connectors are leasable in general, which connectors and resources are already part of a lease, and keeps track of when leases get revoked. When leasing out connectors, the required drm resources to drive the connectors are included in the lease as well. Part-of: --- src/backends/native/meta-crtc-kms.c | 9 + src/backends/native/meta-crtc-kms.h | 4 + src/backends/native/meta-drm-lease.c | 962 ++++++++++++++++++++ src/backends/native/meta-drm-lease.h | 57 ++ src/backends/native/meta-kms-crtc-private.h | 3 + src/backends/native/meta-kms-crtc.c | 7 + src/meson.build | 2 + 7 files changed, 1044 insertions(+) create mode 100644 src/backends/native/meta-drm-lease.c create mode 100644 src/backends/native/meta-drm-lease.h diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c index 90c539196ec..f4bd931254c 100644 --- a/src/backends/native/meta-crtc-kms.c +++ b/src/backends/native/meta-crtc-kms.c @@ -357,6 +357,15 @@ meta_crtc_kms_set_config (MetaCrtc *crtc, crtc_kms->assigned_cursor_plane = kms_assignment->cursor_plane; } +void +meta_crtc_kms_assign_planes (MetaCrtcKms *crtc_kms, + MetaKmsPlane *primary_plane, + MetaKmsPlane *cursor_plane) +{ + crtc_kms->assigned_primary_plane = primary_plane; + crtc_kms->assigned_cursor_plane = cursor_plane; +} + static void meta_crtc_kms_unset_config (MetaCrtc *crtc) { diff --git a/src/backends/native/meta-crtc-kms.h b/src/backends/native/meta-crtc-kms.h index c132b990723..38298253462 100644 --- a/src/backends/native/meta-crtc-kms.h +++ b/src/backends/native/meta-crtc-kms.h @@ -41,6 +41,10 @@ MetaKmsPlane * meta_crtc_kms_get_assigned_primary_plane (MetaCrtcKms *crtc_kms); MetaKmsPlane * meta_crtc_kms_get_assigned_cursor_plane (MetaCrtcKms *crtc_kms); +void meta_crtc_kms_assign_planes (MetaCrtcKms *crtc_kms, + MetaKmsPlane *primary_plane, + MetaKmsPlane *cursor_plane); + void meta_crtc_kms_set_mode (MetaCrtcKms *crtc_kms, MetaKmsUpdate *kms_update); diff --git a/src/backends/native/meta-drm-lease.c b/src/backends/native/meta-drm-lease.c new file mode 100644 index 00000000000..07fe304eda3 --- /dev/null +++ b/src/backends/native/meta-drm-lease.c @@ -0,0 +1,962 @@ +/* + * Copyright (C) 2023 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, see . + */ + +#include "config.h" + +#include "backends/native/meta-drm-lease.h" + +#include + +#include "backends/native/meta-crtc-kms.h" +#include "backends/native/meta-kms.h" +#include "backends/native/meta-kms-connector.h" +#include "backends/native/meta-kms-crtc-private.h" +#include "backends/native/meta-kms-device.h" +#include "backends/native/meta-kms-plane.h" + +enum +{ + PROP_0, + + PROP_MANAGER_META_KMS, + + N_PROPS_MANAGER, +}; + +static GParamSpec *props_manager[N_PROPS_MANAGER] = { NULL }; + +enum +{ + MANAGER_DEVICE_ADDED, + MANAGER_DEVICE_REMOVED, + MANAGER_CONNECTOR_ADDED, + MANAGER_CONNECTOR_REMOVED, + + N_SIGNALS_MANAGER, +}; + +static guint signals_manager[N_SIGNALS_MANAGER] = { 0 }; + +enum +{ + LEASE_REVOKED, + + N_SIGNALS_LEASE, +}; + +static guint signals_lease[N_SIGNALS_LEASE] = { 0 }; + +struct _MetaDrmLeaseManager +{ + GObject parent; + + MetaKms *kms; + + gulong resources_changed_handler_id; + gulong lease_changed_handler_id; + + GList *devices; + GHashTable *leases; + GHashTable *connectors; +}; + +G_DEFINE_TYPE (MetaDrmLeaseManager, meta_drm_lease_manager, G_TYPE_OBJECT) + +typedef struct _LeasingKmsAssignment +{ + MetaKmsConnector *connector; + MetaKmsCrtc *crtc; + MetaKmsPlane *primary_plane; + MetaKmsPlane *cursor_plane; +} LeasingKmsAssignment; + +struct _MetaDrmLease +{ + GObject parent; + + uint32_t lessee_id; + int fd; + MetaKmsDevice *kms_device; + GList *assignments; +}; + +G_DEFINE_TYPE (MetaDrmLease, meta_drm_lease, G_TYPE_OBJECT) + +static MetaKmsCrtc * +find_crtc_to_lease (MetaKmsConnector *kms_connector) +{ + MetaKmsDevice *device = meta_kms_connector_get_device (kms_connector); + const MetaKmsConnectorState *connector_state = + meta_kms_connector_get_current_state (kms_connector); + GList *l; + + for (l = meta_kms_device_get_crtcs (device); l; l = l->next) + { + MetaKmsCrtc *kms_crtc = l->data; + MetaCrtcKms *crtc_kms = meta_crtc_kms_from_kms_crtc (kms_crtc); + uint32_t crtc_idx; + + if (meta_crtc_is_leased (META_CRTC (crtc_kms))) + continue; + + if (meta_crtc_get_outputs (META_CRTC (crtc_kms)) != NULL) + continue; + + crtc_idx = meta_kms_crtc_get_idx (kms_crtc); + if (!(connector_state->common_possible_crtcs & (1 << crtc_idx))) + continue; + + return kms_crtc; + } + + return NULL; +} + +static gboolean +is_plane_assigned (MetaKmsDevice *kms_device, + MetaKmsPlane *kms_plane) +{ + GList *l; + + for (l = meta_kms_device_get_crtcs (kms_device); l; l = l->next) + { + MetaKmsCrtc *kms_crtc = l->data; + MetaCrtcKms *crtc_kms = meta_crtc_kms_from_kms_crtc (kms_crtc); + + if (meta_crtc_kms_get_assigned_primary_plane (crtc_kms) == kms_plane) + return TRUE; + } + + return FALSE; +} + +static MetaKmsPlane * +find_plane_to_lease (MetaKmsCrtc *kms_crtc, + MetaKmsPlaneType plane_type) +{ + MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc); + GList *l; + + for (l = meta_kms_device_get_planes (kms_device); l; l = l->next) + { + MetaKmsPlane *kms_plane = l->data; + + if (meta_kms_plane_get_plane_type (kms_plane) != plane_type) + continue; + + if (!meta_kms_plane_is_usable_with (kms_plane, kms_crtc)) + continue; + + if (is_plane_assigned (kms_device, kms_plane)) + continue; + + return kms_plane; + } + + return NULL; +} + +static gboolean +find_resources_to_lease (MetaDrmLeaseManager *lease_manager, + MetaKmsDevice *kms_device, + GList *connectors, + GList **out_assignments, + GList **out_crtcs, + GList **out_planes, + GError **error) +{ + MetaKms *kms = lease_manager->kms; + g_autoptr (GList) assignments = NULL; + g_autoptr (GList) crtcs = NULL; + g_autoptr (GList) planes = NULL; + GList *available_devices; + GList *available_connectors; + GList *l; + + if (!kms_device) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Cannot create lease without device"); + return FALSE; + } + + if (!connectors) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Cannot create lease without connectors"); + return FALSE; + } + + available_devices = meta_kms_get_devices (kms); + if (!g_list_find (available_devices, kms_device)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Failed to find KMS device %s", + meta_kms_device_get_path (kms_device)); + return FALSE; + } + + available_connectors = meta_kms_device_get_connectors (kms_device); + + for (l = connectors; l; l = l->next) + { + MetaKmsConnector *connector = l->data; + MetaKmsDevice *connector_device; + + if (!g_list_find (available_connectors, connector) || + !meta_kms_connector_is_for_lease (connector)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Failed to find connector %u (%s)", + meta_kms_connector_get_id (connector), + meta_kms_device_get_path (kms_device)); + return FALSE; + } + + connector_device = meta_kms_connector_get_device (connector); + if (connector_device != kms_device) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Cannot create lease on multiple devices"); + return FALSE; + } + } + + for (l = connectors; l; l = l->next) + { + MetaKmsConnector *connector = l->data; + LeasingKmsAssignment *assignment; + MetaKmsCrtc *crtc; + MetaKmsPlane *primary_plane; + MetaKmsPlane *cursor_plane; + + crtc = find_crtc_to_lease (connector); + if (!crtc) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Failed to find CRTC to lease with connector %u (%s)", + meta_kms_connector_get_id (connector), + meta_kms_device_get_path (kms_device)); + return FALSE; + } + + crtcs = g_list_append (crtcs, crtc); + + primary_plane = find_plane_to_lease (crtc, META_KMS_PLANE_TYPE_PRIMARY); + if (!primary_plane) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Failed to find primary plane " + "to lease with connector %u (%s)", + meta_kms_connector_get_id (connector), + meta_kms_device_get_path (kms_device)); + return FALSE; + } + + planes = g_list_append (planes, primary_plane); + + cursor_plane = find_plane_to_lease (crtc, META_KMS_PLANE_TYPE_CURSOR); + if (!cursor_plane) + { + g_warning ("Failed to find cursor plane " + "to lease with connector %u (%s)", + meta_kms_connector_get_id (connector), + meta_kms_device_get_path (kms_device)); + } + else + { + planes = g_list_append (planes, cursor_plane); + } + + assignment = g_new0 (LeasingKmsAssignment, 1); + assignment->connector = connector; + assignment->crtc = crtc; + assignment->primary_plane = primary_plane; + assignment->cursor_plane = cursor_plane; + + assignments = g_list_append (assignments, assignment); + } + + *out_assignments = g_steal_pointer (&assignments); + *out_crtcs = g_steal_pointer (&crtcs); + *out_planes = g_steal_pointer (&planes); + return TRUE; +} + +uint32_t +meta_drm_lease_get_id (MetaDrmLease *lease) +{ + return lease->lessee_id; +} + +int +meta_drm_lease_steal_fd (MetaDrmLease *lease) +{ + int fd = lease->fd; + lease->fd = -1; + return fd; +} + +gboolean +meta_drm_lease_is_active (MetaDrmLease *lease) +{ + return lease->lessee_id != 0; +} + +static void +meta_drm_lease_assign (MetaDrmLease *lease) +{ + GList *l; + + for (l = lease->assignments; l; l = l->next) + { + LeasingKmsAssignment *assignment = l->data; + MetaCrtcKms *crtc_kms = meta_crtc_kms_from_kms_crtc (assignment->crtc); + + meta_kms_crtc_set_is_leased (assignment->crtc, TRUE); + meta_crtc_kms_assign_planes (crtc_kms, + assignment->primary_plane, + assignment->cursor_plane); + } +} + +static void +meta_drm_lease_unassign (MetaDrmLease *lease) +{ + GList *l; + + for (l = lease->assignments; l; l = l->next) + { + LeasingKmsAssignment *assignment = l->data; + MetaCrtcKms *crtc_kms = meta_crtc_kms_from_kms_crtc (assignment->crtc); + + meta_kms_crtc_set_is_leased (assignment->crtc, FALSE); + meta_crtc_kms_assign_planes (crtc_kms, NULL, NULL); + } +} + +static void +mark_revoked (MetaDrmLease *lease) +{ + meta_drm_lease_unassign (lease); + + g_signal_emit (lease, signals_lease[LEASE_REVOKED], 0); + lease->lessee_id = 0; +} + +void +meta_drm_lease_revoke (MetaDrmLease *lease) +{ + g_autoptr (GError) error; + + if (!lease->lessee_id) + return; + + if (!meta_kms_device_revoke_lease (lease->kms_device, lease->lessee_id, &error)) + { + g_warning ("Failed to revoke DRM lease on %s: %s", + meta_kms_device_get_path (lease->kms_device), + error->message); + return; + } + + mark_revoked (lease); +} + +static void +meta_drm_lease_disappeared (MetaDrmLease *lease) +{ + mark_revoked (lease); +} + +static void +meta_drm_lease_dispose (GObject *object) +{ + MetaDrmLease *lease = META_DRM_LEASE (object); + + g_clear_object (&lease->kms_device); + + if (lease->assignments) + { + g_list_free_full (lease->assignments, g_free); + lease->assignments = NULL; + } + + G_OBJECT_CLASS (meta_drm_lease_parent_class)->dispose (object); +} + +static void +meta_drm_lease_finalize (GObject *object) +{ + MetaDrmLease *lease = META_DRM_LEASE (object); + + close (lease->fd); + + G_OBJECT_CLASS (meta_drm_lease_parent_class)->finalize (object); +} + +static void +meta_drm_lease_class_init (MetaDrmLeaseClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = meta_drm_lease_dispose; + object_class->finalize = meta_drm_lease_finalize; + + signals_lease[LEASE_REVOKED] = + g_signal_new ("revoked", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + +static void +meta_drm_lease_init (MetaDrmLease *lease) +{ +} + +static void +on_lease_revoked (MetaDrmLease *lease, + MetaDrmLeaseManager *lease_manager) +{ + GHashTableIter iter; + MetaKmsConnector *connector; + MetaDrmLease *other_lease; + + g_signal_handlers_disconnect_by_func (lease, + on_lease_revoked, + lease_manager); + + g_hash_table_iter_init (&iter, lease_manager->connectors); + while (g_hash_table_iter_next (&iter, + (gpointer *)&connector, + (gpointer *)&other_lease)) + { + if (lease == other_lease) + g_hash_table_insert (lease_manager->connectors, connector, NULL); + } + + g_hash_table_remove (lease_manager->leases, + GUINT_TO_POINTER (lease->lessee_id)); +} + +MetaDrmLease * +meta_drm_lease_manager_lease_connectors (MetaDrmLeaseManager *lease_manager, + MetaKmsDevice *kms_device, + GList *connectors, + GError **error) +{ + MetaDrmLease *lease; + g_autoptr (GList) assignments = NULL; + g_autoptr (GList) crtcs = NULL; + g_autoptr (GList) planes = NULL; + int fd; + uint32_t lessee_id; + GList *l; + + if (!find_resources_to_lease (lease_manager, + kms_device, connectors, + &assignments, &crtcs, &planes, + error)) + return NULL; + + if (!meta_kms_device_lease_objects (kms_device, + connectors, crtcs, planes, + &fd, &lessee_id, + error)) + return NULL; + + lease = g_object_new (META_TYPE_DRM_LEASE, NULL); + lease->lessee_id = lessee_id; + lease->fd = fd; + lease->kms_device = g_object_ref (kms_device); + lease->assignments = g_steal_pointer (&assignments); + + meta_drm_lease_assign (lease); + + g_signal_connect_after (lease, "revoked", G_CALLBACK (on_lease_revoked), + lease_manager); + + for (l = connectors; l; l = l->next) + { + MetaKmsConnector *connector = l->data; + + g_hash_table_insert (lease_manager->connectors, + connector, lease); + } + + g_hash_table_insert (lease_manager->leases, + GUINT_TO_POINTER (lessee_id), g_object_ref (lease)); + + return lease; +} + +GList * +meta_drm_lease_manager_get_devices (MetaDrmLeaseManager *lease_manager) +{ + return lease_manager->devices; +} + +GList * +meta_drm_lease_manager_get_connectors (MetaDrmLeaseManager *lease_manager, + MetaKmsDevice *kms_device) +{ + GHashTableIter iter; + MetaKmsConnector *connector; + GList *connectors = NULL; + + g_hash_table_iter_init (&iter, lease_manager->connectors); + while (g_hash_table_iter_next (&iter, (gpointer *)&connector, NULL)) + { + if (meta_kms_connector_get_device (connector) == kms_device) + connectors = g_list_append (connectors, connector); + } + + return connectors; +} + +MetaKmsConnector * +meta_drm_lease_manager_get_connector_from_id (MetaDrmLeaseManager *lease_manager, + uint32_t connector_id) +{ + GHashTableIter iter; + MetaKmsConnector *connector; + + g_hash_table_iter_init (&iter, lease_manager->connectors); + while (g_hash_table_iter_next (&iter, (gpointer *)&connector, NULL)) + { + if (meta_kms_connector_get_id (connector) == connector_id) + return connector; + } + + return NULL; +} + +MetaDrmLease * +meta_drm_lease_manager_get_lease_from_connector (MetaDrmLeaseManager *lease_manager, + MetaKmsConnector *kms_connector) +{ + return g_hash_table_lookup (lease_manager->connectors, kms_connector); +} + + + +MetaDrmLease * +meta_drm_lease_manager_get_lease_from_id (MetaDrmLeaseManager *lease_manager, + uint32_t lessee_id) +{ + return g_hash_table_lookup (lease_manager->leases, + GUINT_TO_POINTER (lessee_id)); +} + +static void +update_devices (MetaDrmLeaseManager *lease_manager, + GList **added_devices_out, + GList **removed_devices_out) +{ + g_autoptr (GList) added_devices = NULL; + GList *new_devices; + GList *l; + + new_devices = g_list_copy (meta_kms_get_devices (lease_manager->kms)); + + for (l = new_devices; l; l = l->next) + { + MetaKmsDevice *kms_device = l->data; + + if (g_list_find (lease_manager->devices, kms_device)) + { + lease_manager->devices = g_list_remove (lease_manager->devices, + kms_device); + } + else + { + added_devices = g_list_append (added_devices, kms_device); + } + } + + *removed_devices_out = g_steal_pointer (&lease_manager->devices); + *added_devices_out = g_steal_pointer (&added_devices); + lease_manager->devices = new_devices; +} + +static void +update_connectors (MetaDrmLeaseManager *lease_manager, + GList **added_connectors_out, + GList **removed_connectors_out, + GList **leases_to_revoke_out) +{ + MetaKms *kms = lease_manager->kms; + GHashTable *new_connectors; + MetaDrmLease *lease = NULL; + GList *l; + GList *o; + g_autoptr (GList) added_connectors = NULL; + g_autoptr (GList) removed_connectors = NULL; + g_autoptr (GList) leases_to_revoke = NULL; + MetaKmsConnector *kms_connector; + GHashTableIter iter; + + new_connectors = g_hash_table_new_similar (lease_manager->connectors); + + for (l = meta_kms_get_devices (kms); l; l = l->next) + { + MetaKmsDevice *kms_device = l->data; + + for (o = meta_kms_device_get_connectors (kms_device); o; o = o->next) + { + kms_connector = o->data; + + if (!meta_kms_connector_is_for_lease (kms_connector)) + continue; + + if (!g_hash_table_steal_extended (lease_manager->connectors, + kms_connector, + NULL, (gpointer *) &lease)) + added_connectors = g_list_append (added_connectors, kms_connector); + g_hash_table_insert (new_connectors, kms_connector, lease); + } + } + + g_hash_table_iter_init (&iter, lease_manager->connectors); + while (g_hash_table_iter_next (&iter, (gpointer *)&kms_connector, NULL)) + { + removed_connectors = g_list_append (removed_connectors, kms_connector); + + lease = meta_drm_lease_manager_get_lease_from_connector (lease_manager, + kms_connector); + if (lease && meta_drm_lease_is_active (lease)) + leases_to_revoke = g_list_append (leases_to_revoke, lease); + } + + g_clear_pointer (&lease_manager->connectors, g_hash_table_unref); + lease_manager->connectors = new_connectors; + + *added_connectors_out = g_steal_pointer (&added_connectors); + *removed_connectors_out = g_steal_pointer (&removed_connectors); + *leases_to_revoke_out = g_steal_pointer (&leases_to_revoke); +} + +static void +update_resources (MetaDrmLeaseManager *lease_manager) +{ + g_autoptr (GList) added_devices = NULL; + g_autoptr (GList) removed_devices = NULL; + g_autoptr (GList) added_connectors = NULL; + g_autoptr (GList) removed_connectors = NULL; + g_autoptr (GList) leases_to_revoke = NULL; + GList *l; + + update_devices (lease_manager, &added_devices, &removed_devices); + update_connectors (lease_manager, &added_connectors, &removed_connectors, + &leases_to_revoke); + + for (l = added_devices; l; l = l->next) + { + MetaKmsDevice *kms_device = l->data; + + g_object_ref (kms_device); + g_signal_emit (lease_manager, signals_manager[MANAGER_DEVICE_ADDED], + 0, kms_device); + } + + for (l = added_connectors; l; l = l->next) + { + MetaKmsConnector *kms_connector = l->data; + gboolean is_last_connector_update = FALSE; + + if (g_list_length (removed_connectors) == 0 && + kms_connector == g_list_last (added_connectors)->data) + is_last_connector_update = TRUE; + + g_object_ref (kms_connector); + g_signal_emit (lease_manager, signals_manager[MANAGER_CONNECTOR_ADDED], + 0, kms_connector, is_last_connector_update); + } + + for (l = removed_connectors; l; l = l->next) + { + MetaKmsConnector *kms_connector = l->data; + gboolean is_last_connector_update = FALSE; + + if (kms_connector == g_list_last (removed_connectors)->data) + is_last_connector_update = TRUE; + + g_signal_emit (lease_manager, signals_manager[MANAGER_CONNECTOR_REMOVED], + 0, kms_connector, is_last_connector_update); + g_object_unref (kms_connector); + } + + for (l = leases_to_revoke; l; l = l->next) + { + MetaDrmLease *lease = l->data; + + meta_drm_lease_revoke (lease); + } + + for (l = removed_devices; l; l = l->next) + { + MetaKmsDevice *kms_device = l->data; + + g_signal_emit (lease_manager, signals_manager[MANAGER_DEVICE_REMOVED], + 0, kms_device); + g_object_unref (kms_device); + } +} + +static void +lease_disappeared (MetaDrmLeaseManager *lease_manager, + MetaDrmLease *lease) +{ + GList *l; + + for (l = lease->assignments; l; l = l->next) + { + LeasingKmsAssignment *assignment = l->data; + MetaKmsConnector *kms_connector = assignment->connector; + + if (g_hash_table_lookup_extended (lease_manager->connectors, + kms_connector, + NULL, NULL)) + g_hash_table_insert (lease_manager->connectors, kms_connector, NULL); + } + + meta_drm_lease_disappeared (lease); +} + +static gboolean +did_lease_disappear (MetaDrmLease *lease, + uint32_t *lessees, + int num_lessees, + MetaKmsDevice *kms_device) +{ + int i; + + if (lease->kms_device != kms_device) + return FALSE; + + for (i = 0; i < num_lessees; i++) + { + if (lease->lessee_id == lessees[i]) + return FALSE; + } + + return TRUE; +} + +static void +update_leases (MetaDrmLeaseManager *lease_manager) +{ + MetaKms *kms = lease_manager->kms; + MetaDrmLease *lease; + GList *l; + g_autoptr (GList) disappeared_leases = NULL; + + for (l = meta_kms_get_devices (kms); l; l = l->next) + { + MetaKmsDevice *kms_device = l->data; + g_autofree uint32_t *lessees = NULL; + int num_lessees; + g_autoptr (GError) error = NULL; + GHashTableIter iter; + + if (!meta_kms_device_list_lessees (kms_device, + &lessees, &num_lessees, + &error)) + { + g_warning ("Failed to list leases: %s", error->message); + continue; + } + + g_hash_table_iter_init (&iter, lease_manager->leases); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&lease)) + { + if (did_lease_disappear (lease, lessees, num_lessees, kms_device)) + disappeared_leases = g_list_append (disappeared_leases, lease); + } + } + + for (l = disappeared_leases; l; l = l->next) + { + lease = l->data; + + lease_disappeared (lease_manager, lease); + } +} + +static void +on_resources_changed (MetaKms *kms, + MetaKmsResourceChanges changes, + MetaDrmLeaseManager *lease_manager) +{ + if (changes != META_KMS_RESOURCE_CHANGE_FULL) + return; + + update_resources (lease_manager); +} + +static void +on_lease_changed (MetaKms *kms, + MetaDrmLeaseManager *lease_manager) +{ + update_leases (lease_manager); +} + +static void +meta_drm_lease_manager_constructed (GObject *object) +{ + MetaDrmLeaseManager *lease_manager = META_DRM_LEASE_MANAGER (object); + MetaKms *kms = lease_manager->kms; + + lease_manager->resources_changed_handler_id = + g_signal_connect (kms, "resources-changed", + G_CALLBACK (on_resources_changed), + lease_manager); + lease_manager->lease_changed_handler_id = + g_signal_connect (kms, "lease-changed", + G_CALLBACK (on_lease_changed), + lease_manager); + + lease_manager->leases = + g_hash_table_new_full (NULL, NULL, + NULL, + (GDestroyNotify) g_object_unref); + + lease_manager->connectors = + g_hash_table_new_full (NULL, NULL, + NULL, NULL); + + update_resources (lease_manager); + + G_OBJECT_CLASS (meta_drm_lease_manager_parent_class)->constructed (object); +} + +static void +meta_drm_lease_manager_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaDrmLeaseManager *lease_manager = META_DRM_LEASE_MANAGER (object); + switch (prop_id) + { + case PROP_MANAGER_META_KMS: + lease_manager->kms = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_drm_lease_manager_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaDrmLeaseManager *lease_manager = META_DRM_LEASE_MANAGER (object); + switch (prop_id) + { + case PROP_MANAGER_META_KMS: + g_value_set_object (value, lease_manager->kms); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_drm_lease_manager_dispose (GObject *object) +{ + MetaDrmLeaseManager *lease_manager = META_DRM_LEASE_MANAGER (object); + MetaKms *kms = lease_manager->kms; + + g_clear_signal_handler (&lease_manager->resources_changed_handler_id, kms); + g_clear_signal_handler (&lease_manager->lease_changed_handler_id, kms); + + g_list_free_full (g_steal_pointer (&lease_manager->devices), g_object_unref); + g_clear_pointer (&lease_manager->leases, g_hash_table_unref); + g_clear_pointer (&lease_manager->connectors, g_hash_table_unref); + + G_OBJECT_CLASS (meta_drm_lease_manager_parent_class)->dispose (object); +} + +static void +meta_drm_lease_manager_class_init (MetaDrmLeaseManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = meta_drm_lease_manager_constructed; + object_class->set_property = meta_drm_lease_manager_set_property; + object_class->get_property = meta_drm_lease_manager_get_property; + object_class->dispose = meta_drm_lease_manager_dispose; + + props_manager[PROP_MANAGER_META_KMS] = + g_param_spec_object ("meta-kms", NULL, NULL, + META_TYPE_KMS, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, + N_PROPS_MANAGER, props_manager); + + signals_manager[MANAGER_DEVICE_ADDED] = + g_signal_new ("device-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 1, + META_TYPE_KMS_DEVICE); + + signals_manager[MANAGER_DEVICE_REMOVED] = + g_signal_new ("device-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 1, + META_TYPE_KMS_DEVICE); + + signals_manager[MANAGER_CONNECTOR_ADDED] = + g_signal_new ("connector-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 2, + META_TYPE_KMS_CONNECTOR, + G_TYPE_BOOLEAN); + + signals_manager[MANAGER_CONNECTOR_REMOVED] = + g_signal_new ("connector-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 2, + META_TYPE_KMS_CONNECTOR, + G_TYPE_BOOLEAN); +} + +static void +meta_drm_lease_manager_init (MetaDrmLeaseManager *lease_manager) +{ +} diff --git a/src/backends/native/meta-drm-lease.h b/src/backends/native/meta-drm-lease.h new file mode 100644 index 00000000000..65f348c4538 --- /dev/null +++ b/src/backends/native/meta-drm-lease.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 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, see . + */ + +#pragma once + +#include + +#include "backends/native/meta-backend-native.h" + +#define META_TYPE_DRM_LEASE (meta_drm_lease_get_type ()) +G_DECLARE_FINAL_TYPE (MetaDrmLease, meta_drm_lease, + META, DRM_LEASE, GObject) + +#define META_TYPE_DRM_LEASE_MANAGER (meta_drm_lease_manager_get_type ()) +G_DECLARE_FINAL_TYPE (MetaDrmLeaseManager, meta_drm_lease_manager, + META, DRM_LEASE_MANAGER, GObject) + +uint32_t meta_drm_lease_get_id (MetaDrmLease *lease); + +int meta_drm_lease_steal_fd (MetaDrmLease *lease); + +gboolean meta_drm_lease_is_active (MetaDrmLease *lease); + +void meta_drm_lease_revoke (MetaDrmLease *lease); + +MetaDrmLease * meta_drm_lease_manager_lease_connectors (MetaDrmLeaseManager *lease_manager, + MetaKmsDevice *kms_device, + GList *connectors, + GError **error); + +GList * meta_drm_lease_manager_get_devices (MetaDrmLeaseManager *lease_manager); + +GList * meta_drm_lease_manager_get_connectors (MetaDrmLeaseManager *lease_manager, + MetaKmsDevice *kms_device); + +MetaKmsConnector * meta_drm_lease_manager_get_connector_from_id (MetaDrmLeaseManager *lease_manager, + uint32_t connector_id); + +MetaDrmLease * meta_drm_lease_manager_get_lease_from_connector (MetaDrmLeaseManager *lease_manager, + MetaKmsConnector *kms_connector); + +MetaDrmLease * meta_drm_lease_manager_get_lease_from_id (MetaDrmLeaseManager *lease_manager, + uint32_t lessee_id); diff --git a/src/backends/native/meta-kms-crtc-private.h b/src/backends/native/meta-kms-crtc-private.h index 299482d6ec6..237a736257b 100644 --- a/src/backends/native/meta-kms-crtc-private.h +++ b/src/backends/native/meta-kms-crtc-private.h @@ -58,3 +58,6 @@ gboolean meta_kms_crtc_determine_deadline (MetaKmsCrtc *crtc, int64_t *out_next_deadline_us, int64_t *out_next_presentation_us, GError **error); + +void meta_kms_crtc_set_is_leased (MetaKmsCrtc *crtc, + gboolean leased); diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c index 6ca1c08d318..40237fff9cd 100644 --- a/src/backends/native/meta-kms-crtc.c +++ b/src/backends/native/meta-kms-crtc.c @@ -115,6 +115,13 @@ meta_kms_crtc_is_leased (MetaKmsCrtc *crtc) return crtc->is_leased; } +void +meta_kms_crtc_set_is_leased (MetaKmsCrtc *crtc, + gboolean leased) +{ + crtc->is_leased = leased; +} + static void read_crtc_gamma (MetaKmsCrtc *crtc, MetaKmsCrtcState *crtc_state, diff --git a/src/meson.build b/src/meson.build index b4f9a2a596d..0eee9bc2405 100644 --- a/src/meson.build +++ b/src/meson.build @@ -808,6 +808,8 @@ if have_native_backend 'backends/native/meta-kms-impl-device.h', 'backends/native/meta-kms-impl.c', 'backends/native/meta-kms-impl.h', + 'backends/native/meta-drm-lease.c', + 'backends/native/meta-drm-lease.h', 'backends/native/meta-kms-mode.c', 'backends/native/meta-kms-mode.h', 'backends/native/meta-kms-page-flip.c', -- GitLab From 4e4d88e5378f51ba3c40aef7de1d2cff10e62fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Fri, 19 Apr 2024 16:54:40 +0200 Subject: [PATCH 11/18] kms/impl-device: Add function to get a non-master fd Add meta_kms_impl_device_open_non_privileged_fd() that returns a non-master file descriptor for a MetaKmsImplDevice. It'll be required to implement wp_drm_lease_device_v1_send_drm_fd() in a future commit. Part-of: --- src/backends/native/meta-kms-impl-device.c | 47 ++++++++++++++++++++++ src/backends/native/meta-kms-impl-device.h | 2 + 2 files changed, 49 insertions(+) diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index 3465857fea5..07c7f6daf59 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -20,6 +20,7 @@ #include "backends/native/meta-kms-impl-device.h" #include +#include #include #include #include @@ -1193,6 +1194,52 @@ meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device) return meta_device_file_get_fd (priv->device_file); } +/** + * meta_kms_impl_device_open_non_privileged_fd: + * @impl_device: a #MetaKmsImplDevice object + * + * Returns a non-master file descriptor for the given impl_device. The caller is + * responsable of closing the file descriptor. + * + * On error, returns a negative value. + */ +int +meta_kms_impl_device_open_non_privileged_fd (MetaKmsImplDevice *impl_device) +{ + int fd; + const char *path; + MetaKmsImplDevicePrivate *priv = + meta_kms_impl_device_get_instance_private (impl_device); + + if (!priv->device_file) + return -1; + + path = meta_device_file_get_path (priv->device_file); + + fd = open (path, O_RDWR | O_CLOEXEC); + if (fd < 0) + { + meta_topic (META_DEBUG_KMS, + "Error getting non-master fd for device at '%s': %s", + path, + g_strerror (errno)); + return -1; + } + + if (drmIsMaster (fd)) + { + if (drmDropMaster (fd) < 0) + { + meta_topic (META_DEBUG_KMS, + "Error dropping master for device at '%s'", + path); + return -1; + } + } + + return fd; +} + /** * meta_kms_impl_device_get_signaled_sync_file: * @impl_device: a #MetaKmsImplDevice object diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h index dd6a224ed0f..0bbbefa7556 100644 --- a/src/backends/native/meta-kms-impl-device.h +++ b/src/backends/native/meta-kms-impl-device.h @@ -165,6 +165,8 @@ void meta_kms_impl_device_hold_fd (MetaKmsImplDevice *impl_device); void meta_kms_impl_device_unhold_fd (MetaKmsImplDevice *impl_device); +int meta_kms_impl_device_open_non_privileged_fd (MetaKmsImplDevice *impl_device); + int meta_kms_impl_device_get_signaled_sync_file (MetaKmsImplDevice *impl_device); MetaKmsResourceChanges meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device, -- GitLab From 536c52bdb10c195ddaa85541814ef7537db41eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 9 May 2024 11:35:02 +0200 Subject: [PATCH 12/18] wayland/drm-lease: Advertise initial devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Advertise one wp_drm_lease_device_v1 global for each DRM node. Co-authored-by: José Expósito Part-of: --- src/meson.build | 8 ++ src/wayland/meta-wayland-drm-lease.c | 208 +++++++++++++++++++++++++++ src/wayland/meta-wayland-drm-lease.h | 25 ++++ src/wayland/meta-wayland-types.h | 2 + src/wayland/meta-wayland-versions.h | 1 + 5 files changed, 244 insertions(+) create mode 100644 src/wayland/meta-wayland-drm-lease.c create mode 100644 src/wayland/meta-wayland-drm-lease.h diff --git a/src/meson.build b/src/meson.build index 0eee9bc2405..6126cc91dea 100644 --- a/src/meson.build +++ b/src/meson.build @@ -725,6 +725,13 @@ if have_wayland 'wayland/meta-xwayland-surface.h', ] endif + + if have_native_backend + mutter_sources += [ + 'wayland/meta-wayland-drm-lease.c', + 'wayland/meta-wayland-drm-lease.h', + ] + endif endif if have_native_backend @@ -1066,6 +1073,7 @@ if have_wayland # - protocol stability ('private', 'stable' or 'unstable') # - protocol version (if stability is 'unstable') wayland_protocols = [ + ['drm-lease', 'staging', 'v1', ], ['fractional-scale', 'staging', 'v1', ], ['gtk-shell', 'private', ], ['idle-inhibit', 'unstable', 'v1', ], diff --git a/src/wayland/meta-wayland-drm-lease.c b/src/wayland/meta-wayland-drm-lease.c new file mode 100644 index 00000000000..ab231f41b13 --- /dev/null +++ b/src/wayland/meta-wayland-drm-lease.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2016 Red Hat Inc. + * Copyright (C) 2017 Intel Corporation + * Copyright (C) 2018,2019 DisplayLink (UK) Ltd. + * + * 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 "wayland/meta-wayland-drm-lease.h" + +#include + +#include "backends/native/meta-backend-native.h" +#include "backends/native/meta-drm-lease.h" +#include "backends/native/meta-kms-connector.h" +#include "backends/native/meta-kms-device.h" +#include "backends/native/meta-kms-device-private.h" +#include "backends/native/meta-kms-impl-device.h" +#include "backends/native/meta-kms.h" +#include "backends/edid.h" +#include "wayland/meta-wayland-private.h" + +#include "drm-lease-v1-server-protocol.h" + +struct _MetaWaylandDrmLeaseManager +{ + MetaWaylandCompositor *compositor; + MetaDrmLeaseManager *drm_lease_manager; + + /* Key: MetaKmsDevice *kms_device + * Value: MetaWaylandDrmLeaseDevice *lease_device + */ + GHashTable *devices; +}; + +typedef struct _MetaWaylandDrmLeaseDevice +{ + MetaWaylandDrmLeaseManager *lease_manager; + + struct wl_global *global; + MetaKmsDevice *kms_device; + + GList *resources; +} MetaWaylandDrmLeaseDevice; + +static void +meta_wayland_drm_lease_device_free (MetaWaylandDrmLeaseDevice *lease_device) +{ + g_object_unref (lease_device->kms_device); +} + +static void +meta_wayland_drm_lease_device_release (MetaWaylandDrmLeaseDevice *lease_device) +{ + g_rc_box_release_full (lease_device, + (GDestroyNotify) meta_wayland_drm_lease_device_free); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaWaylandDrmLeaseDevice, + meta_wayland_drm_lease_device_release); + +static void +wp_drm_lease_device_create_lease_request (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ +} + +static void +wp_drm_lease_device_release (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct wp_drm_lease_device_v1_interface drm_lease_device_implementation = { + wp_drm_lease_device_create_lease_request, + wp_drm_lease_device_release, +}; + +static void +wp_drm_lease_device_destructor (struct wl_resource *resource) +{ + MetaWaylandDrmLeaseDevice *lease_device = + wl_resource_get_user_data (resource); + + lease_device->resources = g_list_remove (lease_device->resources, resource); + meta_wayland_drm_lease_device_release (lease_device); +} + +static void +lease_device_bind (struct wl_client *client, + void *user_data, + uint32_t version, + uint32_t id) +{ + MetaWaylandDrmLeaseDevice *lease_device = user_data; + struct wl_resource *resource; + + resource = wl_resource_create (client, &wp_drm_lease_device_v1_interface, + version, id); + wl_resource_set_implementation (resource, + &drm_lease_device_implementation, + g_rc_box_acquire (lease_device), + wp_drm_lease_device_destructor); + + lease_device->resources = g_list_prepend (lease_device->resources, resource); +} + +static MetaWaylandDrmLeaseDevice * +meta_wayland_drm_lease_device_new (MetaWaylandDrmLeaseManager *lease_manager, + MetaKmsDevice *kms_device) +{ + struct wl_display *wayland_display = + meta_wayland_compositor_get_wayland_display (lease_manager->compositor); + MetaWaylandDrmLeaseDevice *lease_device; + + lease_device = g_rc_box_new0 (MetaWaylandDrmLeaseDevice); + lease_device->lease_manager = lease_manager; + lease_device->kms_device = g_object_ref (kms_device); + lease_device->global = wl_global_create (wayland_display, + &wp_drm_lease_device_v1_interface, + META_WP_DRM_LEASE_DEVICE_V1_VERSION, + lease_device, + lease_device_bind); + + return lease_device; +} + +static void +meta_wayland_drm_lease_manager_add_device (MetaKmsDevice *kms_device, + MetaWaylandDrmLeaseManager *lease_manager) +{ + g_autoptr (MetaWaylandDrmLeaseDevice) lease_device = NULL; + + lease_device = meta_wayland_drm_lease_device_new (lease_manager, kms_device); + g_hash_table_insert (lease_manager->devices, + kms_device, + g_steal_pointer (&lease_device)); +} + +static MetaWaylandDrmLeaseManager * +meta_wayland_drm_lease_manager_new (MetaWaylandCompositor *compositor) +{ + MetaContext *context = meta_wayland_compositor_get_context (compositor); + MetaBackend *backend = meta_context_get_backend (context); + MetaBackendNative *backend_native; + MetaKms *kms; + MetaWaylandDrmLeaseManager *lease_manager; + MetaDrmLeaseManager *drm_lease_manager; + + if (!META_IS_BACKEND_NATIVE (backend)) + return NULL; + + backend_native = META_BACKEND_NATIVE (backend); + kms = meta_backend_native_get_kms (backend_native); + drm_lease_manager = g_object_new (META_TYPE_DRM_LEASE_MANAGER, + "meta-kms", kms, + NULL); + + lease_manager = g_new0 (MetaWaylandDrmLeaseManager, 1); + lease_manager->compositor = compositor; + lease_manager->drm_lease_manager = drm_lease_manager; + lease_manager->devices = + g_hash_table_new_full (NULL, NULL, + NULL, + (GDestroyNotify) meta_wayland_drm_lease_device_release); + + g_list_foreach (meta_drm_lease_manager_get_devices (drm_lease_manager), + (GFunc) meta_wayland_drm_lease_manager_add_device, + lease_manager); + + return lease_manager; +} + +static void +meta_wayland_drm_lease_manager_free (gpointer data) +{ + MetaWaylandDrmLeaseManager *lease_manager = data; + + g_clear_pointer (&lease_manager->devices, g_hash_table_unref); + g_clear_pointer (&lease_manager->drm_lease_manager, g_object_unref); + g_free (lease_manager); +} + +void +meta_wayland_drm_lease_manager_init (MetaWaylandCompositor *compositor) +{ + g_object_set_data_full (G_OBJECT (compositor), "-meta-wayland-drm-lease", + meta_wayland_drm_lease_manager_new (compositor), + meta_wayland_drm_lease_manager_free); +} diff --git a/src/wayland/meta-wayland-drm-lease.h b/src/wayland/meta-wayland-drm-lease.h new file mode 100644 index 00000000000..c223daca8e7 --- /dev/null +++ b/src/wayland/meta-wayland-drm-lease.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 Red Hat Inc. + * + * 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. + * + */ + +#pragma once + +#include "wayland/meta-wayland-types.h" + +void meta_wayland_drm_lease_manager_init (MetaWaylandCompositor *compositor); diff --git a/src/wayland/meta-wayland-types.h b/src/wayland/meta-wayland-types.h index 4f224a90045..99b2dc5ad56 100644 --- a/src/wayland/meta-wayland-types.h +++ b/src/wayland/meta-wayland-types.h @@ -71,3 +71,5 @@ typedef struct _MetaWaylandXdgForeign MetaWaylandXdgForeign; typedef struct _MetaWaylandFilterManager MetaWaylandFilterManager; typedef struct _MetaWaylandClient MetaWaylandClient; + +typedef struct _MetaWaylandDrmLeaseManager MetaWaylandDrmLeaseManager; diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h index 5326ba3a1ac..1f837623618 100644 --- a/src/wayland/meta-wayland-versions.h +++ b/src/wayland/meta-wayland-versions.h @@ -58,3 +58,4 @@ #define META_MUTTER_X11_INTEROP_VERSION 1 #define META_WP_FRACTIONAL_SCALE_VERSION 1 #define META_XDG_DIALOG_VERSION 1 +#define META_WP_DRM_LEASE_DEVICE_V1_VERSION 1 -- GitLab From 145de4df8d22d8ba17c32c17030773e4fd99013b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Tue, 23 Apr 2024 17:00:38 +0200 Subject: [PATCH 13/18] wayland/drm-lease: Send non-master DRM fd Some time after a client binds to the wp_drm_lease_device_v1 global, send a drm_fd event. Part-of: --- src/wayland/meta-wayland-drm-lease.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/wayland/meta-wayland-drm-lease.c b/src/wayland/meta-wayland-drm-lease.c index ab231f41b13..f6f6911c688 100644 --- a/src/wayland/meta-wayland-drm-lease.c +++ b/src/wayland/meta-wayland-drm-lease.c @@ -25,6 +25,7 @@ #include "wayland/meta-wayland-drm-lease.h" #include +#include #include "backends/native/meta-backend-native.h" #include "backends/native/meta-drm-lease.h" @@ -94,6 +95,26 @@ static const struct wp_drm_lease_device_v1_interface drm_lease_device_implementa wp_drm_lease_device_release, }; +static void +send_drm_fd (struct wl_client *client, + MetaWaylandDrmLeaseDevice *lease_device, + struct wl_resource *device_resource) +{ + g_autofd int fd = -1; + MetaKmsImplDevice *impl_device; + + impl_device = meta_kms_device_get_impl_device (lease_device->kms_device); + fd = meta_kms_impl_device_open_non_privileged_fd (impl_device); + if (fd < 0) + { + wl_client_post_implementation_error (client, + "Error getting DRM lease device fd"); + return; + } + + wp_drm_lease_device_v1_send_drm_fd (device_resource, fd); +} + static void wp_drm_lease_device_destructor (struct wl_resource *resource) { @@ -120,6 +141,9 @@ lease_device_bind (struct wl_client *client, g_rc_box_acquire (lease_device), wp_drm_lease_device_destructor); + send_drm_fd (client, lease_device, resource); + wp_drm_lease_device_v1_send_done (resource); + lease_device->resources = g_list_prepend (lease_device->resources, resource); } -- GitLab From fb08a597e1d302f8c98f125df3b807b011eb8764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 23 Apr 2024 17:55:55 +0200 Subject: [PATCH 14/18] wayland/drm-lease: Advertize initial connectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After sending the drm_fd event, send zero, one or more connector events. After all currently available connectors have been sent, send a wp_drm_lease_device_v1.done event. Co-authored-by: José Expósito Part-of: --- src/wayland/meta-wayland-drm-lease.c | 185 +++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/src/wayland/meta-wayland-drm-lease.c b/src/wayland/meta-wayland-drm-lease.c index f6f6911c688..c3dc4986aa7 100644 --- a/src/wayland/meta-wayland-drm-lease.c +++ b/src/wayland/meta-wayland-drm-lease.c @@ -57,13 +57,29 @@ typedef struct _MetaWaylandDrmLeaseDevice struct wl_global *global; MetaKmsDevice *kms_device; + /* Key: MetaKmsConnector *kms_connector + * Value: MetaWaylandDrmLeaseConnector *lease_connector + */ + GHashTable *connectors; + GList *resources; } MetaWaylandDrmLeaseDevice; +typedef struct _MetaWaylandDrmLeaseConnector +{ + MetaWaylandDrmLeaseDevice *lease_device; + + MetaKmsConnector *kms_connector; + char *description; + + GList *resources; +} MetaWaylandDrmLeaseConnector; + static void meta_wayland_drm_lease_device_free (MetaWaylandDrmLeaseDevice *lease_device) { g_object_unref (lease_device->kms_device); + g_clear_pointer (&lease_device->connectors, g_hash_table_unref); } static void @@ -76,6 +92,24 @@ meta_wayland_drm_lease_device_release (MetaWaylandDrmLeaseDevice *lease_device) G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaWaylandDrmLeaseDevice, meta_wayland_drm_lease_device_release); +static void +meta_wayland_drm_lease_connector_free (MetaWaylandDrmLeaseConnector *lease_connector) +{ + g_object_unref (lease_connector->kms_connector); + g_free (lease_connector->description); + meta_wayland_drm_lease_device_release (lease_connector->lease_device); +} + +static void +meta_wayland_drm_lease_connector_release (MetaWaylandDrmLeaseConnector *lease_connector) +{ + g_rc_box_release_full (lease_connector, + (GDestroyNotify) meta_wayland_drm_lease_connector_free); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaWaylandDrmLeaseConnector, + meta_wayland_drm_lease_connector_release); + static void wp_drm_lease_device_create_lease_request (struct wl_client *client, struct wl_resource *resource, @@ -95,6 +129,129 @@ static const struct wp_drm_lease_device_v1_interface drm_lease_device_implementa wp_drm_lease_device_release, }; +static char * +get_connector_description (MetaKmsConnector *kms_connector) +{ + const MetaKmsConnectorState *connector_state; + gconstpointer edid_data; + g_autofree MetaEdidInfo *edid_info = NULL; + size_t edid_size; + g_autofree char *vendor = NULL; + g_autofree char *product = NULL; + GString *description; + + connector_state = meta_kms_connector_get_current_state (kms_connector); + if (!connector_state || !connector_state->edid_data) + return g_strdup (""); + + edid_data = g_bytes_get_data (connector_state->edid_data, &edid_size); + edid_info = meta_edid_info_new_parse (edid_data, edid_size); + + description = g_string_new (NULL); + + vendor = g_strndup (edid_info->manufacturer_code, 4); + if (vendor && g_utf8_validate (vendor, -1, NULL)) + g_string_append_printf (description, "%s", vendor); + + product = g_strndup (edid_info->dsc_product_name, 14); + if (product && g_utf8_validate (product, -1, NULL)) + { + if (description->len > 0) + g_string_append_c (description, ' '); + g_string_append_printf (description, "%s", product); + } + + if (description->len == 0) + { + g_string_append_printf (description, "%s", + meta_kms_connector_get_name (kms_connector)); + } + + return g_string_free_and_steal (description); +} + +static MetaWaylandDrmLeaseConnector * +meta_wayland_drm_lease_connector_new (MetaWaylandDrmLeaseDevice *lease_device, + MetaKmsConnector *kms_connector) +{ + MetaWaylandDrmLeaseConnector *lease_connector; + + lease_connector = g_rc_box_new0 (MetaWaylandDrmLeaseConnector); + lease_connector->lease_device = g_rc_box_acquire (lease_device); + lease_connector->kms_connector = g_object_ref (kms_connector); + lease_connector->description = get_connector_description (kms_connector); + + return lease_connector; +} + +static void +drm_lease_connector_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct wp_drm_lease_connector_v1_interface drm_lease_connector_implementation = { + drm_lease_connector_destroy, +}; + +static void +wp_drm_lease_connector_destructor (struct wl_resource *resource) +{ + MetaWaylandDrmLeaseConnector *lease_connector = + wl_resource_get_user_data (resource); + + lease_connector->resources = g_list_remove (lease_connector->resources, + resource); + meta_wayland_drm_lease_connector_release (lease_connector); +} + +static void +send_new_connector_resource (MetaWaylandDrmLeaseDevice *lease_device, + struct wl_resource *device_resource, + MetaWaylandDrmLeaseConnector *lease_connector) +{ + struct wl_resource *connector_resource; + const char *connector_name; + uint32_t connector_id; + + connector_resource = + wl_resource_create (wl_resource_get_client (device_resource), + &wp_drm_lease_connector_v1_interface, + wl_resource_get_version (device_resource), + 0); + wl_resource_set_implementation (connector_resource, + &drm_lease_connector_implementation, + g_rc_box_acquire (lease_connector), + wp_drm_lease_connector_destructor); + + lease_connector->resources = g_list_append (lease_connector->resources, + connector_resource); + + connector_name = meta_kms_connector_get_name (lease_connector->kms_connector); + connector_id = meta_kms_connector_get_id (lease_connector->kms_connector); + + wp_drm_lease_device_v1_send_connector (device_resource, connector_resource); + wp_drm_lease_connector_v1_send_name (connector_resource, connector_name); + wp_drm_lease_connector_v1_send_description (connector_resource, + lease_connector->description); + wp_drm_lease_connector_v1_send_connector_id (connector_resource, + connector_id); + wp_drm_lease_connector_v1_send_done (connector_resource); +} + +static void +send_connectors (MetaWaylandDrmLeaseDevice *lease_device, + struct wl_resource *device_resource) +{ + GHashTableIter iter; + MetaWaylandDrmLeaseConnector *lease_connector; + + g_hash_table_iter_init (&iter, lease_device->connectors); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &lease_connector)) + send_new_connector_resource (lease_device, device_resource, lease_connector); +} + static void send_drm_fd (struct wl_client *client, MetaWaylandDrmLeaseDevice *lease_device, @@ -142,22 +299,50 @@ lease_device_bind (struct wl_client *client, wp_drm_lease_device_destructor); send_drm_fd (client, lease_device, resource); + send_connectors (lease_device, resource); wp_drm_lease_device_v1_send_done (resource); lease_device->resources = g_list_prepend (lease_device->resources, resource); } +static void +meta_wayland_drm_lease_device_add_connector (MetaKmsConnector *kms_connector, + MetaWaylandDrmLeaseDevice *lease_device) +{ + g_autoptr (MetaWaylandDrmLeaseConnector) lease_connector = NULL; + + lease_connector = meta_wayland_drm_lease_connector_new (lease_device, + kms_connector); + g_hash_table_insert (lease_device->connectors, + kms_connector, + g_steal_pointer (&lease_connector)); +} + static MetaWaylandDrmLeaseDevice * meta_wayland_drm_lease_device_new (MetaWaylandDrmLeaseManager *lease_manager, MetaKmsDevice *kms_device) { struct wl_display *wayland_display = meta_wayland_compositor_get_wayland_display (lease_manager->compositor); + MetaDrmLeaseManager *drm_lease_manager = lease_manager->drm_lease_manager; MetaWaylandDrmLeaseDevice *lease_device; + g_autoptr (GList) kms_connectors = NULL; lease_device = g_rc_box_new0 (MetaWaylandDrmLeaseDevice); lease_device->lease_manager = lease_manager; lease_device->kms_device = g_object_ref (kms_device); + + lease_device->connectors = + g_hash_table_new_full (NULL, NULL, + NULL, + (GDestroyNotify) meta_wayland_drm_lease_connector_release); + + kms_connectors = meta_drm_lease_manager_get_connectors (drm_lease_manager, + kms_device); + g_list_foreach (kms_connectors, + (GFunc) meta_wayland_drm_lease_device_add_connector, + lease_device); + lease_device->global = wl_global_create (wayland_display, &wp_drm_lease_device_v1_interface, META_WP_DRM_LEASE_DEVICE_V1_VERSION, -- GitLab From a8a8404cdd6047ee2a6fa91723c5dd09e145f782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 24 Apr 2024 11:15:50 +0200 Subject: [PATCH 15/18] wayland/drm-lease: Update available connectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the list of connectors available for lease changes send wp_drm_lease_device_v1.connector events for added connectors and wp_drm_lease_connector_v1.withdrawn events for removed connectors, followed by a wp_drm_lease_device_v1.done event. Co-authored-by: José Expósito Part-of: --- src/wayland/meta-wayland-drm-lease.c | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/src/wayland/meta-wayland-drm-lease.c b/src/wayland/meta-wayland-drm-lease.c index c3dc4986aa7..28c00dbc9df 100644 --- a/src/wayland/meta-wayland-drm-lease.c +++ b/src/wayland/meta-wayland-drm-lease.c @@ -184,6 +184,20 @@ meta_wayland_drm_lease_connector_new (MetaWaylandDrmLeaseDevice *lease_device, return lease_connector; } +static void +meta_wayland_drm_lease_connector_send_withdrawn (MetaWaylandDrmLeaseConnector *lease_connector) +{ + GList *l; + + for (l = lease_connector->resources; l; l = l->next) + { + struct wl_resource *resource = l->data; + + if (wl_resource_get_user_data (resource) == lease_connector) + wp_drm_lease_connector_v1_send_withdrawn (resource); + } +} + static void drm_lease_connector_destroy (struct wl_client *client, struct wl_resource *resource) @@ -364,6 +378,71 @@ meta_wayland_drm_lease_manager_add_device (MetaKmsDevice *kms_devic g_steal_pointer (&lease_device)); } +static void +on_connector_added (MetaDrmLeaseManager *drm_lease_manager, + MetaKmsConnector *kms_connector, + gboolean is_last_connector_update, + MetaWaylandDrmLeaseManager *lease_manager) +{ + MetaWaylandDrmLeaseConnector *lease_connector; + MetaWaylandDrmLeaseDevice *lease_device; + MetaKmsDevice *kms_device; + GList *l; + + kms_device = meta_kms_connector_get_device (kms_connector); + lease_device = g_hash_table_lookup (lease_manager->devices, kms_device); + g_return_if_fail (lease_device != NULL); + + meta_wayland_drm_lease_device_add_connector (kms_connector, lease_device); + lease_connector = g_hash_table_lookup (lease_device->connectors, + kms_connector); + g_return_if_fail (lease_connector != NULL); + + for (l = lease_device->resources; l; l = l->next) + { + struct wl_resource *resource = l->data; + + if (wl_resource_get_user_data (resource) == lease_device) + send_new_connector_resource (lease_device, resource, lease_connector); + } + + if (is_last_connector_update) + { + g_list_foreach (lease_device->resources, + (GFunc) wp_drm_lease_device_v1_send_done, + NULL); + } +} + +static void +on_connector_removed (MetaDrmLeaseManager *drm_lease_manager, + MetaKmsConnector *kms_connector, + gboolean is_last_connector_update, + MetaWaylandDrmLeaseManager *lease_manager) +{ + MetaWaylandDrmLeaseConnector *lease_connector; + MetaWaylandDrmLeaseDevice *lease_device; + MetaKmsDevice *kms_device; + + kms_device = meta_kms_connector_get_device (kms_connector); + lease_device = g_hash_table_lookup (lease_manager->devices, kms_device); + g_return_if_fail (lease_device != NULL); + + lease_connector = g_hash_table_lookup (lease_device->connectors, + kms_connector); + g_return_if_fail (lease_connector != NULL); + + meta_wayland_drm_lease_connector_send_withdrawn (lease_connector); + g_hash_table_remove (lease_device->connectors, kms_connector); + + if (is_last_connector_update) + { + g_list_foreach (lease_device->resources, + (GFunc) wp_drm_lease_device_v1_send_done, + NULL); + } +} + static MetaWaylandDrmLeaseManager * meta_wayland_drm_lease_manager_new (MetaWaylandCompositor *compositor) { @@ -395,6 +474,13 @@ meta_wayland_drm_lease_manager_new (MetaWaylandCompositor *compositor) (GFunc) meta_wayland_drm_lease_manager_add_device, lease_manager); + g_signal_connect (lease_manager->drm_lease_manager, "connector-added", + G_CALLBACK (on_connector_added), + lease_manager); + g_signal_connect (lease_manager->drm_lease_manager, "connector-removed", + G_CALLBACK (on_connector_removed), + lease_manager); + return lease_manager; } -- GitLab From 5e5d5f0ecb11df7cc1455f41096f9cef589f050a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 7 May 2024 14:14:00 +0200 Subject: [PATCH 16/18] wayland/drm-lease: Update available devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a new device is connected, register a new global for it. When a device is gone, remove the global. Upon receiving this event, the client should destroy any matching wp_drm_lease_device_v1 object. To destroy a wp_drm_lease_device_v1 object, the client must first issue a release request. Upon receiving this request, send a released event and destroy the object. Co-authored-by: José Expósito Part-of: --- src/wayland/meta-wayland-drm-lease.c | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/wayland/meta-wayland-drm-lease.c b/src/wayland/meta-wayland-drm-lease.c index 28c00dbc9df..cf420ae4fd8 100644 --- a/src/wayland/meta-wayland-drm-lease.c +++ b/src/wayland/meta-wayland-drm-lease.c @@ -121,6 +121,7 @@ static void wp_drm_lease_device_release (struct wl_client *client, struct wl_resource *resource) { + wp_drm_lease_device_v1_send_released (resource); wl_resource_destroy (resource); } @@ -378,6 +379,28 @@ meta_wayland_drm_lease_manager_add_device (MetaKmsDevice *kms_devic g_steal_pointer (&lease_device)); } +static void +on_device_added (MetaDrmLeaseManager *drm_lease_manager, + MetaKmsDevice *kms_device, + MetaWaylandDrmLeaseManager *lease_manager) +{ + meta_wayland_drm_lease_manager_add_device (kms_device, lease_manager); +} + +static void +on_device_removed (MetaDrmLeaseManager *drm_lease_manager, + MetaKmsDevice *kms_device, + MetaWaylandDrmLeaseManager *lease_manager) +{ + MetaWaylandDrmLeaseDevice *lease_device; + + lease_device = g_hash_table_lookup (lease_manager->devices, kms_device); + g_return_if_fail (lease_device != NULL); + + wl_global_remove (lease_device->global); + g_hash_table_remove (lease_manager->devices, kms_device); +} + static void on_connector_added (MetaDrmLeaseManager *drm_lease_manager, MetaKmsConnector *kms_connector, @@ -474,6 +497,12 @@ meta_wayland_drm_lease_manager_new (MetaWaylandCompositor *compositor) (GFunc) meta_wayland_drm_lease_manager_add_device, lease_manager); + g_signal_connect (lease_manager->drm_lease_manager, "device-added", + G_CALLBACK (on_device_added), + lease_manager); + g_signal_connect (lease_manager->drm_lease_manager, "device-removed", + G_CALLBACK (on_device_removed), + lease_manager); g_signal_connect (lease_manager->drm_lease_manager, "connector-added", G_CALLBACK (on_connector_added), lease_manager); -- GitLab From a76708350f9f898ea0822925f5a294957f37bcdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 7 May 2024 18:22:18 +0200 Subject: [PATCH 17/18] wayland/drm-lease: Handle DRM lease requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a client wants to lease DRM resources, it will attach the list of connectors is wants to lease and then submit the request. Once the request is submitted, destroy the DRM lease request object. Co-authored-by: José Expósito Part-of: --- src/wayland/meta-wayland-drm-lease.c | 225 +++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) diff --git a/src/wayland/meta-wayland-drm-lease.c b/src/wayland/meta-wayland-drm-lease.c index cf420ae4fd8..6693621c548 100644 --- a/src/wayland/meta-wayland-drm-lease.c +++ b/src/wayland/meta-wayland-drm-lease.c @@ -48,6 +48,8 @@ struct _MetaWaylandDrmLeaseManager * Value: MetaWaylandDrmLeaseDevice *lease_device */ GHashTable *devices; + + GList *leases; }; typedef struct _MetaWaylandDrmLeaseDevice @@ -75,6 +77,21 @@ typedef struct _MetaWaylandDrmLeaseConnector GList *resources; } MetaWaylandDrmLeaseConnector; +typedef struct _MetaWaylandDrmLeaseRequest +{ + MetaWaylandDrmLeaseDevice *lease_device; + GList *lease_connectors; + struct wl_resource *resource; +} MetaWaylandDrmLeaseRequest; + +typedef struct _MetaWaylandDrmLease +{ + MetaWaylandDrmLeaseManager *lease_manager; + MetaWaylandDrmLeaseDevice *lease_device; + uint32_t lessee_id; + struct wl_resource *resource; +} MetaWaylandDrmLease; + static void meta_wayland_drm_lease_device_free (MetaWaylandDrmLeaseDevice *lease_device) { @@ -110,11 +127,216 @@ meta_wayland_drm_lease_connector_release (MetaWaylandDrmLeaseConnector *lease_co G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaWaylandDrmLeaseConnector, meta_wayland_drm_lease_connector_release); +static void +meta_wayland_drm_lease_free (MetaWaylandDrmLease *lease) +{ + meta_wayland_drm_lease_device_release (lease->lease_device); +} + +static void +meta_wayland_drm_lease_release (MetaWaylandDrmLease *lease) +{ + g_rc_box_release_full (lease, (GDestroyNotify) meta_wayland_drm_lease_free); +} + +static void +meta_wayland_drm_lease_revoke (MetaWaylandDrmLease *lease) +{ + MetaDrmLease *drm_lease = + meta_drm_lease_manager_get_lease_from_id (lease->lease_manager->drm_lease_manager, + lease->lessee_id); + + if (drm_lease) + meta_drm_lease_revoke (drm_lease); +} + +static void +on_lease_revoked (MetaDrmLease *drm_lease, + struct wl_resource *resource) +{ + wp_drm_lease_v1_send_finished (resource); +} + +static void +wp_drm_lease_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandDrmLease *lease = wl_resource_get_user_data (resource); + + meta_wayland_drm_lease_revoke (lease); + + wl_resource_destroy (resource); +} + +static const struct wp_drm_lease_v1_interface drm_lease_implementation = { + wp_drm_lease_destroy, +}; + +static void +wp_drm_lease_destructor (struct wl_resource *resource) +{ + MetaWaylandDrmLease *lease = wl_resource_get_user_data (resource); + MetaDrmLease *drm_lease; + + meta_wayland_drm_lease_revoke (lease); + + drm_lease = + meta_drm_lease_manager_get_lease_from_id (lease->lease_manager->drm_lease_manager, + lease->lessee_id); + if (drm_lease) + { + g_signal_handlers_disconnect_by_func (drm_lease, + (gpointer) on_lease_revoked, + lease->resource); + } + + lease->lease_manager->leases = g_list_remove (lease->lease_manager->leases, + lease); + meta_wayland_drm_lease_release (lease); +} + +static void +wp_drm_lease_request_request_connector (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *connector) +{ + MetaWaylandDrmLeaseRequest *lease_request = + wl_resource_get_user_data (resource); + MetaWaylandDrmLeaseConnector *lease_connector = + wl_resource_get_user_data (connector); + + if (lease_request->lease_device != lease_connector->lease_device) + { + wl_resource_post_error (resource, + WP_DRM_LEASE_REQUEST_V1_ERROR_WRONG_DEVICE, + "Wrong lease device"); + return; + } + + if (g_list_find (lease_request->lease_connectors, lease_connector)) + { + wl_resource_post_error (resource, + WP_DRM_LEASE_REQUEST_V1_ERROR_DUPLICATE_CONNECTOR, + "Connector requested twice"); + return; + } + + lease_request->lease_connectors = + g_list_append (lease_request->lease_connectors, + g_rc_box_acquire (lease_connector)); +} + +static void +wp_drm_lease_request_submit (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + MetaWaylandDrmLeaseRequest *lease_request = + wl_resource_get_user_data (resource); + MetaWaylandDrmLeaseDevice *lease_device = lease_request->lease_device; + MetaWaylandDrmLeaseManager *lease_manager = lease_device->lease_manager; + MetaKmsDevice *kms_device = lease_device->kms_device; + MetaDrmLeaseManager *drm_lease_manager = lease_manager->drm_lease_manager; + MetaWaylandDrmLease *lease; + g_autoptr (GList) connectors = NULL; + g_autoptr (MetaDrmLease) drm_lease = NULL; + g_autoptr (GError) error = NULL; + g_autofd int fd = -1; + GList *l; + + if (!lease_request->lease_connectors) + { + wl_resource_post_error (resource, + WP_DRM_LEASE_REQUEST_V1_ERROR_EMPTY_LEASE, + "Empty DRM lease request"); + wl_resource_destroy (resource); + return; + } + + lease = g_rc_box_new0 (MetaWaylandDrmLease); + lease->lease_manager = lease_manager; + lease->lease_device = g_rc_box_acquire (lease_device); + lease->resource = + wl_resource_create (client, &wp_drm_lease_v1_interface, + wl_resource_get_version (resource), id); + + wl_resource_set_implementation (lease->resource, + &drm_lease_implementation, + lease, + wp_drm_lease_destructor); + + lease_manager->leases = g_list_append (lease_manager->leases, lease); + + for (l = lease_request->lease_connectors; l; l = l->next) + { + MetaWaylandDrmLeaseConnector *lease_connector = l->data; + MetaKmsConnector *kms_connector = lease_connector->kms_connector; + + connectors = g_list_append (connectors, kms_connector); + } + + drm_lease = meta_drm_lease_manager_lease_connectors (drm_lease_manager, + kms_device, + connectors, + &error); + if (!drm_lease) + { + g_warning ("Failed to create lease from connector list: %s", + error->message); + wp_drm_lease_v1_send_finished (lease->resource); + wl_resource_destroy (resource); + return; + } + + g_signal_connect (drm_lease, "revoked", + G_CALLBACK (on_lease_revoked), + lease->resource); + + fd = meta_drm_lease_steal_fd (drm_lease); + wp_drm_lease_v1_send_lease_fd (lease->resource, fd); + + lease->lessee_id = meta_drm_lease_get_id (drm_lease); + + wl_resource_destroy (resource); +} + +static const struct wp_drm_lease_request_v1_interface drm_lease_request_implementation = { + wp_drm_lease_request_request_connector, + wp_drm_lease_request_submit, +}; + +static void +wp_drm_lease_request_destructor (struct wl_resource *resource) +{ + MetaWaylandDrmLeaseRequest *lease_request = + wl_resource_get_user_data (resource); + + meta_wayland_drm_lease_device_release (lease_request->lease_device); + g_list_foreach (lease_request->lease_connectors, + (GFunc) meta_wayland_drm_lease_connector_release, + NULL); + g_free (lease_request); +} + static void wp_drm_lease_device_create_lease_request (struct wl_client *client, struct wl_resource *resource, uint32_t id) { + MetaWaylandDrmLeaseDevice *lease_device = + wl_resource_get_user_data (resource); + MetaWaylandDrmLeaseRequest *lease_request; + + lease_request = g_new0 (MetaWaylandDrmLeaseRequest, 1); + lease_request->lease_device = g_rc_box_acquire (lease_device); + lease_request->resource = + wl_resource_create (client, &wp_drm_lease_request_v1_interface, + wl_resource_get_version (resource), id); + + wl_resource_set_implementation (lease_request->resource, + &drm_lease_request_implementation, + lease_request, + wp_drm_lease_request_destructor); } static void @@ -520,6 +742,9 @@ meta_wayland_drm_lease_manager_free (gpointer data) g_clear_pointer (&lease_manager->devices, g_hash_table_unref); g_clear_pointer (&lease_manager->drm_lease_manager, g_object_unref); + g_list_foreach (lease_manager->leases, + (GFunc) meta_wayland_drm_lease_release, + NULL); g_free (lease_manager); } -- GitLab From 8d5beea24695fc4f246fa145260383252577ea29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 9 May 2024 11:39:00 +0200 Subject: [PATCH 18/18] wayland: Add DRM lease manager Now that all the required pieces to support DRM lease are in place, expose the protocol. Part-of: --- src/wayland/meta-wayland.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index a9c9c7b33af..fd58e33f141 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -70,6 +70,7 @@ #ifdef HAVE_NATIVE_BACKEND #include "backends/native/meta-frame-native.h" #include "backends/native/meta-renderer-native.h" +#include "wayland/meta-wayland-drm-lease.h" #endif enum @@ -876,6 +877,10 @@ meta_wayland_compositor_new (MetaContext *context) meta_wayland_drm_syncobj_init (compositor); meta_wayland_init_xdg_wm_dialog (compositor); +#ifdef HAVE_NATIVE_BACKEND + meta_wayland_drm_lease_manager_init (compositor); +#endif + #ifdef HAVE_WAYLAND_EGLSTREAM { gboolean should_enable_eglstream_controller = TRUE; -- GitLab