summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVaxry <vaxry@vaxry.net>2024-05-10 02:27:54 +0100
committerVaxry <vaxry@vaxry.net>2024-05-10 02:38:54 +0100
commita7e23d2f1e27c241c2a72262d14d5dde9ea2e860 (patch)
tree72e9a6b77208f14788cd1387eb147a9475bb3229 /src
parent1753059b07be52cf78fa2676c4c71d2edb560199 (diff)
presentation-time: move to new impl
Diffstat (limited to 'src')
-rw-r--r--src/Compositor.cpp2
-rw-r--r--src/Compositor.hpp1
-rw-r--r--src/helpers/Monitor.cpp25
-rw-r--r--src/helpers/Monitor.hpp1
-rw-r--r--src/includes.hpp1
-rw-r--r--src/managers/ProtocolManager.cpp2
-rw-r--r--src/protocols/PresentationTime.cpp125
-rw-r--r--src/protocols/PresentationTime.hpp73
-rw-r--r--src/render/Renderer.cpp12
9 files changed, 229 insertions, 13 deletions
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index 72502db3..bed2b203 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -232,8 +232,6 @@ void CCompositor::initServer() {
m_sSeat.seat = wlr_seat_create(m_sWLDisplay, "seat0");
- m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend);
-
m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend);
if (!m_sWRLDRMLeaseMgr) {
Debug::log(INFO, "Failed to create wlr_drm_lease_v1_manager");
diff --git a/src/Compositor.hpp b/src/Compositor.hpp
index 20437113..8812f8c8 100644
--- a/src/Compositor.hpp
+++ b/src/Compositor.hpp
@@ -52,7 +52,6 @@ class CCompositor {
wlr_drm* m_sWRLDRM;
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
wlr_xdg_shell* m_sWLRXDGShell;
- wlr_presentation* m_sWLRPresentation;
wlr_egl* m_sWLREGL;
int m_iDRMFD;
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index 2814bc84..d13acf0c 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -5,6 +5,7 @@
#include "../protocols/GammaControl.hpp"
#include "../devices/ITouch.hpp"
#include "../protocols/LayerShell.hpp"
+#include "../protocols/PresentationTime.hpp"
int ratHandler(void* data) {
g_pHyprRenderer->renderMonitor((CMonitor*)data);
@@ -30,6 +31,13 @@ CMonitor::~CMonitor() {
events.destroy.emit();
}
+static void onPresented(void* owner, void* data) {
+ const auto PMONITOR = (CMonitor*)owner;
+ auto E = (wlr_output_event_present*)data;
+
+ PROTO::presentation->onPresented(PMONITOR, E->when, E->refresh, E->seq, E->flags);
+}
+
void CMonitor::onConnect(bool noRule) {
hyprListener_monitorDestroy.removeCallback();
hyprListener_monitorFrame.removeCallback();
@@ -38,13 +46,15 @@ void CMonitor::onConnect(bool noRule) {
hyprListener_monitorNeedsFrame.removeCallback();
hyprListener_monitorCommit.removeCallback();
hyprListener_monitorBind.removeCallback();
- hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
- hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
- hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this);
- hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this);
- hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this);
- hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this);
- hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this);
+ hyprListener_monitorPresented.removeCallback();
+ hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this, "CMonitor");
+ hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this, "CMonitor");
+ hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this, "CMonitor");
+ hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this, "CMonitor");
+ hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this, "CMonitor");
+ hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this, "CMonitor");
+ hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this, "CMonitor");
+ hyprListener_monitorPresented.initCallback(&output->events.present, ::onPresented, this, "CMonitor");
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
@@ -247,6 +257,7 @@ void CMonitor::onDisconnect(bool destroy) {
}
hyprListener_monitorFrame.removeCallback();
+ hyprListener_monitorPresented.removeCallback();
hyprListener_monitorDamage.removeCallback();
hyprListener_monitorNeedsFrame.removeCallback();
hyprListener_monitorCommit.removeCallback();
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index 48bb67e5..7aa07a86 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -149,6 +149,7 @@ class CMonitor {
DYNLISTENER(monitorNeedsFrame);
DYNLISTENER(monitorCommit);
DYNLISTENER(monitorBind);
+ DYNLISTENER(monitorPresented);
// methods
void onConnect(bool noRule);
diff --git a/src/includes.hpp b/src/includes.hpp
index 98416a1a..eb01f4a1 100644
--- a/src/includes.hpp
+++ b/src/includes.hpp
@@ -51,7 +51,6 @@ extern "C" {
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_pointer.h>
-#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_primary_selection_v1.h>
#include <wlr/types/wlr_screencopy_v1.h>
diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp
index 73f33a20..2904ed53 100644
--- a/src/managers/ProtocolManager.cpp
+++ b/src/managers/ProtocolManager.cpp
@@ -27,6 +27,7 @@
#include "../protocols/FocusGrab.hpp"
#include "../protocols/Tablet.hpp"
#include "../protocols/LayerShell.hpp"
+#include "../protocols/PresentationTime.hpp"
CProtocolManager::CProtocolManager() {
@@ -57,6 +58,7 @@ CProtocolManager::CProtocolManager() {
PROTO::focusGrab = std::make_unique<CFocusGrabProtocol>(&hyprland_focus_grab_manager_v1_interface, 1, "FocusGrab");
PROTO::tablet = std::make_unique<CTabletV2Protocol>(&zwp_tablet_manager_v2_interface, 1, "TabletV2");
PROTO::layerShell = std::make_unique<CLayerShellProtocol>(&zwlr_layer_shell_v1_interface, 5, "LayerShell");
+ PROTO::presentation = std::make_unique<CPresentationProtocol>(&wp_presentation_interface, 1, "Presentation");
// Old protocol implementations.
// TODO: rewrite them to use hyprwayland-scanner.
diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp
new file mode 100644
index 00000000..e21c8403
--- /dev/null
+++ b/src/protocols/PresentationTime.cpp
@@ -0,0 +1,125 @@
+#include "PresentationTime.hpp"
+#include <algorithm>
+#include "../helpers/Monitor.hpp"
+#include "../managers/HookSystemManager.hpp"
+
+#define LOGM PROTO::presentation->protoLog
+
+CQueuedPresentationData::CQueuedPresentationData(wlr_surface* surf) : surface(surf) {
+ ;
+}
+
+void CQueuedPresentationData::setPresentationType(bool zeroCopy_) {
+ zeroCopy = zeroCopy_;
+}
+
+void CQueuedPresentationData::attachMonitor(CMonitor* pMonitor_) {
+ pMonitor = pMonitor_;
+}
+
+void CQueuedPresentationData::presented() {
+ wasPresented = true;
+}
+
+void CQueuedPresentationData::discarded() {
+ wasPresented = false;
+}
+
+CPresentationFeedback::CPresentationFeedback(SP<CWpPresentationFeedback> resource_, wlr_surface* surf) : resource(resource_), surface(surf) {
+ if (!good())
+ return;
+
+ resource->setOnDestroy([this](CWpPresentationFeedback* pMgr) {
+ if (!done) // if it's done, it's probably already destroyed. If not, it will be in a sec.
+ PROTO::presentation->destroyResource(this);
+ });
+}
+
+bool CPresentationFeedback::good() {
+ return resource->resource();
+}
+
+void CPresentationFeedback::sendQueued(SP<CQueuedPresentationData> data, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) {
+ auto client = resource->client();
+ wl_resource* res;
+ wl_resource_for_each(res, &data->pMonitor->output->resources) {
+ if (client == wl_resource_get_client(res)) {
+ resource->sendSyncOutput(res);
+ break;
+ }
+ }
+
+ uint32_t flags = 0;
+ if (!data->pMonitor->tearingState.activelyTearing)
+ flags |= WP_PRESENTATION_FEEDBACK_KIND_VSYNC;
+ if (data->zeroCopy)
+ flags |= WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
+ if (reportedFlags & WLR_OUTPUT_PRESENT_HW_CLOCK)
+ flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
+ if (reportedFlags & WLR_OUTPUT_PRESENT_HW_COMPLETION)
+ flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
+
+ if (data->wasPresented)
+ resource->sendPresented((uint32_t)(when->tv_sec >> 32), (uint32_t)(when->tv_sec & 0xFFFFFFFF), (uint32_t)(when->tv_nsec), untilRefreshNs, (uint32_t)(seq >> 32),
+ (uint32_t)(seq & 0xFFFFFFFF), (wpPresentationFeedbackKind)flags);
+ else
+ resource->sendDiscarded();
+}
+
+CPresentationProtocol::CPresentationProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
+ static auto P = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) {
+ const auto PMONITOR = std::any_cast<CMonitor*>(param);
+ std::erase_if(m_vQueue, [PMONITOR, this](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; });
+ });
+}
+
+void CPresentationProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
+ const auto RESOURCE = m_vManagers.emplace_back(std::make_unique<CWpPresentation>(client, ver, id)).get();
+ RESOURCE->setOnDestroy([this](CWpPresentation* p) { this->onManagerResourceDestroy(p->resource()); });
+
+ RESOURCE->setDestroy([this](CWpPresentation* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
+ RESOURCE->setFeedback([this](CWpPresentation* pMgr, wl_resource* surf, uint32_t id) { this->onGetFeedback(pMgr, surf, id); });
+}
+
+void CPresentationProtocol::onManagerResourceDestroy(wl_resource* res) {
+ std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; });
+}
+
+void CPresentationProtocol::destroyResource(CPresentationFeedback* feedback) {
+ std::erase_if(m_vFeedbacks, [&](const auto& other) { return other.get() == feedback; });
+}
+
+void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* surf, uint32_t id) {
+ const auto CLIENT = pMgr->client();
+ const auto RESOURCE =
+ m_vFeedbacks.emplace_back(makeShared<CPresentationFeedback>(makeShared<CWpPresentationFeedback>(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surf))).get();
+
+ if (!RESOURCE->good()) {
+ pMgr->noMemory();
+ m_vFeedbacks.pop_back();
+ return;
+ }
+}
+
+void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) {
+ for (auto& feedback : m_vFeedbacks) {
+ if (!feedback->surface)
+ continue;
+
+ for (auto& data : m_vQueue) {
+ if (!data->surface || data->surface != feedback->surface)
+ continue;
+
+ feedback->sendQueued(data, when, untilRefreshNs, seq, reportedFlags);
+ feedback->done = true;
+ break;
+ }
+ }
+
+ std::erase_if(m_vFeedbacks, [pMonitor, this](const auto& other) { return !other->surface || other->done; });
+ std::erase_if(m_vQueue, [pMonitor, this](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor; });
+}
+
+void CPresentationProtocol::queueData(SP<CQueuedPresentationData> data) {
+ m_vQueue.emplace_back(data);
+}
diff --git a/src/protocols/PresentationTime.hpp b/src/protocols/PresentationTime.hpp
new file mode 100644
index 00000000..2df1c781
--- /dev/null
+++ b/src/protocols/PresentationTime.hpp
@@ -0,0 +1,73 @@
+#pragma once
+
+#include <memory>
+#include <vector>
+#include <cstdint>
+#include "WaylandProtocol.hpp"
+#include "presentation-time.hpp"
+
+class CMonitor;
+
+class CQueuedPresentationData {
+ public:
+ CQueuedPresentationData(wlr_surface* surf);
+
+ void setPresentationType(bool zeroCopy);
+ void attachMonitor(CMonitor* pMonitor);
+
+ void presented();
+ void discarded();
+
+ private:
+ bool wasPresented = false;
+ bool zeroCopy = false;
+ CMonitor* pMonitor = nullptr;
+ wlr_surface* surface = nullptr; // READ-ONLY
+
+ DYNLISTENER(destroySurface);
+
+ friend class CPresentationFeedback;
+ friend class CPresentationProtocol;
+};
+
+class CPresentationFeedback {
+ public:
+ CPresentationFeedback(SP<CWpPresentationFeedback> resource_, wlr_surface* surf);
+
+ bool good();
+
+ void sendQueued(SP<CQueuedPresentationData> data, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags);
+
+ private:
+ SP<CWpPresentationFeedback> resource;
+ wlr_surface* surface = nullptr; // READ-ONLY
+ bool done = false;
+
+ friend class CPresentationProtocol;
+};
+
+class CPresentationProtocol : public IWaylandProtocol {
+ public:
+ CPresentationProtocol(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 onPresented(CMonitor* pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags);
+ void queueData(SP<CQueuedPresentationData> data);
+
+ private:
+ void onManagerResourceDestroy(wl_resource* res);
+ void destroyResource(CPresentationFeedback* feedback);
+ void onGetFeedback(CWpPresentation* pMgr, wl_resource* surf, uint32_t id);
+
+ //
+ std::vector<UP<CWpPresentation>> m_vManagers;
+ std::vector<SP<CPresentationFeedback>> m_vFeedbacks;
+ std::vector<SP<CQueuedPresentationData>> m_vQueue;
+
+ friend class CPresentationFeedback;
+};
+
+namespace PROTO {
+ inline UP<CPresentationProtocol> presentation;
+};
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index d1baf461..d02ed4e2 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -10,6 +10,7 @@
#include "../desktop/LayerSurface.hpp"
#include "../protocols/SessionLock.hpp"
#include "../protocols/LayerShell.hpp"
+#include "../protocols/PresentationTime.hpp"
extern "C" {
#include <xf86drm.h>
@@ -206,7 +207,10 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
wlr_surface_send_frame_done(surface, RDATA->when);
- wlr_presentation_surface_textured_on_output(surface, RDATA->pMonitor->output);
+ auto FEEDBACK = makeShared<CQueuedPresentationData>(surface);
+ FEEDBACK->attachMonitor(RDATA->pMonitor);
+ FEEDBACK->presented();
+ PROTO::presentation->queueData(FEEDBACK);
}
g_pHyprOpenGL->blend(true);
@@ -1067,7 +1071,11 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_surface_send_frame_done(PSURFACE, &now);
- wlr_presentation_surface_scanned_out_on_output(PSURFACE, pMonitor->output);
+ auto FEEDBACK = makeShared<CQueuedPresentationData>(PSURFACE);
+ FEEDBACK->attachMonitor(pMonitor);
+ FEEDBACK->presented();
+ FEEDBACK->setPresentationType(true);
+ PROTO::presentation->queueData(FEEDBACK);
if (pMonitor->state.commit()) {
if (m_pLastScanout.expired()) {