From b52a49b4c4c344784b3085cb93d3882d3ce9b4bb Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Fri, 19 Apr 2024 22:16:35 +0100 Subject: [PATCH] tearing-control: hyprland impl (#5655) * tearing: hl impl * format --- CMakeLists.txt | 1 + src/Compositor.cpp | 6 +- src/Compositor.hpp | 1 - src/desktop/Window.cpp | 8 --- src/events/Events.hpp | 3 - src/events/Misc.cpp | 31 --------- src/helpers/WLClasses.hpp | 11 ---- src/includes.hpp | 1 - src/managers/ProtocolManager.cpp | 4 ++ src/protocols/TearingControl.cpp | 106 ++++++++++++++++++++++++++++++ src/protocols/TearingControl.hpp | 60 +++++++++++++++++ src/protocols/WaylandProtocol.cpp | 11 ++++ src/protocols/WaylandProtocol.hpp | 20 ++++-- src/render/Renderer.hpp | 18 +++-- 14 files changed, 207 insertions(+), 74 deletions(-) create mode 100644 src/protocols/TearingControl.cpp create mode 100644 src/protocols/TearingControl.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c949928..b056402a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -263,6 +263,7 @@ protocol("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1 protocol("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false) protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false) +protocol("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false) # tools add_subdirectory(hyprctl) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index ae1c352c..6e739c5f 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -253,8 +253,6 @@ void CCompositor::initServer() { m_sWLRCursorShapeMgr = wlr_cursor_shape_manager_v1_create(m_sWLDisplay, 1); - m_sWLRTearingControlMgr = wlr_tearing_control_manager_v1_create(m_sWLDisplay, 1); - if (!m_sWLRHeadlessBackend) { Debug::log(CRIT, "Couldn't create the headless backend"); throwError("wlr_headless_backend_create() failed!"); @@ -311,7 +309,6 @@ void CCompositor::initAllSignals() { addWLSignal(&m_sWLRSessionLockMgr->events.new_lock, &Events::listen_newSessionLock, m_sWLRSessionLockMgr, "SessionLockMgr"); addWLSignal(&m_sWLRGammaCtrlMgr->events.set_gamma, &Events::listen_setGamma, m_sWLRGammaCtrlMgr, "GammaCtrlMgr"); addWLSignal(&m_sWLRCursorShapeMgr->events.request_set_shape, &Events::listen_setCursorShape, m_sWLRCursorShapeMgr, "CursorShapeMgr"); - addWLSignal(&m_sWLRTearingControlMgr->events.new_object, &Events::listen_newTearingHint, m_sWLRTearingControlMgr, "TearingControlMgr"); addWLSignal(&m_sWLRKbShInhibitMgr->events.new_inhibitor, &Events::listen_newShortcutInhibitor, m_sWLRKbShInhibitMgr, "ShortcutInhibitMgr"); if (m_sWRLDRMLeaseMgr) @@ -365,7 +362,6 @@ void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_newSessionLock); removeWLSignal(&Events::listen_setGamma); removeWLSignal(&Events::listen_setCursorShape); - removeWLSignal(&Events::listen_newTearingHint); removeWLSignal(&Events::listen_newShortcutInhibitor); if (m_sWRLDRMLeaseMgr) @@ -695,6 +691,8 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) { if (windowExists(pWindow) && !pWindow->m_bFadingOut) { + EMIT_HOOK_EVENT("destroyWindow", pWindow); + std::erase_if(m_vWindows, [&](std::unique_ptr& el) { return el.get() == pWindow; }); std::erase_if(m_vWindowsFadingOut, [&](CWindow* el) { return el == pWindow; }); } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 11c02814..9244c673 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -82,7 +82,6 @@ class CCompositor { wlr_session_lock_manager_v1* m_sWLRSessionLockMgr; wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr; wlr_cursor_shape_manager_v1* m_sWLRCursorShapeMgr; - wlr_tearing_control_manager_v1* m_sWLRTearingControlMgr; // ------------------------------------------------- // std::string m_szWLDisplaySocket = ""; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 737d5ef7..35b4ff97 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -535,14 +535,6 @@ void CWindow::onMap() { m_vReportedSize = m_vPendingReportedSize; m_bAnimatingIn = true; - for (const auto& ctrl : g_pHyprRenderer->m_vTearingControllers) { - if (ctrl->pWlrHint->surface != m_pWLSurface.wlr()) - continue; - - m_bTearingHint = ctrl->pWlrHint->current; - break; - } - if (m_bIsX11) return; diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 9dbd75df..4c4503ad 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -144,9 +144,6 @@ namespace Events { // Cursor shape LISTENER(setCursorShape); - // Tearing hints - LISTENER(newTearingHint); - // Shortcut inhibitor LISTENER(newShortcutInhibitor); }; diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp index 8d0a9710..53bd6f9f 100644 --- a/src/events/Misc.cpp +++ b/src/events/Misc.cpp @@ -245,37 +245,6 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) { g_pInputManager->processMouseRequest(E); } -void Events::listener_newTearingHint(wl_listener* listener, void* data) { - Debug::log(LOG, "New tearing hint at {:x}", (uintptr_t)data); - - const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique()).get(); - NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data; - - NEWCTRL->hyprListener_destroy.initCallback( - &NEWCTRL->pWlrHint->events.destroy, - [&](void* owner, void* data) { - Debug::log(LOG, "Destroyed {:x} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint); - - std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; }); - }, - NEWCTRL, "TearingController"); - - NEWCTRL->hyprListener_set.initCallback( - &NEWCTRL->pWlrHint->events.set_hint, - [&](void* owner, void* data) { - const auto TEARINGHINT = (STearingController*)owner; - - const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface); - - if (PWINDOW) { - PWINDOW->m_bTearingHint = (bool)TEARINGHINT->pWlrHint->current; - - Debug::log(LOG, "Hint {:x} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->current); - } - }, - NEWCTRL, "TearingController"); -} - void Events::listener_newShortcutInhibitor(wl_listener* listener, void* data) { const auto INHIBITOR = (wlr_keyboard_shortcuts_inhibitor_v1*)data; diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 5d93b91d..b85517e8 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -329,17 +329,6 @@ struct SSwitchDevice { } }; -struct STearingController { - wlr_tearing_control_v1* pWlrHint = nullptr; - - DYNLISTENER(set); - DYNLISTENER(destroy); - - bool operator==(const STearingController& other) const { - return pWlrHint == other.pWlrHint; - } -}; - struct SShortcutInhibitor { wlr_keyboard_shortcuts_inhibitor_v1* pWlrInhibitor = nullptr; diff --git a/src/includes.hpp b/src/includes.hpp index 6a1e5bc3..c43c2eaf 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -103,7 +103,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index bc3a4570..f6cb66df 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -1,6 +1,9 @@ #include "ProtocolManager.hpp" +#include "../protocols/TearingControl.hpp" + #include "xdg-output-unstable-v1-protocol.h" +#include "tearing-control-v1-protocol.h" CProtocolManager::CProtocolManager() { m_pToplevelExportProtocolManager = std::make_unique(); @@ -10,4 +13,5 @@ CProtocolManager::CProtocolManager() { m_pScreencopyProtocolManager = std::make_unique(); m_pXDGOutputProtocol = std::make_unique(&zxdg_output_manager_v1_interface, 3, "XDGOutput"); + PROTO::tearing = std::make_unique(&wp_tearing_control_manager_v1_interface, 1, "TearingControl"); } diff --git a/src/protocols/TearingControl.cpp b/src/protocols/TearingControl.cpp new file mode 100644 index 00000000..0ed495bd --- /dev/null +++ b/src/protocols/TearingControl.cpp @@ -0,0 +1,106 @@ +#include "TearingControl.hpp" +#include "tearing-control-v1-protocol.h" +#include "../managers/ProtocolManager.hpp" +#include "../desktop/Window.hpp" +#include "../Compositor.hpp" + +static void destroyManager(wl_client* client, wl_resource* resource) { + RESOURCE_OR_BAIL(PRESOURCE); + reinterpret_cast(PRESOURCE->data())->onManagerResourceDestroy(resource); +} + +static void getTearingControl(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* surface) { + RESOURCE_OR_BAIL(PRESOURCE); + reinterpret_cast(PRESOURCE->data())->onGetController(client, resource, id, wlr_surface_from_resource(surface)); +} + +// + +CTearingControlProtocol::CTearingControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + g_pHookSystem->hookDynamic("destroyWindow", [this](void* self, SCallbackInfo& info, std::any param) { this->onWindowDestroy(std::any_cast(param)); }); +} + +static const struct wp_tearing_control_manager_v1_interface MANAGER_IMPL = { + .destroy = ::destroyManager, + .get_tearing_control = ::getTearingControl, +}; + +void CTearingControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, &wp_tearing_control_manager_v1_interface, ver, id)).get(); + + if (!RESOURCE->good()) { + Debug::log(LOG, "Couldn't bind TearingControlMgr"); + return; + } + + RESOURCE->setImplementation(&MANAGER_IMPL, nullptr); + RESOURCE->setData(this); +} + +void CTearingControlProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CTearingControlProtocol::onGetController(wl_client* client, wl_resource* resource, uint32_t id, wlr_surface* surf) { + const auto CONTROLLER = m_vTearingControllers + .emplace_back(std::make_unique( + std::make_shared(client, &wp_tearing_control_v1_interface, wl_resource_get_version(resource), id), surf)) + .get(); + + if (!CONTROLLER->good()) { + m_vTearingControllers.pop_back(); + return; + } +} + +void CTearingControlProtocol::onControllerDestroy(CTearingControl* control) { + std::erase_if(m_vTearingControllers, [control](const auto& other) { return other.get() == control; }); +} + +void CTearingControlProtocol::onWindowDestroy(CWindow* pWindow) { + for (auto& c : m_vTearingControllers) { + if (c->pWindow == pWindow) + c->pWindow = nullptr; + } +} + +// + +static void destroyController(wl_client* client, wl_resource* resource) { + RESOURCE_OR_BAIL(PRESOURCE); + PROTO::tearing->onControllerDestroy(reinterpret_cast(PRESOURCE->data())); +} + +static void setPresentationHint(wl_client* client, wl_resource* resource, uint32_t hint) { + RESOURCE_OR_BAIL(PRESOURCE); + reinterpret_cast(PRESOURCE->data())->onHint(hint); +} + +static const struct wp_tearing_control_v1_interface CONTROLLER_IMPL = { + .set_presentation_hint = ::setPresentationHint, + .destroy = ::destroyController, +}; + +CTearingControl::CTearingControl(SP resource_, wlr_surface* surf_) : resource(resource_) { + resource->setImplementation(&CONTROLLER_IMPL, nullptr); + resource->setData(this); + resource->setOnDestroyHandler([](CWaylandResource* res) { PROTO::tearing->onControllerDestroy(reinterpret_cast(res->data())); }); + + pWindow = g_pCompositor->getWindowFromSurface(surf_); +} + +void CTearingControl::onHint(uint32_t hint_) { + hint = hint_ == WP_TEARING_CONTROL_V1_PRESENTATION_HINT_VSYNC ? TEARING_VSYNC : TEARING_ASYNC; + updateWindow(); +} + +void CTearingControl::updateWindow() { + if (!pWindow) + return; + + pWindow->m_bTearingHint = hint == TEARING_ASYNC; +} + +bool CTearingControl::good() { + return resource->good(); +} diff --git a/src/protocols/TearingControl.hpp b/src/protocols/TearingControl.hpp new file mode 100644 index 00000000..f0dd8bfa --- /dev/null +++ b/src/protocols/TearingControl.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include "WaylandProtocol.hpp" + +class CWindow; + +enum eTearingPresentationHint { + TEARING_VSYNC = 0, + TEARING_ASYNC, +}; + +class CTearingControlProtocol; + +class CTearingControl { + public: + CTearingControl(SP resource_, wlr_surface* surf_); + + void onHint(uint32_t hint_); + + bool good(); + + bool operator==(const wl_resource* other) const { + return other == resource->resource(); + } + + bool operator==(const CTearingControl* other) const { + return other->resource == resource; + } + + private: + void updateWindow(); + + SP resource; + CWindow* pWindow = nullptr; + eTearingPresentationHint hint = TEARING_VSYNC; + + friend class CTearingControlProtocol; +}; + +class CTearingControlProtocol : public IWaylandProtocol { + public: + CTearingControlProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + void onManagerResourceDestroy(wl_resource* res); + void onControllerDestroy(CTearingControl* control); + void onGetController(wl_client* client, wl_resource* resource, uint32_t id, wlr_surface* surf); + + private: + void onWindowDestroy(CWindow* pWindow); + + std::vector> m_vManagers; + std::vector> m_vTearingControllers; +}; + +namespace PROTO { + inline UP tearing; +}; \ No newline at end of file diff --git a/src/protocols/WaylandProtocol.cpp b/src/protocols/WaylandProtocol.cpp index 4600126c..76f5eba0 100644 --- a/src/protocols/WaylandProtocol.cpp +++ b/src/protocols/WaylandProtocol.cpp @@ -31,7 +31,14 @@ void CWaylandResource::markDefunct() { Debug::log(TRACE, "[wl res {:x}] now defunct", (uintptr_t)m_pWLResource); m_bDefunct = true; + wl_resource_set_user_data(m_pWLResource, nullptr); + + // we call it here because we need defunct to be set to true. + // if this function destroys us, we can't call wl_resource_set_user_data or + // destroy the resource. + if (m_fOnDestroyHandler) + m_fOnDestroyHandler(this); } CWaylandResource::~CWaylandResource() { @@ -80,6 +87,10 @@ void* CWaylandResource::data() { return m_pData; } +void CWaylandResource::setOnDestroyHandler(std::function fn) { + m_fOnDestroyHandler = fn; +} + static void bindManagerInternal(wl_client* client, void* data, uint32_t ver, uint32_t id) { ((IWaylandProtocol*)data)->bindManager(client, data, ver, id); } diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index a87bd519..cc8a0e53 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -2,11 +2,18 @@ #include "../defines.hpp" +#include + #define RESOURCE_OR_BAIL(resname) \ const auto resname = (CWaylandResource*)wl_resource_get_user_data(resource); \ if (!resname) \ return; +#define SP std::shared_ptr +#define UP std::unique_ptr + +#define PROTO NProtocols + class CWaylandResource { public: CWaylandResource(wl_client* client, const wl_interface* wlInterface, uint32_t version, uint32_t id); @@ -24,12 +31,15 @@ class CWaylandResource { void* data(); void setData(void* data); + void setOnDestroyHandler(std::function fn); + private: - bool m_bImplementationSet = false; - bool m_bDefunct = false; // m_liResourceDestroy fired - wl_client* m_pWLClient = nullptr; - wl_resource* m_pWLResource = nullptr; - void* m_pData = nullptr; + bool m_bImplementationSet = false; + bool m_bDefunct = false; // m_liResourceDestroy fired + wl_client* m_pWLClient = nullptr; + wl_resource* m_pWLResource = nullptr; + void* m_pData = nullptr; + std::function m_fOnDestroyHandler; }; class IWaylandProtocol { diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index bc5ff43c..2e2b8b92 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -89,18 +89,16 @@ class CHyprRenderer { DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); - bool attemptDirectScanout(CMonitor*); - void setWindowScanoutMode(CWindow*); - void initiateManualCrash(); + bool attemptDirectScanout(CMonitor*); + void setWindowScanoutMode(CWindow*); + void initiateManualCrash(); - bool m_bCrashingInProgress = false; - float m_fCrashingDistort = 0.5f; - wl_event_source* m_pCrashingLoop = nullptr; - wl_event_source* m_pCursorTicker = nullptr; + bool m_bCrashingInProgress = false; + float m_fCrashingDistort = 0.5f; + wl_event_source* m_pCrashingLoop = nullptr; + wl_event_source* m_pCursorTicker = nullptr; - std::vector> m_vTearingControllers; - - CTimer m_tRenderTimer; + CTimer m_tRenderTimer; struct { int hotspotX;