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:
parent
99209958b9
commit
8e9f01d1ce
5 changed files with 324 additions and 0 deletions
|
@ -135,3 +135,6 @@
|
||||||
|
|
||||||
/* Supports malloc_trim */
|
/* Supports malloc_trim */
|
||||||
#mesondefine HAVE_MALLOC_TRIM
|
#mesondefine HAVE_MALLOC_TRIM
|
||||||
|
|
||||||
|
/* Supports eventfd */
|
||||||
|
#mesondefine HAVE_EVENTFD
|
||||||
|
|
|
@ -541,6 +541,8 @@ endif
|
||||||
|
|
||||||
cc.compiles('void main (void) { __builtin_ffsl (0); __builtin_popcountl (0); }')
|
cc.compiles('void main (void) { __builtin_ffsl (0); __builtin_popcountl (0); }')
|
||||||
|
|
||||||
|
have_eventfd = cc.has_header('sys/eventfd.h')
|
||||||
|
|
||||||
cdata = configuration_data()
|
cdata = configuration_data()
|
||||||
cdata.set_quoted('GETTEXT_PACKAGE', gettext_package)
|
cdata.set_quoted('GETTEXT_PACKAGE', gettext_package)
|
||||||
cdata.set_quoted('VERSION', meson.project_version())
|
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_PANGO_FT2', have_pango_ft2)
|
||||||
cdata.set('HAVE_TIMERFD', have_timerfd)
|
cdata.set('HAVE_TIMERFD', have_timerfd)
|
||||||
cdata.set('HAVE_MALLOC_TRIM', have_malloc_trim)
|
cdata.set('HAVE_MALLOC_TRIM', have_malloc_trim)
|
||||||
|
cdata.set('HAVE_EVENTFD', have_eventfd)
|
||||||
|
|
||||||
if have_x11_client
|
if have_x11_client
|
||||||
xkb_base = xkeyboard_config_dep.get_variable('xkb_base')
|
xkb_base = xkeyboard_config_dep.get_variable('xkb_base')
|
||||||
|
|
|
@ -579,6 +579,8 @@ if have_wayland
|
||||||
'core/meta-service-channel.h',
|
'core/meta-service-channel.h',
|
||||||
'wayland/meta-cursor-sprite-wayland.c',
|
'wayland/meta-cursor-sprite-wayland.c',
|
||||||
'wayland/meta-cursor-sprite-wayland.h',
|
'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.c',
|
||||||
'wayland/meta-pointer-confinement-wayland.h',
|
'wayland/meta-pointer-confinement-wayland.h',
|
||||||
'wayland/meta-pointer-lock-wayland.c',
|
'wayland/meta-pointer-lock-wayland.c',
|
||||||
|
|
269
src/wayland/meta-drm-timeline.c
Normal file
269
src/wayland/meta-drm-timeline.c
Normal 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);
|
||||||
|
}
|
47
src/wayland/meta-drm-timeline.h
Normal file
47
src/wayland/meta-drm-timeline.h
Normal 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);
|
Loading…
Reference in a new issue