From edad24c257c1264e2d0c05b04798b6c90515831e Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Sat, 15 Apr 2023 23:43:41 +0100 Subject: [PATCH] Screencopy: unify frame and client between impls + event Adds a new event to both hooks and ipc: screencopy --- src/protocols/Screencopy.cpp | 38 ++++++++++++++++++++-- src/protocols/Screencopy.hpp | 36 ++++++++++++++++----- src/protocols/ToplevelExport.cpp | 25 ++++++++------- src/protocols/ToplevelExport.hpp | 54 +++++++------------------------- 4 files changed, 90 insertions(+), 63 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 2dca96bb..e2c458d4 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -85,9 +85,9 @@ static const struct zwlr_screencopy_frame_v1_interface screencopyFrameImpl = { .copy_with_damage = handleCopyWithDamage, }; -static SScreencopyClient* clientFromResource(wl_resource* resource) { +static CScreencopyClient* clientFromResource(wl_resource* resource) { ASSERT(wl_resource_instance_of(resource, &zwlr_screencopy_manager_v1_interface, &screencopyMgrImpl)); - return (SScreencopyClient*)wl_resource_get_user_data(resource); + return (CScreencopyClient*)wl_resource_get_user_data(resource); } static SScreencopyFrame* frameFromResource(wl_resource* resource) { @@ -95,7 +95,7 @@ static SScreencopyFrame* frameFromResource(wl_resource* resource) { return (SScreencopyFrame*)wl_resource_get_user_data(resource); } -void CScreencopyProtocolManager::removeClient(SScreencopyClient* client, bool force) { +void CScreencopyProtocolManager::removeClient(CScreencopyClient* client, bool force) { if (!force) { if (!client || client->ref <= 0) return; @@ -113,6 +113,36 @@ static void handleManagerResourceDestroy(wl_resource* resource) { g_pProtocolManager->m_pScreencopyProtocolManager->removeClient(PCLIENT, true); } +CScreencopyClient::~CScreencopyClient() { + g_pHookSystem->unhook(tickCallback); +} + +CScreencopyClient::CScreencopyClient() { + lastMeasure = std::chrono::system_clock::now(); + tickCallback = g_pHookSystem->hookDynamic("tick", [&](void* self, std::any data) { onTick(); }); +} + +void CScreencopyClient::onTick() { + const auto SINCELAST = std::chrono::duration_cast(std::chrono::system_clock::now() - lastMeasure).count() / 1000.0; + + if (SINCELAST < 0.5) + return; + + framesInLastHalfSecond = frameCounter; + frameCounter = 0; + lastMeasure = std::chrono::system_clock::now(); + + if (framesInLastHalfSecond > 3 && !sentScreencast) { + EMIT_HOOK_EVENT("screencast", (std::vector{1, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner})); + g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "1," + std::to_string(clientOwner)}); + sentScreencast = true; + } else if (framesInLastHalfSecond < 4 && sentScreencast) { + EMIT_HOOK_EVENT("screencast", (std::vector{0, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner})); + g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "0," + std::to_string(clientOwner)}); + sentScreencast = false; + } +} + void CScreencopyProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) { const auto PCLIENT = &m_lClients.emplace_back(); @@ -320,6 +350,8 @@ void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor, bool dmabuf) shareFrame(f); + ++f->client->frameCounter; + framesToRemove.push_back(f); } diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index 77d2b5c3..17b5ed0b 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -5,21 +5,42 @@ #include #include +#include "../managers/HookSystemManager.hpp" class CMonitor; -struct SScreencopyClient { - int ref = 0; - wl_resource* resource = nullptr; +enum eClientOwners +{ + CLIENT_SCREENCOPY = 0, + CLIENT_TOPLEVEL_EXPORT +}; - bool operator==(const SScreencopyClient& other) const { +class CScreencopyClient { + public: + CScreencopyClient(); + ~CScreencopyClient(); + + int ref = 0; + wl_resource* resource = nullptr; + + eClientOwners clientOwner = CLIENT_SCREENCOPY; + + int frameCounter = 0; + int framesInLastHalfSecond = 0; + std::chrono::system_clock::time_point lastMeasure; + bool sentScreencast = false; + + void onTick(); + HOOK_CALLBACK_FN* tickCallback = nullptr; + + bool operator==(const CScreencopyClient& other) const { return resource == other.resource; } }; struct SScreencopyFrame { wl_resource* resource = nullptr; - SScreencopyClient* client = nullptr; + CScreencopyClient* client = nullptr; uint32_t shmFormat = 0; uint32_t dmabufFormat = 0; @@ -34,6 +55,7 @@ struct SScreencopyFrame { wlr_buffer* buffer = nullptr; CMonitor* pMonitor = nullptr; + CWindow* pWindow = nullptr; bool operator==(const SScreencopyFrame& other) const { return resource == other.resource && client == other.client; @@ -45,7 +67,7 @@ class CScreencopyProtocolManager { CScreencopyProtocolManager(); void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); - void removeClient(SScreencopyClient* client, bool force = false); + void removeClient(CScreencopyClient* client, bool force = false); void removeFrame(SScreencopyFrame* frame, bool force = false); void displayDestroy(); @@ -59,7 +81,7 @@ class CScreencopyProtocolManager { private: wl_global* m_pGlobal = nullptr; std::list m_lFrames; - std::list m_lClients; + std::list m_lClients; wl_listener m_liDisplayDestroy; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index a51f2632..600c9ea0 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -75,17 +75,17 @@ static const struct hyprland_toplevel_export_manager_v1_interface toplevelExport static const struct hyprland_toplevel_export_frame_v1_interface toplevelFrameImpl = {.copy = handleCopyFrame, .destroy = handleDestroyFrame}; -static SToplevelClient* clientFromResource(wl_resource* resource) { +static CScreencopyClient* clientFromResource(wl_resource* resource) { ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_manager_v1_interface, &toplevelExportManagerImpl)); - return (SToplevelClient*)wl_resource_get_user_data(resource); + return (CScreencopyClient*)wl_resource_get_user_data(resource); } -static SToplevelFrame* frameFromResource(wl_resource* resource) { +static SScreencopyFrame* frameFromResource(wl_resource* resource) { ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_frame_v1_interface, &toplevelFrameImpl)); - return (SToplevelFrame*)wl_resource_get_user_data(resource); + return (SScreencopyFrame*)wl_resource_get_user_data(resource); } -void CToplevelExportProtocolManager::removeClient(SToplevelClient* client, bool force) { +void CToplevelExportProtocolManager::removeClient(CScreencopyClient* client, bool force) { if (!force) { if (!client || client->ref <= 0) return; @@ -106,7 +106,8 @@ static void handleManagerResourceDestroy(wl_resource* resource) { void CToplevelExportProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) { const auto PCLIENT = &m_lClients.emplace_back(); - PCLIENT->resource = wl_resource_create(client, &hyprland_toplevel_export_manager_v1_interface, version, id); + PCLIENT->clientOwner = CLIENT_TOPLEVEL_EXPORT; + PCLIENT->resource = wl_resource_create(client, &hyprland_toplevel_export_manager_v1_interface, version, id); if (!PCLIENT->resource) { Debug::log(ERR, "ToplevelExportManager could not bind! (out of memory?)"); @@ -128,7 +129,7 @@ static void handleFrameResourceDestroy(wl_resource* resource) { g_pProtocolManager->m_pToplevelExportProtocolManager->removeFrame(PFRAME); } -void CToplevelExportProtocolManager::removeFrame(SToplevelFrame* frame, bool force) { +void CToplevelExportProtocolManager::removeFrame(SScreencopyFrame* frame, bool force) { if (!frame) return; @@ -283,7 +284,7 @@ void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) { if (m_vFramesAwaitingWrite.empty()) return; // nothing to share - std::vector framesToRemove; + std::vector framesToRemove; // share frame if correct output for (auto& f : m_vFramesAwaitingWrite) { @@ -299,6 +300,8 @@ void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) { shareFrame(f); + ++f->client->frameCounter; + framesToRemove.push_back(f); } @@ -307,7 +310,7 @@ void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) { } } -void CToplevelExportProtocolManager::shareFrame(SToplevelFrame* frame) { +void CToplevelExportProtocolManager::shareFrame(SScreencopyFrame* frame) { if (!frame->buffer) { return; } @@ -337,7 +340,7 @@ void CToplevelExportProtocolManager::shareFrame(SToplevelFrame* frame) { hyprland_toplevel_export_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec); } -bool CToplevelExportProtocolManager::copyFrameShm(SToplevelFrame* frame, timespec* now) { +bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { void* data; uint32_t format; size_t stride; @@ -423,7 +426,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SToplevelFrame* frame, timespe return true; } -bool CToplevelExportProtocolManager::copyFrameDmabuf(SToplevelFrame* frame) { +bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { // todo Debug::log(ERR, "DMABUF copying not impl'd!"); return false; diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index e9042e66..eb94fb86 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -3,6 +3,7 @@ #include "../defines.hpp" #include "wlr-foreign-toplevel-management-unstable-v1-protocol.h" #include "hyprland-toplevel-export-v1-protocol.h" +#include "Screencopy.hpp" #include #include @@ -10,61 +11,30 @@ class CMonitor; class CWindow; -struct SToplevelClient { - int ref = 0; - wl_resource* resource = nullptr; - - bool operator==(const SToplevelClient& other) const { - return resource == other.resource; - } -}; - -struct SToplevelFrame { - wl_resource* resource = nullptr; - SToplevelClient* client = nullptr; - - uint32_t shmFormat = 0; - uint32_t dmabufFormat = 0; - wlr_box box = {0}; - int shmStride = 0; - - bool overlayCursor = false; - - wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM; - - wlr_buffer* buffer = nullptr; - - CWindow* pWindow = nullptr; - - bool operator==(const SToplevelFrame& other) const { - return resource == other.resource && client == other.client; - } -}; - class CToplevelExportProtocolManager { public: CToplevelExportProtocolManager(); void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); void captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, CWindow* handle); - void removeClient(SToplevelClient* client, bool force = false); - void removeFrame(SToplevelFrame* frame, bool force = false); + void removeClient(CScreencopyClient* client, bool force = false); + void removeFrame(SScreencopyFrame* frame, bool force = false); void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage); void displayDestroy(); void onWindowUnmap(CWindow* pWindow); private: - wl_global* m_pGlobal = nullptr; - std::list m_lFrames; - std::list m_lClients; + wl_global* m_pGlobal = nullptr; + std::list m_lFrames; + std::list m_lClients; - wl_listener m_liDisplayDestroy; + wl_listener m_liDisplayDestroy; - std::vector m_vFramesAwaitingWrite; + std::vector m_vFramesAwaitingWrite; - void shareFrame(SToplevelFrame* frame); - bool copyFrameDmabuf(SToplevelFrame* frame); - bool copyFrameShm(SToplevelFrame* frame, timespec* now); + void shareFrame(SScreencopyFrame* frame); + bool copyFrameDmabuf(SScreencopyFrame* frame); + bool copyFrameShm(SScreencopyFrame* frame, timespec* now); - void onMonitorRender(CMonitor* pMonitor); + void onMonitorRender(CMonitor* pMonitor); }; \ No newline at end of file