diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index c7d4168ae..504a05285 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -15,6 +15,7 @@ #include "../protocols/PresentationTime.hpp" #include "../protocols/DRMLease.hpp" #include "../protocols/DRMSyncobj.hpp" +#include "../protocols/Fifo.hpp" #include "../protocols/core/Output.hpp" #include "../protocols/Screencopy.hpp" #include "../protocols/ToplevelExport.hpp" @@ -156,6 +157,7 @@ void CMonitor::onConnect(bool noRule) { } m_frameScheduler->onPresented(); + m_lastPresentationTimer.reset(); m_events.presented.emit(); }); @@ -1129,24 +1131,31 @@ void CMonitor::addDamage(const CBox& box) { g_pCompositor->scheduleFrameForMonitor(m_self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } -bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { +bool CMonitor::shouldSuppressCursorCommit() { static auto PNOBREAK = CConfigValue("cursor:no_break_fs_vrr"); - static auto PMINRR = CConfigValue("cursor:min_refresh_rate"); - // skip scheduling extra frames for fullsreen apps with vrr + if (!m_output) + return false; + const auto FS_WINDOW = getFullscreenWindow(); const bool shouldRenderCursor = g_pHyprRenderer->shouldRenderCursor(); const bool noBreak = FS_WINDOW && (*PNOBREAK == 1 || (*PNOBREAK == 2 && FS_WINDOW->getContentType() == CONTENT_TYPE_GAME)); - const bool shouldSkip = (!shouldRenderCursor || noBreak) && m_output->state->state().adaptiveSync; + + return (!shouldRenderCursor || noBreak) && m_output->state->state().adaptiveSync; +} + +bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { + if (!shouldSuppressCursorCommit()) + return false; // keep requested minimum refresh rate - if (shouldSkip && *PMINRR && m_lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) { + if (isVrrKeepaliveDue()) { // damage whole screen because some previous cursor box damages were skipped m_damage.damageEntire(); return false; } - return shouldSkip; + return true; } bool CMonitor::isMirror() { @@ -1941,6 +1950,15 @@ uint16_t CMonitor::isDSBlocked(bool full) { return reasons; } +bool CMonitor::isVrrKeepaliveDue() { + static auto PMINRR = CConfigValue("cursor:min_refresh_rate"); + + if (!m_output || !m_output->state->state().adaptiveSync || *PMINRR <= 0) + return false; + + return m_lastPresentationTimer.getMillis() > 1000.0f / *PMINRR; +} + bool CMonitor::attemptDirectScanout() { static const auto PSAME = CConfigValue("debug:ds_handle_same_buffer"); static const auto PSAMEFIFO = CConfigValue("debug:ds_handle_same_buffer_fifo"); @@ -1953,28 +1971,28 @@ bool CMonitor::attemptDirectScanout() { const auto PSURFACE = PCANDIDATE->getSolitaryResource(); auto PBUFFER = PSURFACE->m_current.buffer.m_buffer; - // #TODO this entire bit needs figuring out, vrr goes down the drain without it if (PBUFFER == m_output->state->state().buffer && *PSAME) { PSURFACE->presentFeedback(Time::steadyNow(), m_self.lock()); - if (m_scanoutNeedsCursorUpdate) { - if (!m_state.test()) { - Log::logger->log(Log::TRACE, "attemptDirectScanout: failed basic test on cursor update"); - return false; - } + const bool cursorCommitDue = m_scanoutNeedsCursorUpdate && !shouldSuppressCursorCommit(); + const bool vrrKeepaliveDue = isVrrKeepaliveDue(); - if (!m_output->commit()) { - Log::logger->log(Log::TRACE, "attemptDirectScanout: failed to commit cursor update"); + if (cursorCommitDue || vrrKeepaliveDue) { + m_output->state->setBuffer(PBUFFER); + if (!m_state.test() || !m_output->commit()) { + Log::logger->log(Log::TRACE, "attemptDirectScanout: failed same-buffer commit, cursorCommitDue: {}, vrrKeepaliveDue: {}", cursorCommitDue, vrrKeepaliveDue); m_lastScanout.reset(); return false; } m_scanoutNeedsCursorUpdate = false; + return true; } - //#TODO this entire bit is bootleg deluxe, above bit is to not make vrr go down the drain, returning early here means fifo gets forever locked. - if (PSURFACE->m_fifo && !m_tearingState.activelyTearing && *PSAMEFIFO) - PSURFACE->m_stateQueue.unlockFirst(LOCK_REASON_FIFO); + if (PSURFACE->m_fifo && !m_tearingState.activelyTearing && *PSAMEFIFO) { + if (const auto fifo = PSURFACE->m_fifo.lock()) + fifo->presented(); + } return true; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 59a64237e..a8c07a2bc 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -305,6 +305,8 @@ class CMonitor { void addDamage(const CRegion& rg); void addDamage(const CBox& box); bool shouldSkipScheduleFrameOnMouseEvent(); + bool shouldSuppressCursorCommit(); + bool isVrrKeepaliveDue(); void setMirror(const std::string&); bool isMirror(); bool matchesStaticSelector(const std::string& selector) const; diff --git a/src/helpers/MonitorFrameScheduler.cpp b/src/helpers/MonitorFrameScheduler.cpp index 40c464177..d0af6c609 100644 --- a/src/helpers/MonitorFrameScheduler.cpp +++ b/src/helpers/MonitorFrameScheduler.cpp @@ -98,8 +98,6 @@ void CMonitorFrameScheduler::onFrame() { } if (!newSchedulingEnabled()) { - PMONITOR->m_lastPresentationTimer.reset(); - g_pHyprRenderer->renderMonitor(PMONITOR); return; } diff --git a/src/protocols/Fifo.hpp b/src/protocols/Fifo.hpp index 5b143f792..601659d4a 100644 --- a/src/protocols/Fifo.hpp +++ b/src/protocols/Fifo.hpp @@ -15,6 +15,7 @@ class CFifoResource { ~CFifoResource(); bool good(); + void presented(); private: UP m_resource; @@ -25,7 +26,6 @@ class CFifoResource { CHyprSignalListener surfaceStateCommit; } m_listeners; - void presented(); bool checkMonitors(bool needsSchedule = false); friend class CFifoProtocol;