diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 6e0c2958..aaaa0704 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1830,6 +1830,30 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{false}, }, + SConfigOptionDescription{ + .value = "debug:ds_handle_same_buffer", + .description = "Special case for DS with unmodified buffer", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "debug:ds_handle_same_buffer_fifo", + .description = "Special case for DS with unmodified buffer unlocks fifo", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "debug:fifo_pending_workaround", + .description = "Fifo workaround for empty pending list", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "debug:render_solitary_wo_damage", + .description = "Render solitary window with empty damage", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, /* * dwindle: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index d5ffe8f2..0890cc4e 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -571,6 +571,10 @@ CConfigManager::CConfigManager() { registerConfigVar("debug:disable_scale_checks", Hyprlang::INT{0}); registerConfigVar("debug:colored_stdout_logs", Hyprlang::INT{1}); registerConfigVar("debug:full_cm_proto", Hyprlang::INT{0}); + registerConfigVar("debug:ds_handle_same_buffer", Hyprlang::INT{1}); + registerConfigVar("debug:ds_handle_same_buffer_fifo", Hyprlang::INT{1}); + registerConfigVar("debug:fifo_pending_workaround", Hyprlang::INT{1}); + registerConfigVar("debug:render_solitary_wo_damage", Hyprlang::INT{0}); registerConfigVar("decoration:rounding", Hyprlang::INT{0}); registerConfigVar("decoration:rounding_power", {2.F}); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index cee9ff1b..d3b374e7 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1823,7 +1823,10 @@ uint16_t CMonitor::isDSBlocked(bool full) { } bool CMonitor::attemptDirectScanout() { - const auto blockedReason = isDSBlocked(); + static const auto PSAME = CConfigValue("debug:ds_handle_same_buffer"); + static const auto PSAMEFIFO = CConfigValue("debug:ds_handle_same_buffer_fifo"); + + const auto blockedReason = isDSBlocked(); if (blockedReason) return false; @@ -1837,7 +1840,7 @@ bool CMonitor::attemptDirectScanout() { 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) { + if (PBUFFER == m_output->state->state().buffer && *PSAME) { PSURFACE->presentFeedback(Time::steadyNow(), m_self.lock()); if (m_scanoutNeedsCursorUpdate) { @@ -1856,7 +1859,7 @@ bool CMonitor::attemptDirectScanout() { } //#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) + if (PSURFACE->m_fifo && *PSAMEFIFO) PSURFACE->m_stateQueue.unlockFirst(LOCK_REASON_FIFO); return true; diff --git a/src/protocols/CommitTiming.cpp b/src/protocols/CommitTiming.cpp index 2fcd8e9c..bce14f6b 100644 --- a/src/protocols/CommitTiming.cpp +++ b/src/protocols/CommitTiming.cpp @@ -32,9 +32,7 @@ CCommitTimerResource::CCommitTimerResource(UP&& resource_, SP< const auto TIME_NOW = Time::steadyNow(); if (TIME_NOW > TIME) { - // TODO: should we err here? - // for now just do nothing I guess, thats some lag. - m_pendingTimeout = Time::steady_dur::min(); + m_pendingTimeout.reset(); } else m_pendingTimeout = TIME - TIME_NOW; }); @@ -56,6 +54,7 @@ CCommitTimerResource::CCommitTimerResource(UP&& resource_, SP< m_surface->m_stateQueue.unlockFirst(LOCK_REASON_TIMER); }, nullptr); + g_pEventLoopManager->addTimer(timer); } else timer->updateTimeout(m_pendingTimeout); @@ -64,7 +63,8 @@ CCommitTimerResource::CCommitTimerResource(UP&& resource_, SP< } CCommitTimerResource::~CCommitTimerResource() { - ; + if (m_timerPresent) + g_pEventLoopManager->removeTimer(timer); } bool CCommitTimerResource::good() { diff --git a/src/protocols/Fifo.cpp b/src/protocols/Fifo.cpp index d9f873c9..386327b5 100644 --- a/src/protocols/Fifo.cpp +++ b/src/protocols/Fifo.cpp @@ -34,35 +34,40 @@ CFifoResource::CFifoResource(UP&& resource_, SP s }); m_listeners.surfaceStateCommit = m_surface->m_events.stateCommit.listen([this](auto state) { + static const auto PPEND = CConfigValue("debug:fifo_pending_workaround"); + if (!m_pending.surfaceLocked) return; - //#TODO: - // this feels wrong, but if we have no pending frames, presented might never come because - // we are waiting on the barrier to unlock and no damage is around. - if (m_surface->m_enteredOutputs.empty() && m_surface->m_hlSurface) { - for (auto& m : g_pCompositor->m_monitors) { - if (!m || !m->m_enabled) - continue; + if (*PPEND) { + //#TODO: + // this feels wrong, but if we have no pending frames, presented might never come because + // we are waiting on the barrier to unlock and no damage is around. + // unlock on timeout instead? + if (m_surface->m_enteredOutputs.empty() && m_surface->m_hlSurface) { + for (auto& m : g_pCompositor->m_monitors) { + if (!m || !m->m_enabled) + continue; + + auto box = m_surface->m_hlSurface->getSurfaceBoxGlobal(); + if (box && !box->intersection({m->m_position, m->m_size}).empty()) { + if (m->m_tearingState.activelyTearing) + return; // dont fifo lock on tearing. + + g_pCompositor->scheduleFrameForMonitor(m, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); + } + } + } else { + for (auto& m : m_surface->m_enteredOutputs) { + if (!m) + continue; - auto box = m_surface->m_hlSurface->getSurfaceBoxGlobal(); - if (box && !box->intersection({m->m_position, m->m_size}).empty()) { if (m->m_tearingState.activelyTearing) return; // dont fifo lock on tearing. - g_pCompositor->scheduleFrameForMonitor(m, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); + g_pCompositor->scheduleFrameForMonitor(m.lock(), Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); } } - } else { - for (auto& m : m_surface->m_enteredOutputs) { - if (!m) - continue; - - if (m->m_tearingState.activelyTearing) - return; // dont fifo lock on tearing. - - g_pCompositor->scheduleFrameForMonitor(m.lock(), Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); - } } // only lock once its mapped. diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index c897bfe8..9fc44703 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -506,13 +506,13 @@ void CWLSurfaceResource::scheduleState(WP state) { } } else if (state->buffer && state->buffer->isSynchronous()) { // synchronous (shm) buffers can be read immediately - m_stateQueue.unlock(state); + m_stateQueue.unlock(state, LOCK_REASON_FENCE); } else if (state->buffer && state->buffer->m_syncFd.isValid()) { // async buffer and is dmabuf, then we can wait on implicit fences g_pEventLoopManager->doOnReadable(std::move(state->buffer->m_syncFd), [state, whenReadable]() { whenReadable(state, LOCK_REASON_FENCE); }); } else { // state commit without a buffer. - m_stateQueue.unlock(state); + m_stateQueue.unlock(state, LOCK_REASON_FENCE); } } diff --git a/src/protocols/types/SurfaceStateQueue.cpp b/src/protocols/types/SurfaceStateQueue.cpp index c10b556f..348ac711 100644 --- a/src/protocols/types/SurfaceStateQueue.cpp +++ b/src/protocols/types/SurfaceStateQueue.cpp @@ -21,6 +21,7 @@ void CSurfaceStateQueue::dropState(const WP& state) { } void CSurfaceStateQueue::lock(const WP& weakState, eLockReason reason) { + ASSERT(reason != LOCK_REASON_NONE); auto it = find(weakState); if (it == m_queue.end()) return; @@ -29,6 +30,7 @@ void CSurfaceStateQueue::lock(const WP& weakState, eLockReason re } void CSurfaceStateQueue::unlock(const WP& state, eLockReason reason) { + ASSERT(reason != LOCK_REASON_NONE); auto it = find(state); if (it == m_queue.end()) return; @@ -38,6 +40,7 @@ void CSurfaceStateQueue::unlock(const WP& state, eLockReason reas } void CSurfaceStateQueue::unlockFirst(eLockReason reason) { + ASSERT(reason != LOCK_REASON_NONE); for (auto& it : m_queue) { if ((it->lockMask & reason) != LOCK_REASON_NONE) { it->lockMask &= ~reason; diff --git a/src/protocols/types/SurfaceStateQueue.hpp b/src/protocols/types/SurfaceStateQueue.hpp index 1841ed20..8d9db7a5 100644 --- a/src/protocols/types/SurfaceStateQueue.hpp +++ b/src/protocols/types/SurfaceStateQueue.hpp @@ -15,7 +15,7 @@ class CSurfaceStateQueue { WP enqueue(UP&& state); void dropState(const WP& state); void lock(const WP& state, eLockReason reason); - void unlock(const WP& state, eLockReason reason = LOCK_REASON_NONE); + void unlock(const WP& state, eLockReason reason); void unlockFirst(eLockReason reason); void tryProcess(); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b3684a0e..abecb2f9 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1268,6 +1268,7 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) { static auto PDEBUGOVERLAY = CConfigValue("debug:overlay"); static auto PDAMAGETRACKINGMODE = CConfigValue("debug:damage_tracking"); static auto PDAMAGEBLINK = CConfigValue("debug:damage_blink"); + static auto PSOLDAMAGE = CConfigValue("debug:render_solitary_wo_damage"); static auto PVFR = CConfigValue("misc:vfr"); static int damageBlinkCleanup = 0; // because double-buffered @@ -1398,46 +1399,45 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) { bool renderCursor = true; - if (!finalDamage.empty()) { - if (pMonitor->m_solitaryClient.expired()) { - if (pMonitor->isMirror()) { - g_pHyprOpenGL->blend(false); - g_pHyprOpenGL->renderMirrored(); - g_pHyprOpenGL->blend(true); - EMIT_HOOK_EVENT("render", RENDER_POST_MIRROR); - renderCursor = false; - } else { - CBox renderBox = {0, 0, sc(pMonitor->m_pixelSize.x), sc(pMonitor->m_pixelSize.y)}; - renderWorkspace(pMonitor, pMonitor->m_activeWorkspace, NOW, renderBox); + if (pMonitor->m_solitaryClient && (!finalDamage.empty() || *PSOLDAMAGE)) + renderWindow(pMonitor->m_solitaryClient.lock(), pMonitor, NOW, false, RENDER_PASS_MAIN /* solitary = no popups */); + else if (!finalDamage.empty()) { + if (pMonitor->isMirror()) { + g_pHyprOpenGL->blend(false); + g_pHyprOpenGL->renderMirrored(); + g_pHyprOpenGL->blend(true); + EMIT_HOOK_EVENT("render", RENDER_POST_MIRROR); + renderCursor = false; + } else { + CBox renderBox = {0, 0, sc(pMonitor->m_pixelSize.x), sc(pMonitor->m_pixelSize.y)}; + renderWorkspace(pMonitor, pMonitor->m_activeWorkspace, NOW, renderBox); - renderLockscreen(pMonitor, NOW, renderBox); + renderLockscreen(pMonitor, NOW, renderBox); - if (pMonitor == Desktop::focusState()->monitor()) { - g_pHyprNotificationOverlay->draw(pMonitor); - g_pHyprError->draw(); - } - - // for drawing the debug overlay - if (pMonitor == g_pCompositor->m_monitors.front() && *PDEBUGOVERLAY == 1) { - renderStartOverlay = std::chrono::high_resolution_clock::now(); - g_pDebugOverlay->draw(); - endRenderOverlay = std::chrono::high_resolution_clock::now(); - } - - if (*PDAMAGEBLINK && damageBlinkCleanup == 0) { - CRectPassElement::SRectData data; - data.box = {0, 0, pMonitor->m_transformedSize.x, pMonitor->m_transformedSize.y}; - data.color = CHyprColor(1.0, 0.0, 1.0, 100.0 / 255.0); - m_renderPass.add(makeUnique(data)); - damageBlinkCleanup = 1; - } else if (*PDAMAGEBLINK) { - damageBlinkCleanup++; - if (damageBlinkCleanup > 3) - damageBlinkCleanup = 0; - } + if (pMonitor == Desktop::focusState()->monitor()) { + g_pHyprNotificationOverlay->draw(pMonitor); + g_pHyprError->draw(); } - } else - renderWindow(pMonitor->m_solitaryClient.lock(), pMonitor, NOW, false, RENDER_PASS_MAIN /* solitary = no popups */); + + // for drawing the debug overlay + if (pMonitor == g_pCompositor->m_monitors.front() && *PDEBUGOVERLAY == 1) { + renderStartOverlay = std::chrono::high_resolution_clock::now(); + g_pDebugOverlay->draw(); + endRenderOverlay = std::chrono::high_resolution_clock::now(); + } + + if (*PDAMAGEBLINK && damageBlinkCleanup == 0) { + CRectPassElement::SRectData data; + data.box = {0, 0, pMonitor->m_transformedSize.x, pMonitor->m_transformedSize.y}; + data.color = CHyprColor(1.0, 0.0, 1.0, 100.0 / 255.0); + m_renderPass.add(makeUnique(data)); + damageBlinkCleanup = 1; + } else if (*PDAMAGEBLINK) { + damageBlinkCleanup++; + if (damageBlinkCleanup > 3) + damageBlinkCleanup = 0; + } + } } else if (!pMonitor->isMirror()) { sendFrameEventsToWorkspace(pMonitor, pMonitor->m_activeWorkspace, NOW); if (pMonitor->m_activeSpecialWorkspace)