Commit fef5753a authored by Jonas Ådahl's avatar Jonas Ådahl Committed by Georges Basile Stavracas Neto

backends/native: Add basic KMS abstraction building blocks

The intention with KMS abstraction is to hide away accessing the drm
functions behind an API that allows us to have different kind of KMS
implementations, including legacy non-atomic and atomic. The intention
is also that the code interacting with the drm device should be able to
be run in a different thread than the main thread. This means that we
need to make sure that all drm*() API usage must only occur from within
tasks that eventually can be run in the dedicated thread.

The idea here is that MetaKms provides a outward facing API other places
of mutter can use (e.g. MetaGpuKms and friends), while MetaKmsImpl is
an internal implementation that only gets interacted with via "tasks"
posted via the MetaKms object. These tasks will in the future
potentially be run on the dedicated KMS thread. Initially, we don't
create any new threads.

Likewise, MetaKmsDevice is a outward facing representation of a KMS
device, while MetaKmsImplDevice is the corresponding implementation,
which only runs from within the MetaKmsImpl tasks.

This commit only moves opening and closing the device to this new API,
while leaking the fd outside of the impl enclosure, effectively making
the isolation for drm*() calls pointless. This, however, is necessary to
allow gradual porting of drm interaction, and eventually the file
descriptor in MetaGpuKms will be removed. For now, it's harmless, since
everything still run in the main thread.

