From 511600133c64e29cd10a08b7e0773f8a68ca362c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 27 Jun 2024 00:07:59 +0200 Subject: [PATCH] backend: rework event loop api --- include/aquamarine/backend/Backend.hpp | 36 ++++++----- include/aquamarine/backend/DRM.hpp | 28 ++++----- include/aquamarine/backend/Session.hpp | 13 ++-- include/aquamarine/backend/Wayland.hpp | 22 +++---- src/backend/Backend.cpp | 84 +++----------------------- src/backend/Session.cpp | 18 ++++-- src/backend/Wayland.cpp | 6 +- src/backend/drm/DRM.cpp | 4 +- tests/SimpleWindow.cpp | 3 +- 9 files changed, 77 insertions(+), 137 deletions(-) diff --git a/include/aquamarine/backend/Backend.hpp b/include/aquamarine/backend/Backend.hpp index 36e95d2..05a6391 100644 --- a/include/aquamarine/backend/Backend.hpp +++ b/include/aquamarine/backend/Backend.hpp @@ -51,6 +51,11 @@ namespace Aquamarine { std::function logFunction; }; + struct SPollFD { + int fd = -1; + std::function onSignal; /* call this when signaled */ + }; + class IBackendImplementation { public: virtual ~IBackendImplementation() { @@ -61,15 +66,15 @@ namespace Aquamarine { AQ_BACKEND_CAPABILITY_POINTER = (1 << 0), }; - virtual eBackendType type() = 0; - virtual bool start() = 0; - virtual int pollFD() = 0; - virtual int drmFD() = 0; - virtual bool dispatchEvents() = 0; - virtual uint32_t capabilities() = 0; - virtual void onReady() = 0; - virtual std::vector getRenderFormats() = 0; - virtual std::vector getCursorFormats() = 0; + virtual eBackendType type() = 0; + virtual bool start() = 0; + virtual std::vector> pollFDs() = 0; + virtual int drmFD() = 0; + virtual bool dispatchEvents() = 0; + virtual uint32_t capabilities() = 0; + virtual void onReady() = 0; + virtual std::vector getRenderFormats() = 0; + virtual std::vector getCursorFormats() = 0; }; class CBackend { @@ -84,15 +89,8 @@ namespace Aquamarine { void log(eBackendLogLevel level, const std::string& msg); - /* Enters the event loop synchronously. For simple clients, this is probably what you want. For more complex ones, - see the async methods further below */ - void enterLoop(); - - /* Gets all the FDs you have to poll. When any single one fires, call dispatchEventsAsync */ - std::vector getPollFDs(); - - /* Dispatches all pending events on all queues then returns */ - void dispatchEventsAsync(); + /* Gets all the FDs you have to poll. When any single one fires, call its onPoll */ + std::vector> getPollFDs(); /* Checks if the backend has a session - iow if it's a DRM backend */ bool hasSession(); @@ -126,7 +124,7 @@ namespace Aquamarine { std::vector> implementations; SBackendOptions options; Hyprutils::Memory::CWeakPointer self; - std::vector sessionFDs; + std::vector> sessionFDs; // struct { diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index e47e210..0eff697 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -253,23 +253,23 @@ namespace Aquamarine { class CDRMBackend : public IBackendImplementation { public: virtual ~CDRMBackend(); - virtual eBackendType type(); - virtual bool start(); - virtual int pollFD(); - virtual int drmFD(); - virtual bool dispatchEvents(); - virtual uint32_t capabilities(); - virtual bool setCursor(Hyprutils::Memory::CSharedPointer buffer, const Hyprutils::Math::Vector2D& hotspot); - virtual void onReady(); - virtual std::vector getRenderFormats(); - virtual std::vector getCursorFormats(); + virtual eBackendType type(); + virtual bool start(); + virtual std::vector> pollFDs(); + virtual int drmFD(); + virtual bool dispatchEvents(); + virtual uint32_t capabilities(); + virtual bool setCursor(Hyprutils::Memory::CSharedPointer buffer, const Hyprutils::Math::Vector2D& hotspot); + virtual void onReady(); + virtual std::vector getRenderFormats(); + virtual std::vector getCursorFormats(); - Hyprutils::Memory::CWeakPointer self; + Hyprutils::Memory::CWeakPointer self; - void log(eBackendLogLevel, const std::string&); - bool sessionActive(); + void log(eBackendLogLevel, const std::string&); + bool sessionActive(); - std::vector idleCallbacks; + std::vector idleCallbacks; private: CDRMBackend(Hyprutils::Memory::CSharedPointer backend); diff --git a/include/aquamarine/backend/Session.hpp b/include/aquamarine/backend/Session.hpp index 87cfc62..be9a774 100644 --- a/include/aquamarine/backend/Session.hpp +++ b/include/aquamarine/backend/Session.hpp @@ -18,6 +18,7 @@ namespace Aquamarine { class CBackend; class CSession; class CLibinputDevice; + struct SPollFD; class CSessionDevice { public: @@ -118,7 +119,7 @@ namespace Aquamarine { libseat* libseatHandle = nullptr; libinput* libinputHandle = nullptr; - std::vector pollFDs(); + std::vector> pollFDs(); void dispatchPendingEventsAsync(); bool switchVT(uint32_t vt); void onReady(); @@ -134,11 +135,13 @@ namespace Aquamarine { } events; private: - Hyprutils::Memory::CWeakPointer backend; + Hyprutils::Memory::CWeakPointer backend; + std::vector> polls; - void dispatchUdevEvents(); - void dispatchLibinputEvents(); - void handleLibinputEvent(libinput_event* e); + void dispatchUdevEvents(); + void dispatchLibinputEvents(); + void dispatchLibseatEvents(); + void handleLibinputEvent(libinput_event* e); friend class CSessionDevice; friend class CLibinputDevice; diff --git a/include/aquamarine/backend/Wayland.hpp b/include/aquamarine/backend/Wayland.hpp index 70eb705..54bf1a7 100644 --- a/include/aquamarine/backend/Wayland.hpp +++ b/include/aquamarine/backend/Wayland.hpp @@ -121,18 +121,18 @@ namespace Aquamarine { class CWaylandBackend : public IBackendImplementation { public: virtual ~CWaylandBackend(); - virtual eBackendType type(); - virtual bool start(); - virtual int pollFD(); - virtual int drmFD(); - virtual bool dispatchEvents(); - virtual uint32_t capabilities(); - virtual bool setCursor(Hyprutils::Memory::CSharedPointer buffer, const Hyprutils::Math::Vector2D& hotspot); - virtual void onReady(); - virtual std::vector getRenderFormats(); - virtual std::vector getCursorFormats(); + virtual eBackendType type(); + virtual bool start(); + virtual std::vector> pollFDs(); + virtual int drmFD(); + virtual bool dispatchEvents(); + virtual uint32_t capabilities(); + virtual bool setCursor(Hyprutils::Memory::CSharedPointer buffer, const Hyprutils::Math::Vector2D& hotspot); + virtual void onReady(); + virtual std::vector getRenderFormats(); + virtual std::vector getCursorFormats(); - Hyprutils::Memory::CWeakPointer self; + Hyprutils::Memory::CWeakPointer self; private: CWaylandBackend(Hyprutils::Memory::CSharedPointer backend); diff --git a/src/backend/Backend.cpp b/src/backend/Backend.cpp index 818560a..fd33564 100644 --- a/src/backend/Backend.cpp +++ b/src/backend/Backend.cpp @@ -100,7 +100,7 @@ bool Aquamarine::CBackend::start() { // erase failed impls std::erase_if(implementations, [this](const auto& i) { - bool failed = i->pollFD() < 0; + bool failed = i->pollFDs().empty(); if (failed) log(AQ_LOG_ERROR, std::format("Implementation {} failed, erasing.", backendTypeToName(i->type()))); return failed; @@ -122,7 +122,7 @@ bool Aquamarine::CBackend::start() { b->onReady(); } - sessionFDs = session ? session->pollFDs() : std::vector{}; + sessionFDs = session ? session->pollFDs() : std::vector>{}; return true; } @@ -134,76 +134,17 @@ void Aquamarine::CBackend::log(eBackendLogLevel level, const std::string& msg) { options.logFunction(level, msg); } -void Aquamarine::CBackend::enterLoop() { - std::vector pollFDs; - +std::vector> Aquamarine::CBackend::getPollFDs() { + std::vector> result; for (auto& i : implementations) { - auto fd = i->pollFD(); - - pollFDs.emplace_back(pollfd{.fd = fd, .events = POLLIN, .revents = 0}); - } - - std::thread pollThr([this, &pollFDs]() { - int ret = 0; - while (1) { - ret = poll(pollFDs.data(), pollFDs.size(), 5000 /* 5 seconds, reasonable. It's because we might need to terminate */); - if (ret < 0) { - log(AQ_LOG_CRITICAL, std::format("Polling fds failed with {}", errno)); - terminate = true; - exit(1); - } - - for (size_t i = 0; i < pollFDs.size(); ++i) { - if (pollFDs[i].revents & POLLHUP) { - log(AQ_LOG_CRITICAL, std::format("disconnected from pollfd {}", i)); - terminate = true; - exit(1); - } - } - - if (terminate) - break; - - if (ret != 0) { - std::lock_guard lg(m_sEventLoopInternals.loopRequestMutex); - m_sEventLoopInternals.shouldProcess = true; - m_sEventLoopInternals.loopSignal.notify_all(); - } + auto pollfds = i->pollFDs(); + for (auto& p : pollfds) { + result.emplace_back(p); } - }); - - while (1) { - m_sEventLoopInternals.loopRequestMutex.unlock(); // unlock, we are ready to take events - - std::unique_lock lk(m_sEventLoopInternals.loopMutex); - if (m_sEventLoopInternals.shouldProcess == false) // avoid a lock if a thread managed to request something already since we .unlock()ed - m_sEventLoopInternals.loopSignal.wait_for(lk, std::chrono::seconds(5), [this] { return m_sEventLoopInternals.shouldProcess == true; }); // wait for events - - m_sEventLoopInternals.loopRequestMutex.lock(); // lock incoming events - - if (terminate) - break; - - m_sEventLoopInternals.shouldProcess = false; - - std::lock_guard lg(m_sEventLoopInternals.eventLock); - - dispatchEventsAsync(); - } -} - -std::vector Aquamarine::CBackend::getPollFDs() { - std::vector result; - for (auto& i : implementations) { - int fd = i->pollFD(); - if (fd < 0) - continue; - - result.push_back(fd); } for (auto& sfd : sessionFDs) { - result.push_back(sfd); + result.emplace_back(sfd); } return result; @@ -220,15 +161,6 @@ int Aquamarine::CBackend::drmFD() { return -1; } -void Aquamarine::CBackend::dispatchEventsAsync() { - for (auto& i : implementations) { - i->dispatchEvents(); - } - - if (session) - session->dispatchPendingEventsAsync(); -} - bool Aquamarine::CBackend::hasSession() { return session; } diff --git a/src/backend/Session.cpp b/src/backend/Session.cpp index d3ac5dc..ca097ff 100644 --- a/src/backend/Session.cpp +++ b/src/backend/Session.cpp @@ -353,19 +353,25 @@ void Aquamarine::CSession::dispatchLibinputEvents() { } } -void Aquamarine::CSession::dispatchPendingEventsAsync() { +void Aquamarine::CSession::dispatchLibseatEvents() { if (libseat_dispatch(libseatHandle, 0) == -1) backend->log(AQ_LOG_ERROR, "Couldn't dispatch libseat events"); +} +void Aquamarine::CSession::dispatchPendingEventsAsync() { + dispatchLibseatEvents(); dispatchUdevEvents(); dispatchLibinputEvents(); } -std::vector Aquamarine::CSession::pollFDs() { - if (!libseatHandle || !udevMonitor || !udevHandle) - return {}; - - return {libseat_get_fd(libseatHandle), udev_monitor_get_fd(udevMonitor), libinput_get_fd(libinputHandle)}; +std::vector> Aquamarine::CSession::pollFDs() { + // clang-format off + return { + makeShared(libseat_get_fd(libseatHandle), [this](){ dispatchLibseatEvents(); }), + makeShared(udev_monitor_get_fd(udevMonitor), [this](){ dispatchUdevEvents(); }), + makeShared(libinput_get_fd(libinputHandle), [this](){ dispatchLibinputEvents(); }) + }; + // clang-format on } bool Aquamarine::CSession::switchVT(uint32_t vt) { diff --git a/src/backend/Wayland.cpp b/src/backend/Wayland.cpp index 9f5cea2..846347d 100644 --- a/src/backend/Wayland.cpp +++ b/src/backend/Wayland.cpp @@ -140,11 +140,11 @@ void Aquamarine::CWaylandBackend::createOutput(const std::string& szName) { idleCallbacks.emplace_back([this, o]() { backend->events.newOutput.emit(SP(o)); }); } -int Aquamarine::CWaylandBackend::pollFD() { +std::vector> Aquamarine::CWaylandBackend::pollFDs() { if (!waylandState.display) - return -1; + return {}; - return wl_display_get_fd(waylandState.display); + return {makeShared(wl_display_get_fd(waylandState.display), [this]() { dispatchEvents(); })}; } bool Aquamarine::CWaylandBackend::dispatchEvents() { diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 9680a87..d5855fc 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -476,8 +476,8 @@ bool Aquamarine::CDRMBackend::start() { return true; } -int Aquamarine::CDRMBackend::pollFD() { - return gpu->fd; +std::vector> Aquamarine::CDRMBackend::pollFDs() { + return {makeShared(gpu->fd, [this]() { dispatchEvents(); })}; } int Aquamarine::CDRMBackend::drmFD() { diff --git a/tests/SimpleWindow.cpp b/tests/SimpleWindow.cpp index 52b6fda..7bc0ad5 100644 --- a/tests/SimpleWindow.cpp +++ b/tests/SimpleWindow.cpp @@ -90,7 +90,8 @@ int main(int argc, char** argv, char** envp) { return 1; } - aqBackend->enterLoop(); + // FIXME: write an event loop. + // aqBackend->enterLoop(); return 0; } \ No newline at end of file