1
0
Fork 0

backend/native: Prepare render devices earlier than KMS

The type of render device used for a specific GPU affects the mode
setting backend that can be used, more specifically, when the render
device is an EGLStream based one, atomic mode setting isn't possible, as
page flipping is done via EGL, not via atomic mode setting commits.

Preparing the render devices before KMS devices means can make a more
informed decision whether to deny-list atomic mode setting for when
a certain GPU uses a EGLStream based render device instance.

This also means we need to translate mode setting devices to render node
devices when creating the render device itself, as doing it later when
creating the mode setting device is already too late.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2578>
This commit is contained in:
Jonas Ådahl 2022-08-17 12:11:29 +02:00 committed by Marge Bot
parent 1a0bd44694
commit 58c3734d78
6 changed files with 207 additions and 151 deletions

View file

@ -821,6 +821,10 @@ meta_backend_constructed (GObject *object)
NULL);
}
#ifdef HAVE_EGL
priv->egl = g_object_new (META_TYPE_EGL, NULL);
#endif
G_OBJECT_CLASS (meta_backend_parent_class)->constructed (object);
}
@ -1199,11 +1203,6 @@ meta_backend_initable_init (GInitable *initable,
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
priv->settings = meta_settings_new (backend);
#ifdef HAVE_EGL
priv->egl = g_object_new (META_TYPE_EGL, NULL);
#endif
priv->orientation_manager = g_object_new (META_TYPE_ORIENTATION_MANAGER, NULL);
priv->monitor_manager = meta_backend_create_monitor_manager (backend, error);

View file

@ -33,4 +33,7 @@ MetaBarrierManagerNative *meta_backend_native_get_barrier_manager (MetaBackendNa
META_EXPORT_TEST
MetaDevicePool * meta_backend_native_get_device_pool (MetaBackendNative *native);
MetaRenderDevice * meta_backend_native_take_render_device (MetaBackendNative *backend_native,
const char *device_path);
#endif /* META_BACKEND_NATIVE_PRIVATE_H */

View file

@ -32,6 +32,7 @@ typedef struct _MetaCrtcModeVirtual MetaCrtcModeVirtual;
typedef struct _MetaDevicePool MetaDevicePool;
typedef struct _MetaDeviceFile MetaDeviceFile;
typedef struct _MetaDrmBuffer MetaDrmBuffer;
typedef struct _MetaRenderDevice MetaRenderDevice;
typedef enum _MetaSeatNativeFlag
{

View file

@ -55,6 +55,7 @@
#include "backends/native/meta-kms-device.h"
#include "backends/native/meta-launcher.h"
#include "backends/native/meta-monitor-manager-native.h"
#include "backends/native/meta-render-device-gbm.h"
#include "backends/native/meta-renderer-native.h"
#include "backends/native/meta-seat-native.h"
#include "backends/native/meta-stage-native.h"
@ -67,6 +68,10 @@
#include "backends/meta-screen-cast.h"
#endif
#ifdef HAVE_EGL_DEVICE
#include "backends/native/meta-render-device-egl-stream.h"
#endif
#include "meta-private-enum-types.h"
enum
@ -89,6 +94,8 @@ struct _MetaBackendNative
MetaUdev *udev;
MetaKms *kms;
GHashTable *startup_render_devices;
MetaBackendNativeMode mode;
};
@ -111,6 +118,7 @@ meta_backend_native_dispose (GObject *object)
G_OBJECT_CLASS (meta_backend_native_parent_class)->dispose (object);
g_clear_pointer (&native->startup_render_devices, g_hash_table_unref);
g_clear_object (&native->kms);
g_clear_object (&native->udev);
g_clear_object (&native->device_pool);
@ -206,6 +214,7 @@ update_viewports (MetaBackend *backend)
static void
meta_backend_native_post_init (MetaBackend *backend)
{
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
MetaSettings *settings = meta_backend_get_settings (backend);
META_BACKEND_CLASS (meta_backend_native_parent_class)->post_init (backend);
@ -246,9 +255,12 @@ meta_backend_native_post_init (MetaBackend *backend)
}
#ifdef HAVE_REMOTE_DESKTOP
maybe_disable_screen_cast_dma_bufs (META_BACKEND_NATIVE (backend));
maybe_disable_screen_cast_dma_bufs (backend_native);
#endif
g_clear_pointer (&backend_native->startup_render_devices,
g_hash_table_unref);
update_viewports (backend);
}
@ -450,14 +462,129 @@ meta_backend_native_update_screen_size (MetaBackend *backend,
clutter_actor_set_size (stage, width, height);
}
static MetaGpuKms *
create_gpu_from_udev_device (MetaBackendNative *native,
GUdevDevice *device,
GError **error)
static MetaRenderDevice *
create_render_device (MetaBackendNative *backend_native,
const char *device_path,
GError **error)
{
MetaBackend *backend = META_BACKEND (backend_native);
MetaDevicePool *device_pool =
meta_backend_native_get_device_pool (backend_native);
g_autoptr (MetaDeviceFile) device_file = NULL;
MetaDeviceFileFlags device_file_flags;
g_autoptr (MetaRenderDeviceGbm) render_device_gbm = NULL;
g_autoptr (GError) gbm_error = NULL;
#ifdef HAVE_EGL_DEVICE
g_autoptr (MetaRenderDeviceEglStream) render_device_egl_stream = NULL;
g_autoptr (GError) egl_stream_error = NULL;
#endif
if (meta_backend_is_headless (backend))
device_file_flags = META_DEVICE_FILE_FLAG_NONE;
else
device_file_flags = META_DEVICE_FILE_FLAG_TAKE_CONTROL;
device_file = meta_device_pool_open (device_pool,
device_path,
device_file_flags,
error);
if (!device_file)
return NULL;
if (meta_backend_is_headless (backend))
{
int fd;
g_autofree char *render_node_path = NULL;
g_autoptr (MetaDeviceFile) render_node_device_file = NULL;
fd = meta_device_file_get_fd (device_file);
render_node_path = drmGetRenderDeviceNameFromFd (fd);
if (!render_node_path)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Couldn't find render node device for '%s'",
meta_device_file_get_path (device_file));
return NULL;
}
meta_topic (META_DEBUG_KMS, "Found render node '%s' from '%s'",
render_node_path,
meta_device_file_get_path (device_file));
render_node_device_file =
meta_device_pool_open (device_pool, render_node_path,
META_DEVICE_FILE_FLAG_NONE,
error);
if (!render_node_device_file)
return NULL;
g_clear_pointer (&device_file, meta_device_file_release);
device_file = g_steal_pointer (&render_node_device_file);
}
#ifdef HAVE_EGL_DEVICE
if (g_strcmp0 (getenv ("MUTTER_DEBUG_FORCE_EGL_STREAM"), "1") != 0)
#endif
{
render_device_gbm = meta_render_device_gbm_new (backend, device_file,
&gbm_error);
if (render_device_gbm)
{
MetaRenderDevice *render_device =
META_RENDER_DEVICE (render_device_gbm);
if (meta_render_device_is_hardware_accelerated (render_device))
return META_RENDER_DEVICE (g_steal_pointer (&render_device_gbm));
}
}
#ifdef HAVE_EGL_DEVICE
else
{
g_set_error (&gbm_error, G_IO_ERROR, G_IO_ERROR_FAILED,
"GBM backend was disabled using env var");
}
#endif
#ifdef HAVE_EGL_DEVICE
render_device_egl_stream =
meta_render_device_egl_stream_new (backend,
device_file,
&egl_stream_error);
if (render_device_egl_stream)
return META_RENDER_DEVICE (g_steal_pointer (&render_device_egl_stream));
#endif
if (render_device_gbm)
return META_RENDER_DEVICE (g_steal_pointer (&render_device_gbm));
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
"Failed to initialize render device for %s: "
"%s"
#ifdef HAVE_EGL_DEVICE
", %s"
#endif
, device_path
, gbm_error->message
#ifdef HAVE_EGL_DEVICE
, egl_stream_error->message
#endif
);
return NULL;
}
static gboolean
add_drm_device (MetaBackendNative *backend_native,
GUdevDevice *device,
GError **error)
{
MetaKmsDeviceFlag flags = META_KMS_DEVICE_FLAG_NONE;
const char *device_path;
g_autoptr (MetaRenderDevice) render_device = NULL;
MetaKmsDevice *kms_device;
MetaGpuKms *gpu_kms;
if (meta_is_udev_device_platform_device (device))
flags |= META_KMS_DEVICE_FLAG_PLATFORM_DEVICE;
@ -473,12 +600,22 @@ create_gpu_from_udev_device (MetaBackendNative *native,
device_path = g_udev_device_get_device_file (device);
kms_device = meta_kms_create_device (native->kms, device_path, flags,
render_device = create_render_device (backend_native, device_path, error);
if (!render_device)
return FALSE;
kms_device = meta_kms_create_device (backend_native->kms, device_path, flags,
error);
if (!kms_device)
return NULL;
return FALSE;
return meta_gpu_kms_new (native, kms_device, error);
g_hash_table_insert (backend_native->startup_render_devices,
g_strdup (device_path),
g_steal_pointer (&render_device));
gpu_kms = meta_gpu_kms_new (backend_native, kms_device, error);
meta_backend_add_gpu (META_BACKEND (backend_native), META_GPU (gpu_kms));
return TRUE;
}
static gboolean
@ -504,7 +641,6 @@ on_udev_device_added (MetaUdev *udev,
MetaBackend *backend = META_BACKEND (native);
g_autoptr (GError) error = NULL;
const char *device_path;
MetaGpuKms *new_gpu_kms;
GList *gpus, *l;
if (!meta_udev_is_drm_device (udev, device))
@ -531,8 +667,7 @@ on_udev_device_added (MetaUdev *udev,
return;
}
new_gpu_kms = create_gpu_from_udev_device (native, device, &error);
if (!new_gpu_kms)
if (!add_drm_device (native, device, &error))
{
if (meta_backend_is_headless (backend) &&
g_error_matches (error, G_IO_ERROR,
@ -547,11 +682,7 @@ on_udev_device_added (MetaUdev *udev,
g_warning ("Failed to hotplug secondary gpu '%s': %s",
device_path, error->message);
}
return;
}
meta_backend_add_gpu (backend, META_GPU (new_gpu_kms));
}
static gboolean
@ -570,7 +701,6 @@ init_gpus (MetaBackendNative *native,
for (l = devices; l; l = l->next)
{
GUdevDevice *device = l->data;
MetaGpuKms *gpu_kms;
GError *local_error = NULL;
if (should_ignore_device (native, device))
@ -580,9 +710,7 @@ init_gpus (MetaBackendNative *native,
continue;
}
gpu_kms = create_gpu_from_udev_device (native, device, &local_error);
if (!gpu_kms)
if (!add_drm_device (native, device, &local_error))
{
if (meta_backend_is_headless (backend) &&
g_error_matches (local_error, G_IO_ERROR,
@ -603,8 +731,6 @@ init_gpus (MetaBackendNative *native,
g_clear_error (&local_error);
continue;
}
meta_backend_add_gpu (backend, META_GPU (gpu_kms));
}
g_list_free_full (devices, g_object_unref);
@ -753,8 +879,11 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
}
static void
meta_backend_native_init (MetaBackendNative *native)
meta_backend_native_init (MetaBackendNative *backend_native)
{
backend_native->startup_render_devices =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
}
MetaLauncher *
@ -860,3 +989,18 @@ void meta_backend_native_resume (MetaBackendNative *native)
clutter_seat_ensure_a11y_state (CLUTTER_SEAT (seat));
}
MetaRenderDevice *
meta_backend_native_take_render_device (MetaBackendNative *backend_native,
const char *device_path)
{
MetaRenderDevice *render_device;
if (g_hash_table_steal_extended (backend_native->startup_render_devices,
device_path,
NULL,
(gpointer *) &render_device))
return render_device;
else
return NULL;
}

View file

@ -55,31 +55,8 @@ meta_kms_impl_device_dummy_open_device_file (MetaKmsImplDevice *impl_device,
MetaBackend *backend = meta_kms_get_backend (kms);
MetaDevicePool *device_pool =
meta_backend_native_get_device_pool (META_BACKEND_NATIVE (backend));
g_autoptr (MetaDeviceFile) device_file = NULL;
int fd;
g_autofree char *render_node_path = NULL;
device_file = meta_device_pool_open (device_pool, path,
META_DEVICE_FILE_FLAG_NONE,
error);
if (!device_file)
return NULL;
fd = meta_device_file_get_fd (device_file);
render_node_path = drmGetRenderDeviceNameFromFd (fd);
if (!render_node_path)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Couldn't find render node device for '%s' (%s)",
meta_kms_impl_device_get_path (impl_device),
meta_kms_impl_device_get_driver_name (impl_device));
return NULL;
}
meta_topic (META_DEBUG_KMS, "Found render node '%s' from '%s'",
render_node_path, path);
return meta_device_pool_open (device_pool, render_node_path,
return meta_device_pool_open (device_pool, path,
META_DEVICE_FILE_FLAG_NONE,
error);
}

View file

@ -1701,24 +1701,16 @@ gpu_kms_is_hardware_rendering (MetaRendererNative *renderer_native,
}
static MetaRendererNativeGpuData *
create_renderer_gpu_data_gbm (MetaRendererNative *renderer_native,
MetaDeviceFile *device_file,
MetaGpuKms *gpu_kms,
GError **error)
create_renderer_gpu_data_gbm (MetaRendererNative *renderer_native,
MetaRenderDevice *render_device,
MetaGpuKms *gpu_kms)
{
MetaRenderer *renderer = META_RENDERER (renderer_native);
MetaBackend *backend = meta_renderer_get_backend (renderer);
MetaRenderDeviceGbm *render_device_gbm;
MetaRendererNativeGpuData *renderer_gpu_data;
render_device_gbm = meta_render_device_gbm_new (backend, device_file, error);
if (!render_device_gbm)
return NULL;
renderer_gpu_data = meta_create_renderer_native_gpu_data ();
renderer_gpu_data->renderer_native = renderer_native;
renderer_gpu_data->mode = META_RENDERER_NATIVE_MODE_GBM;
renderer_gpu_data->render_device = META_RENDER_DEVICE (render_device_gbm);
renderer_gpu_data->render_device = render_device;
renderer_gpu_data->gpu_kms = gpu_kms;
init_secondary_gpu_data (renderer_gpu_data);
@ -1751,26 +1743,15 @@ create_renderer_gpu_data_surfaceless (MetaRendererNative *renderer_native,
#ifdef HAVE_EGL_DEVICE
static MetaRendererNativeGpuData *
create_renderer_gpu_data_egl_device (MetaRendererNative *renderer_native,
MetaDeviceFile *device_file,
MetaGpuKms *gpu_kms,
GError **error)
MetaRenderDevice *render_device,
MetaGpuKms *gpu_kms)
{
MetaRenderer *renderer = META_RENDERER (renderer_native);
MetaBackend *backend = meta_renderer_get_backend (renderer);
MetaRenderDeviceEglStream *render_device_egl_stream;
MetaRendererNativeGpuData *renderer_gpu_data;
render_device_egl_stream = meta_render_device_egl_stream_new (backend,
device_file,
error);
if (!render_device_egl_stream)
return NULL;
renderer_gpu_data = meta_create_renderer_native_gpu_data ();
renderer_gpu_data->renderer_native = renderer_native;
renderer_gpu_data->mode = META_RENDERER_NATIVE_MODE_EGL_DEVICE;
renderer_gpu_data->render_device =
META_RENDER_DEVICE (render_device_egl_stream);
renderer_gpu_data->render_device = render_device;
renderer_gpu_data->gpu_kms = gpu_kms;
return renderer_gpu_data;
@ -1784,91 +1765,42 @@ meta_renderer_native_create_renderer_gpu_data (MetaRendererNative *renderer_nat
{
MetaRenderer *renderer = META_RENDERER (renderer_native);
MetaBackend *backend = meta_renderer_get_backend (renderer);
MetaDevicePool *device_pool =
meta_backend_native_get_device_pool (META_BACKEND_NATIVE (backend));
MetaRendererNativeGpuData *gbm_renderer_gpu_data = NULL;
MetaDeviceFileFlags device_file_flags = META_DEVICE_FILE_FLAG_NONE;
g_autoptr (MetaDeviceFile) device_file = NULL;
GError *gbm_error = NULL;
#ifdef HAVE_EGL_DEVICE
MetaRendererNativeGpuData *egl_stream_renderer_gpu_data;
GError *egl_device_error = NULL;
#endif
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
const char *device_path;
MetaRenderDevice *render_device;
if (!gpu_kms)
return create_renderer_gpu_data_surfaceless (renderer_native, error);
if (!(meta_kms_device_get_flags (meta_gpu_kms_get_kms_device (gpu_kms)) &
META_KMS_DEVICE_FLAG_NO_MODE_SETTING))
device_file_flags = META_DEVICE_FILE_FLAG_TAKE_CONTROL;
device_file = meta_device_pool_open (device_pool,
meta_gpu_kms_get_file_path (gpu_kms),
device_file_flags,
error);
if (!device_file)
return NULL;
#ifdef HAVE_EGL_DEVICE
if (g_strcmp0 (getenv ("MUTTER_DEBUG_FORCE_EGL_STREAM"), "1") != 0)
#endif
device_path = meta_gpu_kms_get_file_path (gpu_kms);
render_device = meta_backend_native_take_render_device (backend_native,
device_path);
if (!render_device)
{
gbm_renderer_gpu_data = create_renderer_gpu_data_gbm (renderer_native,
device_file,
gpu_kms,
&gbm_error);
if (gbm_renderer_gpu_data)
{
MetaRenderDevice *render_device = gbm_renderer_gpu_data->render_device;
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"No render device found for %s", device_path);
return NULL;
}
if (meta_render_device_is_hardware_accelerated (render_device))
return gbm_renderer_gpu_data;
}
if (META_IS_RENDER_DEVICE_GBM (render_device))
{
return create_renderer_gpu_data_gbm (renderer_native,
render_device,
gpu_kms);
}
#ifdef HAVE_EGL_DEVICE
else if (META_IS_RENDER_DEVICE_EGL_STREAM (render_device))
{
return create_renderer_gpu_data_egl_device (renderer_native,
render_device,
gpu_kms);
}
#endif
else
{
g_set_error (&gbm_error, G_IO_ERROR, G_IO_ERROR_FAILED,
"GBM backend was disabled using env var");
g_assert_not_reached ();
return NULL;
}
#endif
#ifdef HAVE_EGL_DEVICE
egl_stream_renderer_gpu_data =
create_renderer_gpu_data_egl_device (renderer_native,
device_file,
gpu_kms,
&egl_device_error);
if (egl_stream_renderer_gpu_data)
{
g_clear_pointer (&gbm_renderer_gpu_data,
meta_renderer_native_gpu_data_free);
return egl_stream_renderer_gpu_data;
}
#endif
if (gbm_renderer_gpu_data)
return gbm_renderer_gpu_data;
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
"Failed to initialize renderer: "
"%s"
#ifdef HAVE_EGL_DEVICE
", %s"
#endif
, gbm_error->message
#ifdef HAVE_EGL_DEVICE
, egl_device_error->message
#endif
);
g_error_free (gbm_error);
#ifdef HAVE_EGL_DEVICE
g_error_free (egl_device_error);
#endif
return NULL;
}
static const char *