mutter/src/backends/native/meta-kms-device.c
Jonas Ådahl 227eea1e31 kms-impl-simple: Add fake cursor planes if no real ones
Non-atomic drivers may support drmModeSetCursor() even if no cursor
plane is advertised. To deal with this, add a fake cursor plane for
every CRTC when using MetaKmsImplSimple. This will eventually be
translated to drmModeSetCursor() calls without any explicit cursor plane
usage.

Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/1058

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1079
2020-03-07 21:40:50 +00:00

387 lines
10 KiB
C

/*
* Copyright (C) 2019 Red Hat
* Copyright (C) 2019 DisplayLink (UK) Ltd.
*
* 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-private.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-plane.h"
#include "backends/native/meta-kms-private.h"
struct _MetaKmsDevice
{
GObject parent;
MetaKms *kms;
MetaKmsImplDevice *impl_device;
MetaKmsDeviceFlag flags;
char *path;
GList *crtcs;
GList *connectors;
GList *planes;
MetaKmsDeviceCaps caps;
};
G_DEFINE_TYPE (MetaKmsDevice, meta_kms_device, G_TYPE_OBJECT);
MetaKmsImplDevice *
meta_kms_device_get_impl_device (MetaKmsDevice *device)
{
return device->impl_device;
}
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;
}
gboolean
meta_kms_device_get_cursor_size (MetaKmsDevice *device,
uint64_t *out_cursor_width,
uint64_t *out_cursor_height)
{
if (device->caps.has_cursor_size)
{
*out_cursor_width = device->caps.cursor_width;
*out_cursor_height = device->caps.cursor_height;
return TRUE;
}
else
{
return FALSE;
}
}
GList *
meta_kms_device_get_connectors (MetaKmsDevice *device)
{
return device->connectors;
}
GList *
meta_kms_device_get_crtcs (MetaKmsDevice *device)
{
return device->crtcs;
}
static GList *
meta_kms_device_get_planes (MetaKmsDevice *device)
{
return device->planes;
}
static MetaKmsPlane *
get_plane_with_type_for (MetaKmsDevice *device,
MetaKmsCrtc *crtc,
MetaKmsPlaneType type)
{
GList *l;
for (l = meta_kms_device_get_planes (device); l; l = l->next)
{
MetaKmsPlane *plane = l->data;
if (meta_kms_plane_get_plane_type (plane) != type)
continue;
if (meta_kms_plane_is_usable_with (plane, crtc))
return plane;
}
return NULL;
}
MetaKmsPlane *
meta_kms_device_get_primary_plane_for (MetaKmsDevice *device,
MetaKmsCrtc *crtc)
{
return get_plane_with_type_for (device, crtc, META_KMS_PLANE_TYPE_PRIMARY);
}
MetaKmsPlane *
meta_kms_device_get_cursor_plane_for (MetaKmsDevice *device,
MetaKmsCrtc *crtc)
{
return get_plane_with_type_for (device, crtc, META_KMS_PLANE_TYPE_CURSOR);
}
void
meta_kms_device_update_states_in_impl (MetaKmsDevice *device)
{
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
meta_assert_in_kms_impl (device->kms);
meta_assert_is_waiting_for_kms_impl_task (device->kms);
meta_kms_impl_device_update_states (impl_device);
g_list_free (device->crtcs);
device->crtcs = meta_kms_impl_device_copy_crtcs (impl_device);
g_list_free (device->connectors);
device->connectors = meta_kms_impl_device_copy_connectors (impl_device);
g_list_free (device->planes);
device->planes = meta_kms_impl_device_copy_planes (impl_device);
}
void
meta_kms_device_predict_states_in_impl (MetaKmsDevice *device,
MetaKmsUpdate *update)
{
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
meta_assert_in_kms_impl (device->kms);
meta_kms_impl_device_predict_states (impl_device, update);
}
static gpointer
dispatch_in_impl (MetaKmsImpl *impl,
gpointer user_data,
GError **error)
{
MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (user_data);
gboolean ret;
ret = meta_kms_impl_device_dispatch (impl_device, error);
return GINT_TO_POINTER (ret);
}
static gpointer
dispatch_idle_in_impl (MetaKmsImpl *impl,
gpointer user_data,
GError **error)
{
meta_kms_impl_dispatch_idle (impl);
return GINT_TO_POINTER (TRUE);
}
int
meta_kms_device_dispatch_sync (MetaKmsDevice *device,
GError **error)
{
int callback_count;
if (!meta_kms_run_impl_task_sync (device->kms,
dispatch_idle_in_impl,
device->impl_device,
error))
return -1;
callback_count = meta_kms_flush_callbacks (device->kms);
if (callback_count > 0)
return TRUE;
if (!meta_kms_run_impl_task_sync (device->kms,
dispatch_in_impl,
device->impl_device,
error))
return -1;
return meta_kms_flush_callbacks (device->kms);
}
void
meta_kms_device_add_fake_plane_in_impl (MetaKmsDevice *device,
MetaKmsPlaneType plane_type,
MetaKmsCrtc *crtc)
{
MetaKmsImplDevice *impl_device = device->impl_device;
MetaKmsPlane *plane;
meta_assert_in_kms_impl (device->kms);
plane = meta_kms_impl_device_add_fake_plane (impl_device,
plane_type,
crtc);
device->planes = g_list_append (device->planes, plane);
}
typedef struct _CreateImplDeviceData
{
MetaKmsDevice *device;
int fd;
MetaKmsImplDevice *out_impl_device;
GList *out_crtcs;
GList *out_connectors;
GList *out_planes;
MetaKmsDeviceCaps out_caps;
} CreateImplDeviceData;
static gpointer
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, error);
if (!impl_device)
return FALSE;
data->out_impl_device = impl_device;
data->out_crtcs = meta_kms_impl_device_copy_crtcs (impl_device);
data->out_connectors = meta_kms_impl_device_copy_connectors (impl_device);
data->out_planes = meta_kms_impl_device_copy_planes (impl_device);
data->out_caps = *meta_kms_impl_device_get_caps (impl_device);
return GINT_TO_POINTER (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);
device->kms = kms;
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->impl_device = data.out_impl_device;
device->flags = flags;
device->path = g_strdup (path);
device->crtcs = data.out_crtcs;
device->connectors = data.out_connectors;
device->planes = data.out_planes;
device->caps = data.out_caps;
return device;
}
typedef struct _FreeImplDeviceData
{
MetaKmsImplDevice *impl_device;
int out_fd;
} FreeImplDeviceData;
static gpointer
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 GINT_TO_POINTER (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);
g_free (device->path);
g_list_free (device->crtcs);
g_list_free (device->connectors);
g_list_free (device->planes);
if (device->impl_device)
{
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;
}