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,