1
0
Fork 0

wayland: Add MetaDrmTimeline

This abstracts away directly dealing with DRM syncobjs. Explicit
sync code can simply create a MetaDrmTimeline and request an fd at
a particular sync point.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3300>
This commit is contained in:
Austin Shafer 2023-09-06 13:06:54 -04:00
parent 99209958b9
commit 8e9f01d1ce
5 changed files with 324 additions and 0 deletions

View file

@ -135,3 +135,6 @@
/* Supports malloc_trim */
#mesondefine HAVE_MALLOC_TRIM
/* Supports eventfd */
#mesondefine HAVE_EVENTFD

View file

@ -541,6 +541,8 @@ endif
cc.compiles('void main (void) { __builtin_ffsl (0); __builtin_popcountl (0); }')
have_eventfd = cc.has_header('sys/eventfd.h')
cdata = configuration_data()
cdata.set_quoted('GETTEXT_PACKAGE', gettext_package)
cdata.set_quoted('VERSION', meson.project_version())
@ -573,6 +575,7 @@ cdata.set('HAVE_LIBDISPLAY_INFO', have_libdisplay_info)
cdata.set('HAVE_PANGO_FT2', have_pango_ft2)
cdata.set('HAVE_TIMERFD', have_timerfd)
cdata.set('HAVE_MALLOC_TRIM', have_malloc_trim)
cdata.set('HAVE_EVENTFD', have_eventfd)
if have_x11_client
xkb_base = xkeyboard_config_dep.get_variable('xkb_base')

View file

@ -579,6 +579,8 @@ if have_wayland
'core/meta-service-channel.h',
'wayland/meta-cursor-sprite-wayland.c',
'wayland/meta-cursor-sprite-wayland.h',
'wayland/meta-drm-timeline.c',
'wayland/meta-drm-timeline.h',
'wayland/meta-pointer-confinement-wayland.c',
'wayland/meta-pointer-confinement-wayland.h',
'wayland/meta-pointer-lock-wayland.c',

View file

