From ce5a5789bb149c7dd91c7c43d1523a3a6f302cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 12 Apr 2021 16:25:53 +0200 Subject: [PATCH] native: Release output device files that are unused In order to make it possible to e.g. unload an unused DRM device, we need to make sure that we don't keep the file descriptor open if we don't need it; otherwise we block anyone from unloading the corresponding module. Part-of: --- src/backends/native/meta-device-pool.h | 2 + src/backends/native/meta-kms-connector.c | 35 ++++ .../native/meta-kms-impl-device-atomic.c | 46 +++-- .../native/meta-kms-impl-device-simple.c | 58 ++++-- src/backends/native/meta-kms-impl-device.c | 169 ++++++++++++++++-- src/backends/native/meta-kms-impl-device.h | 12 ++ src/backends/native/meta-kms-impl.c | 10 ++ src/backends/native/meta-kms-impl.h | 2 + src/backends/native/meta-kms.c | 18 ++ src/backends/native/meta-kms.h | 2 + src/backends/native/meta-renderer-native.c | 143 ++++++++++++--- 11 files changed, 426 insertions(+), 71 deletions(-) diff --git a/src/backends/native/meta-device-pool.h b/src/backends/native/meta-device-pool.h index 083bc7b53..0e9653bd6 100644 --- a/src/backends/native/meta-device-pool.h +++ b/src/backends/native/meta-device-pool.h @@ -32,6 +32,8 @@ typedef enum _MetaDeviceFileFlags typedef enum _MetaDeviceFileTags { + META_DEVICE_FILE_TAG_KMS, + META_DEVICE_FILE_N_TAGS, } MetaDeviceFileTags; diff --git a/src/backends/native/meta-kms-connector.c b/src/backends/native/meta-kms-connector.c index 3508d22cc..a666bb45c 100644 --- a/src/backends/native/meta-kms-connector.c +++ b/src/backends/native/meta-kms-connector.c @@ -52,6 +52,8 @@ struct _MetaKmsConnector uint32_t edid_blob_id; uint32_t tile_blob_id; + + gboolean fd_held; }; G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT) @@ -128,6 +130,25 @@ meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector) return underscan_prop_id != 0; } +static void +sync_fd_held (MetaKmsConnector *connector, + MetaKmsImplDevice *impl_device) +{ + gboolean should_hold_fd; + + should_hold_fd = connector->current_state->current_crtc_id != 0; + + if (connector->fd_held == should_hold_fd) + return; + + if (should_hold_fd) + meta_kms_impl_device_hold_fd (impl_device); + else + meta_kms_impl_device_unhold_fd (impl_device); + + connector->fd_held = should_hold_fd; +} + static void set_panel_orientation (MetaKmsConnectorState *state, drmModePropertyPtr prop, @@ -475,6 +496,8 @@ meta_kms_connector_read_state (MetaKmsConnector *connector, state_set_crtc_state (state, drm_connector, impl_device, drm_resources); connector->current_state = state; + + sync_fd_held (connector, impl_device); } void @@ -498,6 +521,7 @@ void meta_kms_connector_predict_state (MetaKmsConnector *connector, MetaKmsUpdate *update) { + MetaKmsImplDevice *impl_device; MetaKmsConnectorState *current_state; GList *mode_sets; GList *l; @@ -527,6 +551,9 @@ meta_kms_connector_predict_state (MetaKmsConnector *connector, } } } + + impl_device = meta_kms_device_get_impl_device (connector->device); + sync_fd_held (connector, impl_device); } static void @@ -645,6 +672,14 @@ meta_kms_connector_finalize (GObject *object) { MetaKmsConnector *connector = META_KMS_CONNECTOR (object); + if (connector->fd_held) + { + MetaKmsImplDevice *impl_device; + + impl_device = meta_kms_device_get_impl_device (connector->device); + meta_kms_impl_device_unhold_fd (impl_device); + } + g_clear_pointer (&connector->current_state, meta_kms_connector_state_free); g_free (connector->name); diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c index 85897e330..66246e87e 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c @@ -602,6 +602,8 @@ process_page_flip_listener (MetaKmsImplDevice *impl_device, GUINT_TO_POINTER (crtc_id), page_flip_data); + meta_kms_impl_device_hold_fd (impl_device); + meta_topic (META_DEBUG_KMS, "[atomic] Adding page flip data for (%u, %s): %p", crtc_id, @@ -709,6 +711,8 @@ atomic_page_flip_handler (int fd, if (!page_flip_data) return; + meta_kms_impl_device_unhold_fd (impl_device); + meta_kms_page_flip_data_set_timings_in_impl (page_flip_data, sequence, tv_sec, tv_usec); meta_kms_impl_device_handle_page_flip_callback (impl_device, page_flip_data); @@ -1014,8 +1018,10 @@ dispose_page_flip_data (gpointer key, gpointer user_data) { MetaKmsPageFlipData *page_flip_data = value; + MetaKmsImplDevice *impl_device = user_data; meta_kms_page_flip_data_discard_in_impl (page_flip_data, NULL); + meta_kms_impl_device_unhold_fd (impl_device); return TRUE; } @@ -1028,7 +1034,7 @@ meta_kms_impl_device_atomic_prepare_shutdown (MetaKmsImplDevice *impl_device) g_hash_table_foreach_remove (impl_device_atomic->page_flip_datas, dispose_page_flip_data, - NULL); + impl_device); } static void @@ -1055,7 +1061,6 @@ meta_kms_impl_device_atomic_open_device_file (MetaKmsImplDevice *impl_device, MetaDevicePool *device_pool = meta_backend_native_get_device_pool (META_BACKEND_NATIVE (backend)); g_autoptr (MetaDeviceFile) device_file = NULL; - int fd; device_file = meta_device_pool_open (device_pool, path, META_DEVICE_FILE_FLAG_TAKE_CONTROL, @@ -1063,20 +1068,33 @@ meta_kms_impl_device_atomic_open_device_file (MetaKmsImplDevice *impl_device, if (!device_file) return NULL; - fd = meta_device_file_get_fd (device_file); - - if (drmSetClientCap (fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) != 0) + if (!meta_device_file_has_tag (device_file, + META_DEVICE_FILE_TAG_KMS, + META_KMS_DEVICE_FILE_TAG_ATOMIC)) { - g_set_error (error, META_KMS_ERROR, META_KMS_ERROR_NOT_SUPPORTED, - "DRM_CLIENT_CAP_UNIVERSAL_PLANES not supported"); - return NULL; - } + int fd = meta_device_file_get_fd (device_file); - if (drmSetClientCap (fd, DRM_CLIENT_CAP_ATOMIC, 1) != 0) - { - g_set_error (error, META_KMS_ERROR, META_KMS_ERROR_NOT_SUPPORTED, - "DRM_CLIENT_CAP_ATOMIC not supported"); - return NULL; + g_warn_if_fail (!meta_device_file_has_tag (device_file, + META_DEVICE_FILE_TAG_KMS, + META_KMS_DEVICE_FILE_TAG_SIMPLE)); + + if (drmSetClientCap (fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) != 0) + { + g_set_error (error, META_KMS_ERROR, META_KMS_ERROR_NOT_SUPPORTED, + "DRM_CLIENT_CAP_UNIVERSAL_PLANES not supported"); + return NULL; + } + + if (drmSetClientCap (fd, DRM_CLIENT_CAP_ATOMIC, 1) != 0) + { + g_set_error (error, META_KMS_ERROR, META_KMS_ERROR_NOT_SUPPORTED, + "DRM_CLIENT_CAP_ATOMIC not supported"); + return NULL; + } + + meta_device_file_tag (device_file, + META_DEVICE_FILE_TAG_KMS, + META_KMS_DEVICE_FILE_TAG_ATOMIC); } return g_steal_pointer (&device_file); diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c index eabafa096..28d512720 100644 --- a/src/backends/native/meta-kms-impl-device-simple.c +++ b/src/backends/native/meta-kms-impl-device-simple.c @@ -655,6 +655,7 @@ retry_page_flips (gpointer user_data) g_critical ("Failed to page flip: %s", error->message); meta_kms_page_flip_data_discard_in_impl (page_flip_data, error); + meta_kms_impl_device_unhold_fd (impl_device); } else { @@ -977,6 +978,7 @@ dispatch_page_flip (MetaKmsImplDevice *impl_device, fb_id = 0; drm_mode = cached_mode_set->drm_mode; refresh_rate = meta_calculate_drm_mode_refresh_rate (drm_mode); + meta_kms_impl_device_hold_fd (impl_device); schedule_retry_page_flip (impl_device_simple, crtc, fb_id, @@ -1016,6 +1018,8 @@ dispatch_page_flip (MetaKmsImplDevice *impl_device, } else { + meta_kms_impl_device_hold_fd (impl_device); + impl_device_simple->posted_page_flip_datas = g_list_prepend (impl_device_simple->posted_page_flip_datas, page_flip_data); @@ -1367,6 +1371,8 @@ page_flip_handler (int fd, page_flip_data, meta_kms_crtc_get_id (crtc)); + meta_kms_impl_device_unhold_fd (impl_device); + meta_kms_impl_device_handle_page_flip_callback (impl_device, page_flip_data); impl_device_simple->posted_page_flip_datas = g_list_remove (impl_device_simple->posted_page_flip_datas, @@ -1465,6 +1471,14 @@ meta_kms_impl_device_simple_handle_page_flip_callback (MetaKmsImplDevice *impl } } +static void +dispose_page_flip_data (MetaKmsPageFlipData *page_flip_data, + MetaKmsImplDevice *impl_device) +{ + meta_kms_page_flip_data_discard_in_impl (page_flip_data, NULL); + meta_kms_impl_device_unhold_fd (impl_device); +} + static void meta_kms_impl_device_simple_discard_pending_page_flips (MetaKmsImplDevice *impl_device) { @@ -1489,7 +1503,7 @@ meta_kms_impl_device_simple_discard_pending_page_flips (MetaKmsImplDevice *impl_ meta_kms_impl_device_get_path ( meta_kms_page_flip_data_get_impl_device (page_flip_data))); - meta_kms_page_flip_data_discard_in_impl (page_flip_data, NULL); + dispose_page_flip_data (page_flip_data, impl_device); retry_page_flip_data_free (retry_page_flip_data); } g_clear_pointer (&impl_device_simple->pending_page_flip_retries, g_list_free); @@ -1505,8 +1519,8 @@ meta_kms_impl_device_simple_prepare_shutdown (MetaKmsImplDevice *impl_device) META_KMS_IMPL_DEVICE_SIMPLE (impl_device); g_list_foreach (impl_device_simple->posted_page_flip_datas, - (GFunc) meta_kms_page_flip_data_discard_in_impl, - NULL); + (GFunc) dispose_page_flip_data, + impl_device); g_clear_list (&impl_device_simple->posted_page_flip_datas, NULL); } @@ -1515,18 +1529,16 @@ meta_kms_impl_device_simple_finalize (GObject *object) { MetaKmsImplDeviceSimple *impl_device_simple = META_KMS_IMPL_DEVICE_SIMPLE (object); + MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (impl_device_simple); g_list_free_full (impl_device_simple->pending_page_flip_retries, (GDestroyNotify) retry_page_flip_data_free); - dispatch_page_flip_datas (&impl_device_simple->posted_page_flip_datas, - (GFunc) meta_kms_page_flip_data_discard_in_impl, - NULL); dispatch_page_flip_datas (&impl_device_simple->postponed_page_flip_datas, - (GFunc) meta_kms_page_flip_data_discard_in_impl, - NULL); + (GFunc) dispose_page_flip_data, + impl_device); dispatch_page_flip_datas (&impl_device_simple->postponed_mode_set_fallback_datas, - (GFunc) meta_kms_page_flip_data_discard_in_impl, - NULL); + (GFunc) dispose_page_flip_data, + impl_device); g_assert (!impl_device_simple->posted_page_flip_datas); @@ -1548,7 +1560,6 @@ meta_kms_impl_device_simple_open_device_file (MetaKmsImplDevice *impl_device, MetaDevicePool *device_pool = meta_backend_native_get_device_pool (META_BACKEND_NATIVE (backend)); g_autoptr (MetaDeviceFile) device_file = NULL; - int fd; device_file = meta_device_pool_open (device_pool, path, META_DEVICE_FILE_FLAG_TAKE_CONTROL, @@ -1556,13 +1567,26 @@ meta_kms_impl_device_simple_open_device_file (MetaKmsImplDevice *impl_device, if (!device_file) return NULL; - fd = meta_device_file_get_fd (device_file); - - if (drmSetClientCap (fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) != 0) + if (!meta_device_file_has_tag (device_file, + META_DEVICE_FILE_TAG_KMS, + META_KMS_DEVICE_FILE_TAG_SIMPLE)) { - g_set_error (error, META_KMS_ERROR, META_KMS_ERROR_NOT_SUPPORTED, - "DRM_CLIENT_CAP_UNIVERSAL_PLANES not supported"); - return NULL; + int fd = meta_device_file_get_fd (device_file); + + g_warn_if_fail (!meta_device_file_has_tag (device_file, + META_DEVICE_FILE_TAG_KMS, + META_KMS_DEVICE_FILE_TAG_ATOMIC)); + + if (drmSetClientCap (fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) != 0) + { + g_set_error (error, META_KMS_ERROR, META_KMS_ERROR_NOT_SUPPORTED, + "DRM_CLIENT_CAP_UNIVERSAL_PLANES not supported"); + return NULL; + } + + meta_device_file_tag (device_file, + META_DEVICE_FILE_TAG_KMS, + META_KMS_DEVICE_FILE_TAG_SIMPLE); } return g_steal_pointer (&device_file); diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index d288ec411..e08e672e5 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -36,7 +36,7 @@ #include "backends/native/meta-kms-plane-private.h" #include "backends/native/meta-kms-plane.h" #include "backends/native/meta-kms-private.h" -#include "backends/native/meta-kms-update.h" +#include "backends/native/meta-kms-update-private.h" #include "meta-default-modes.h" #include "meta-private-enum-types.h" @@ -60,10 +60,12 @@ typedef struct _MetaKmsImplDevicePrivate MetaKmsDevice *device; MetaKmsImpl *impl; + int fd_hold_count; MetaDeviceFile *device_file; GSource *fd_source; char *path; MetaKmsDeviceFlag flags; + gboolean has_latched_fd_hold; char *driver_name; char *driver_description; @@ -619,11 +621,81 @@ 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_kms_register_fd_in_impl (meta_kms_impl_get_kms (priv->impl), + meta_device_file_get_fd (device_file), + kms_event_dispatch_in_impl, + impl_device); + } + + return TRUE; +} + +static void +ensure_latched_fd_hold (MetaKmsImplDevice *impl_device) +{ + MetaKmsImplDevicePrivate *priv = + meta_kms_impl_device_get_instance_private (impl_device); + + if (!priv->has_latched_fd_hold) + { + meta_kms_impl_device_hold_fd (impl_device); + priv->has_latched_fd_hold = TRUE; + } +} + +static void +clear_latched_fd_hold (MetaKmsImplDevice *impl_device) +{ + MetaKmsImplDevicePrivate *priv = + meta_kms_impl_device_get_instance_private (impl_device); + + if (priv->has_latched_fd_hold) + { + meta_kms_impl_device_unhold_fd (impl_device); + priv->has_latched_fd_hold = FALSE; + } +} + void meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device) { MetaKmsImplDevicePrivate *priv = meta_kms_impl_device_get_instance_private (impl_device); + g_autoptr (GError) error = NULL; int fd; drmModeRes *drm_resources; @@ -631,17 +703,21 @@ meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device) meta_topic (META_DEBUG_KMS, "Updating device state for %s", priv->path); + if (!ensure_device_file (impl_device, &error)) + { + g_warning ("Failed to reopen '%s': %s", priv->path, error->message); + goto err; + } + + ensure_latched_fd_hold (impl_device); + fd = meta_device_file_get_fd (priv->device_file); drm_resources = drmModeGetResources (fd); if (!drm_resources) { - g_list_free_full (priv->planes, g_object_unref); - g_list_free_full (priv->crtcs, g_object_unref); - g_list_free_full (priv->connectors, g_object_unref); - priv->planes = NULL; - priv->crtcs = NULL; - priv->connectors = NULL; - return; + meta_topic (META_DEBUG_KMS, "Device '%s' didn't return any resources", + priv->path); + goto err; } update_connectors (impl_device, drm_resources); @@ -651,6 +727,13 @@ meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device) g_list_foreach (priv->connectors, (GFunc) meta_kms_connector_update_state, drm_resources); drmModeFreeResources (drm_resources); + + return; + +err: + g_clear_list (&priv->planes, g_object_unref); + g_clear_list (&priv->crtcs, g_object_unref); + g_clear_list (&priv->connectors, g_object_unref); } void @@ -666,6 +749,12 @@ meta_kms_impl_device_predict_states (MetaKmsImplDevice *impl_device, update); } +void +meta_kms_impl_device_notify_modes_set (MetaKmsImplDevice *impl_device) +{ + clear_latched_fd_hold (impl_device); +} + int meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device) { @@ -683,8 +772,17 @@ meta_kms_impl_device_process_update (MetaKmsImplDevice *impl_device, MetaKmsUpdateFlag flags) { MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device); + MetaKmsFeedback *feedback; + g_autoptr (GError) error = NULL; - return klass->process_update (impl_device, update, flags); + if (!ensure_device_file (impl_device, &error)) + return meta_kms_feedback_new_failed (NULL, g_steal_pointer (&error)); + + meta_kms_impl_device_hold_fd (impl_device); + feedback = klass->process_update (impl_device, update, flags); + meta_kms_impl_device_unhold_fd (impl_device); + + return feedback; } void @@ -704,6 +802,44 @@ meta_kms_impl_device_discard_pending_page_flips (MetaKmsImplDevice *impl_device) klass->discard_pending_page_flips (impl_device); } +void +meta_kms_impl_device_hold_fd (MetaKmsImplDevice *impl_device) +{ + MetaKmsImplDevicePrivate *priv = + meta_kms_impl_device_get_instance_private (impl_device); + MetaKms *kms = meta_kms_device_get_kms (priv->device); + + meta_assert_in_kms_impl (kms); + + g_assert (priv->device_file); + + priv->fd_hold_count++; +} + +void +meta_kms_impl_device_unhold_fd (MetaKmsImplDevice *impl_device) +{ + MetaKmsImplDevicePrivate *priv = + meta_kms_impl_device_get_instance_private (impl_device); + MetaKms *kms = meta_kms_device_get_kms (priv->device); + + meta_assert_in_kms_impl (kms); + + g_return_if_fail (priv->fd_hold_count > 0); + + priv->fd_hold_count--; + if (priv->fd_hold_count == 0) + { + g_clear_pointer (&priv->device_file, meta_device_file_release); + + if (priv->fd_source) + { + g_source_destroy (priv->fd_source); + g_clear_pointer (&priv->fd_source, g_source_unref); + } + } +} + static void meta_kms_impl_device_get_property (GObject *object, guint prop_id, @@ -776,7 +912,8 @@ meta_kms_impl_device_finalize (GObject *object) g_list_free_full (priv->fallback_modes, (GDestroyNotify) meta_kms_mode_free); - g_clear_pointer (&priv->device_file, meta_device_file_release); + clear_latched_fd_hold (impl_device); + g_warn_if_fail (!priv->device_file); g_free (priv->driver_name); g_free (priv->driver_description); @@ -816,12 +953,6 @@ meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device, drmModeFreeResources (drm_resources); - priv->fd_source = - meta_kms_register_fd_in_impl (meta_kms_impl_get_kms (priv->impl), - fd, - kms_event_dispatch_in_impl, - impl_device); - return TRUE; } @@ -862,13 +993,13 @@ meta_kms_impl_device_initable_init (GInitable *initable, MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (initable); MetaKmsImplDevicePrivate *priv = meta_kms_impl_device_get_instance_private (impl_device); - MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device); int fd; - priv->device_file = klass->open_device_file (impl_device, priv->path, error); - if (!priv->device_file) + if (!ensure_device_file (impl_device, error)) return FALSE; + ensure_latched_fd_hold (impl_device); + g_clear_pointer (&priv->path, g_free); priv->path = g_strdup (meta_device_file_get_path (priv->device_file)); diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h index 3826b2c5b..7dbb14b8e 100644 --- a/src/backends/native/meta-kms-impl-device.h +++ b/src/backends/native/meta-kms-impl-device.h @@ -87,6 +87,12 @@ enum META_KMS_ERROR_NOT_SUPPORTED, }; +enum +{ + META_KMS_DEVICE_FILE_TAG_ATOMIC = 1 << 0, + META_KMS_DEVICE_FILE_TAG_SIMPLE = 1 << 1, +}; + #define META_KMS_ERROR meta_kms_error_quark () GQuark meta_kms_error_quark (void); @@ -124,11 +130,17 @@ drmModePropertyPtr meta_kms_impl_device_find_property (MetaKmsImplDevice * int meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device); +void meta_kms_impl_device_hold_fd (MetaKmsImplDevice *impl_device); + +void meta_kms_impl_device_unhold_fd (MetaKmsImplDevice *impl_device); + void meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device); void meta_kms_impl_device_predict_states (MetaKmsImplDevice *impl_device, MetaKmsUpdate *update); +void meta_kms_impl_device_notify_modes_set (MetaKmsImplDevice *impl_device); + MetaKmsPlane * meta_kms_impl_device_add_fake_plane (MetaKmsImplDevice *impl_device, MetaKmsPlaneType plane_type, MetaKmsCrtc *crtc); diff --git a/src/backends/native/meta-kms-impl.c b/src/backends/native/meta-kms-impl.c index 3a186209c..0ad76e085 100644 --- a/src/backends/native/meta-kms-impl.c +++ b/src/backends/native/meta-kms-impl.c @@ -119,6 +119,16 @@ meta_kms_impl_prepare_shutdown (MetaKmsImpl *impl) } } +void +meta_kms_impl_notify_modes_set (MetaKmsImpl *impl) +{ + MetaKmsImplPrivate *priv = meta_kms_impl_get_instance_private (impl); + + g_list_foreach (priv->impl_devices, + (GFunc) meta_kms_impl_device_notify_modes_set, + NULL); +} + MetaKmsImpl * meta_kms_impl_new (MetaKms *kms) { diff --git a/src/backends/native/meta-kms-impl.h b/src/backends/native/meta-kms-impl.h index 00cf5538d..58f03f81a 100644 --- a/src/backends/native/meta-kms-impl.h +++ b/src/backends/native/meta-kms-impl.h @@ -45,6 +45,8 @@ void meta_kms_impl_discard_pending_page_flips (MetaKmsImpl *impl); void meta_kms_impl_prepare_shutdown (MetaKmsImpl *impl); +void meta_kms_impl_notify_modes_set (MetaKmsImpl *impl); + MetaKmsImpl * meta_kms_impl_new (MetaKms *kms); #endif /* META_KMS_IMPL_H */ diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c index edb6f29ee..70feccc22 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c @@ -345,6 +345,24 @@ meta_kms_discard_pending_page_flips (MetaKms *kms) NULL); } +static gpointer +meta_kms_notify_modes_set_in_impl (MetaKmsImpl *impl, + gpointer user_data, + GError **error) +{ + meta_kms_impl_notify_modes_set (impl); + return GINT_TO_POINTER (TRUE); +} + +void +meta_kms_notify_modes_set (MetaKms *kms) +{ + meta_kms_run_impl_task_sync (kms, + meta_kms_notify_modes_set_in_impl, + NULL, + NULL); +} + static void meta_kms_callback_data_free (MetaKmsCallbackData *callback_data) { diff --git a/src/backends/native/meta-kms.h b/src/backends/native/meta-kms.h index 79713cc40..9eae80e3f 100644 --- a/src/backends/native/meta-kms.h +++ b/src/backends/native/meta-kms.h @@ -52,6 +52,8 @@ MetaKmsFeedback * meta_kms_post_pending_update_sync (MetaKms *kms, void meta_kms_discard_pending_page_flips (MetaKms *kms); +void meta_kms_notify_modes_set (MetaKms *kms); + MetaBackend * meta_kms_get_backend (MetaKms *kms); GList * meta_kms_get_devices (MetaKms *kms); diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 54216224a..9256b679d 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -102,6 +102,11 @@ G_DEFINE_TYPE_WITH_CODE (MetaRendererNative, static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable; static const CoglWinsysVtable *parent_vtable; +static gboolean +meta_renderer_native_ensure_gpu_data (MetaRendererNative *renderer_native, + MetaGpuKms *gpu_kms, + GError **error); + static void meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native); @@ -625,6 +630,44 @@ clear_kept_alive_onscreens (MetaRendererNative *renderer_native) g_object_unref); } +static gboolean +is_gpu_unused (gpointer key, + gpointer value, + gpointer user_data) +{ + GHashTable *used_gpus = user_data; + + return !g_hash_table_contains (used_gpus, key); +} + +static void +free_unused_gpu_datas (MetaRendererNative *renderer_native) +{ + MetaRenderer *renderer = META_RENDERER (renderer_native); + g_autoptr (GHashTable) used_gpus = NULL; + GList *l; + + used_gpus = g_hash_table_new (NULL, NULL); + g_hash_table_add (used_gpus, renderer_native->primary_gpu_kms); + + for (l = meta_renderer_get_views (renderer); l; l = l->next) + { + MetaRendererView *view = l->data; + MetaCrtc *crtc = meta_renderer_view_get_crtc (view); + MetaGpu *gpu; + + gpu = meta_crtc_get_gpu (crtc); + if (!gpu) + continue; + + g_hash_table_add (used_gpus, gpu); + } + + g_hash_table_foreach_remove (renderer_native->gpu_datas, + is_gpu_unused, + used_gpus); +} + void meta_renderer_native_post_mode_set_updates (MetaRendererNative *renderer_native) { @@ -665,6 +708,10 @@ meta_renderer_native_post_mode_set_updates (MetaRendererNative *renderer_native) } clear_kept_alive_onscreens (renderer_native); + + meta_kms_notify_modes_set (kms); + + free_unused_gpu_datas (renderer_native); } static void @@ -1061,21 +1108,15 @@ meta_renderer_native_create_view (MetaRenderer *renderer, if (META_IS_CRTC_KMS (crtc)) { MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); - MetaGpuKms *primary_gpu_kms = renderer_native->primary_gpu_kms; MetaOnscreenNative *onscreen_native; - onscreen_native = meta_onscreen_native_new (renderer_native, - primary_gpu_kms, - output, - crtc, - cogl_context, - onscreen_width, - onscreen_height); - - if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (onscreen_native), &error)) + if (!meta_renderer_native_ensure_gpu_data (renderer_native, + gpu_kms, + &error)) { - g_warning ("Failed to allocate onscreen framebuffer for %s", - meta_gpu_kms_get_file_path (gpu_kms)); + g_warning ("Failed to create secondary GPU data for %s", + meta_gpu_kms_get_file_path (gpu_kms)); + use_shadowfb = FALSE; framebuffer = create_fallback_offscreen (renderer_native, cogl_context, onscreen_width, @@ -1083,9 +1124,32 @@ meta_renderer_native_create_view (MetaRenderer *renderer, } else { - use_shadowfb = should_force_shadow_fb (renderer_native, - primary_gpu_kms); - framebuffer = COGL_FRAMEBUFFER (onscreen_native); + MetaGpuKms *primary_gpu_kms = renderer_native->primary_gpu_kms; + + onscreen_native = meta_onscreen_native_new (renderer_native, + primary_gpu_kms, + output, + crtc, + cogl_context, + onscreen_width, + onscreen_height); + + if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (onscreen_native), &error)) + { + g_warning ("Failed to allocate onscreen framebuffer for %s", + meta_gpu_kms_get_file_path (gpu_kms)); + use_shadowfb = FALSE; + framebuffer = create_fallback_offscreen (renderer_native, + cogl_context, + onscreen_width, + onscreen_height); + } + else + { + use_shadowfb = should_force_shadow_fb (renderer_native, + primary_gpu_kms); + framebuffer = COGL_FRAMEBUFFER (onscreen_native); + } } } else @@ -1331,6 +1395,22 @@ meta_renderer_native_ensure_gles3 (MetaRendererNative *renderer_native) renderer_native->gles3 = meta_gles3_new (egl); } +static void +maybe_restore_cogl_egl_api (MetaRendererNative *renderer_native) +{ + CoglContext *cogl_context; + CoglDisplay *cogl_display; + CoglRenderer *cogl_renderer; + + cogl_context = cogl_context_from_renderer_native (renderer_native); + if (!cogl_context) + return; + + cogl_display = cogl_context_get_display (cogl_context); + cogl_renderer = cogl_display_get_renderer (cogl_display); + cogl_renderer_bind_api (cogl_renderer); +} + static gboolean init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data, GError **error) @@ -1343,13 +1423,15 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data, const char **missing_gl_extensions; const char *renderer_str; + meta_egl_bind_api (egl, EGL_OPENGL_ES_API, NULL); + if (!create_secondary_egl_config (egl, renderer_gpu_data->mode, egl_display, &egl_config, error)) - return FALSE; + goto err; egl_context = create_secondary_egl_context (egl, egl_display, egl_config, error); if (egl_context == EGL_NO_CONTEXT) - return FALSE; + goto err; meta_renderer_native_ensure_gles3 (renderer_native); @@ -1361,7 +1443,7 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data, error)) { meta_egl_destroy_context (egl, egl_display, egl_context, NULL); - return FALSE; + goto err; } renderer_str = (const char *) glGetString (GL_RENDERER); @@ -1372,7 +1454,7 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data, g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Do not want to use software renderer (%s), falling back to CPU copy path", renderer_str); - goto out_fail_with_context; + goto err_fail_with_context; } if (!meta_gles3_has_extensions (renderer_native->gles3, @@ -1390,7 +1472,7 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data, g_free (missing_gl_extensions_str); g_free (missing_gl_extensions); - goto out_fail_with_context; + goto err_fail_with_context; } renderer_gpu_data->secondary.is_hardware_rendering = TRUE; @@ -1403,9 +1485,11 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data, "EGL_EXT_image_dma_buf_import_modifiers", NULL); + maybe_restore_cogl_egl_api (renderer_native); + return TRUE; -out_fail_with_context: +err_fail_with_context: meta_egl_make_current (egl, egl_display, EGL_NO_SURFACE, @@ -1414,6 +1498,9 @@ out_fail_with_context: NULL); meta_egl_destroy_context (egl, egl_display, egl_context, NULL); +err: + maybe_restore_cogl_egl_api (renderer_native); + return FALSE; } @@ -1874,6 +1961,20 @@ create_renderer_gpu_data (MetaRendererNative *renderer_native, return TRUE; } +static gboolean +meta_renderer_native_ensure_gpu_data (MetaRendererNative *renderer_native, + MetaGpuKms *gpu_kms, + GError **error) +{ + MetaRendererNativeGpuData *renderer_gpu_data; + + renderer_gpu_data = g_hash_table_lookup (renderer_native->gpu_datas, gpu_kms); + if (renderer_gpu_data) + return TRUE; + + return create_renderer_gpu_data (renderer_native, gpu_kms, error); +} + static void on_gpu_added (MetaBackendNative *backend_native, MetaGpuKms *gpu_kms,