renderer: allow tearing with DS with invisible cursors (#13155)

This commit is contained in:
UjinT34 2026-02-07 15:38:01 +03:00 committed by GitHub
parent cfbbfb591a
commit 9f9dbb0dc5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 27 additions and 22 deletions

View file

@ -144,13 +144,13 @@ std::string CHyprCtl::getSolitaryBlockedReason(Hyprutils::Memory::CSharedPointer
} }
const std::array<const char*, CMonitor::DS_CHECKS_COUNT> DS_REASONS_JSON = { const std::array<const char*, CMonitor::DS_CHECKS_COUNT> DS_REASONS_JSON = {
"\"UNKNOWN\"", "\"USER\"", "\"WINDOWED\"", "\"CONTENT\"", "\"MIRROR\"", "\"RECORD\"", "\"SW\"", "\"UNKNOWN\"", "\"USER\"", "\"WINDOWED\"", "\"CONTENT\"", "\"MIRROR\"", "\"RECORD\"", "\"SW\"",
"\"CANDIDATE\"", "\"SURFACE\"", "\"TRANSFORM\"", "\"DMA\"", "\"TEARING\"", "\"FAILED\"", "\"CM\"", "\"CANDIDATE\"", "\"SURFACE\"", "\"TRANSFORM\"", "\"DMA\"", "\"FAILED\"", "\"CM\"",
}; };
const std::array<const char*, CMonitor::DS_CHECKS_COUNT> DS_REASONS_TEXT = { const std::array<const char*, CMonitor::DS_CHECKS_COUNT> DS_REASONS_TEXT = {
"unknown reason", "user settings", "windowed mode", "content type", "monitor mirrors", "screen record/screenshot", "software renders/cursors", "unknown reason", "user settings", "windowed mode", "content type", "monitor mirrors", "screen record/screenshot", "software renders/cursors",
"missing candidate", "invalid surface", "surface transformations", "invalid buffer", "tearing", "activation failed", "color management", "missing candidate", "invalid surface", "surface transformations", "invalid buffer", "activation failed", "color management",
}; };
std::string CHyprCtl::getDSBlockedReason(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) { std::string CHyprCtl::getDSBlockedReason(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) {
@ -173,14 +173,13 @@ std::string CHyprCtl::getDSBlockedReason(Hyprutils::Memory::CSharedPointer<CMoni
} }
const std::array<const char*, CMonitor::TC_CHECKS_COUNT> TEARING_REASONS_JSON = { const std::array<const char*, CMonitor::TC_CHECKS_COUNT> TEARING_REASONS_JSON = {
"\"UNKNOWN\"", "\"NOT_TORN\"", "\"USER\"", "\"ZOOM\"", "\"SUPPORT\"", "\"CANDIDATE\"", "\"WINDOW\"", "\"UNKNOWN\"", "\"NOT_TORN\"", "\"USER\"", "\"ZOOM\"", "\"SUPPORT\"", "\"CANDIDATE\"", "\"WINDOW\"", "\"HW_CURSOR\"",
}; };
const std::array<const char*, CMonitor::TC_CHECKS_COUNT> TEARING_REASONS_TEXT = { const std::array<const char*, CMonitor::TC_CHECKS_COUNT> TEARING_REASONS_TEXT = {"unknown reason", "next frame is not torn", "user settings", "zoom",
"unknown reason", "next frame is not torn", "user settings", "zoom", "not supported by monitor", "missing candidate", "window settings", "not supported by monitor", "missing candidate", "window settings", "hw cursor"};
};
std::string CHyprCtl::getTearingBlockedReason(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) { std::string CHyprCtl::getTearingBlockedReason(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) {
const auto reasons = m->isTearingBlocked(true); const auto reasons = m->isTearingBlocked(true);
if (!reasons || (reasons == CMonitor::TC_NOT_TORN && m->m_tearingState.activelyTearing)) if (!reasons || (reasons == CMonitor::TC_NOT_TORN && m->m_tearingState.activelyTearing))
return "null"; return "null";

View file

@ -1724,6 +1724,10 @@ uint8_t CMonitor::isTearingBlocked(bool full) {
} }
} }
// TODO: remove this when kernel allows tearing + hw cursor updated
if (g_pPointerManager->hasVisibleHWCursor(m_self.lock()))
reasons |= TC_HW_CURSOR;
if (m_solitaryClient.expired()) { if (m_solitaryClient.expired()) {
reasons |= TC_CANDIDATE; reasons |= TC_CANDIDATE;
return reasons; return reasons;
@ -1765,12 +1769,6 @@ uint16_t CMonitor::isDSBlocked(bool full) {
} }
} }
if (m_tearingState.activelyTearing) {
reasons |= DS_BLOCK_TEARING;
if (!full)
return reasons;
}
if (!m_mirrors.empty() || isMirror()) { if (!m_mirrors.empty() || isMirror()) {
reasons |= DS_BLOCK_MIRROR; reasons |= DS_BLOCK_MIRROR;
if (!full) if (!full)
@ -1862,7 +1860,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. //#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 && *PSAMEFIFO) if (PSURFACE->m_fifo && !m_tearingState.activelyTearing && *PSAMEFIFO)
PSURFACE->m_stateQueue.unlockFirst(LOCK_REASON_FIFO); PSURFACE->m_stateQueue.unlockFirst(LOCK_REASON_FIFO);
return true; return true;

View file

@ -233,9 +233,8 @@ class CMonitor {
DS_BLOCK_SURFACE = (1 << 8), DS_BLOCK_SURFACE = (1 << 8),
DS_BLOCK_TRANSFORM = (1 << 9), DS_BLOCK_TRANSFORM = (1 << 9),
DS_BLOCK_DMA = (1 << 10), DS_BLOCK_DMA = (1 << 10),
DS_BLOCK_TEARING = (1 << 11), DS_BLOCK_FAILED = (1 << 11),
DS_BLOCK_FAILED = (1 << 12), DS_BLOCK_CM = (1 << 12),
DS_BLOCK_CM = (1 << 13),
DS_CHECKS_COUNT = 14, DS_CHECKS_COUNT = 14,
}; };
@ -276,8 +275,9 @@ class CMonitor {
TC_SUPPORT = (1 << 4), TC_SUPPORT = (1 << 4),
TC_CANDIDATE = (1 << 5), TC_CANDIDATE = (1 << 5),
TC_WINDOW = (1 << 6), TC_WINDOW = (1 << 6),
TC_HW_CURSOR = (1 << 7),
TC_CHECKS_COUNT = 7, TC_CHECKS_COUNT = 8,
}; };
// methods // methods

