From e87bc3a83e24f1ea3afbb99a41cc5e8744f96a4b Mon Sep 17 00:00:00 2001 From: Quantum Date: Thu, 13 May 2021 22:51:45 -0400 Subject: [PATCH] [client] wayland: measure presentation time --- client/displayservers/Wayland/CMakeLists.txt | 5 +- client/displayservers/Wayland/gl.c | 4 + client/displayservers/Wayland/presentation.c | 110 +++++++++++++++++++ client/displayservers/Wayland/registry.c | 3 + client/displayservers/Wayland/wayland.c | 3 + client/displayservers/Wayland/wayland.h | 9 ++ 6 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 client/displayservers/Wayland/presentation.c diff --git a/client/displayservers/Wayland/CMakeLists.txt b/client/displayservers/Wayland/CMakeLists.txt index ed88de7e..e2bf0c98 100644 --- a/client/displayservers/Wayland/CMakeLists.txt +++ b/client/displayservers/Wayland/CMakeLists.txt @@ -31,6 +31,7 @@ add_library(displayserver_Wayland STATIC input.c output.c poll.c + presentation.c state.c registry.c wayland.c @@ -74,6 +75,9 @@ include_directories("${CMAKE_BINARY_DIR}/wayland") wayland_generate( "${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml" "${CMAKE_BINARY_DIR}/wayland/wayland-xdg-shell-client-protocol") +wayland_generate( + "${WAYLAND_PROTOCOLS_BASE}/stable/presentation-time/presentation-time.xml" + "${CMAKE_BINARY_DIR}/wayland/wayland-presentation-time-client-protocol") wayland_generate( "${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" "${CMAKE_BINARY_DIR}/wayland/wayland-xdg-decoration-unstable-v1-client-protocol") @@ -89,4 +93,3 @@ wayland_generate( wayland_generate( "${WAYLAND_PROTOCOLS_BASE}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" "${CMAKE_BINARY_DIR}/wayland/wayland-idle-inhibit-unstable-v1-client-protocol") - diff --git a/client/displayservers/Wayland/gl.c b/client/displayservers/Wayland/gl.c index 045d1faf..73309309 100644 --- a/client/displayservers/Wayland/gl.c +++ b/client/displayservers/Wayland/gl.c @@ -110,10 +110,14 @@ void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct wlWm.eglDamageRects[i*4+3] = damage[i].h; } + waylandPresentationFrame(); wlWm.eglSwapWithDamage(display, surface, wlWm.eglDamageRects, count); } else + { + waylandPresentationFrame(); eglSwapBuffers(display, surface); + } if (wlWm.needsResize) { diff --git a/client/displayservers/Wayland/presentation.c b/client/displayservers/Wayland/presentation.c new file mode 100644 index 00000000..7ccd355a --- /dev/null +++ b/client/displayservers/Wayland/presentation.c @@ -0,0 +1,110 @@ +/** + * Looking Glass + * Copyright (C) 2017-2021 The Looking Glass Authors + * https://looking-glass.io + * + * 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 + */ + +#define _GNU_SOURCE +#include "wayland.h" + +#include +#include +#include + +#include + +#include "common/debug.h" +#include "common/time.h" + +struct FrameData +{ + struct timespec sent; +}; + +static void presentationClockId(void * data, + struct wp_presentation * presentation, uint32_t clkId) +{ + wlWm.clkId = clkId; +} + +static const struct wp_presentation_listener presentationListener = { + .clock_id = presentationClockId, +}; + +static void presentationFeedbackSyncOutput(void * data, + struct wp_presentation_feedback * feedback, struct wl_output * output) +{ + // Do nothing. +} + +static void presentationFeedbackPresented(void * opaque, + struct wp_presentation_feedback * feedback, uint32_t tvSecHi, uint32_t tvSecLo, + uint32_t tvNsec, uint32_t refresh, uint32_t seqHi, uint32_t seqLo, uint32_t flags) +{ + struct FrameData * data = opaque; + struct timespec present = { + .tv_sec = (uint64_t) tvSecHi << 32 | tvSecLo, + .tv_nsec = tvNsec, + }; + struct timespec delta; + + tsDiff(&delta, &present, &data->sent); + printf("Presented in %3jd.%06lums, vsync: %d, hw_clock: %d, hw_compl: %d, zero_copy: %d\n", + (intmax_t) delta.tv_sec * 1000 + delta.tv_nsec / 1000000, delta.tv_nsec % 1000000, + (bool) (flags & WP_PRESENTATION_FEEDBACK_KIND_VSYNC), + (bool) (flags & WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK), + (bool) (flags & WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION), + (bool) (flags & WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY)); + free(data); +} + +static void presentationFeedbackDiscarded(void * data, + struct wp_presentation_feedback * feedback) +{ + free(data); +} + +static const struct wp_presentation_feedback_listener presentationFeedbackListener = { + .sync_output = presentationFeedbackSyncOutput, + .presented = presentationFeedbackPresented, + .discarded = presentationFeedbackDiscarded, +}; + +bool waylandPresentationInit(void) +{ + if (wlWm.presentation) + wp_presentation_add_listener(wlWm.presentation, &presentationListener, NULL); + return true; +} + +void waylandPresentationFree(void) +{ + wp_presentation_destroy(wlWm.presentation); +} + +void waylandPresentationFrame(void) +{ + struct FrameData * data = malloc(sizeof(struct FrameData)); + if (clock_gettime(wlWm.clkId, &data->sent)) + { + DEBUG_ERROR("clock_gettime failed: %s\n", strerror(errno)); + free(data); + } + + struct wp_presentation_feedback * feedback = wp_presentation_feedback(wlWm.presentation, wlWm.surface); + wp_presentation_feedback_add_listener(feedback, &presentationFeedbackListener, data); +} diff --git a/client/displayservers/Wayland/registry.c b/client/displayservers/Wayland/registry.c index d66bd4f1..afde486b 100644 --- a/client/displayservers/Wayland/registry.c +++ b/client/displayservers/Wayland/registry.c @@ -47,6 +47,9 @@ static void registryGlobalHandler(void * data, struct wl_registry * registry, wlWm.xdgDecorationManager = wl_registry_bind(wlWm.registry, name, &zxdg_decoration_manager_v1_interface, 1); #endif + else if (!strcmp(interface, wp_presentation_interface.name)) + wlWm.presentation = wl_registry_bind(wlWm.registry, name, + &wp_presentation_interface, 1); else if (!strcmp(interface, zwp_relative_pointer_manager_v1_interface.name)) wlWm.relativePointerManager = wl_registry_bind(wlWm.registry, name, &zwp_relative_pointer_manager_v1_interface, 1); diff --git a/client/displayservers/Wayland/wayland.c b/client/displayservers/Wayland/wayland.c index d6a39793..65b9b65f 100644 --- a/client/displayservers/Wayland/wayland.c +++ b/client/displayservers/Wayland/wayland.c @@ -84,6 +84,9 @@ static bool waylandInit(const LG_DSInitParams params) if (!waylandIdleInit()) return false; + if (!waylandPresentationInit()) + return false; + if (!waylandInputInit()) return false; diff --git a/client/displayservers/Wayland/wayland.h b/client/displayservers/Wayland/wayland.h index 5b65772b..9a9a042b 100644 --- a/client/displayservers/Wayland/wayland.h +++ b/client/displayservers/Wayland/wayland.h @@ -35,6 +35,7 @@ #include "interface/displayserver.h" #include "wayland-xdg-shell-client-protocol.h" +#include "wayland-presentation-time-client-protocol.h" #include "wayland-xdg-decoration-unstable-v1-client-protocol.h" #include "wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h" @@ -110,6 +111,9 @@ struct WaylandDSState EGLSurface glSurface; #endif + struct wp_presentation * presentation; + clockid_t clkId; + #ifdef ENABLE_LIBDECOR struct libdecor * libdecor; struct libdecor_frame * libdecorFrame; @@ -255,6 +259,11 @@ void waylandWait(unsigned int time); bool waylandPollRegister(int fd, WaylandPollCallback callback, void * opaque, uint32_t events); bool waylandPollUnregister(int fd); +// presentation module +bool waylandPresentationInit(void); +void waylandPresentationFrame(void); +void waylandPresentationFree(void); + // registry module bool waylandRegistryInit(void); void waylandRegistryFree(void);