From b261050be196620d3b05812b389498cfefa37bb5 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Tue, 13 Sep 2022 14:21:43 +0200 Subject: [PATCH] wayland: implement tearing_control_v1 --- CMakeLists.txt | 2 +- src/wayland/CMakeLists.txt | 5 + src/wayland/surface_interface.cpp | 9 ++ src/wayland/surface_interface.h | 10 ++ src/wayland/surface_interface_p.h | 4 + src/wayland/tearingcontrol_v1_interface.cpp | 104 ++++++++++++++++++++ src/wayland/tearingcontrol_v1_interface.h | 31 ++++++ src/wayland_server.cpp | 2 + src/wayland_server.h | 2 + 9 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/wayland/tearingcontrol_v1_interface.cpp create mode 100644 src/wayland/tearingcontrol_v1_interface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cc68d1fd3..1a6cf6fd9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,7 +205,7 @@ find_package(Wayland 1.21 REQUIRED COMPONENTS Server ) -find_package(WaylandProtocols 1.27) +find_package(WaylandProtocols 1.30) set_package_properties(WaylandProtocols PROPERTIES TYPE REQUIRED PURPOSE "Collection of Wayland protocols that add functionality not available in the Wayland core protocol" diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index d590696d00..a84c2a0190 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -184,6 +184,10 @@ ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml PROTOCOL ${WaylandProtocols_DATADIR}/staging/ext-idle-notify/ext-idle-notify-v1.xml BASENAME ext-idle-notify-v1 ) +ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml + PROTOCOL ${WaylandProtocols_DATADIR}/staging/tearing-control/tearing-control-v1.xml + BASENAME tearing-control-v1 +) ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml PROTOCOL ${WaylandProtocols_DATADIR}/unstable/xwayland-keyboard-grab/xwayland-keyboard-grab-unstable-v1.xml @@ -256,6 +260,7 @@ target_sources(kwin PRIVATE surface_interface.cpp surfacerole.cpp tablet_v2_interface.cpp + tearingcontrol_v1_interface.cpp textinput.cpp textinput_v2_interface.cpp textinput_v3_interface.cpp diff --git a/src/wayland/surface_interface.cpp b/src/wayland/surface_interface.cpp index 78ca478e98..45949ef6b2 100644 --- a/src/wayland/surface_interface.cpp +++ b/src/wayland/surface_interface.cpp @@ -536,6 +536,10 @@ void SurfaceState::mergeInto(SurfaceState *target) target->contentType = contentType; target->contentTypeIsSet = true; } + if (tearingIsSet) { + target->presentationHint = presentationHint; + target->tearingIsSet = true; + } *this = SurfaceState{}; below = target->below; @@ -1097,4 +1101,9 @@ QPointF SurfaceInterface::toSurfaceLocal(const QPointF &point) const return QPointF(point.x() * d->scaleOverride, point.y() * d->scaleOverride); } +PresentationHint SurfaceInterface::presentationHint() const +{ + return d->current.presentationHint; +} + } // namespace KWaylandServer diff --git a/src/wayland/surface_interface.h b/src/wayland/surface_interface.h index 01371d14fe..3d051a1510 100644 --- a/src/wayland/surface_interface.h +++ b/src/wayland/surface_interface.h @@ -28,6 +28,11 @@ class SubSurfaceInterface; class SurfaceInterfacePrivate; class LinuxDmaBufV1Feedback; +enum class PresentationHint { + VSync, + Async +}; + /** * @brief Resource representing a wl_surface. * @@ -336,6 +341,11 @@ public: */ QPointF toSurfaceLocal(const QPointF &point) const; + /** + * @returns if the client thinks the content of this surface is suitable for presentation with tearing + */ + PresentationHint presentationHint() const; + Q_SIGNALS: /** * This signal is emitted when the underlying wl_surface resource is about to be freed. diff --git a/src/wayland/surface_interface_p.h b/src/wayland/surface_interface_p.h index 89fc555a2a..b4bf52c8ca 100644 --- a/src/wayland/surface_interface_p.h +++ b/src/wayland/surface_interface_p.h @@ -20,6 +20,7 @@ class IdleInhibitorV1Interface; class SurfaceRole; class ViewportInterface; class ContentTypeV1Interface; +class TearingControlV1Interface; struct SurfaceState { @@ -40,6 +41,7 @@ struct SurfaceState bool bufferScaleIsSet = false; bool bufferTransformIsSet = false; bool contentTypeIsSet = false; + bool tearingIsSet = false; qint32 bufferScale = 1; KWin::Output::Transform bufferTransform = KWin::Output::Transform::Normal; wl_list frameCallbacks; @@ -50,6 +52,7 @@ struct SurfaceState QPointer contrast; QPointer slide; KWin::ContentType contentType = KWin::ContentType::None; + PresentationHint presentationHint = PresentationHint::VSync; // Subsurfaces are stored in two lists. The below list contains subsurfaces that // are below their parent surface; the above list contains subsurfaces that are @@ -139,6 +142,7 @@ public: std::unique_ptr dmabufFeedbackV1; QPointer contentTypeInterface; ClientConnection *client = nullptr; + TearingControlV1Interface *tearing = nullptr; protected: void surface_destroy_resource(Resource *resource) override; diff --git a/src/wayland/tearingcontrol_v1_interface.cpp b/src/wayland/tearingcontrol_v1_interface.cpp new file mode 100644 index 0000000000..5698846a37 --- /dev/null +++ b/src/wayland/tearingcontrol_v1_interface.cpp @@ -0,0 +1,104 @@ +/* + SPDX-FileCopyrightText: 2022 Xaver Hugl + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ +#include "tearingcontrol_v1_interface.h" +#include "display.h" +#include "surface_interface_p.h" + +namespace KWaylandServer +{ + +static constexpr uint32_t s_version = 1; + +class TearingControlManagerV1InterfacePrivate : public QtWaylandServer::wp_tearing_control_manager_v1 +{ +public: + TearingControlManagerV1InterfacePrivate(Display *display); + +private: + void wp_tearing_control_manager_v1_destroy(Resource *resource) override; + void wp_tearing_control_manager_v1_get_tearing_control(Resource *resource, uint32_t id, struct ::wl_resource *surface) override; +}; + +class TearingControlV1Interface : private QtWaylandServer::wp_tearing_control_v1 +{ +public: + TearingControlV1Interface(SurfaceInterface *surface, wl_client *client, uint32_t id); + ~TearingControlV1Interface(); + +private: + void wp_tearing_control_v1_set_presentation_hint(Resource *resource, uint32_t hint) override; + void wp_tearing_control_v1_destroy(Resource *resource) override; + void wp_tearing_control_v1_destroy_resource(Resource *resource) override; + + const QPointer m_surface; +}; + +TearingControlManagerV1Interface::TearingControlManagerV1Interface(Display *display, QObject *parent) + : QObject(parent) +{ +} + +TearingControlManagerV1Interface::~TearingControlManagerV1Interface() = default; + +TearingControlManagerV1InterfacePrivate::TearingControlManagerV1InterfacePrivate(Display *display) + : QtWaylandServer::wp_tearing_control_manager_v1(*display, s_version) +{ +} + +void TearingControlManagerV1InterfacePrivate::wp_tearing_control_manager_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void TearingControlManagerV1InterfacePrivate::wp_tearing_control_manager_v1_get_tearing_control(Resource *resource, uint32_t id, struct ::wl_resource *wlSurface) +{ + SurfaceInterface *surface = SurfaceInterface::get(wlSurface); + if (SurfaceInterfacePrivate::get(surface)->tearing) { + wl_resource_post_error(resource->handle, QtWaylandServer::wp_tearing_control_manager_v1::error_tearing_control_exists, "Surface already has a wp_surface_tearing_control_v1"); + return; + } + SurfaceInterfacePrivate::get(surface)->tearing = new TearingControlV1Interface(surface, resource->client(), id); +} + +TearingControlV1Interface::TearingControlV1Interface(SurfaceInterface *surface, wl_client *client, uint32_t id) + : QtWaylandServer::wp_tearing_control_v1(client, id, s_version) + , m_surface(surface) +{ +} + +TearingControlV1Interface::~TearingControlV1Interface() +{ + if (m_surface) { + SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(m_surface); + surfacePrivate->pending.presentationHint = PresentationHint::VSync; + surfacePrivate->pending.tearingIsSet = true; + surfacePrivate->tearing = nullptr; + } +} + +void TearingControlV1Interface::wp_tearing_control_v1_set_presentation_hint(Resource *resource, uint32_t hint) +{ + if (m_surface) { + SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(m_surface); + if (hint == presentation_hint::presentation_hint_async) { + surfacePrivate->pending.presentationHint = PresentationHint::Async; + } else { + surfacePrivate->pending.presentationHint = PresentationHint::VSync; + } + surfacePrivate->pending.tearingIsSet = true; + } +} + +void TearingControlV1Interface::wp_tearing_control_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void TearingControlV1Interface::wp_tearing_control_v1_destroy_resource(Resource *resource) +{ + delete this; +} +} diff --git a/src/wayland/tearingcontrol_v1_interface.h b/src/wayland/tearingcontrol_v1_interface.h new file mode 100644 index 0000000000..de2487ac6a --- /dev/null +++ b/src/wayland/tearingcontrol_v1_interface.h @@ -0,0 +1,31 @@ +/* + SPDX-FileCopyrightText: 2022 Xaver Hugl + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ +#pragma once + +#include "surface_interface.h" + +#include "qwayland-server-tearing-control-v1.h" + +#include + +namespace KWaylandServer +{ + +class TearingControlManagerV1InterfacePrivate; +class TearingControlV1Interface; +class Display; + +class TearingControlManagerV1Interface : public QObject +{ + Q_OBJECT +public: + TearingControlManagerV1Interface(Display *display, QObject *parent = nullptr); + ~TearingControlManagerV1Interface() override; + +private: + std::unique_ptr d; +}; +} diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp index 3c5e41130a..c86ac12925 100644 --- a/src/wayland_server.cpp +++ b/src/wayland_server.cpp @@ -59,6 +59,7 @@ #include "wayland/shadow_interface.h" #include "wayland/subcompositor_interface.h" #include "wayland/tablet_v2_interface.h" +#include "wayland/tearingcontrol_v1_interface.h" #include "wayland/viewporter_interface.h" #include "wayland/xdgactivation_v1_interface.h" #include "wayland/xdgdecoration_v1_interface.h" @@ -487,6 +488,7 @@ bool WaylandServer::init(InitializationFlags flags) }); m_contentTypeManager = new KWaylandServer::ContentTypeManagerV1Interface(m_display, m_display); + m_tearingControlInterface = new KWaylandServer::TearingControlManagerV1Interface(m_display, m_display); return true; } diff --git a/src/wayland_server.h b/src/wayland_server.h index c838cc67cf..6afd1e5394 100644 --- a/src/wayland_server.h +++ b/src/wayland_server.h @@ -51,6 +51,7 @@ class XdgDecorationManagerV1Interface; class XWaylandKeyboardGrabManagerV1Interface; class ContentTypeManagerV1Interface; class DrmLeaseManagerV1; +class TearingControlManagerV1Interface; } namespace KWin @@ -290,6 +291,7 @@ private: XdgActivationV1Integration *m_xdgActivationIntegration = nullptr; KWaylandServer::XWaylandKeyboardGrabManagerV1Interface *m_xWaylandKeyboardGrabManager = nullptr; KWaylandServer::ContentTypeManagerV1Interface *m_contentTypeManager = nullptr; + KWaylandServer::TearingControlManagerV1Interface *m_tearingControlInterface = nullptr; QList m_windows; InitializationFlags m_initFlags; QHash m_waylandOutputs;