View file

@ -72,8 +72,10 @@ void CPointerManager::lockSoftwareForMonitor(PHLMONITOR mon) {
void CPointerManager::unlockSoftwareForMonitor(PHLMONITOR mon) { void CPointerManager::unlockSoftwareForMonitor(PHLMONITOR mon) {
auto const state = stateFor(mon); auto const state = stateFor(mon);
state->softwareLocks--; state->softwareLocks--;
if (state->softwareLocks < 0) if (state->softwareLocks < 0) {
state->softwareLocks = 0; state->softwareLocks = 0;
Log::logger->log(Log::WARN, "Unlocking SW for monitor while it's not locked");
}
if (state->softwareLocks == 0) if (state->softwareLocks == 0)
updateCursorBackend(); updateCursorBackend();
@ -81,7 +83,12 @@ void CPointerManager::unlockSoftwareForMonitor(PHLMONITOR mon) {
bool CPointerManager::softwareLockedFor(PHLMONITOR mon) { bool CPointerManager::softwareLockedFor(PHLMONITOR mon) {
auto const state = stateFor(mon); auto const state = stateFor(mon);
return state->softwareLocks > 0 || state->hardwareFailed; return state->softwareLocks > 0 || (state->hardwareFailed && hasCursor() && g_pHyprRenderer->shouldRenderCursor());
}
bool CPointerManager::hasVisibleHWCursor(PHLMONITOR pMonitor) {
auto const state = stateFor(pMonitor);
return state->softwareLocks == 0 && !state->hardwareFailed && hasCursor() && g_pHyprRenderer->shouldRenderCursor();
} }
Vector2D CPointerManager::position() { Vector2D CPointerManager::position() {

View file

@ -48,6 +48,7 @@ class CPointerManager {
void lockSoftwareAll(); void lockSoftwareAll();
void unlockSoftwareAll(); void unlockSoftwareAll();
bool softwareLockedFor(PHLMONITOR pMonitor); bool softwareLockedFor(PHLMONITOR pMonitor);
bool hasVisibleHWCursor(PHLMONITOR pMonitor);
void renderSoftwareCursorsFor(PHLMONITOR pMonitor, const Time::steady_tp& now, CRegion& damage /* logical */, std::optional<Vector2D> overridePos = {} /* monitor-local */, void renderSoftwareCursorsFor(PHLMONITOR pMonitor, const Time::steady_tp& now, CRegion& damage /* logical */, std::optional<Vector2D> overridePos = {} /* monitor-local */,
bool forceRender = false); bool forceRender = false);