diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 56fc9fcf..a86ac33e 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -72,7 +72,7 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) { m->specialWorkspaceID, escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), - m->activelyTearing ? "true" : "false"); + m->tearingState.activelyTearing ? "true" : "false"); } trimTrailingComma(result); @@ -93,7 +93,7 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) { (m->output->serial ? m->output->serial : ""), m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName, m->specialWorkspaceID, getWorkspaceNameFromSpecialID(m->specialWorkspaceID), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, - (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->activelyTearing); + (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing); } } diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 24e7cc26..0b90ba1e 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -149,19 +149,22 @@ void Events::listener_monitorFrame(void* owner, void* data) { if (!PMONITOR->m_bEnabled) return; - if (PMONITOR->ignoreNextFlipEvent) { - PMONITOR->ignoreNextFlipEvent = false; - return; - } + PMONITOR->tearingState.busy = false; - PMONITOR->renderingFromVblankEvent = true; + if (PMONITOR->tearingState.activelyTearing) { + + if (!PMONITOR->tearingState.frameScheduledWhileBusy) + return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render? + + PMONITOR->tearingState.nextRenderTorn = true; + } static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue; static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue; PMONITOR->lastPresentationTimer.reset(); - if (*PENABLERAT) { + if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) { if (!PMONITOR->RATScheduled) { // render g_pHyprRenderer->renderMonitor(PMONITOR); @@ -188,8 +191,6 @@ void Events::listener_monitorFrame(void* owner, void* data) { } else { g_pHyprRenderer->renderMonitor(PMONITOR); } - - PMONITOR->renderingFromVblankEvent = false; } void Events::listener_monitorDestroy(void* owner, void* data) { diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 0d0b2a64..25a17189 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -40,7 +40,7 @@ void CMonitor::onConnect(bool noRule) { hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this); hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this); - canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm + tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm if (m_bEnabled) { wlr_output_enable(output, 1); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index d0a86f3f..71c84273 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -82,12 +82,16 @@ class CMonitor { CRegion lastFrameDamage; // stores last frame damage // for tearing - CWindow* solitaryClient = nullptr; - bool canTear = false; - bool nextRenderTorn = false; - bool ignoreNextFlipEvent = false; - bool renderingFromVblankEvent = false; - bool activelyTearing = false; + CWindow* solitaryClient = nullptr; + + struct { + bool canTear = false; + bool nextRenderTorn = false; + bool activelyTearing = false; + + bool busy = false; + bool frameScheduledWhileBusy = false; + } tearingState; // for the special workspace. 0 means not open. int specialWorkspaceID = 0; diff --git a/src/helpers/SubsurfaceTree.cpp b/src/helpers/SubsurfaceTree.cpp index 0efa4c49..76a392e8 100644 --- a/src/helpers/SubsurfaceTree.cpp +++ b/src/helpers/SubsurfaceTree.cpp @@ -249,14 +249,19 @@ void Events::listener_commitSubsurface(void* owner, void* data) { if (pNode->pWindowOwner) { // tearing: if solitary, redraw it. This still might be a single surface window const auto PMONITOR = g_pCompositor->getMonitorFromID(pNode->pWindowOwner->m_iMonitorID); - if (PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->canTear) { + if (PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear) { CRegion damageBox; wlr_surface_get_effective_damage(pNode->pSurface->wlr(), damageBox.pixman()); if (!damageBox.empty()) { - PMONITOR->nextRenderTorn = true; - g_pHyprRenderer->renderMonitor(PMONITOR); + + if (PMONITOR->tearingState.busy) { + PMONITOR->tearingState.frameScheduledWhileBusy = true; + } else { + PMONITOR->tearingState.nextRenderTorn = true; + g_pHyprRenderer->renderMonitor(PMONITOR); + } } } } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index ea6a246a..12b745ff 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -846,10 +846,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { // tearing and DS first bool shouldTear = false; - bool canTear = *PTEARINGENABLED && g_pHyprOpenGL->m_RenderData.mouseZoomFactor == 1.0; recheckSolitaryForMonitor(pMonitor); - if (pMonitor->nextRenderTorn) { - pMonitor->nextRenderTorn = false; + if (pMonitor->tearingState.nextRenderTorn) { + pMonitor->tearingState.nextRenderTorn = false; if (!*PTEARINGENABLED) { Debug::log(WARN, "Tearing commit requested but the master switch general:allow_tearing is off, ignoring"); @@ -861,18 +860,13 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { return; } - if (!pMonitor->canTear) { + if (!pMonitor->tearingState.canTear) { Debug::log(WARN, "Tearing commit requested but monitor doesn't support it, ignoring"); return; } if (pMonitor->solitaryClient) shouldTear = true; - } else { - // if this is a non-tearing commit, and we are in a state where we should tear - // then this is a vblank commit that we should ignore - if (canTear && pMonitor->solitaryClient && pMonitor->canTear && pMonitor->solitaryClient->canBeTorn() && pMonitor->renderingFromVblankEvent) - return; } if (!*PNODIRECTSCANOUT && !shouldTear) { @@ -884,12 +878,12 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } } - if (pMonitor->activelyTearing != shouldTear) { + if (pMonitor->tearingState.activelyTearing != shouldTear) { // change of state - pMonitor->activelyTearing = shouldTear; + pMonitor->tearingState.activelyTearing = shouldTear; for (auto& m : g_pCompositor->m_vMonitors) { - wlr_output_lock_software_cursors(m->output, pMonitor->activelyTearing); + wlr_output_lock_software_cursors(m->output, pMonitor->tearingState.activelyTearing); } } @@ -1090,7 +1084,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } if (shouldTear) - pMonitor->ignoreNextFlipEvent = true; + pMonitor->tearingState.busy = true; wlr_damage_ring_rotate(&pMonitor->damage);