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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1828>
This commit is contained in:
Jonas Ådahl 2021-04-12 16:25:53 +02:00
parent 3c47661b78
commit ce5a5789bb
11 changed files with 426 additions and 71 deletions

View File

@ -32,6 +32,8 @@ typedef enum _MetaDeviceFileFlags
typedef enum _MetaDeviceFileTags typedef enum _MetaDeviceFileTags
{ {
META_DEVICE_FILE_TAG_KMS,
META_DEVICE_FILE_N_TAGS, META_DEVICE_FILE_N_TAGS,
} MetaDeviceFileTags; } MetaDeviceFileTags;

View File

@ -52,6 +52,8 @@ struct _MetaKmsConnector
uint32_t edid_blob_id; uint32_t edid_blob_id;
uint32_t tile_blob_id; uint32_t tile_blob_id;
gboolean fd_held;
}; };
G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT) 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; 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 static void
set_panel_orientation (MetaKmsConnectorState *state, set_panel_orientation (MetaKmsConnectorState *state,
drmModePropertyPtr prop, drmModePropertyPtr prop,
@ -475,6 +496,8 @@ meta_kms_connector_read_state (MetaKmsConnector *connector,
state_set_crtc_state (state, drm_connector, impl_device, drm_resources); state_set_crtc_state (state, drm_connector, impl_device, drm_resources);
connector->current_state = state; connector->current_state = state;
sync_fd_held (connector, impl_device);
} }
void void
@ -498,6 +521,7 @@ void
meta_kms_connector_predict_state (MetaKmsConnector *connector, meta_kms_connector_predict_state (MetaKmsConnector *connector,
MetaKmsUpdate *update) MetaKmsUpdate *update)
{ {
MetaKmsImplDevice *impl_device;
MetaKmsConnectorState *current_state; MetaKmsConnectorState *current_state;
GList *mode_sets; GList *mode_sets;
GList *l; 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 static void
@ -645,6 +672,14 @@ meta_kms_connector_finalize (GObject *object)
{ {
MetaKmsConnector *connector = META_KMS_CONNECTOR (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_clear_pointer (&connector->current_state, meta_kms_connector_state_free);
g_free (connector->name); g_free (connector->name);

View File

@ -602,6 +602,8 @@ process_page_flip_listener (MetaKmsImplDevice *impl_device,
GUINT_TO_POINTER (crtc_id), GUINT_TO_POINTER (crtc_id),
page_flip_data); page_flip_data);
meta_kms_impl_device_hold_fd (impl_device);
meta_topic (META_DEBUG_KMS, meta_topic (META_DEBUG_KMS,
"[atomic] Adding page flip data for (%u, %s): %p", "[atomic] Adding page flip data for (%u, %s): %p",
crtc_id, crtc_id,
@ -709,6 +711,8 @@ atomic_page_flip_handler (int fd,
if (!page_flip_data) if (!page_flip_data)
return; return;
meta_kms_impl_device_unhold_fd (impl_device);
meta_kms_page_flip_data_set_timings_in_impl (page_flip_data, meta_kms_page_flip_data_set_timings_in_impl (page_flip_data,
sequence, tv_sec, tv_usec); sequence, tv_sec, tv_usec);
meta_kms_impl_device_handle_page_flip_callback (impl_device, page_flip_data); 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) gpointer user_data)
{ {
MetaKmsPageFlipData *page_flip_data = value; MetaKmsPageFlipData *page_flip_data = value;
MetaKmsImplDevice *impl_device = user_data;
meta_kms_page_flip_data_discard_in_impl (page_flip_data, NULL); meta_kms_page_flip_data_discard_in_impl (page_flip_data, NULL);
meta_kms_impl_device_unhold_fd (impl_device);
return TRUE; 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, g_hash_table_foreach_remove (impl_device_atomic->page_flip_datas,
dispose_page_flip_data, dispose_page_flip_data,
NULL); impl_device);
} }
static void static void
@ -1055,7 +1061,6 @@ meta_kms_impl_device_atomic_open_device_file (MetaKmsImplDevice *impl_device,
MetaDevicePool *device_pool = MetaDevicePool *device_pool =
meta_backend_native_get_device_pool (META_BACKEND_NATIVE (backend)); meta_backend_native_get_device_pool (META_BACKEND_NATIVE (backend));
g_autoptr (MetaDeviceFile) device_file = NULL; g_autoptr (MetaDeviceFile) device_file = NULL;
int fd;
device_file = meta_device_pool_open (device_pool, path, device_file = meta_device_pool_open (device_pool, path,
META_DEVICE_FILE_FLAG_TAKE_CONTROL, META_DEVICE_FILE_FLAG_TAKE_CONTROL,
@ -1063,20 +1068,33 @@ meta_kms_impl_device_atomic_open_device_file (MetaKmsImplDevice *impl_device,
if (!device_file) if (!device_file)
return NULL; return NULL;
fd = meta_device_file_get_fd (device_file); if (!meta_device_file_has_tag (device_file,
META_DEVICE_FILE_TAG_KMS,
if (drmSetClientCap (fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) != 0) META_KMS_DEVICE_FILE_TAG_ATOMIC))
{ {
g_set_error (error, META_KMS_ERROR, META_KMS_ERROR_NOT_SUPPORTED, int fd = meta_device_file_get_fd (device_file);
"DRM_CLIENT_CAP_UNIVERSAL_PLANES not supported");
return NULL;
}
if (drmSetClientCap (fd, DRM_CLIENT_CAP_ATOMIC, 1) != 0) g_warn_if_fail (!meta_device_file_has_tag (device_file,
{ META_DEVICE_FILE_TAG_KMS,
g_set_error (error, META_KMS_ERROR, META_KMS_ERROR_NOT_SUPPORTED, META_KMS_DEVICE_FILE_TAG_SIMPLE));
"DRM_CLIENT_CAP_ATOMIC not supported");
return NULL; 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); return g_steal_pointer (&device_file);

View File

@ -655,6 +655,7 @@ retry_page_flips (gpointer user_data)
g_critical ("Failed to page flip: %s", error->message); g_critical ("Failed to page flip: %s", error->message);
meta_kms_page_flip_data_discard_in_impl (page_flip_data, error); meta_kms_page_flip_data_discard_in_impl (page_flip_data, error);
meta_kms_impl_device_unhold_fd (impl_device);
} }
else else
{ {
@ -977,6 +978,7 @@ dispatch_page_flip (MetaKmsImplDevice *impl_device,
fb_id = 0; fb_id = 0;
drm_mode = cached_mode_set->drm_mode; drm_mode = cached_mode_set->drm_mode;
refresh_rate = meta_calculate_drm_mode_refresh_rate (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, schedule_retry_page_flip (impl_device_simple,
crtc, crtc,
fb_id, fb_id,
@ -1016,6 +1018,8 @@ dispatch_page_flip (MetaKmsImplDevice *impl_device,
} }
else else
{ {
meta_kms_impl_device_hold_fd (impl_device);
impl_device_simple->posted_page_flip_datas = impl_device_simple->posted_page_flip_datas =
g_list_prepend (impl_device_simple->posted_page_flip_datas, g_list_prepend (impl_device_simple->posted_page_flip_datas,
page_flip_data); page_flip_data);
@ -1367,6 +1371,8 @@ page_flip_handler (int fd,
page_flip_data, page_flip_data,
meta_kms_crtc_get_id (crtc)); 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); meta_kms_impl_device_handle_page_flip_callback (impl_device, page_flip_data);
impl_device_simple->posted_page_flip_datas = impl_device_simple->posted_page_flip_datas =
g_list_remove (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 static void
meta_kms_impl_device_simple_discard_pending_page_flips (MetaKmsImplDevice *impl_device) 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_impl_device_get_path (
meta_kms_page_flip_data_get_impl_device (page_flip_data))); 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); retry_page_flip_data_free (retry_page_flip_data);
} }
g_clear_pointer (&impl_device_simple->pending_page_flip_retries, g_list_free); 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); META_KMS_IMPL_DEVICE_SIMPLE (impl_device);
g_list_foreach (impl_device_simple->posted_page_flip_datas, g_list_foreach (impl_device_simple->posted_page_flip_datas,
(GFunc) meta_kms_page_flip_data_discard_in_impl, (GFunc) dispose_page_flip_data,
NULL); impl_device);
g_clear_list (&impl_device_simple->posted_page_flip_datas, NULL); 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 = MetaKmsImplDeviceSimple *impl_device_simple =
META_KMS_IMPL_DEVICE_SIMPLE (object); 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, g_list_free_full (impl_device_simple->pending_page_flip_retries,
(GDestroyNotify) retry_page_flip_data_free); (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, dispatch_page_flip_datas (&impl_device_simple->postponed_page_flip_datas,
(GFunc) meta_kms_page_flip_data_discard_in_impl, (GFunc) dispose_page_flip_data,
NULL); impl_device);
dispatch_page_flip_datas (&impl_device_simple->postponed_mode_set_fallback_datas, dispatch_page_flip_datas (&impl_device_simple->postponed_mode_set_fallback_datas,
(GFunc) meta_kms_page_flip_data_discard_in_impl, (GFunc) dispose_page_flip_data,
NULL); impl_device);
g_assert (!impl_device_simple->posted_page_flip_datas); 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 = MetaDevicePool *device_pool =
meta_backend_native_get_device_pool (META_BACKEND_NATIVE (backend)); meta_backend_native_get_device_pool (META_BACKEND_NATIVE (backend));
g_autoptr (MetaDeviceFile) device_file = NULL; g_autoptr (MetaDeviceFile) device_file = NULL;
int fd;
device_file = meta_device_pool_open (device_pool, path, device_file = meta_device_pool_open (device_pool, path,
META_DEVICE_FILE_FLAG_TAKE_CONTROL, META_DEVICE_FILE_FLAG_TAKE_CONTROL,
@ -1556,13 +1567,26 @@ meta_kms_impl_device_simple_open_device_file (MetaKmsImplDevice *impl_device,
if (!device_file) if (!device_file)
return NULL; return NULL;
fd = meta_device_file_get_fd (device_file); if (!meta_device_file_has_tag (device_file,
META_DEVICE_FILE_TAG_KMS,
if (drmSetClientCap (fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) != 0) META_KMS_DEVICE_FILE_TAG_SIMPLE))
{ {
g_set_error (error, META_KMS_ERROR, META_KMS_ERROR_NOT_SUPPORTED, int fd = meta_device_file_get_fd (device_file);
"DRM_CLIENT_CAP_UNIVERSAL_PLANES 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_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); return g_steal_pointer (&device_file);

View File

@ -36,7 +36,7 @@
#include "backends/native/meta-kms-plane-private.h" #include "backends/native/meta-kms-plane-private.h"
#include "backends/native/meta-kms-plane.h" #include "backends/native/meta-kms-plane.h"
#include "backends/native/meta-kms-private.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-default-modes.h"
#include "meta-private-enum-types.h" #include "meta-private-enum-types.h"
@ -60,10 +60,12 @@ typedef struct _MetaKmsImplDevicePrivate
MetaKmsDevice *device; MetaKmsDevice *device;
MetaKmsImpl *impl; MetaKmsImpl *impl;
int fd_hold_count;
MetaDeviceFile *device_file; MetaDeviceFile *device_file;
GSource *fd_source; GSource *fd_source;
char *path; char *path;
MetaKmsDeviceFlag flags; MetaKmsDeviceFlag flags;
gboolean has_latched_fd_hold;
char *driver_name; char *driver_name;
char *driver_description; char *driver_description;
@ -619,11 +621,81 @@ init_fallback_modes (MetaKmsImplDevice *impl_device)
priv->fallback_modes = g_list_reverse (modes); 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 void
meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device) meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device)
{ {
MetaKmsImplDevicePrivate *priv = MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device); meta_kms_impl_device_get_instance_private (impl_device);
g_autoptr (GError) error = NULL;
int fd; int fd;
drmModeRes *drm_resources; 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); 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); fd = meta_device_file_get_fd (priv->device_file);
drm_resources = drmModeGetResources (fd); drm_resources = drmModeGetResources (fd);
if (!drm_resources) if (!drm_resources)
{ {
g_list_free_full (priv->planes, g_object_unref); meta_topic (META_DEBUG_KMS, "Device '%s' didn't return any resources",
g_list_free_full (priv->crtcs, g_object_unref); priv->path);
g_list_free_full (priv->connectors, g_object_unref); goto err;
priv->planes = NULL;
priv->crtcs = NULL;
priv->connectors = NULL;
return;
} }
update_connectors (impl_device, drm_resources); 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, g_list_foreach (priv->connectors, (GFunc) meta_kms_connector_update_state,
drm_resources); drm_resources);
drmModeFreeResources (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 void
@ -666,6 +749,12 @@ meta_kms_impl_device_predict_states (MetaKmsImplDevice *impl_device,
update); update);
} }
void
meta_kms_impl_device_notify_modes_set (MetaKmsImplDevice *impl_device)
{
clear_latched_fd_hold (impl_device);
}
int int
meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device) meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device)
{ {
@ -683,8 +772,17 @@ meta_kms_impl_device_process_update (MetaKmsImplDevice *impl_device,
MetaKmsUpdateFlag flags) MetaKmsUpdateFlag flags)
{ {
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device); 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 void
@ -704,6 +802,44 @@ meta_kms_impl_device_discard_pending_page_flips (MetaKmsImplDevice *impl_device)
klass->discard_pending_page_flips (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 static void
meta_kms_impl_device_get_property (GObject *object, meta_kms_impl_device_get_property (GObject *object,
guint prop_id, guint prop_id,
@ -776,7 +912,8 @@ meta_kms_impl_device_finalize (GObject *object)
g_list_free_full (priv->fallback_modes, g_list_free_full (priv->fallback_modes,
(GDestroyNotify) meta_kms_mode_free); (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_name);
g_free (priv->driver_description); g_free (priv->driver_description);
@ -816,12 +953,6 @@ meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device,
drmModeFreeResources (drm_resources); 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; return TRUE;
} }
@ -862,13 +993,13 @@ meta_kms_impl_device_initable_init (GInitable *initable,
MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (initable); MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (initable);
MetaKmsImplDevicePrivate *priv = MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device); meta_kms_impl_device_get_instance_private (impl_device);
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
int fd; int fd;
priv->device_file = klass->open_device_file (impl_device, priv->path, error); if (!ensure_device_file (impl_device, error))
if (!priv->device_file)
return FALSE; return FALSE;
ensure_latched_fd_hold (impl_device);
g_clear_pointer (&priv->path, g_free); g_clear_pointer (&priv->path, g_free);
priv->path = g_strdup (meta_device_file_get_path (priv->device_file)); priv->path = g_strdup (meta_device_file_get_path (priv->device_file));

View File

@ -87,6 +87,12 @@ enum
META_KMS_ERROR_NOT_SUPPORTED, 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 () #define META_KMS_ERROR meta_kms_error_quark ()
GQuark meta_kms_error_quark (void); 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); 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_update_states (MetaKmsImplDevice *impl_device);
void meta_kms_impl_device_predict_states (MetaKmsImplDevice *impl_device, void meta_kms_impl_device_predict_states (MetaKmsImplDevice *impl_device,
MetaKmsUpdate *update); MetaKmsUpdate *update);
void meta_kms_impl_device_notify_modes_set (MetaKmsImplDevice *impl_device);
MetaKmsPlane * meta_kms_impl_device_add_fake_plane (MetaKmsImplDevice *impl_device, MetaKmsPlane * meta_kms_impl_device_add_fake_plane (MetaKmsImplDevice *impl_device,
MetaKmsPlaneType plane_type, MetaKmsPlaneType plane_type,
MetaKmsCrtc *crtc); MetaKmsCrtc *crtc);

View File

@ -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 * MetaKmsImpl *
meta_kms_impl_new (MetaKms *kms) meta_kms_impl_new (MetaKms *kms)
{ {

View File

@ -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_prepare_shutdown (MetaKmsImpl *impl);
void meta_kms_impl_notify_modes_set (MetaKmsImpl *impl);
MetaKmsImpl * meta_kms_impl_new (MetaKms *kms); MetaKmsImpl * meta_kms_impl_new (MetaKms *kms);
#endif /* META_KMS_IMPL_H */ #endif /* META_KMS_IMPL_H */

View File

@ -345,6 +345,24 @@ meta_kms_discard_pending_page_flips (MetaKms *kms)
NULL); 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 static void
meta_kms_callback_data_free (MetaKmsCallbackData *callback_data) meta_kms_callback_data_free (MetaKmsCallbackData *callback_data)
{ {

View File

@ -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_discard_pending_page_flips (MetaKms *kms);
void meta_kms_notify_modes_set (MetaKms *kms);
MetaBackend * meta_kms_get_backend (MetaKms *kms); MetaBackend * meta_kms_get_backend (MetaKms *kms);
GList * meta_kms_get_devices (MetaKms *kms); GList * meta_kms_get_devices (MetaKms *kms);

View File

@ -102,6 +102,11 @@ G_DEFINE_TYPE_WITH_CODE (MetaRendererNative,
static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable; static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
static const CoglWinsysVtable *parent_vtable; static const CoglWinsysVtable *parent_vtable;
static gboolean
meta_renderer_native_ensure_gpu_data (MetaRendererNative *renderer_native,
MetaGpuKms *gpu_kms,
GError **error);
static void static void
meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native); meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native);
@ -625,6 +630,44 @@ clear_kept_alive_onscreens (MetaRendererNative *renderer_native)
g_object_unref); 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 void
meta_renderer_native_post_mode_set_updates (MetaRendererNative *renderer_native) 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); clear_kept_alive_onscreens (renderer_native);
meta_kms_notify_modes_set (kms);
free_unused_gpu_datas (renderer_native);
} }
static void static void
@ -1061,21 +1108,15 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
if (META_IS_CRTC_KMS (crtc)) if (META_IS_CRTC_KMS (crtc))
{ {
MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
MetaGpuKms *primary_gpu_kms = renderer_native->primary_gpu_kms;
MetaOnscreenNative *onscreen_native; MetaOnscreenNative *onscreen_native;
onscreen_native = meta_onscreen_native_new (renderer_native, if (!meta_renderer_native_ensure_gpu_data (renderer_native,
primary_gpu_kms, gpu_kms,
output, &error))
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", g_warning ("Failed to create secondary GPU data for %s",
meta_gpu_kms_get_file_path (gpu_kms)); meta_gpu_kms_get_file_path (gpu_kms));
use_shadowfb = FALSE;
framebuffer = create_fallback_offscreen (renderer_native, framebuffer = create_fallback_offscreen (renderer_native,
cogl_context, cogl_context,
onscreen_width, onscreen_width,
@ -1083,9 +1124,32 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
} }
else else
{ {
use_shadowfb = should_force_shadow_fb (renderer_native, MetaGpuKms *primary_gpu_kms = renderer_native->primary_gpu_kms;
primary_gpu_kms);
framebuffer = COGL_FRAMEBUFFER (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))
{
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 else
@ -1331,6 +1395,22 @@ meta_renderer_native_ensure_gles3 (MetaRendererNative *renderer_native)
renderer_native->gles3 = meta_gles3_new (egl); 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 static gboolean
init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data, init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
GError **error) GError **error)
@ -1343,13 +1423,15 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
const char **missing_gl_extensions; const char **missing_gl_extensions;
const char *renderer_str; 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, if (!create_secondary_egl_config (egl, renderer_gpu_data->mode, egl_display,
&egl_config, error)) &egl_config, error))
return FALSE; goto err;
egl_context = create_secondary_egl_context (egl, egl_display, egl_config, error); egl_context = create_secondary_egl_context (egl, egl_display, egl_config, error);
if (egl_context == EGL_NO_CONTEXT) if (egl_context == EGL_NO_CONTEXT)
return FALSE; goto err;
meta_renderer_native_ensure_gles3 (renderer_native); meta_renderer_native_ensure_gles3 (renderer_native);
@ -1361,7 +1443,7 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
error)) error))
{ {
meta_egl_destroy_context (egl, egl_display, egl_context, NULL); meta_egl_destroy_context (egl, egl_display, egl_context, NULL);
return FALSE; goto err;
} }
renderer_str = (const char *) glGetString (GL_RENDERER); 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, 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", "Do not want to use software renderer (%s), falling back to CPU copy path",
renderer_str); renderer_str);
goto out_fail_with_context; goto err_fail_with_context;
} }
if (!meta_gles3_has_extensions (renderer_native->gles3, 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_str);
g_free (missing_gl_extensions); g_free (missing_gl_extensions);
goto out_fail_with_context; goto err_fail_with_context;
} }
renderer_gpu_data->secondary.is_hardware_rendering = TRUE; 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", "EGL_EXT_image_dma_buf_import_modifiers",
NULL); NULL);
maybe_restore_cogl_egl_api (renderer_native);
return TRUE; return TRUE;
out_fail_with_context: err_fail_with_context:
meta_egl_make_current (egl, meta_egl_make_current (egl,
egl_display, egl_display,
EGL_NO_SURFACE, EGL_NO_SURFACE,
@ -1414,6 +1498,9 @@ out_fail_with_context:
NULL); NULL);
meta_egl_destroy_context (egl, egl_display, egl_context, NULL); meta_egl_destroy_context (egl, egl_display, egl_context, NULL);
err:
maybe_restore_cogl_egl_api (renderer_native);
return FALSE; return FALSE;
} }
@ -1874,6 +1961,20 @@ create_renderer_gpu_data (MetaRendererNative *renderer_native,
return TRUE; 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 static void
on_gpu_added (MetaBackendNative *backend_native, on_gpu_added (MetaBackendNative *backend_native,
MetaGpuKms *gpu_kms, MetaGpuKms *gpu_kms,