diff --git a/src/meson.build b/src/meson.build
index 84640debe..9d187b294 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -606,6 +606,7 @@ if have_wayland
'wayland/meta-wayland-client-private.h',
'wayland/meta-wayland-color-management.c',
'wayland/meta-wayland-color-management.h',
+ 'wayland/meta-wayland-commit-timing.c',
'wayland/meta-wayland-cursor-surface.c',
'wayland/meta-wayland-cursor-surface.h',
'wayland/meta-wayland-data-device.c',
@@ -1128,6 +1129,7 @@ if have_wayland
['linux-drm-syncobj-v1', 'private', ],
['color-management-v1', 'private', ],
['session-management-v1', 'private', ],
+ ['commit-timing', 'staging', 'v1', ],
]
if have_wayland_eglstream
wayland_eglstream_protocols_dir = wayland_eglstream_protocols_dep.get_variable('pkgdatadir')
diff --git a/src/wayland/meta-wayland-commit-timing.c b/src/wayland/meta-wayland-commit-timing.c
new file mode 100644
index 000000000..b84d92b33
--- /dev/null
+++ b/src/wayland/meta-wayland-commit-timing.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2023 Valve Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ */
+
+#include "config.h"
+
+#include
+
+#include "commit-timing-v1-server-protocol.h"
+#include "wayland/meta-wayland-commit-timing.h"
+#include "wayland/meta-wayland-private.h"
+#include "wayland/meta-wayland-versions.h"
+
+typedef struct _MetaWaylandCommitTimerSurface
+{
+ MetaWaylandSurface *surface;
+ gulong destroy_handler_id;
+} MetaWaylandCommitTimerSurface;
+
+static void
+commit_timer_destructor (struct wl_resource *resource)
+{
+ MetaWaylandCommitTimerSurface *timer = wl_resource_get_user_data (resource);
+
+ if (timer->surface)
+ {
+ g_object_set_data (G_OBJECT (timer->surface),
+ "-meta-wayland-commit-timer", NULL);
+
+ g_clear_signal_handler (&timer->destroy_handler_id, timer->surface);
+ }
+
+ g_free (timer);
+}
+
+static void
+commit_timer_destroy (struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static void
+commit_timer_set_target_time (struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t sec_hi,
+ uint32_t sec_lo,
+ uint32_t nsec)
+{
+ MetaWaylandCommitTimerSurface *timer = wl_resource_get_user_data (resource);
+ MetaWaylandSurface *surface = timer->surface;
+ MetaWaylandSurfaceState *pending;
+ uint64_t target_time_us;
+
+ if (!surface)
+ {
+ wl_resource_post_error (resource,
+ WP_COMMIT_TIMER_V1_ERROR_SURFACE_DESTROYED,
+ "Surface destroyed");
+ return;
+ }
+
+ pending = meta_wayland_surface_get_pending_state (surface);
+
+ if (pending->has_target_time)
+ {
+ wl_resource_post_error (resource,
+ WP_COMMIT_TIMER_V1_ERROR_TIMESTAMP_EXISTS,
+ "Commit already has timestamp");
+ return;
+ }
+
+ if (nsec > 999999999)
+ {
+ wl_resource_post_error (resource,
+ WP_COMMIT_TIMER_V1_ERROR_INVALID_TIMESTAMP,
+ "Timestamp is invalid");
+ return;
+ }
+
+ target_time_us = (((uint64_t) sec_hi << 32) + sec_lo) * 1000000;
+ target_time_us += nsec / 1000;
+
+ pending->has_target_time = TRUE;
+ pending->target_time_us = target_time_us;
+}
+
+static const struct wp_commit_timer_v1_interface meta_wayland_commit_timer_interface =
+{
+ commit_timer_set_target_time,
+ commit_timer_destroy,
+};
+
+static void
+commit_timing_manager_destroy (struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static void
+on_surface_destroyed (MetaWaylandSurface *surface,
+ MetaWaylandCommitTimerSurface *timer)
+{
+ timer->surface = NULL;
+}
+
+static void
+commit_timing_manager_get_timer (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);
+ MetaWaylandCommitTimerSurface *timer;
+ struct wl_resource *timer_resource;
+
+ timer = g_object_get_data (G_OBJECT (surface), "-meta-wayland-commit-timer");
+
+ if (timer)
+ {
+ wl_resource_post_error (resource,
+ WP_COMMIT_TIMING_MANAGER_V1_ERROR_COMMIT_TIMER_EXISTS,
+ "Commit timing resource already exists on surface");
+ return;
+ }
+
+ timer_resource = wl_resource_create (client,
+ &wp_commit_timer_v1_interface,
+ wl_resource_get_version (resource),
+ id);
+
+ timer = g_new0 (MetaWaylandCommitTimerSurface, 1);
+ timer->surface = surface;
+
+ timer->destroy_handler_id =
+ g_signal_connect (surface,
+ "destroy",
+ G_CALLBACK (on_surface_destroyed),
+ timer);
+
+ g_object_set_data (G_OBJECT (surface), "-meta-wayland-commit-timer", timer);
+
+ wl_resource_set_implementation (timer_resource,
+ &meta_wayland_commit_timer_interface,
+ timer,
+ commit_timer_destructor);
+}
+
+static const struct wp_commit_timing_manager_v1_interface meta_wayland_commit_timing_manager_interface =
+{
+ commit_timing_manager_destroy,
+ commit_timing_manager_get_timer,
+};
+
+static void
+bind_commit_timing (struct wl_client *client,
+ void *data,
+ uint32_t version,
+ uint32_t id)
+{
+ struct wl_resource *resource;
+
+ resource = wl_resource_create (client,
+ &wp_commit_timing_manager_v1_interface,
+ version, id);
+
+ wl_resource_set_implementation (resource,
+ &meta_wayland_commit_timing_manager_interface,
+ NULL, NULL);
+}
+
+void
+meta_wayland_commit_timing_init (MetaWaylandCompositor *compositor)
+{
+ if (wl_global_create (compositor->wayland_display,
+ &wp_commit_timing_manager_v1_interface,
+ META_WP_COMMIT_TIMING_V1_VERSION,
+ NULL,
+ bind_commit_timing) == NULL)
+ g_error ("Failed to register a global commit_timing_manager object");
+}
diff --git a/src/wayland/meta-wayland-commit-timing.h b/src/wayland/meta-wayland-commit-timing.h
new file mode 100644
index 000000000..9e22ac4d4
--- /dev/null
+++ b/src/wayland/meta-wayland-commit-timing.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 Valve Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ */
+
+#pragma once
+
+#include
+
+#include "wayland/meta-wayland-types.h"
+
+void meta_wayland_commit_timing_init (MetaWaylandCompositor *compositor);
diff --git a/src/wayland/meta-wayland-surface-private.h b/src/wayland/meta-wayland-surface-private.h
index 7a791770d..be0a38bf5 100644
--- a/src/wayland/meta-wayland-surface-private.h
+++ b/src/wayland/meta-wayland-surface-private.h
@@ -23,6 +23,7 @@
#include "backends/meta-monitor-manager-private.h"
#include "clutter/clutter.h"
+#include "commit-timing-v1-server-protocol.h"
#include "compositor/meta-shaped-texture-private.h"
#include "compositor/meta-surface-actor.h"
#include "meta/meta-cursor-tracker.h"
diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h
index de847b2eb..771352a37 100644
--- a/src/wayland/meta-wayland-versions.h
+++ b/src/wayland/meta-wayland-versions.h
@@ -63,3 +63,4 @@
#define META_XDG_SESSION_MANAGER_V1_VERSION 1
#define META_WP_SYSTEM_BELL_V1_VERSION 1
#define META_XDG_TOPLEVEL_DRAG_VERSION 1
+#define META_WP_COMMIT_TIMING_V1_VERSION 1
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 48e1dee4b..b3d179836 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -40,6 +40,7 @@
#include "wayland/meta-wayland-activation.h"
#include "wayland/meta-wayland-buffer.h"
#include "wayland/meta-wayland-color-management.h"
+#include "wayland/meta-wayland-commit-timing.h"
#include "wayland/meta-wayland-data-device.h"
#include "wayland/meta-wayland-dma-buf.h"
#include "wayland/meta-wayland-egl-stream.h"
@@ -971,6 +972,7 @@ meta_wayland_compositor_new (MetaContext *context)
#ifdef HAVE_NATIVE_BACKEND
meta_wayland_drm_lease_manager_init (compositor);
#endif
+ meta_wayland_commit_timing_init (compositor);
#ifdef HAVE_WAYLAND_EGLSTREAM
{