3
0
mirror of https://github.com/hyprwm/Hyprland.git synced 2025-10-29 11:22:47 +00:00

monitor/dpms: fix possible invalid state

If dpms gets immediately re-enabled, a commit could fail, not schedule any frames anymore, and the monitor would be stuck off. Fix this by adding a timer to retry if commit fails.

ref #12045
This commit is contained in:
Vaxry 2025-10-27 13:34:08 +00:00
parent fd42e9d082
commit 560c53d87d
No known key found for this signature in database
GPG Key ID: 665806380871D640
2 changed files with 28 additions and 2 deletions

View File

@ -1882,13 +1882,14 @@ void CMonitor::setDPMS(bool on) {
if (on) {
// enable the monitor. Wait for the frame to be presented, then begin animation
m_dpmsBlackOpacity->setValueAndWarp(1.F);
m_dpmsBlackOpacity->setCallbackOnEnd(nullptr);
m_dpmsBlackOpacity->setValueAndWarp(1.F);
m_pendingDpmsAnimation = true;
m_pendingDpmsAnimationCounter = 0;
commitDPMSState(true);
} else {
// disable the monitor. Begin the animation, then do dpms on its end.
m_dpmsBlackOpacity->setCallbackOnEnd(nullptr);
m_dpmsBlackOpacity->setValueAndWarp(0.F);
*m_dpmsBlackOpacity = 1.F;
m_dpmsBlackOpacity->setCallbackOnEnd(
@ -1908,7 +1909,29 @@ void CMonitor::commitDPMSState(bool state) {
m_output->state->setEnabled(state);
if (!m_state.commit()) {
Debug::log(ERR, "Couldn't commit output {} for DPMS = {}", m_name, state);
Debug::log(ERR, "Couldn't commit output {} for DPMS = {}, will retry.", m_name, state);
// retry in 2 frames. This could happen when the DRM backend rejects our commit
// because disable + enable were sent almost instantly
m_dpmsRetryTimer = makeShared<CEventLoopTimer>(
std::chrono::milliseconds(2000 / sc<int>(m_refreshRate)),
[this, self = m_self](SP<CEventLoopTimer> s, void* d) {
if (!self)
return;
m_output->state->resetExplicitFences();
m_output->state->setEnabled(m_dpmsStatus);
if (!m_state.commit()) {
Debug::log(ERR, "Couldn't retry committing output {} for DPMS = {}", m_name, m_dpmsStatus);
return;
}
m_dpmsRetryTimer.reset();
},
nullptr);
g_pEventLoopManager->addTimer(m_dpmsRetryTimer);
return;
}

View File

@ -68,6 +68,7 @@ struct SMonitorRule {
class CMonitor;
class CSyncTimeline;
class CEGLSync;
class CEventLoopTimer;
class CMonitorState {
public:
@ -138,6 +139,8 @@ class CMonitor {
bool m_createdByUser = false;
bool m_isUnsafeFallback = false;
SP<CEventLoopTimer> m_dpmsRetryTimer;
bool m_pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool m_renderingActive = false;