From d5b00bbc1759d2e8f6486152c0e622e57fc54b72 Mon Sep 17 00:00:00 2001 From: Pppp1116 Date: Fri, 3 Apr 2026 13:24:54 +0100 Subject: [PATCH] scheduler: keep a strong monitor ref in frame callbacks --- src/helpers/MonitorFrameScheduler.cpp | 46 ++++++++++++++------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/helpers/MonitorFrameScheduler.cpp b/src/helpers/MonitorFrameScheduler.cpp index 9773bb0a2..58caeca5d 100644 --- a/src/helpers/MonitorFrameScheduler.cpp +++ b/src/helpers/MonitorFrameScheduler.cpp @@ -17,21 +17,21 @@ bool CMonitorFrameScheduler::newSchedulingEnabled() { } void CMonitorFrameScheduler::onSyncFired() { - - if (!newSchedulingEnabled()) + const auto PMONITOR = m_monitor.lock(); + if (!PMONITOR || !newSchedulingEnabled()) return; // Sync fired: reset submitted state, set as rendered. Check the last render time. If we are running // late, we will instantly render here. - if (std::chrono::duration_cast(hrc::now() - m_lastRenderBegun).count() / 1000.F < 1000.F / m_monitor->m_refreshRate) { + if (std::chrono::duration_cast(hrc::now() - m_lastRenderBegun).count() / 1000.F < 1000.F / PMONITOR->m_refreshRate) { // we are in. Frame is valid. We can just render as normal. - Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onSyncFired, didn't miss.", m_monitor->m_name); + Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onSyncFired, didn't miss.", PMONITOR->m_name); m_renderAtFrame = true; return; } - Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onSyncFired, missed.", m_monitor->m_name); + Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onSyncFired, missed.", PMONITOR->m_name); // we are out. The frame is taking too long to render. Begin rendering immediately, but don't commit yet. m_pendingThird = true; @@ -43,7 +43,7 @@ void CMonitorFrameScheduler::onSyncFired() { // FIXME: this is horrible. "renderMonitor" should not be able to do that. auto self = m_self; - g_pHyprRenderer->renderMonitor(m_monitor.lock(), false); + g_pHyprRenderer->renderMonitor(PMONITOR, false); if (!self) return; @@ -52,21 +52,22 @@ void CMonitorFrameScheduler::onSyncFired() { } void CMonitorFrameScheduler::onPresented() { - if (!newSchedulingEnabled()) + const auto PMONITOR = m_monitor.lock(); + if (!PMONITOR || !newSchedulingEnabled()) return; if (!m_pendingThird) return; - Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onPresented, missed, committing pending.", m_monitor->m_name); + Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onPresented, missed, committing pending.", PMONITOR->m_name); m_pendingThird = false; - Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onPresented, missed, committing pending at the earliest convenience.", m_monitor->m_name); + Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onPresented, missed, committing pending at the earliest convenience.", PMONITOR->m_name); m_pendingThird = false; - g_pEventLoopManager->doLater([m = m_monitor.lock()] { + g_pEventLoopManager->doLater([m = PMONITOR] { if (!m) return; g_pHyprRenderer->commitPendingAndDoExplicitSync(m); // commit the pending frame. If it didn't fire yet (is not rendered) it doesn't matter. Syncs will wait. @@ -79,35 +80,36 @@ void CMonitorFrameScheduler::onPresented() { } void CMonitorFrameScheduler::onFrame() { - if (!canRender()) + const auto PMONITOR = m_monitor.lock(); + if (!PMONITOR || !canRender()) return; - m_monitor->recheckSolitary(); + PMONITOR->recheckSolitary(); - m_monitor->m_tearingState.busy = false; + PMONITOR->m_tearingState.busy = false; - if (m_monitor->m_tearingState.activelyTearing && m_monitor->m_solitaryClient.lock() /* can be invalidated by a recheck */) { + if (PMONITOR->m_tearingState.activelyTearing && PMONITOR->m_solitaryClient.lock() /* can be invalidated by a recheck */) { - if (!m_monitor->m_tearingState.frameScheduledWhileBusy) + if (!PMONITOR->m_tearingState.frameScheduledWhileBusy) return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render? - m_monitor->m_tearingState.nextRenderTorn = true; - m_monitor->m_tearingState.frameScheduledWhileBusy = false; + PMONITOR->m_tearingState.nextRenderTorn = true; + PMONITOR->m_tearingState.frameScheduledWhileBusy = false; } if (!newSchedulingEnabled()) { - m_monitor->m_lastPresentationTimer.reset(); + PMONITOR->m_lastPresentationTimer.reset(); - g_pHyprRenderer->renderMonitor(m_monitor.lock()); + g_pHyprRenderer->renderMonitor(PMONITOR); return; } if (!m_renderAtFrame) { - Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> frame event, but m_renderAtFrame = false.", m_monitor->m_name); + Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> frame event, but m_renderAtFrame = false.", PMONITOR->m_name); return; } - Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> frame event, render = true, rendering normally.", m_monitor->m_name); + Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> frame event, render = true, rendering normally.", PMONITOR->m_name); m_lastRenderBegun = hrc::now(); @@ -115,7 +117,7 @@ void CMonitorFrameScheduler::onFrame() { // FIXME: this is horrible. "renderMonitor" should not be able to do that. auto self = m_self; - g_pHyprRenderer->renderMonitor(m_monitor.lock()); + g_pHyprRenderer->renderMonitor(PMONITOR); if (!self) return;