Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Tobi_Peter:yuga:unstable
mutter
3300.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 3300.patch of Package mutter
From 022f77f78c33dd51efab201ece564d3c46f27c93 Mon Sep 17 00:00:00 2001 From: Austin Shafer <ashafer@badland.io> Date: Thu, 26 Oct 2023 13:33:34 -0400 Subject: [PATCH 1/5] cogl: Store latest GPU work completed sync fd This keeps an internal sync_fd for the latest work submitted to the GPU. This can then be fetched with cogl_context_get_latest_sync_fd for use. This is intended for use with linux-drm-syncobj-v1 --- cogl/cogl/cogl-context-private.h | 3 ++ cogl/cogl/cogl-context.c | 22 ++++++++++++++ cogl/cogl/cogl-context.h | 14 +++++++++ cogl/cogl/winsys/cogl-onscreen-egl.c | 3 ++ .../cogl-winsys-egl-feature-functions.h | 9 ++++++ cogl/cogl/winsys/cogl-winsys-egl-private.h | 4 +++ cogl/cogl/winsys/cogl-winsys-egl-x11.c | 1 + cogl/cogl/winsys/cogl-winsys-egl.c | 29 +++++++++++++++++++ cogl/cogl/winsys/cogl-winsys-private.h | 6 ++++ 9 files changed, 91 insertions(+) diff --git a/cogl/cogl/cogl-context-private.h b/cogl/cogl/cogl-context-private.h index 4c0bc4beab4..cd5db0ee3c0 100644 --- a/cogl/cogl/cogl-context-private.h +++ b/cogl/cogl/cogl-context-private.h @@ -311,3 +311,6 @@ _cogl_context_set_current_projection_entry (CoglContext *context, void _cogl_context_set_current_modelview_entry (CoglContext *context, CoglMatrixEntry *entry); + +void +_cogl_context_update_sync (CoglContext *context); diff --git a/cogl/cogl/cogl-context.c b/cogl/cogl/cogl-context.c index be13933ec6f..492d495424f 100644 --- a/cogl/cogl/cogl-context.c +++ b/cogl/cogl/cogl-context.c @@ -463,6 +463,28 @@ _cogl_context_set_current_modelview_entry (CoglContext *context, context->current_modelview_entry = entry; } +void +_cogl_context_update_sync (CoglContext *context) +{ + const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context); + + if (!winsys->update_sync) + return; + + winsys->update_sync (context); +} + +int +cogl_context_get_latest_sync_fd (CoglContext *context) +{ + const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context); + + if (!winsys->get_sync_fd) + return -1; + + return winsys->get_sync_fd (context); +} + CoglGraphicsResetStatus cogl_get_graphics_reset_status (CoglContext *context) { diff --git a/cogl/cogl/cogl-context.h b/cogl/cogl/cogl-context.h index e0e37961cb3..35996f793c5 100644 --- a/cogl/cogl/cogl-context.h +++ b/cogl/cogl/cogl-context.h @@ -360,4 +360,18 @@ cogl_context_timestamp_query_get_time_ns (CoglContext *context, COGL_EXPORT int64_t cogl_context_get_gpu_time_ns (CoglContext *context); +/** + * cogl_context_get_latest_sync_fd + * @context: a #CoglContext pointer + * + * This function is used to get support for waiting on previous + * GPU work through sync fds. It will return a sync fd which will + * signal when the previous work has completed. + * + * Return value: sync fd for latest GPU submission if available, + * returns -1 if not. + */ +COGL_EXPORT int +cogl_context_get_latest_sync_fd (CoglContext *context); + G_END_DECLS diff --git a/cogl/cogl/winsys/cogl-onscreen-egl.c b/cogl/cogl/winsys/cogl-onscreen-egl.c index 94c52a3eacc..0ba33220f8a 100644 --- a/cogl/cogl/winsys/cogl-onscreen-egl.c +++ b/cogl/cogl/winsys/cogl-onscreen-egl.c @@ -299,6 +299,9 @@ cogl_onscreen_egl_swap_buffers_with_damage (CoglOnscreen *onscreen, COGL_TRACE_BEGIN_SCOPED (CoglOnscreenEGLSwapBuffersWithDamage, "Cogl::Onscreen::egl_swap_buffers_with_damage()"); + /* Update our "latest" sync fd to contain all previous work */ + _cogl_context_update_sync (context); + /* The specification for EGL (at least in 1.4) says that the surface needs to be bound to the current context for the swap to work although it may change in future. Mesa explicitly checks for this diff --git a/cogl/cogl/winsys/cogl-winsys-egl-feature-functions.h b/cogl/cogl/winsys/cogl-winsys-egl-feature-functions.h index 4b74e20885c..a0d03a3c4f9 100644 --- a/cogl/cogl/winsys/cogl-winsys-egl-feature-functions.h +++ b/cogl/cogl/winsys/cogl-winsys-egl-feature-functions.h @@ -162,6 +162,15 @@ COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglDestroySync, (EGLDisplay dpy, EGLSyncKHR sync)) COGL_WINSYS_FEATURE_END () + +COGL_WINSYS_FEATURE_BEGIN (native_fence_sync, + "ANDROID\0", + "native_fence_sync\0", + COGL_EGL_WINSYS_FEATURE_NATIVE_FENCE_SYNC) +COGL_WINSYS_FEATURE_FUNCTION (EGLint, eglDupNativeFenceFD, + (EGLDisplay dpy, + EGLSyncKHR sync)) +COGL_WINSYS_FEATURE_END () #endif COGL_WINSYS_FEATURE_BEGIN (surfaceless_context, diff --git a/cogl/cogl/winsys/cogl-winsys-egl-private.h b/cogl/cogl/winsys/cogl-winsys-egl-private.h index 178fb2270d3..93c16cd5ecd 100644 --- a/cogl/cogl/winsys/cogl-winsys-egl-private.h +++ b/cogl/cogl/winsys/cogl-winsys-egl-private.h @@ -102,6 +102,7 @@ typedef enum _CoglEGLWinsysFeature COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT = 1L << 6, COGL_EGL_WINSYS_FEATURE_CONTEXT_PRIORITY = 1L << 7, COGL_EGL_WINSYS_FEATURE_NO_CONFIG_CONTEXT = 1L << 8, + COGL_EGL_WINSYS_FEATURE_NATIVE_FENCE_SYNC = 1L << 9, } CoglEGLWinsysFeature; typedef struct _CoglRendererEGL @@ -120,6 +121,9 @@ typedef struct _CoglRendererEGL /* vtable for platform specific parts */ const CoglWinsysEGLVtable *platform_vtable; + /* Sync for latest submitted work */ + EGLSyncKHR sync; + /* Function pointers for EGL specific extensions */ #define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d) diff --git a/cogl/cogl/winsys/cogl-winsys-egl-x11.c b/cogl/cogl/winsys/cogl-winsys-egl-x11.c index 5472ba9d99b..7a52129c229 100644 --- a/cogl/cogl/winsys/cogl-winsys-egl-x11.c +++ b/cogl/cogl/winsys/cogl-winsys-egl-x11.c @@ -243,6 +243,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer, xlib_renderer = _cogl_xlib_renderer_get_data (renderer); egl_renderer->platform_vtable = &_cogl_winsys_egl_vtable; + egl_renderer->sync = EGL_NO_SYNC_KHR; if (!_cogl_xlib_renderer_connect (renderer, error)) goto error; diff --git a/cogl/cogl/winsys/cogl-winsys-egl.c b/cogl/cogl/winsys/cogl-winsys-egl.c index bea87bcf28f..24f9a0c63e7 100644 --- a/cogl/cogl/winsys/cogl-winsys-egl.c +++ b/cogl/cogl/winsys/cogl-winsys-egl.c @@ -452,6 +452,9 @@ _cogl_winsys_display_destroy (CoglDisplay *display) g_return_if_fail (egl_display != NULL); + if (egl_renderer->sync != EGL_NO_SYNC_KHR) + egl_renderer->pf_eglDestroySync (egl_renderer->edpy, egl_renderer->sync); + cleanup_context (display); if (egl_renderer->platform_vtable->display_destroy) @@ -584,6 +587,30 @@ _cogl_winsys_fence_destroy (CoglContext *context, void *fence) renderer->pf_eglDestroySync (renderer->edpy, fence); } + +static int +_cogl_winsys_get_sync_fd (CoglContext *context) +{ + CoglRendererEGL *renderer = context->display->renderer->winsys; + int fd = renderer->pf_eglDupNativeFenceFD (renderer->edpy, sync); + + if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) + return -1; + + return fd; +} + +static void +_cogl_winsys_update_sync (CoglContext *context) +{ + CoglRendererEGL *renderer = context->display->renderer->winsys; + + if (renderer->sync != EGL_NO_SYNC_KHR) + renderer->pf_eglDestroySync (renderer->edpy, renderer->sync); + + renderer->sync = renderer->pf_eglCreateSync (renderer->edpy, + EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); +} #endif static CoglWinsysVtable _cogl_winsys_vtable = @@ -606,6 +633,8 @@ static CoglWinsysVtable _cogl_winsys_vtable = .fence_add = _cogl_winsys_fence_add, .fence_is_complete = _cogl_winsys_fence_is_complete, .fence_destroy = _cogl_winsys_fence_destroy, + .get_sync_fd = _cogl_winsys_get_sync_fd, + .update_sync = _cogl_winsys_update_sync, #endif }; diff --git a/cogl/cogl/winsys/cogl-winsys-private.h b/cogl/cogl/winsys/cogl-winsys-private.h index 502ac4cb212..8583285c14c 100644 --- a/cogl/cogl/winsys/cogl-winsys-private.h +++ b/cogl/cogl/winsys/cogl-winsys-private.h @@ -140,6 +140,12 @@ typedef struct _CoglWinsysVtable (*fence_destroy) (CoglContext *ctx, void *fence); + void + (*update_sync) (CoglContext *ctx); + + int + (*get_sync_fd) (CoglContext *ctx); + } CoglWinsysVtable; typedef const CoglWinsysVtable *(*CoglWinsysVtableGetter) (void); -- GitLab From 9db50b9ec2fdb5f54c37169829355c49a631222a Mon Sep 17 00:00:00 2001 From: Austin Shafer <ashafer@badland.io> Date: Wed, 6 Sep 2023 13:06:54 -0400 Subject: [PATCH 2/5] 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. --- meson.build | 3 + src/meson.build | 2 + src/wayland/meta-drm-timeline.c | 259 ++++++++++++++++++++++++++++++++ src/wayland/meta-drm-timeline.h | 49 ++++++ 4 files changed, 313 insertions(+) create mode 100644 src/wayland/meta-drm-timeline.c create mode 100644 src/wayland/meta-drm-timeline.h diff --git a/meson.build b/meson.build index f6d55646a5c..1426f5d5f94 100644 --- a/meson.build +++ b/meson.build @@ -326,6 +326,8 @@ if have_introspection ] endif +have_eventfd = cc.has_header('sys/eventfd.h') + have_documentation = get_option('docs') if have_documentation gidocgen_dep = dependency('gi-docgen', version: '>= 2021.1', @@ -550,6 +552,7 @@ cdata.set('HAVE_INTROSPECTION', have_introspection) cdata.set('HAVE_PROFILER', have_profiler) cdata.set('HAVE_LIBDISPLAY_INFO', have_libdisplay_info) cdata.set('HAVE_PANGO_FT2', have_pango_ft2) +cdata.set('HAVE_EVENTFD', have_eventfd) if have_x11_client xkb_base = xkeyboard_config_dep.get_variable('xkb_base') diff --git a/src/meson.build b/src/meson.build index 74fdc2bac2d..dc60c36708b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -586,6 +586,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', diff --git a/src/wayland/meta-drm-timeline.c b/src/wayland/meta-drm-timeline.c new file mode 100644 index 00000000000..09dbdb5596d --- /dev/null +++ b/src/wayland/meta-drm-timeline.c @@ -0,0 +1,259 @@ +/* + * 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 <xf86drm.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_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 = dup (fd); + break; + case PROP_SYNCOBJ_FD: + fd = g_value_get_int (value); + timeline->drm_syncobj_fd = dup (fd); + 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) +{ + int fd = -1; +#ifdef HAVE_EVENTFD + struct drm_syncobj_eventfd syncobj_eventfd; + + fd = eventfd (0, EFD_CLOEXEC); + if (fd < 0) + return -1; + + syncobj_eventfd = { + .handle = timeline->drm_syncobj, + .flags = 0, + .point = sync_point, + .fd = fd, + }; + + if (drmIoctl (timeline->drm, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobj_eventfd) != 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "DRM_IOCTL_SYNCOBJ_EVENTFD: Failed to export eventfd"); + close (fd); + return -1; + } + +#endif + return fd; +} + +int +meta_drm_timeline_set_sync_point (MetaDrmTimeline *timeline, + uint64_t sync_point, + int sync_fd, + GError **error) +{ + int fd = -1; +#ifdef HAVE_EVENTFD + fd = eventfd (0, EFD_CLOEXEC); + if (fd < 0) + return -1; + + if (drmSyncobjImportSyncFileTimeline (timeline->drm, timeline->drm_syncobj, + sync_fd, sync_point)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "DRM_IOCTL_SYNCOBJ_IMPORT: Failed to import syncfd"); + close (fd); + return -1; + } + +#endif + return fd; +} + +static void +meta_drm_timeline_finalize (GObject *object) +{ + MetaDrmTimeline *timeline = META_DRM_TIMELINE (object); + + drmSyncobjDestroy (timeline->drm, timeline->drm_syncobj); + close (timeline->drm_syncobj_fd); + close (timeline->drm); + + 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", + "drm-fd", + "DRM fd", + 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", + "syncobj-fd", + "DRM Syncobj fd", + 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); +} diff --git a/src/wayland/meta-drm-timeline.h b/src/wayland/meta-drm-timeline.h new file mode 100644 index 00000000000..bbe85b47ab5 --- /dev/null +++ b/src/wayland/meta-drm-timeline.h @@ -0,0 +1,49 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * 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); + +int meta_drm_timeline_set_sync_point (MetaDrmTimeline *timeline, + uint64_t sync_point, + int sync_fd, + GError **error); -- GitLab From eb6a1c82925b07f986c77ca39548c0e320d0e241 Mon Sep 17 00:00:00 2001 From: Austin Shafer <ashafer@badland.io> Date: Thu, 7 Sep 2023 10:32:21 -0400 Subject: [PATCH 3/5] Add linux-drm-syncobj v1 to build --- src/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/src/meson.build b/src/meson.build index dc60c36708b..15144e1474b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1082,6 +1082,7 @@ if have_wayland ['xdg-output', 'unstable', 'v1', ], ['xdg-shell', 'stable', ], ['xwayland-keyboard-grab', 'unstable', 'v1', ], + ['linux-drm-syncobj', 'staging', 'v1'], ] if have_wayland_eglstream wayland_eglstream_protocols_dir = wayland_eglstream_protocols_dep.get_variable('pkgdatadir') -- GitLab From 1bd517a138cbedff24202f93c6b9298c9c2e6095 Mon Sep 17 00:00:00 2001 From: Austin Shafer <ashafer@badland.io> Date: Fri, 8 Sep 2023 16:40:56 -0400 Subject: [PATCH 4/5] Implement linux-drm-syncobj-v1 --- src/meson.build | 2 + src/wayland/meta-wayland-buffer.c | 30 +- src/wayland/meta-wayland-buffer.h | 2 + src/wayland/meta-wayland-linux-drm-syncobj.c | 419 +++++++++++++++++++ src/wayland/meta-wayland-linux-drm-syncobj.h | 56 +++ src/wayland/meta-wayland-surface-private.h | 19 + src/wayland/meta-wayland-surface.c | 53 +++ src/wayland/meta-wayland-types.h | 3 + src/wayland/meta-wayland.c | 2 + 9 files changed, 585 insertions(+), 1 deletion(-) create mode 100644 src/wayland/meta-wayland-linux-drm-syncobj.c create mode 100644 src/wayland/meta-wayland-linux-drm-syncobj.h diff --git a/src/meson.build b/src/meson.build index 15144e1474b..c7252209fa8 100644 --- a/src/meson.build +++ b/src/meson.build @@ -640,6 +640,8 @@ if have_wayland 'wayland/meta-wayland-keyboard.h', 'wayland/meta-wayland-legacy-xdg-foreign.c', 'wayland/meta-wayland-legacy-xdg-foreign.h', + 'wayland/meta-wayland-linux-drm-syncobj.c', + 'wayland/meta-wayland-linux-drm-syncobj.h', 'wayland/meta-wayland-outputs.c', 'wayland/meta-wayland-outputs.h', 'wayland/meta-wayland-pointer.c', diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c index 0fd1aee6cdf..7fd664e1f27 100644 --- a/src/wayland/meta-wayland-buffer.c +++ b/src/wayland/meta-wayland-buffer.c @@ -58,6 +58,8 @@ #include "wayland/meta-wayland-private.h" #include "common/meta-cogl-drm-formats.h" #include "compositor/meta-multi-texture-format-private.h" +#include "wayland/meta-drm-timeline.h" +#include "wayland/meta-wayland-linux-drm-syncobj.h" #ifdef HAVE_NATIVE_BACKEND #include "backends/native/meta-drm-buffer-gbm.h" @@ -592,12 +594,36 @@ meta_wayland_buffer_inc_use_count (MetaWaylandBuffer *buffer) void meta_wayland_buffer_dec_use_count (MetaWaylandBuffer *buffer) { + MetaContext *context = meta_wayland_compositor_get_context (buffer->compositor); + MetaBackend *backend = meta_context_get_backend (context); + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); + MetaWaylandSyncPoint *sync_point; + GError *error = NULL; + int sync_fd; + g_return_if_fail (buffer->use_count > 0); buffer->use_count--; if (buffer->use_count == 0 && buffer->resource) - wl_buffer_send_release (buffer->resource); + { + wl_buffer_send_release (buffer->resource); + + sync_fd = cogl_context_get_latest_sync_fd (cogl_context); + g_return_if_fail (sync_fd >= 0); + for (int i = 0; i < buffer->release_points->len; i++) + { + sync_point = g_ptr_array_index (buffer->release_points, i); + meta_drm_timeline_set_sync_point (sync_point->timeline->drm_timeline, + sync_point->sync_point, sync_fd, &error); + if (error) + { + g_warning ("Failed to import sync point: %s", error ? error->message : "Unknown error"); + g_clear_pointer (&error, g_free); + } + } + } } gboolean @@ -814,6 +840,7 @@ meta_wayland_buffer_finalize (GObject *object) clear_tainted_scanout_onscreens (buffer); g_clear_pointer (&buffer->tainted_scanout_onscreens, g_hash_table_unref); + g_clear_pointer (&buffer->release_points, g_ptr_array_unref); g_clear_object (&buffer->egl_image.texture); #ifdef HAVE_WAYLAND_EGLSTREAM @@ -832,6 +859,7 @@ meta_wayland_buffer_finalize (GObject *object) static void meta_wayland_buffer_init (MetaWaylandBuffer *buffer) { + buffer->release_points = g_ptr_array_new (); } static void diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h index 70a58d62277..4856bf5084d 100644 --- a/src/wayland/meta-wayland-buffer.h +++ b/src/wayland/meta-wayland-buffer.h @@ -79,6 +79,8 @@ struct _MetaWaylandBuffer } single_pixel; GHashTable *tainted_scanout_onscreens; + + GPtrArray *release_points; }; #define META_TYPE_WAYLAND_BUFFER (meta_wayland_buffer_get_type ()) diff --git a/src/wayland/meta-wayland-linux-drm-syncobj.c b/src/wayland/meta-wayland-linux-drm-syncobj.c new file mode 100644 index 00000000000..fda56dfe732 --- /dev/null +++ b/src/wayland/meta-wayland-linux-drm-syncobj.c @@ -0,0 +1,419 @@ +/* + * 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> + */ + +#include "config.h" + +#include "meta/util.h" +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-linux-drm-syncobj.h" +#include "backends/native/meta-backend-native-types.h" +#include "backends/native/meta-renderer-native.h" +#include "backends/native/meta-device-pool.h" + +#include "linux-drm-syncobj-v1-server-protocol.h" + +typedef struct _MetaWaylandDrmSyncobjManager +{ + GObject parent; + + // TODO: Needs multi-GPU handling? + int drm; +} MetaWaylandDrmSyncobjManager; + +typedef struct _MetaWaylandSyncobjSurface +{ + GObject parent; + + struct wl_resource *resource; + MetaWaylandSurface *surface; +} MetaWaylandSyncobjSurface; + +static void +syncobj_surface_handle_destroy (struct wl_client *client, + struct wl_resource *resource); +static void +syncobj_surface_handle_set_acquire_point (struct wl_client *client, struct wl_resource *resource, + struct wl_resource *timeline_resource, uint32_t point_hi, + uint32_t point_lo); +static void syncobj_surface_handle_set_release_point (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *timeline_resource, + uint32_t point_hi, uint32_t point_lo); +static void +syncobj_timeline_handle_destroy (struct wl_client *client, + struct wl_resource *resource); +static void +drm_syncobj_handle_destroy (struct wl_client *client, + struct wl_resource *resource); +static void +drm_syncobj_handle_get_surface (struct wl_client *client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *surface_resource); +static void +drm_syncobj_handle_import_timeline (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, int drm_syncobj_fd); + +G_DEFINE_TYPE (MetaWaylandDrmSyncobjManager, meta_wayland_drm_syncobj_manager, + G_TYPE_OBJECT) + +G_DEFINE_TYPE (MetaWaylandSyncobjSurface, meta_wayland_syncobj_surface, + G_TYPE_OBJECT) + +G_DEFINE_TYPE (MetaWaylandSyncobjTimeline, meta_wayland_syncobj_timeline, + G_TYPE_OBJECT) + +static GQuark quark_syncobj_surface; + +static const struct wp_linux_drm_syncobj_surface_v1_interface syncobj_surface_implementation = +{ + syncobj_surface_handle_destroy, + syncobj_surface_handle_set_acquire_point, + syncobj_surface_handle_set_release_point, +}; + +static const struct wp_linux_drm_syncobj_timeline_v1_interface syncobj_timeline_implementation = +{ + syncobj_timeline_handle_destroy, +}; + +static const struct wp_linux_drm_syncobj_v1_interface drm_syncobj_implementation = +{ + drm_syncobj_handle_destroy, + drm_syncobj_handle_get_surface, + drm_syncobj_handle_import_timeline, +}; + +static void +syncobj_timeline_handle_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +syncobj_surface_handle_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +syncobj_surface_handle_set_acquire_point (struct wl_client *client, struct wl_resource *resource, + struct wl_resource *timeline_resource, uint32_t point_hi, + uint32_t point_lo) +{ + MetaWaylandSyncobjSurface *syncobj_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = syncobj_surface->surface; + MetaWaylandSyncobjTimeline *syncobj_timeline = wl_resource_get_user_data (timeline_resource); + + if (!syncobj_surface) + { + wl_resource_post_error (resource, WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, + "Surface Sync object does not have surface attached"); + return; + } + + if (!syncobj_timeline) + { + meta_topic (META_DEBUG_RENDER, "Invalid sync timeline object"); + return; + } + + if (!surface->pending_state->drm_syncobj.acquire) + surface->pending_state->drm_syncobj.acquire = g_object_new (META_TYPE_WAYLAND_SYNC_POINT, NULL); + + g_set_object (&surface->pending_state->drm_syncobj.acquire->timeline, syncobj_timeline); + surface->pending_state->drm_syncobj.acquire->sync_point = (uint64_t)point_hi << 32 | point_lo; +} + +static void syncobj_surface_handle_set_release_point (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *timeline_resource, + uint32_t point_hi, uint32_t point_lo) +{ + MetaWaylandSyncobjSurface *syncobj_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = syncobj_surface->surface; + MetaWaylandSyncobjTimeline *syncobj_timeline = wl_resource_get_user_data (timeline_resource); + + if (!syncobj_surface) + { + wl_resource_post_error (resource, WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, + "Surface Sync object does not have surface attached"); + return; + } + + if (!syncobj_timeline) + { + meta_topic (META_DEBUG_RENDER, "Invalid sync timeline object"); + return; + } + + if (!surface->pending_state->drm_syncobj.release) + surface->pending_state->drm_syncobj.release = g_object_new (META_TYPE_WAYLAND_SYNC_POINT, NULL); + + g_set_object (&surface->pending_state->drm_syncobj.release->timeline, syncobj_timeline); + surface->pending_state->drm_syncobj.release->sync_point = (uint64_t)point_hi << 32 | point_lo; +} + +static void +drm_syncobj_handle_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +syncobj_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSyncobjSurface *syncobj_surface = wl_resource_get_user_data (resource); + + if (!syncobj_surface) + return; + + g_object_set_qdata (G_OBJECT (syncobj_surface->surface), + quark_syncobj_surface, NULL); + g_object_unref (syncobj_surface->surface); + g_object_unref (syncobj_surface); +} + +static void +drm_syncobj_handle_get_surface (struct wl_client *client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *surface_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandSyncobjSurface *syncobj_surface = g_object_get_qdata (G_OBJECT (surface), + quark_syncobj_surface); + struct wl_resource *sync_resource; + + if (syncobj_surface) + return; + + syncobj_surface = g_object_new (META_TYPE_WAYLAND_SYNCOBJ_SURFACE, NULL); + syncobj_surface->surface = g_object_ref (surface); + g_object_set_qdata (G_OBJECT (surface), + quark_syncobj_surface, + syncobj_surface); + + sync_resource = + wl_resource_create (client, + &wp_linux_drm_syncobj_surface_v1_interface, + wl_resource_get_version (resource), + id); + if (sync_resource == NULL) + { + wl_resource_post_no_memory (resource); + g_object_unref (syncobj_surface); + return; + } + + wl_resource_set_implementation (sync_resource, + &syncobj_surface_implementation, + syncobj_surface, + syncobj_surface_destructor); + syncobj_surface->resource = sync_resource; +} + +static void +syncobj_timeline_handle_resource_destroy (struct wl_resource *resource) +{ + MetaWaylandSyncobjTimeline *syncobj_timeline = wl_resource_get_user_data (resource); + g_object_unref (syncobj_timeline); +} + +static void +drm_syncobj_handle_import_timeline (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, int drm_syncobj_fd) +{ + MetaWaylandDrmSyncobjManager *drm_syncobj = wl_resource_get_user_data (resource); + GError *error = NULL; + MetaDrmTimeline *drm_timeline = meta_drm_timeline_import_syncobj (drm_syncobj->drm, + drm_syncobj_fd, + &error); + MetaWaylandSyncobjTimeline *syncobj_timeline; + struct wl_resource *timeline_resource; + + close(drm_syncobj_fd); + if (!drm_timeline) + { + wl_resource_post_error (resource, WP_LINUX_DRM_SYNCOBJ_V1_ERROR_INVALID_TIMELINE, + "Failed to import DRM syncobj: %s", + error ? error->message : "unknown error"); + return; + } + + syncobj_timeline = g_object_new (META_TYPE_WAYLAND_SYNCOBJ_TIMELINE, NULL); + + timeline_resource = wl_resource_create (client, &wp_linux_drm_syncobj_timeline_v1_interface, + wl_resource_get_version (resource), id); + if (timeline_resource == NULL) + { + wl_resource_post_no_memory (resource); + g_object_unref (drm_timeline); + g_object_unref (syncobj_timeline); + return; + } + + wl_resource_set_implementation(timeline_resource, + &syncobj_timeline_implementation, syncobj_timeline, syncobj_timeline_handle_resource_destroy); + + syncobj_timeline->drm_timeline = drm_timeline; +} + +static void +meta_wayland_syncobj_timeline_finalize (GObject *object) +{ + MetaWaylandSyncobjTimeline *syncobj_timeline = + META_WAYLAND_SYNCOBJ_TIMELINE (object); + + g_object_unref (syncobj_timeline->drm_timeline); + + G_OBJECT_CLASS (meta_wayland_syncobj_timeline_parent_class)->finalize (object); +} + +static void +meta_wayland_syncobj_timeline_class_init (MetaWaylandSyncobjTimelineClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_wayland_syncobj_timeline_finalize; +} + +static void +meta_wayland_syncobj_timeline_init (MetaWaylandSyncobjTimeline *syncobj_timeline) +{ + syncobj_timeline->drm_timeline = NULL; +} + +static void +meta_wayland_syncobj_surface_finalize (GObject *object) +{ + G_OBJECT_CLASS (meta_wayland_syncobj_surface_parent_class)->finalize (object); +} + +static void +meta_wayland_syncobj_surface_class_init (MetaWaylandSyncobjSurfaceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_wayland_syncobj_surface_finalize; +} + +static void +meta_wayland_syncobj_surface_init (MetaWaylandSyncobjSurface *syncobj_surface) +{ + syncobj_surface->resource = NULL; + syncobj_surface->surface = NULL; +} + +static void +meta_wayland_drm_syncobj_manager_finalize (GObject *object) +{ + MetaWaylandDrmSyncobjManager *drm_syncobj = + META_WAYLAND_DRM_SYNCOBJ_MANAGER (object); + + close(drm_syncobj->drm); + + G_OBJECT_CLASS (meta_wayland_drm_syncobj_manager_parent_class)->finalize (object); +} + +static void +meta_wayland_drm_syncobj_manager_class_init (MetaWaylandDrmSyncobjManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_wayland_drm_syncobj_manager_finalize; +} + +static void +meta_wayland_drm_syncobj_manager_init (MetaWaylandDrmSyncobjManager *drm_syncobj) +{ + drm_syncobj->drm = -1; +} + +static void +drm_syncobj_bind (struct wl_client *client, + void *user_data, + uint32_t version, + uint32_t id) +{ + MetaWaylandDrmSyncobjManager *drm_syncobj_manager = user_data; + struct wl_resource *resource; + + resource = wl_resource_create (client, &wp_linux_drm_syncobj_v1_interface, + version, id); + wl_resource_set_implementation (resource, &drm_syncobj_implementation, + drm_syncobj_manager, NULL); +} + +/* + * Validate that the appropriate acquire and release points have been set + * for this surface. + */ +void +meta_wayland_surface_explicit_sync_validate (MetaWaylandSurface *surface, + MetaWaylandSurfaceState *state) +{ + MetaWaylandSyncobjSurface *syncobj_surface = g_object_get_qdata (G_OBJECT (surface), + quark_syncobj_surface); + + if (!syncobj_surface) + return; + + if ((state->drm_syncobj.acquire || state->drm_syncobj.release) + && !state->buffer) + wl_resource_post_error (syncobj_surface->resource, + WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, + "Release or Acquire point set but no buffer attached"); +} + +void +meta_wayland_drm_syncobj_init (MetaWaylandCompositor *compositor) +{ +#ifdef HAVE_NATIVE_BACKEND + MetaContext *context = + meta_wayland_compositor_get_context (compositor); + MetaBackend *backend = meta_context_get_backend (context); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); + MetaDeviceFile *device_file = meta_renderer_native_get_primary_device_file (renderer_native); + MetaWaylandDrmSyncobjManager *drm_syncobj_manager; + + if (!device_file) + { + meta_topic (META_DEBUG_RENDER, "Failed to get device file"); + return; + } + + drm_syncobj_manager = g_object_new (META_TYPE_WAYLAND_DRM_SYNCOBJ_MANAGER, NULL); + drm_syncobj_manager->drm = dup (meta_device_file_get_fd (device_file)); + + if (!wl_global_create (compositor->wayland_display, + &wp_linux_drm_syncobj_v1_interface, + 1, + drm_syncobj_manager, + drm_syncobj_bind)) + { + g_error ("Failed to create wp_linux_drm_syncobjhronization_v1_interface global"); + } +#endif +} diff --git a/src/wayland/meta-wayland-linux-drm-syncobj.h b/src/wayland/meta-wayland-linux-drm-syncobj.h new file mode 100644 index 00000000000..b6bea2ae440 --- /dev/null +++ b/src/wayland/meta-wayland-linux-drm-syncobj.h @@ -0,0 +1,56 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * 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 "wayland/meta-wayland-types.h" +#include "wayland/meta-drm-timeline.h" + +#define META_TYPE_WAYLAND_DRM_SYNCOBJ_MANAGER (meta_wayland_drm_syncobj_manager_get_type ()) +G_DECLARE_FINAL_TYPE (MetaWaylandDrmSyncobjManager, meta_wayland_drm_syncobj_manager, + META, WAYLAND_DRM_SYNCOBJ_MANAGER, GObject) + +#define META_TYPE_WAYLAND_SYNCOBJ_SURFACE (meta_wayland_syncobj_surface_get_type ()) +G_DECLARE_FINAL_TYPE (MetaWaylandSyncobjSurface, meta_wayland_syncobj_surface, + META, WAYLAND_SYNCOBJ_SURFACE, GObject) + +#define META_TYPE_WAYLAND_SYNCOBJ_TIMELINE (meta_wayland_syncobj_timeline_get_type ()) +G_DECLARE_FINAL_TYPE (MetaWaylandSyncobjTimeline, meta_wayland_syncobj_timeline, + META, WAYLAND_SYNCOBJ_TIMELINE, GObject) + +typedef struct _MetaWaylandSyncobjSurface MetaWaylandSyncobjSurface; + +typedef struct _MetaWaylandSyncobjTimeline +{ + GObject parent; + + MetaDrmTimeline *drm_timeline; +} MetaWaylandSyncobjTimeline; + +void +meta_wayland_surface_explicit_sync_validate (MetaWaylandSurface *surface, + MetaWaylandSurfaceState *state); + +void +meta_wayland_drm_syncobj_init (MetaWaylandCompositor *compositor); diff --git a/src/wayland/meta-wayland-surface-private.h b/src/wayland/meta-wayland-surface-private.h index 4d6f19bdd4b..d8f7f72c16d 100644 --- a/src/wayland/meta-wayland-surface-private.h +++ b/src/wayland/meta-wayland-surface-private.h @@ -40,6 +40,12 @@ G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceState, META, WAYLAND_SURFACE_STATE, GObject) +#define META_TYPE_WAYLAND_SYNC_POINT (meta_wayland_sync_point_get_type ()) +G_DECLARE_FINAL_TYPE (MetaWaylandSyncPoint, + meta_wayland_sync_point, + META, WAYLAND_SYNC_POINT, + GObject) + struct _MetaWaylandSurfaceRoleClass { GObjectClass parent_class; @@ -67,6 +73,13 @@ struct _MetaWaylandSurfaceRoleClass MetaWindow * (*get_window) (MetaWaylandSurfaceRole *surface_role); }; +typedef struct _MetaWaylandSyncPoint { + GObject parent; + + MetaWaylandSyncobjTimeline *timeline; + uint64_t sync_point; +} MetaWaylandSyncPoint; + struct _MetaWaylandSurfaceState { GObject parent; @@ -128,6 +141,12 @@ struct _MetaWaylandSurfaceState /* xdg_popup */ MetaWaylandXdgPositioner *xdg_positioner; uint32_t xdg_popup_reposition_token; + + /* Explicit Synchronization */ + struct { + MetaWaylandSyncPoint *acquire; + MetaWaylandSyncPoint *release; + } drm_syncobj; }; struct _MetaWaylandDragDestFuncs diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index c789ae4b48f..e7fd36d767b 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -51,6 +51,7 @@ #include "wayland/meta-wayland-viewporter.h" #include "wayland/meta-wayland-xdg-shell.h" #include "wayland/meta-window-wayland.h" +#include "wayland/meta-wayland-linux-drm-syncobj.h" #ifdef HAVE_XWAYLAND #include "wayland/meta-xwayland-private.h" @@ -99,6 +100,8 @@ G_DEFINE_TYPE (MetaWaylandSurfaceState, meta_wayland_surface_state, G_TYPE_OBJECT) +G_DEFINE_TYPE (MetaWaylandSyncPoint, meta_wayland_sync_point, G_TYPE_OBJECT); + enum { SURFACE_DESTROY, @@ -417,6 +420,9 @@ meta_wayland_surface_state_set_default (MetaWaylandSurfaceState *state) wl_list_init (&state->presentation_feedback_list); state->xdg_popup_reposition_token = 0; + + state->drm_syncobj.acquire = NULL; + state->drm_syncobj.release = NULL; } static void @@ -437,6 +443,8 @@ meta_wayland_surface_state_clear (MetaWaylandSurfaceState *state) MetaWaylandFrameCallback *cb, *next; g_clear_object (&state->texture); + g_clear_object (&state->drm_syncobj.acquire); + g_clear_object (&state->drm_syncobj.release); g_clear_pointer (&state->surface_damage, mtk_region_unref); g_clear_pointer (&state->buffer_damage, mtk_region_unref); @@ -601,6 +609,20 @@ meta_wayland_surface_state_merge_into (MetaWaylandSurfaceState *from, to->xdg_positioner = g_steal_pointer (&from->xdg_positioner); to->xdg_popup_reposition_token = from->xdg_popup_reposition_token; } + + g_clear_object (&to->drm_syncobj.acquire); + if (from->drm_syncobj.acquire) + { + to->drm_syncobj.acquire = g_object_ref (from->drm_syncobj.acquire); + g_clear_object (&from->drm_syncobj.acquire); + } + + g_clear_object (&to->drm_syncobj.release); + if (from->drm_syncobj.release) + { + to->drm_syncobj.release = g_object_ref (from->drm_syncobj.release); + g_clear_object (&from->drm_syncobj.release); + } } static void @@ -635,6 +657,30 @@ meta_wayland_surface_state_class_init (MetaWaylandSurfaceStateClass *klass) G_TYPE_NONE, 0); } +static void +meta_wayland_sync_point_finalize (GObject *object) +{ + MetaWaylandSyncPoint *sync = META_WAYLAND_SYNC_POINT (object); + + g_object_unref (sync->timeline); + + G_OBJECT_CLASS (meta_wayland_sync_point_parent_class)->finalize (object); +} + +static void +meta_wayland_sync_point_init (MetaWaylandSyncPoint *sync) +{ +} + +static void +meta_wayland_sync_point_class_init (MetaWaylandSyncPointClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_wayland_sync_point_finalize; +} + + static void meta_wayland_surface_discard_presentation_feedback (MetaWaylandSurface *surface) { @@ -914,6 +960,7 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface) MetaWaylandBuffer *buffer = pending->buffer; MetaWaylandTransaction *transaction; MetaWaylandSurface *subsurface_surface; + MetaWaylandSyncPoint *release_point; COGL_TRACE_BEGIN_SCOPED (MetaWaylandSurfaceCommit, "Meta::WaylandSurface::commit()"); @@ -943,6 +990,10 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface) pending->texture = g_object_ref (surface->committed_state.texture); + release_point = surface->pending_state->drm_syncobj.release; + if (release_point) + g_ptr_array_add (buffer->release_points, g_object_ref (release_point)); + g_object_ref (buffer); meta_wayland_buffer_inc_use_count (buffer); } @@ -951,6 +1002,8 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface) g_clear_object (&surface->committed_state.texture); } + meta_wayland_surface_explicit_sync_validate (surface, pending); + if (meta_wayland_surface_is_synchronized (surface)) transaction = meta_wayland_surface_ensure_transaction (surface); else diff --git a/src/wayland/meta-wayland-types.h b/src/wayland/meta-wayland-types.h index c14b340f4e8..c6f85508d83 100644 --- a/src/wayland/meta-wayland-types.h +++ b/src/wayland/meta-wayland-types.h @@ -64,6 +64,9 @@ typedef struct _MetaWaylandActivation MetaWaylandActivation; typedef struct _MetaWaylandDmaBufManager MetaWaylandDmaBufManager; +typedef struct _MetaWaylandDrmSyncobjManager MetaWaylandDrmSyncobjManager; +typedef struct _MetaWaylandSyncobjTimeline MetaWaylandSyncobjTimeline; + typedef struct _MetaWaylandXdgPositioner MetaWaylandXdgPositioner; typedef struct _MetaXWaylandManager MetaXWaylandManager; diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index a2bd7d2abde..a3569af53cc 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -50,6 +50,7 @@ #include "wayland/meta-wayland-tablet-manager.h" #include "wayland/meta-wayland-transaction.h" #include "wayland/meta-wayland-xdg-foreign.h" +#include "wayland/meta-wayland-linux-drm-syncobj.h" #ifdef HAVE_XWAYLAND #include "wayland/meta-wayland-x11-interop.h" @@ -808,6 +809,7 @@ meta_wayland_compositor_new (MetaContext *context) meta_wayland_activation_init (compositor); meta_wayland_transaction_init (compositor); meta_wayland_idle_inhibit_init (compositor); + meta_wayland_drm_syncobj_init (compositor); #ifdef HAVE_WAYLAND_EGLSTREAM { -- GitLab From 9383a1010e2a1c11c452cd73e5c9a9b87f5b458b Mon Sep 17 00:00:00 2001 From: Austin Shafer <ashafer@badland.io> Date: Tue, 12 Sep 2023 17:30:19 -0400 Subject: [PATCH 5/5] wayland-transaction: Check for explicit sync acquire fences --- src/wayland/meta-wayland-dma-buf.c | 211 --------------------- src/wayland/meta-wayland-dma-buf.h | 26 ++- src/wayland/meta-wayland-transaction.c | 253 ++++++++++++++++++++++++- src/wayland/meta-wayland-transaction.h | 3 + 4 files changed, 268 insertions(+), 225 deletions(-) diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c index 52ece21bd6a..d419abe6912 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -67,8 +67,6 @@ #include "linux-dmabuf-unstable-v1-server-protocol.h" -#define META_WAYLAND_DMA_BUF_MAX_FDS 4 - /* Compatible with zwp_linux_dmabuf_feedback_v1.tranche_flags */ typedef enum _MetaWaylandDmaBufTrancheFlags { @@ -125,22 +123,6 @@ struct _MetaWaylandDmaBufManager MetaWaylandDmaBufFeedback *default_feedback; }; -struct _MetaWaylandDmaBufBuffer -{ - GObject parent; - - MetaWaylandDmaBufManager *manager; - - int width; - int height; - uint32_t drm_format; - uint64_t drm_modifier; - bool is_y_inverted; - int fds[META_WAYLAND_DMA_BUF_MAX_FDS]; - uint32_t offsets[META_WAYLAND_DMA_BUF_MAX_FDS]; - uint32_t strides[META_WAYLAND_DMA_BUF_MAX_FDS]; -}; - G_DEFINE_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_TYPE_OBJECT); G_DEFINE_TYPE (MetaWaylandDmaBufManager, meta_wayland_dma_buf_manager, @@ -831,199 +813,6 @@ meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer) return buffer->dma_buf.dma_buf; } -typedef struct _MetaWaylandDmaBufSource -{ - GSource base; - - MetaWaylandDmaBufSourceDispatch dispatch; - MetaWaylandBuffer *buffer; - gpointer user_data; - - gpointer fd_tags[META_WAYLAND_DMA_BUF_MAX_FDS]; - int owned_sync_fd[META_WAYLAND_DMA_BUF_MAX_FDS]; -} MetaWaylandDmaBufSource; - -static gboolean -is_fd_readable (int fd) -{ - GPollFD poll_fd; - - poll_fd.fd = fd; - poll_fd.events = G_IO_IN; - poll_fd.revents = 0; - - if (!g_poll (&poll_fd, 1, 0)) - return FALSE; - - return (poll_fd.revents & (G_IO_IN | G_IO_NVAL)) != 0; -} - -static gboolean -meta_wayland_dma_buf_source_dispatch (GSource *base, - GSourceFunc callback, - gpointer user_data) -{ - MetaWaylandDmaBufSource *source; - MetaWaylandDmaBufBuffer *dma_buf; - gboolean ready; - uint32_t i; - - source = (MetaWaylandDmaBufSource *) base; - dma_buf = source->buffer->dma_buf.dma_buf; - ready = TRUE; - - for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) - { - gpointer fd_tag = source->fd_tags[i]; - int fd; - - if (!fd_tag) - continue; - - fd = source->owned_sync_fd[i]; - if (fd < 0) - fd = dma_buf->fds[i]; - - if (!is_fd_readable (fd)) - { - ready = FALSE; - continue; - } - - g_source_remove_unix_fd (&source->base, fd_tag); - source->fd_tags[i] = NULL; - g_clear_fd (&source->owned_sync_fd[i], NULL); - } - - if (!ready) - return G_SOURCE_CONTINUE; - - source->dispatch (source->buffer, source->user_data); - - return G_SOURCE_REMOVE; -} - -static void -meta_wayland_dma_buf_source_finalize (GSource *base) -{ - MetaWaylandDmaBufSource *source; - uint32_t i; - - source = (MetaWaylandDmaBufSource *) base; - - for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) - { - gpointer fd_tag = source->fd_tags[i]; - - if (fd_tag) - { - g_source_remove_unix_fd (&source->base, fd_tag); - source->fd_tags[i] = NULL; - g_clear_fd (&source->owned_sync_fd[i], NULL); - } - } - - g_clear_object (&source->buffer); -} - -static GSourceFuncs meta_wayland_dma_buf_source_funcs = { - .dispatch = meta_wayland_dma_buf_source_dispatch, - .finalize = meta_wayland_dma_buf_source_finalize -}; - -static MetaWaylandDmaBufSource * -create_source (MetaWaylandBuffer *buffer, - MetaWaylandDmaBufSourceDispatch dispatch, - gpointer user_data) -{ - MetaWaylandDmaBufSource *source; - int i; - - source = - (MetaWaylandDmaBufSource *) g_source_new (&meta_wayland_dma_buf_source_funcs, - sizeof (*source)); - g_source_set_name ((GSource *) source, "[mutter] DmaBuf readiness source"); - - source->buffer = g_object_ref (buffer); - source->dispatch = dispatch; - source->user_data = user_data; - - for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) - source->owned_sync_fd[i] = -1; - - return source; -} - -static int -get_sync_file (int dma_buf_fd) -{ - struct dma_buf_export_sync_file dbesf = { .flags = DMA_BUF_SYNC_READ }; - int ret; - - do - { - ret = ioctl (dma_buf_fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &dbesf); - } - while (ret == -1 && errno == EINTR); - - if (ret == 0) - return dbesf.fd; - - return -1; -} - -/** - * meta_wayland_dma_buf_create_source: - * @buffer: A #MetaWaylandBuffer object - * @dispatch: Callback - * @user_data: User data for the callback - * - * Creates a GSource which will call the specified dispatch callback when all - * dma-buf file descriptors for the buffer have become readable. - * - * Returns: The new GSource (or - * %NULL if there are no dma-buf file descriptors, or they were all readable - * already) - */ -GSource * -meta_wayland_dma_buf_create_source (MetaWaylandBuffer *buffer, - MetaWaylandDmaBufSourceDispatch dispatch, - gpointer user_data) -{ - MetaWaylandDmaBufBuffer *dma_buf; - MetaWaylandDmaBufSource *source = NULL; - uint32_t i; - - dma_buf = buffer->dma_buf.dma_buf; - if (!dma_buf) - return NULL; - - for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) - { - int fd = dma_buf->fds[i]; - - if (fd < 0) - break; - - if (is_fd_readable (fd)) - continue; - - if (!source) - source = create_source (buffer, dispatch, user_data); - - source->owned_sync_fd[i] = get_sync_file (fd); - if (source->owned_sync_fd[i] >= 0) - fd = source->owned_sync_fd[i]; - - source->fd_tags[i] = g_source_add_unix_fd (&source->base, fd, G_IO_IN); - } - - if (!source) - return NULL; - - return &source->base; -} - static void buffer_params_create_common (struct wl_client *client, struct wl_resource *params_resource, diff --git a/src/wayland/meta-wayland-dma-buf.h b/src/wayland/meta-wayland-dma-buf.h index 1c03acb3283..1bce4894cc5 100644 --- a/src/wayland/meta-wayland-dma-buf.h +++ b/src/wayland/meta-wayland-dma-buf.h @@ -31,6 +31,8 @@ #include "meta/meta-multi-texture.h" #include "wayland/meta-wayland-types.h" +#define META_WAYLAND_DMA_BUF_MAX_FDS 4 + #define META_TYPE_WAYLAND_DMA_BUF_BUFFER (meta_wayland_dma_buf_buffer_get_type ()) G_DECLARE_FINAL_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, META, WAYLAND_DMA_BUF_BUFFER, GObject); @@ -39,7 +41,21 @@ G_DECLARE_FINAL_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_DECLARE_FINAL_TYPE (MetaWaylandDmaBufManager, meta_wayland_dma_buf_manager, META, WAYLAND_DMA_BUF_MANAGER, GObject) -typedef struct _MetaWaylandDmaBufBuffer MetaWaylandDmaBufBuffer; +typedef struct _MetaWaylandDmaBufBuffer +{ + GObject parent; + + MetaWaylandDmaBufManager *manager; + + int width; + int height; + uint32_t drm_format; + uint64_t drm_modifier; + bool is_y_inverted; + int fds[META_WAYLAND_DMA_BUF_MAX_FDS]; + uint32_t offsets[META_WAYLAND_DMA_BUF_MAX_FDS]; + uint32_t strides[META_WAYLAND_DMA_BUF_MAX_FDS]; +} MetaWaylandDmaBufBuffer; MetaWaylandDmaBufManager * meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, GError **error); @@ -55,14 +71,6 @@ meta_wayland_dma_buf_fds_for_wayland_buffer (MetaWaylandBuffer *buffer); MetaWaylandDmaBufBuffer * meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer); -typedef void (*MetaWaylandDmaBufSourceDispatch) (MetaWaylandBuffer *buffer, - gpointer user_data); - -GSource * -meta_wayland_dma_buf_create_source (MetaWaylandBuffer *buffer, - MetaWaylandDmaBufSourceDispatch dispatch, - gpointer user_data); - CoglScanout * meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf, CoglOnscreen *onscreen); diff --git a/src/wayland/meta-wayland-transaction.c b/src/wayland/meta-wayland-transaction.c index 70f2b404790..faef973ac10 100644 --- a/src/wayland/meta-wayland-transaction.c +++ b/src/wayland/meta-wayland-transaction.c @@ -26,9 +26,16 @@ #include "wayland/meta-wayland.h" #include "wayland/meta-wayland-buffer.h" #include "wayland/meta-wayland-dma-buf.h" +#include "wayland/meta-wayland-linux-drm-syncobj.h" #define META_WAYLAND_TRANSACTION_NONE ((void *)(uintptr_t) G_MAXSIZE) +typedef enum _MetaDrmSourceType +{ + DMA_BUF_SOURCE, + DRM_SYNCOBJ_SOURCE, +} MetaDrmSourceType; + struct _MetaWaylandTransaction { GList node; @@ -59,6 +66,107 @@ struct _MetaWaylandTransactionEntry int y; }; +typedef struct _MetaWaylandDrmSource +{ + GSource base; + + MetaDrmSourceType type; + MetaWaylandDrmSourceDispatch dispatch; + MetaWaylandBuffer *buffer; + gpointer user_data; + gpointer fd_tags[META_WAYLAND_DMA_BUF_MAX_FDS]; + + /* -- dmabuf source fields -- */ + int dmabuf_fd[META_WAYLAND_DMA_BUF_MAX_FDS]; + + /* -- explicit sync fields -- */ + int sync_fd[META_WAYLAND_DMA_BUF_MAX_FDS]; +} MetaWaylandDrmSource; + +static gboolean +meta_wayland_drm_fd_readable (int fd) +{ + GPollFD poll_fd; + + poll_fd.fd = fd; + poll_fd.events = G_IO_IN; + poll_fd.revents = 0; + + if (!g_poll (&poll_fd, 1, 0)) + return FALSE; + + return (poll_fd.revents & (G_IO_IN | G_IO_NVAL)) != 0; +} + +static gboolean +meta_wayland_drm_source_dispatch (GSource *base, + GSourceFunc callback, + gpointer user_data) +{ + MetaWaylandDrmSource *source; + gboolean ready; + uint32_t i; + + source = (MetaWaylandDrmSource *) base; + + ready = TRUE; + + for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) + { + gpointer fd_tag = source->fd_tags[i]; + int fd = source->sync_fd[i]; + + if (!fd_tag) + continue; + + if (fd < 0) + fd = source->dmabuf_fd[i]; + + if (!meta_wayland_drm_fd_readable (fd)) + { + ready = FALSE; + continue; + } + + g_source_remove_unix_fd (&source->base, fd_tag); + source->fd_tags[i] = NULL; + } + + if (!ready) + return G_SOURCE_CONTINUE; + + source->dispatch (source->buffer, source->user_data); + + return G_SOURCE_REMOVE; +} + +static void +meta_wayland_drm_source_finalize (GSource *base) +{ + MetaWaylandDrmSource *source; + uint32_t i; + + source = (MetaWaylandDrmSource *) base; + + for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) + { + gpointer fd_tag = source->fd_tags[i]; + + if (fd_tag) + { + g_source_remove_unix_fd (&source->base, fd_tag); + source->fd_tags[i] = NULL; + } + } + + g_clear_object (&source->buffer); +} + +static GSourceFuncs meta_wayland_drm_source_funcs = { + .dispatch = meta_wayland_drm_source_dispatch, + .finalize = meta_wayland_drm_source_finalize +}; + static MetaWaylandTransactionEntry * meta_wayland_transaction_get_entry (MetaWaylandTransaction *transaction, MetaWaylandSurface *surface) @@ -302,8 +410,8 @@ meta_wayland_transaction_maybe_apply (MetaWaylandTransaction *transaction) } static void -meta_wayland_transaction_dma_buf_dispatch (MetaWaylandBuffer *buffer, - gpointer user_data) +meta_wayland_transaction_drm_dispatch (MetaWaylandBuffer *buffer, + gpointer user_data) { MetaWaylandTransaction *transaction = user_data; @@ -314,6 +422,100 @@ meta_wayland_transaction_dma_buf_dispatch (MetaWaylandBuffer *buffer, meta_wayland_transaction_maybe_apply (transaction); } +static GSource * +meta_wayland_dma_buf_create_source (MetaWaylandBuffer *buffer, + MetaWaylandDrmSourceDispatch dispatch, + gpointer user_data) +{ + MetaWaylandDmaBufBuffer *dma_buf; + MetaWaylandDrmSource *source = NULL; + uint32_t i; + + dma_buf = buffer->dma_buf.dma_buf; + if (!dma_buf) + return NULL; + + for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) + { + int fd = dma_buf->fds[i]; + + if (fd < 0) + break; + + if (meta_wayland_drm_fd_readable (fd)) + continue; + + if (!source) + { + source = + (MetaWaylandDrmSource *) g_source_new (&meta_wayland_drm_source_funcs, + sizeof (*source)); + g_source_set_name ((GSource *) source, "[mutter] DmaBuf readiness source"); + + source->buffer = g_object_ref (buffer); + source->type = DMA_BUF_SOURCE; + source->dispatch = dispatch; + source->user_data = user_data; + } + + source->dmabuf_fd[i] = fd; + source->fd_tags[i] = g_source_add_unix_fd (&source->base, fd, G_IO_IN); + } + + if (!source) + return NULL; + + return &source->base; +} + +static GSource * +meta_wayland_drm_syncobj_create_source (MetaWaylandBuffer *buffer, + MetaWaylandSyncobjTimeline *timeline, + uint64_t sync_point, + MetaWaylandDrmSourceDispatch dispatch, + gpointer user_data) +{ + MetaWaylandDrmSource *source = NULL; + int sync_fd; + GError *error = NULL; + + if (!timeline) + return NULL; + + sync_fd = meta_drm_timeline_get_eventfd (timeline->drm_timeline, sync_point, &error); + if (sync_fd < 0) + { + g_warning ("Failed to get sync fd: %s", error ? error->message : "Unknown error"); + return NULL; + } + + if (meta_wayland_drm_fd_readable (sync_fd)) + { + close(sync_fd); + return NULL; + } + + source = + (MetaWaylandDrmSource *) g_source_new (&meta_wayland_drm_source_funcs, + sizeof (*source)); + if (!source) + { + close(sync_fd); + return NULL; + } + + g_source_set_name ((GSource *) source, "[mutter] Drm Syncobj readiness source"); + source->buffer = g_object_ref (buffer); + source->type = DRM_SYNCOBJ_SOURCE; + source->dispatch = dispatch; + source->user_data = user_data; + source->sync_fd[0] = sync_fd; + source->fd_tags[0] = g_source_add_unix_fd (&source->base, sync_fd, G_IO_IN); + + return &source->base; +} + + static gboolean meta_wayland_transaction_add_dma_buf_source (MetaWaylandTransaction *transaction, MetaWaylandBuffer *buffer) @@ -325,7 +527,7 @@ meta_wayland_transaction_add_dma_buf_source (MetaWaylandTransaction *transaction return FALSE; source = meta_wayland_dma_buf_create_source (buffer, - meta_wayland_transaction_dma_buf_dispatch, + meta_wayland_transaction_drm_dispatch, transaction); if (!source) return FALSE; @@ -344,6 +546,45 @@ meta_wayland_transaction_add_dma_buf_source (MetaWaylandTransaction *transaction return TRUE; } +static gboolean +meta_wayland_transaction_add_drm_syncobj_source (MetaWaylandTransaction *transaction, + MetaWaylandBuffer *buffer, + MetaWaylandSurface *surface) +{ + GSource *source; + MetaWaylandTransactionEntry *entry; + + if (transaction->buf_sources && + g_hash_table_contains (transaction->buf_sources, buffer)) + return FALSE; + + entry = meta_wayland_transaction_get_entry (transaction, surface); + if (!entry) + return FALSE; + + source = + meta_wayland_drm_syncobj_create_source (buffer, + entry->state->drm_syncobj.acquire->timeline, + entry->state->drm_syncobj.acquire->sync_point, + meta_wayland_transaction_drm_dispatch, + transaction); + if (!source) + return FALSE; + + if (!transaction->buf_sources) + { + transaction->buf_sources = + g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) g_source_destroy); + } + + g_hash_table_insert (transaction->buf_sources, buffer, source); + g_source_attach (source, NULL); + g_source_unref (source); + + return TRUE; +} + static void meta_wayland_transaction_add_placement_surfaces (MetaWaylandTransaction *transaction, MetaWaylandSurfaceState *state) @@ -382,8 +623,10 @@ meta_wayland_transaction_commit (MetaWaylandTransaction *transaction) { MetaWaylandBuffer *buffer = entry->state->buffer; - if (buffer && - meta_wayland_transaction_add_dma_buf_source (transaction, buffer)) + if ((entry->state->drm_syncobj.acquire && + meta_wayland_transaction_add_drm_syncobj_source (transaction, buffer, surface)) + || (buffer && + meta_wayland_transaction_add_dma_buf_source (transaction, buffer))) maybe_apply = FALSE; if (entry->state->subsurface_placement_ops) diff --git a/src/wayland/meta-wayland-transaction.h b/src/wayland/meta-wayland-transaction.h index 165fe7f66ff..9c4834e8d1c 100644 --- a/src/wayland/meta-wayland-transaction.h +++ b/src/wayland/meta-wayland-transaction.h @@ -55,3 +55,6 @@ void meta_wayland_transaction_free (MetaWaylandTransaction *transaction); void meta_wayland_transaction_finalize (MetaWaylandCompositor *compositor); void meta_wayland_transaction_init (MetaWaylandCompositor *compositor); + +typedef void (*MetaWaylandDrmSourceDispatch) (MetaWaylandBuffer *buffer, + gpointer user_data); -- GitLab
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor