summaryrefslogtreecommitdiff
path: root/src/protocols
diff options
context:
space:
mode:
authorUjinT34 <41110182+UjinT34@users.noreply.github.com>2026-02-10 17:55:21 +0300
committerGitHub <noreply@github.com>2026-02-10 14:55:21 +0000
commitff061d177e86435a0d9f5605153a4567e2fcd88b (patch)
tree5c5fad1a485b2af162e3d3e11aecacaa8e03834f /src/protocols
parent407a623801b8cb5b863e5056b2d5a195452776fa (diff)
protocols: commit and presentation timing fixes (#13174)
* move commit timing fields to surface state * fix toTimespec init * update sendQueued api * update onPresented api * set zero copy flag * send clock id * move presented calcs inside condition * use only CLOCK_MONOTONIC for commit/presentation timings * fix setSetTimestamp * do not wait for commit timing while tearing * proto config * fix config defaults
Diffstat (limited to 'src/protocols')
-rw-r--r--src/protocols/CommitTiming.cpp43
-rw-r--r--src/protocols/CommitTiming.hpp9
-rw-r--r--src/protocols/PresentationTime.cpp39
-rw-r--r--src/protocols/PresentationTime.hpp5
-rw-r--r--src/protocols/core/Compositor.cpp32
-rw-r--r--src/protocols/core/Compositor.hpp1
-rw-r--r--src/protocols/types/SurfaceState.cpp3
-rw-r--r--src/protocols/types/SurfaceState.hpp6
8 files changed, 80 insertions, 58 deletions
diff --git a/src/protocols/CommitTiming.cpp b/src/protocols/CommitTiming.cpp
index bce14f6b..c1fca990 100644
--- a/src/protocols/CommitTiming.cpp
+++ b/src/protocols/CommitTiming.cpp
@@ -12,61 +12,48 @@ CCommitTimerResource::CCommitTimerResource(UP<CWpCommitTimerV1>&& resource_, SP<
m_resource->setOnDestroy([this](CWpCommitTimerV1* r) { PROTO::commitTiming->destroyResource(this); });
m_resource->setSetTimestamp([this](CWpCommitTimerV1* r, uint32_t tvHi, uint32_t tvLo, uint32_t tvNsec) {
- return;
-
if (!m_surface) {
r->error(WP_COMMIT_TIMER_V1_ERROR_SURFACE_DESTROYED, "Surface was gone");
return;
}
- if (m_pendingTimeout.has_value()) {
+ if (m_surface->m_pending.pendingTimeout.has_value()) {
r->error(WP_COMMIT_TIMER_V1_ERROR_TIMESTAMP_EXISTS, "Timestamp is already set");
return;
}
- timespec ts;
- ts.tv_sec = (((uint64_t)tvHi) << 32) | (uint64_t)tvLo;
- ts.tv_nsec = tvNsec;
-
- const auto TIME = Time::fromTimespec(&ts);
- const auto TIME_NOW = Time::steadyNow();
+ const auto delay = Time::till({.tv_sec = (((uint64_t)tvHi) << 32) | (uint64_t)tvLo, .tv_nsec = tvNsec});
- if (TIME_NOW > TIME) {
- m_pendingTimeout.reset();
+ if (delay.count() <= 0) {
+ m_surface->m_pending.pendingTimeout.reset();
} else
- m_pendingTimeout = TIME - TIME_NOW;
+ m_surface->m_pending.pendingTimeout = delay;
});
m_listeners.surfaceStateCommit = m_surface->m_events.stateCommit2.listen([this](auto state) {
- if (!m_pendingTimeout.has_value())
+ if (!state || !state->pendingTimeout.has_value() || !m_surface || m_surface->isTearing())
return;
m_surface->m_stateQueue.lock(state, LOCK_REASON_TIMER);
- if (!m_timerPresent) {
- m_timerPresent = true;
- timer = makeShared<CEventLoopTimer>(
- m_pendingTimeout,
- [this](SP<CEventLoopTimer> self, void* data) {
- if (!m_surface)
+ if (!state->timer) {
+ state->timer = makeShared<CEventLoopTimer>(
+ state->pendingTimeout,
+ [this, state](SP<CEventLoopTimer> self, void* data) {
+ if (!m_surface || !state)
return;
- m_surface->m_stateQueue.unlockFirst(LOCK_REASON_TIMER);
+ m_surface->m_stateQueue.unlock(state, LOCK_REASON_TIMER);
},
nullptr);
- g_pEventLoopManager->addTimer(timer);
+ g_pEventLoopManager->addTimer(state->timer);
} else
- timer->updateTimeout(m_pendingTimeout);
+ state->timer->updateTimeout(state->pendingTimeout);
- m_pendingTimeout.reset();
+ state->pendingTimeout.reset();
});
}
-CCommitTimerResource::~CCommitTimerResource() {
- if (m_timerPresent)
- g_pEventLoopManager->removeTimer(timer);
-}
-
bool CCommitTimerResource::good() {
return m_resource->resource();
}
diff --git a/src/protocols/CommitTiming.hpp b/src/protocols/CommitTiming.hpp
index e79face8..b5a1de93 100644
--- a/src/protocols/CommitTiming.hpp
+++ b/src/protocols/CommitTiming.hpp
@@ -1,7 +1,6 @@
#pragma once
#include <vector>
-#include <unordered_map>
#include "WaylandProtocol.hpp"
#include "commit-timing-v1.hpp"
@@ -14,16 +13,12 @@ class CEventLoopTimer;
class CCommitTimerResource {
public:
CCommitTimerResource(UP<CWpCommitTimerV1>&& resource_, SP<CWLSurfaceResource> surface);
- ~CCommitTimerResource();
bool good();
private:
- UP<CWpCommitTimerV1> m_resource;
- WP<CWLSurfaceResource> m_surface;
- bool m_timerPresent = false;
- std::optional<Time::steady_dur> m_pendingTimeout;
- SP<CEventLoopTimer> timer;
+ UP<CWpCommitTimerV1> m_resource;
+ WP<CWLSurfaceResource> m_surface;
struct {
CHyprSignalListener surfaceStateCommit;
diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp
index 82c4b1eb..f1cd42d2 100644
--- a/src/protocols/PresentationTime.cpp
+++ b/src/protocols/PresentationTime.cpp
@@ -40,7 +40,7 @@ bool CPresentationFeedback::good() {
return m_resource->resource();
}
-void CPresentationFeedback::sendQueued(WP<CQueuedPresentationData> data, const Time::steady_tp& when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) {
+void CPresentationFeedback::sendQueued(WP<CQueuedPresentationData> data, const timespec& when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) {
auto client = m_resource->client();
if LIKELY (PROTO::outputs.contains(data->m_monitor->m_name) && data->m_wasPresented) {
@@ -48,28 +48,26 @@ void CPresentationFeedback::sendQueued(WP<CQueuedPresentationData> data, const T
m_resource->sendSyncOutput(outputResource->getResource()->resource());
}
- uint32_t flags = 0;
- if (!data->m_monitor->m_tearingState.activelyTearing)
- flags |= WP_PRESENTATION_FEEDBACK_KIND_VSYNC;
- if (data->m_zeroCopy)
- flags |= WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
- if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_CLOCK)
- flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
- if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION)
- flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
+ if (data->m_wasPresented) {
+ uint32_t flags = 0;
+ if (!data->m_monitor->m_tearingState.activelyTearing)
+ flags |= WP_PRESENTATION_FEEDBACK_KIND_VSYNC;
+ if (data->m_zeroCopy)
+ flags |= WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
+ if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_CLOCK)
+ flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
+ if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION)
+ flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
- const auto TIMESPEC = Time::toTimespec(when);
+ time_t tv_sec = 0;
+ if (sizeof(time_t) > 4)
+ tv_sec = when.tv_sec >> 32;
- time_t tv_sec = 0;
- if (sizeof(time_t) > 4)
- tv_sec = TIMESPEC.tv_sec >> 32;
+ uint32_t refreshNs = m_resource->version() == 1 && data->m_monitor->m_vrrActive && data->m_monitor->m_output->vrrCapable ? 0 : untilRefreshNs;
- uint32_t refreshNs = m_resource->version() == 1 && data->m_monitor->m_vrrActive && data->m_monitor->m_output->vrrCapable ? 0 : untilRefreshNs;
-
- if (data->m_wasPresented)
- m_resource->sendPresented(sc<uint32_t>(tv_sec), sc<uint32_t>(TIMESPEC.tv_sec & 0xFFFFFFFF), sc<uint32_t>(TIMESPEC.tv_nsec), refreshNs, sc<uint32_t>(seq >> 32),
+ m_resource->sendPresented(sc<uint32_t>(tv_sec), sc<uint32_t>(when.tv_sec & 0xFFFFFFFF), sc<uint32_t>(when.tv_nsec), refreshNs, sc<uint32_t>(seq >> 32),
sc<uint32_t>(seq & 0xFFFFFFFF), sc<wpPresentationFeedbackKind>(flags));
- else
+ } else
m_resource->sendDiscarded();
m_done = true;
@@ -88,6 +86,7 @@ void CPresentationProtocol::bindManager(wl_client* client, void* data, uint32_t
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); });
+ RESOURCE->sendClockId(CLOCK_MONOTONIC);
}
void CPresentationProtocol::onManagerResourceDestroy(wl_resource* res) {
@@ -110,7 +109,7 @@ void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* su
}
}
-void CPresentationProtocol::onPresented(PHLMONITOR pMonitor, const Time::steady_tp& when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) {
+void CPresentationProtocol::onPresented(PHLMONITOR pMonitor, const timespec& when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) {
for (auto const& feedback : m_feedbacks) {
if (!feedback->m_surface)
continue;
diff --git a/src/protocols/PresentationTime.hpp b/src/protocols/PresentationTime.hpp
index c348c175..caf63ace 100644
--- a/src/protocols/PresentationTime.hpp
+++ b/src/protocols/PresentationTime.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <ctime>
#include <vector>
#include <cstdint>
#include "WaylandProtocol.hpp"
@@ -37,7 +38,7 @@ class CPresentationFeedback {
bool good();
- void sendQueued(WP<CQueuedPresentationData> data, const Time::steady_tp& when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags);
+ void sendQueued(WP<CQueuedPresentationData> data, const timespec& when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags);
private:
UP<CWpPresentationFeedback> m_resource;
@@ -53,7 +54,7 @@ class CPresentationProtocol : public IWaylandProtocol {
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
- void onPresented(PHLMONITOR pMonitor, const Time::steady_tp& when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags);
+ void onPresented(PHLMONITOR pMonitor, const timespec& when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags);
void queueData(UP<CQueuedPresentationData>&& data);
private:
diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp
index 2fd586a8..2aa72d97 100644
--- a/src/protocols/core/Compositor.cpp
+++ b/src/protocols/core/Compositor.cpp
@@ -626,6 +626,30 @@ bool CWLSurfaceResource::hasVisibleSubsurface() {
return false;
}
+bool CWLSurfaceResource::isTearing() {
+ if (m_enteredOutputs.empty() && m_hlSurface) {
+ for (auto& m : g_pCompositor->m_monitors) {
+ if (!m || !m->m_enabled)
+ continue;
+
+ auto box = m_hlSurface->getSurfaceBoxGlobal();
+ if (box && !box->intersection({m->m_position, m->m_size}).empty()) {
+ if (m->m_tearingState.activelyTearing)
+ return true;
+ }
+ }
+ } else {
+ for (auto& m : m_enteredOutputs) {
+ if (!m)
+ continue;
+
+ if (m->m_tearingState.activelyTearing)
+ return true;
+ }
+ }
+ return false;
+}
+
void CWLSurfaceResource::updateCursorShm(CRegion damage) {
if (damage.empty())
return;
@@ -670,8 +694,14 @@ void CWLSurfaceResource::presentFeedback(const Time::steady_tp& when, PHLMONITOR
FEEDBACK->attachMonitor(pMonitor);
if (discarded)
FEEDBACK->discarded();
- else
+ else {
FEEDBACK->presented();
+ if (!pMonitor->m_lastScanout.expired()) {
+ const auto WINDOW = m_hlSurface ? Desktop::View::CWindow::fromView(m_hlSurface->view()) : nullptr;
+ if (WINDOW == pMonitor->m_lastScanout)
+ FEEDBACK->setPresentationType(true);
+ }
+ }
PROTO::presentation->queueData(std::move(FEEDBACK));
}
diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp
index 89bfb31b..b5357520 100644
--- a/src/protocols/core/Compositor.hpp
+++ b/src/protocols/core/Compositor.hpp
@@ -128,6 +128,7 @@ class CWLSurfaceResource {
NColorManagement::PImageDescription getPreferredImageDescription();
void sortSubsurfaces();
bool hasVisibleSubsurface();
+ bool isTearing();
// returns a pair: found surface (null if not found) and surface local coords.
// localCoords param is relative to 0,0 of this surface
diff --git a/src/protocols/types/SurfaceState.cpp b/src/protocols/types/SurfaceState.cpp
index a85a3c44..46f2a563 100644
--- a/src/protocols/types/SurfaceState.cpp
+++ b/src/protocols/types/SurfaceState.cpp
@@ -67,6 +67,9 @@ void SSurfaceState::reset() {
barrierSet = false;
surfaceLocked = false;
fifoScheduled = false;
+
+ pendingTimeout.reset();
+ timer.reset(); // CEventLoopManager::nudgeTimers should handle it eventually
}
void SSurfaceState::updateFrom(SSurfaceState& ref) {
diff --git a/src/protocols/types/SurfaceState.hpp b/src/protocols/types/SurfaceState.hpp
index 315fa4fc..f6caa83c 100644
--- a/src/protocols/types/SurfaceState.hpp
+++ b/src/protocols/types/SurfaceState.hpp
@@ -1,6 +1,8 @@
#pragma once
#include "../../helpers/math/Math.hpp"
+#include "../../helpers/time/Time.hpp"
+#include "../../managers/eventLoop/EventLoopTimer.hpp"
#include "../WaylandProtocol.hpp"
#include "./Buffer.hpp"
@@ -94,6 +96,10 @@ struct SSurfaceState {
bool surfaceLocked = false;
bool fifoScheduled = false;
+ // commit timing
+ std::optional<Time::steady_dur> pendingTimeout;
+ SP<CEventLoopTimer> timer;
+
// helpers
CRegion accumulateBufferDamage(); // transforms state.damage and merges it into state.bufferDamage
void updateFrom(SSurfaceState& ref); // updates this state based on a reference state.