@ -0,0 +1,269 @@
/*
* Copyright (C) 2023 NVIDIA Corporation.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Written by:
* Austin Shafer <ashafer@nvidia.com>
*/
/**
* MetaDrmTimeline
*
* MetaDrmTimeline is a helper for handling DRM syncobj operations. It
* can import DRM syncobjs and export eventfds at a particular point.
*
* This is heavily inspired by wlroot's wlr_render_timeline, written by
* Simon Ser.
*/
#include "config.h"
#include <fcntl.h>
#include <xf86drm.h>
#include <glib/gstdio.h>
#ifdef HAVE_EVENTFD
#include <sys/eventfd.h>
#endif
#include "meta/util.h"
#include "wayland/meta-drm-timeline.h"
enum
{
PROP_0,
PROP_DRM_FD,
PROP_SYNCOBJ_FD,
N_PROPS
};
typedef struct _MetaDrmTimeline
{
GObject parent;
int drm;
int drm_syncobj_fd;
uint32_t drm_syncobj;
} MetaDrmTimeline;
static GParamSpec *obj_props[N_PROPS];
static void initable_iface_init (GInitableIface *initable_iface);
G_DEFINE_FINAL_TYPE_WITH_CODE (MetaDrmTimeline, meta_drm_timeline, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
initable_iface_init))
static void
meta_drm_timeline_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaDrmTimeline *timeline = META_DRM_TIMELINE (object);
switch (prop_id)
{
case PROP_DRM_FD:
g_value_set_int (value, timeline->drm);
break;
case PROP_SYNCOBJ_FD:
g_value_set_int (value, timeline->drm_syncobj_fd);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_drm_timeline_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaDrmTimeline *timeline = META_DRM_TIMELINE (object);
int fd;
switch (prop_id)
{
case PROP_DRM_FD:
fd = g_value_get_int (value);
timeline->drm = fcntl (fd, F_DUPFD_CLOEXEC, 0);
break;
case PROP_SYNCOBJ_FD:
fd = g_value_get_int (value);
timeline->drm_syncobj_fd = fcntl (fd, F_DUPFD_CLOEXEC, 0);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
meta_drm_timeline_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
MetaDrmTimeline *timeline = META_DRM_TIMELINE (initable);
if (drmSyncobjFDToHandle (timeline->drm,
timeline->drm_syncobj_fd,
&timeline->drm_syncobj) != 0)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"Failed to import DRM syncobj");
return FALSE;
}
return TRUE;
}
static void
initable_iface_init (GInitableIface *initable_iface)
{
initable_iface->init = meta_drm_timeline_initable_init;
}
MetaDrmTimeline *
meta_drm_timeline_import_syncobj (int fd,
int drm_syncobj,
GError **error)
{
MetaDrmTimeline *timeline = g_initable_new (META_TYPE_DRM_TIMELINE,
NULL, error,
"drm-fd", fd,
"syncobj-fd", drm_syncobj,
NULL);
return timeline;
}
int
meta_drm_timeline_get_eventfd (MetaDrmTimeline *timeline,
uint64_t sync_point,
GError **error)
{
g_autofd int fd = -1;
#ifdef HAVE_EVENTFD
fd = eventfd (0, EFD_CLOEXEC);
if (fd < 0)
return -1;
if (drmSyncobjEventfd (timeline->drm, timeline->drm_syncobj,
sync_point, fd, 0) != 0)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"DRM_IOCTL_SYNCOBJ_EVENTFD: Failed to export eventfd");
return -1;
}
#endif
return g_steal_fd (&fd);
}
gboolean
meta_drm_timeline_set_sync_point (MetaDrmTimeline *timeline,
uint64_t sync_point,
int sync_fd,
GError **error)
{
uint32_t tmp;
/* Import our syncfd at a new release point */
if (drmSyncobjCreate (timeline->drm, 0, &tmp) != 0)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Failed to create temporary syncobj");
return FALSE;
}
if (drmSyncobjImportSyncFile (timeline->drm, tmp, sync_fd) != 0)
goto end;
if (drmSyncobjTransfer (timeline->drm, timeline->drm_syncobj,
sync_point, tmp, 0, 0) != 0)
goto end;
drmSyncobjDestroy (timeline->drm, tmp);
return TRUE;
end:
drmSyncobjDestroy (timeline->drm, tmp);
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Failed to import syncfd at specified point");
return FALSE;
}
static void
meta_drm_timeline_finalize (GObject *object)
{
MetaDrmTimeline *timeline = META_DRM_TIMELINE (object);
drmSyncobjDestroy (timeline->drm, timeline->drm_syncobj);
g_clear_fd (&timeline->drm_syncobj_fd, NULL);
g_clear_fd (&timeline->drm, NULL);
G_OBJECT_CLASS (meta_drm_timeline_parent_class)->finalize (object);
}
static void
meta_drm_timeline_init (MetaDrmTimeline *timeline)
{
timeline->drm = -1;
timeline->drm_syncobj_fd = -1;
timeline->drm_syncobj = -1;
}
static void
meta_drm_timeline_class_init (MetaDrmTimelineClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = meta_drm_timeline_get_property;
object_class->set_property = meta_drm_timeline_set_property;
object_class->finalize = meta_drm_timeline_finalize;
obj_props[PROP_DRM_FD] =
g_param_spec_int ("drm-fd",
NULL,
NULL,
0, INT_MAX, 0,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_SYNCOBJ_FD] =
g_param_spec_int ("syncobj-fd",
NULL,
NULL,
0, INT_MAX, 0,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, obj_props);
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (C) 2023 NVIDIA Corporation.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Written by:
* Austin Shafer <ashafer@nvidia.com>
*/
#pragma once
#include <glib.h>
#include <glib-object.h>
#include <stdint.h>
#define META_TYPE_DRM_TIMELINE (meta_drm_timeline_get_type ())
G_DECLARE_FINAL_TYPE (MetaDrmTimeline, meta_drm_timeline,
META, DRM_TIMELINE, GObject);
typedef struct _MetaDrmTimeline MetaDrmTimeline;
MetaDrmTimeline * meta_drm_timeline_create (int fd,
GError **error);
MetaDrmTimeline * meta_drm_timeline_import_syncobj (int fd,
int drm_syncobj,
GError **error);
int meta_drm_timeline_get_eventfd (MetaDrmTimeline *timeline,
uint64_t sync_point,
GError **error);
gboolean meta_drm_timeline_set_sync_point (MetaDrmTimeline *timeline,
uint64_t sync_point,
int sync_fd,
GError **error);