GNOME/mutter#548
GNOME/mutter!525
parent f3fd7cf9
......@@ -51,6 +51,8 @@
#include "backends/native/meta-clutter-backend-native.h"
#include "backends/native/meta-cursor-renderer-native.h"
#include "backends/native/meta-input-settings-native.h"
#include "backends/native/meta-kms.h"
#include "backends/native/meta-kms-device.h"
#include "backends/native/meta-launcher.h"
#include "backends/native/meta-monitor-manager-kms.h"
#include "backends/native/meta-renderer-native.h"
......@@ -65,6 +67,7 @@ struct _MetaBackendNative
MetaLauncher *launcher;
MetaUdev *udev;
MetaKms *kms;
MetaBarrierManagerNative *barrier_manager;
guint udev_device_added_handler_id;
......@@ -91,6 +94,7 @@ meta_backend_native_finalize (GObject *object)
disconnect_udev_device_added_handler (native);
g_clear_object (&native->udev);
g_clear_object (&native->kms);
meta_launcher_free (native->launcher);
G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object);
......@@ -523,17 +527,24 @@ create_gpu_from_udev_device (MetaBackendNative *native,
GUdevDevice *device,
GError **error)
{
MetaGpuKmsFlag flags = META_GPU_KMS_FLAG_NONE;
MetaKmsDeviceFlag flags = META_KMS_DEVICE_FLAG_NONE;
const char *device_path;
MetaKmsDevice *kms_device;
if (meta_is_udev_device_platform_device (device))
flags |= META_GPU_KMS_FLAG_PLATFORM_DEVICE;
flags |= META_KMS_DEVICE_FLAG_PLATFORM_DEVICE;
if (meta_is_udev_device_boot_vga (device))
flags |= META_GPU_KMS_FLAG_BOOT_VGA;
flags |= META_KMS_DEVICE_FLAG_BOOT_VGA;
device_path = g_udev_device_get_device_file (device);
return meta_gpu_kms_new (native, device_path, flags, error);
kms_device = meta_kms_create_device (native->kms, device_path, flags,
error);
if (!kms_device)
return NULL;
return meta_gpu_kms_new (native, kms_device, error);
}
static void
......@@ -661,6 +672,10 @@ meta_backend_native_initable_init (GInitable *initable,
native->udev = meta_udev_new (native);
native->barrier_manager = meta_barrier_manager_native_new ();
native->kms = meta_kms_new (META_BACKEND (native), error);
if (!native->kms)
return FALSE;
if (!init_gpus (native, error))
return FALSE;
......@@ -722,6 +737,12 @@ meta_backend_native_get_udev (MetaBackendNative *native)
return native->udev;
}
MetaKms *
meta_backend_native_get_kms (MetaBackendNative *native)
{
return native->kms;
}
gboolean
meta_activate_vt (int vt, GError **error)
{
......
......@@ -27,6 +27,7 @@
#include "backends/meta-backend-private.h"
#include "backends/native/meta-clutter-backend-native.h"
#include "backends/native/meta-kms-types.h"
#include "backends/native/meta-launcher.h"
#include "backends/native/meta-udev.h"
......@@ -44,4 +45,6 @@ MetaLauncher * meta_backend_native_get_launcher (MetaBackendNative *native);
MetaUdev * meta_backend_native_get_udev (MetaBackendNative *native);
MetaKms * meta_backend_native_get_kms (MetaBackendNative *native);
#endif /* META_BACKEND_NATIVE_H */
......@@ -37,6 +37,8 @@
#include "backends/meta-output.h"
#include "backends/native/meta-backend-native.h"
#include "backends/native/meta-crtc-kms.h"
#include "backends/native/meta-kms-device.h"
#include "backends/native/meta-kms.h"
#include "backends/native/meta-launcher.h"
#include "backends/native/meta-output-kms.h"
......@@ -61,9 +63,10 @@ struct _MetaGpuKms
{
MetaGpu parent;
MetaKmsDevice *kms_device;
uint32_t id;
int fd;
char *file_path;
GSource *source;
clockid_t clock_id;
......@@ -72,8 +75,6 @@ struct _MetaGpuKms
unsigned int n_connectors;
gboolean resources_init_failed_before;
MetaGpuKmsFlag flags;
};
G_DEFINE_TYPE (MetaGpuKms, meta_gpu_kms, META_TYPE_GPU)
......@@ -397,7 +398,7 @@ meta_gpu_kms_get_id (MetaGpuKms *gpu_kms)
const char *
meta_gpu_kms_get_file_path (MetaGpuKms *gpu_kms)
{
return gpu_kms->file_path;
return meta_kms_device_get_path (gpu_kms->kms_device);
}
int64_t
......@@ -428,13 +429,19 @@ meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
gboolean
meta_gpu_kms_is_boot_vga (MetaGpuKms *gpu_kms)
{
return !!(gpu_kms->flags & META_GPU_KMS_FLAG_BOOT_VGA);
MetaKmsDeviceFlag flags;
flags = meta_kms_device_get_flags (gpu_kms->kms_device);
return !!(flags & META_KMS_DEVICE_FLAG_BOOT_VGA);
}
gboolean
meta_gpu_kms_is_platform_device (MetaGpuKms *gpu_kms)
{
return !!(gpu_kms->flags & META_GPU_KMS_FLAG_PLATFORM_DEVICE);
MetaKmsDeviceFlag flags;
flags = meta_kms_device_get_flags (gpu_kms->kms_device);
return !!(flags & META_KMS_DEVICE_FLAG_PLATFORM_DEVICE);
}
static void
......@@ -869,27 +876,22 @@ meta_gpu_kms_can_have_outputs (MetaGpuKms *gpu_kms)
MetaGpuKms *
meta_gpu_kms_new (MetaBackendNative *backend_native,
const char *kms_file_path,
MetaGpuKmsFlag flags,
MetaKmsDevice *kms_device,
GError **error)
{
MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
GSource *source;
MetaKmsSource *kms_source;
MetaGpuKms *gpu_kms;
int kms_fd;
kms_fd = meta_launcher_open_restricted (launcher, kms_file_path, error);
if (kms_fd == -1)
return NULL;
kms_fd = meta_kms_device_leak_fd (kms_device);
gpu_kms = g_object_new (META_TYPE_GPU_KMS,
"backend", backend_native,
NULL);
gpu_kms->flags = flags;
gpu_kms->kms_device = kms_device;
gpu_kms->fd = kms_fd;
gpu_kms->file_path = g_strdup (kms_file_path);
drmSetClientCap (gpu_kms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
......@@ -912,13 +914,6 @@ static void
meta_gpu_kms_finalize (GObject *object)
{
MetaGpuKms *gpu_kms = META_GPU_KMS (object);
MetaBackend *backend = meta_gpu_get_backend (META_GPU (gpu_kms));
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
if (gpu_kms->fd != -1)
meta_launcher_close_restricted (launcher, gpu_kms->fd);
g_clear_pointer (&gpu_kms->file_path, g_free);
g_source_destroy (gpu_kms->source);
......
......@@ -44,16 +44,8 @@ typedef struct _MetaKmsResources
typedef void (*MetaKmsFlipCallback) (void *user_data);
typedef enum _MetaGpuKmsFlag
{
META_GPU_KMS_FLAG_NONE = 0,
META_GPU_KMS_FLAG_BOOT_VGA = (1 << 0),
META_GPU_KMS_FLAG_PLATFORM_DEVICE = (1 << 1),
} MetaGpuKmsFlag;
MetaGpuKms * meta_gpu_kms_new (MetaBackendNative *backend_native,
const char *kms_file_path,
MetaGpuKmsFlag flags,
MetaKmsDevice *kms_device,
GError **error);
gboolean meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms,
......
/*
* Copyright (C) 2019 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "config.h"
#include "backends/native/meta-kms-device.h"
#include "backends/native/meta-backend-native.h"
#include "backends/native/meta-kms-impl-device.h"
#include "backends/native/meta-kms-impl.h"
#include "backends/native/meta-kms-private.h"
struct _MetaKmsDevice
{
GObject parent;
MetaKms *kms;
MetaKmsImplDevice *impl_device;
MetaKmsDeviceFlag flags;
char *path;
};
G_DEFINE_TYPE (MetaKmsDevice, meta_kms_device, G_TYPE_OBJECT);
int
meta_kms_device_leak_fd (MetaKmsDevice *device)
{
return meta_kms_impl_device_leak_fd (device->impl_device);
}
const char *
meta_kms_device_get_path (MetaKmsDevice *device)
{
return device->path;
}
MetaKmsDeviceFlag
meta_kms_device_get_flags (MetaKmsDevice *device)
{
return device->flags;
}
typedef struct _CreateImplDeviceData
{
MetaKmsDevice *device;
int fd;
MetaKmsImplDevice *out_impl_device;
} CreateImplDeviceData;
static gboolean
create_impl_device_in_impl (MetaKmsImpl *impl,
gpointer user_data,
GError **error)
{
CreateImplDeviceData *data = user_data;
MetaKmsImplDevice *impl_device;
impl_device = meta_kms_impl_device_new (data->device, impl, data->fd);
data->out_impl_device = impl_device;
return TRUE;
}
MetaKmsDevice *
meta_kms_device_new (MetaKms *kms,
const char *path,
MetaKmsDeviceFlag flags,
GError **error)
{
MetaBackend *backend = meta_kms_get_backend (kms);
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
MetaKmsDevice *device;
CreateImplDeviceData data;
int fd;
fd = meta_launcher_open_restricted (launcher, path, error);
if (fd == -1)
return NULL;
device = g_object_new (META_TYPE_KMS_DEVICE, NULL);
data = (CreateImplDeviceData) {
.device = device,
.fd = fd,
};
if (!meta_kms_run_impl_task_sync (kms, create_impl_device_in_impl, &data,
error))
{
meta_launcher_close_restricted (launcher, fd);
g_object_unref (device);
return NULL;
}
device->kms = kms;
device->impl_device = data.out_impl_device;
device->flags = flags;
device->path = g_strdup (path);
return device;
}
typedef struct _FreeImplDeviceData
{
MetaKmsImplDevice *impl_device;
int out_fd;
} FreeImplDeviceData;
static gboolean
free_impl_device_in_impl (MetaKmsImpl *impl,
gpointer user_data,
GError **error)
{
FreeImplDeviceData *data = user_data;
MetaKmsImplDevice *impl_device = data->impl_device;
int fd;
fd = meta_kms_impl_device_close (impl_device);
g_object_unref (impl_device);
data->out_fd = fd;
return TRUE;
}
static void
meta_kms_device_finalize (GObject *object)
{
MetaKmsDevice *device = META_KMS_DEVICE (object);
MetaBackend *backend = meta_kms_get_backend (device->kms);
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
FreeImplDeviceData data;
GError *error = NULL;
data = (FreeImplDeviceData) {
.impl_device = device->impl_device,
};
if (!meta_kms_run_impl_task_sync (device->kms, free_impl_device_in_impl, &data,
&error))
{
g_warning ("Failed to close KMS impl device: %s", error->message);
g_error_free (error);
}
else
{
meta_launcher_close_restricted (launcher, data.out_fd);
}
G_OBJECT_CLASS (meta_kms_device_parent_class)->finalize (object);
}
static void
meta_kms_device_init (MetaKmsDevice *device)
{
}
static void
meta_kms_device_class_init (MetaKmsDeviceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_kms_device_finalize;
}
/*
* Copyright (C) 2019 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_KMS_DEVICE_H
#define META_KMS_DEVICE_H
#include <glib-object.h>
#include "backends/native/meta-kms-types.h"
#define META_TYPE_KMS_DEVICE (meta_kms_device_get_type ())
G_DECLARE_FINAL_TYPE (MetaKmsDevice, meta_kms_device,
META, KMS_DEVICE,
GObject)
int meta_kms_device_leak_fd (MetaKmsDevice *device);
const char * meta_kms_device_get_path (MetaKmsDevice *device);
MetaKmsDeviceFlag meta_kms_device_get_flags (MetaKmsDevice *device);
MetaKmsDevice * meta_kms_device_new (MetaKms *kms,
const char *path,
MetaKmsDeviceFlag flags,
GError **error);
#endif /* META_KMS_DEVICE_H */
/*
* Copyright (C) 2019 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "config.h"
#include "backends/native/meta-kms-impl-device.h"
#include "backends/native/meta-kms-impl.h"
#include "backends/native/meta-kms-private.h"
struct _MetaKmsImplDevice
{
GObject parent;
MetaKmsDevice *device;
MetaKmsImpl *impl;
int fd;
};
G_DEFINE_TYPE (MetaKmsImplDevice, meta_kms_impl_device, G_TYPE_OBJECT)
MetaKmsDevice *
meta_kms_impl_device_get_device (MetaKmsImplDevice *impl_device)
{
return impl_device->device;
}
MetaKmsImplDevice *
meta_kms_impl_device_new (MetaKmsDevice *device,
MetaKmsImpl *impl,
int fd)
{
MetaKmsImplDevice *impl_device;
meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl));
impl_device = g_object_new (META_TYPE_KMS_IMPL_DEVICE, NULL);
impl_device->device = device;
impl_device->impl = impl;
impl_device->fd = fd;
return impl_device;
}
int
meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device)
{
meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
return impl_device->fd;
}
int
meta_kms_impl_device_leak_fd (MetaKmsImplDevice *impl_device)
{
return impl_device->fd;
}
int
meta_kms_impl_device_close (MetaKmsImplDevice *impl_device)
{
int fd;
meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
fd = impl_device->fd;
impl_device->fd = -1;
return fd;
}
static void
meta_kms_impl_device_init (MetaKmsImplDevice *device)
{
}
static void
meta_kms_impl_device_class_init (MetaKmsImplDeviceClass *klass)
{
}
/*
* Copyright (C) 2019 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_KMS_IMPL_DEVICE_H
#define META_KMS_IMPL_DEVICE_H
#include <glib-object.h>
#include <stdint.h>
#include "backends/native/meta-kms-device.h"
#include "backends/native/meta-kms-types.h"
#define META_TYPE_KMS_IMPL_DEVICE (meta_kms_impl_device_get_type ())
G_DECLARE_FINAL_TYPE (MetaKmsImplDevice, meta_kms_impl_device,
META, KMS_IMPL_DEVICE,
GObject)
MetaKmsDevice * meta_kms_impl_device_get_device (MetaKmsImplDevice *impl_device);
int meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device);
int meta_kms_impl_device_leak_fd (MetaKmsImplDevice *impl_device);
int meta_kms_impl_device_close (MetaKmsImplDevice *impl_device);
MetaKmsImplDevice * meta_kms_impl_device_new (MetaKmsDevice *device,
MetaKmsImpl *kms_impl,
int fd);
#endif /* META_KMS_IMPL_DEVICE_H */
/*
* Copyright (C) 2018-2019 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "config.h"
#include "backends/native/meta-kms-impl-simple.h"
#include <gbm.h>
struct _MetaKmsImplSimple
{
MetaKmsImpl parent;
};
G_DEFINE_TYPE (MetaKmsImplSimple, meta_kms_impl_simple,
META_TYPE_KMS_IMPL)
MetaKmsImplSimple *
meta_kms_impl_simple_new (MetaKms *kms,
GError **error)
{
return g_object_new (META_TYPE_KMS_IMPL_SIMPLE,
"kms", kms,
NULL);
}
static void
meta_kms_impl_simple_init (MetaKmsImplSimple *impl_simple)
{
}
static void
meta_kms_impl_simple_class_init (MetaKmsImplSimpleClass *klass)
{
}
/*
* Copyright (C) 2018 Red Hat