From bf97fac9b9c7830a9374366d8a471efb48dae5fb Mon Sep 17 00:00:00 2001 From: Anubhav <57067794+imperishableSecret@users.noreply.github.com> Date: Sun, 5 Apr 2026 21:24:56 +0530 Subject: subsurface: use geometry-aware damage and recurse into nested trees (#13933) * subsurface: use geometry-aware damage and recurse into nested trees Replace per-surface damageSurface() calls in recheckDamageForSubsurfaces() with box-based damage that tracks each subsurface's last known global position and size. When geometry changes, both the old and new areas are damaged to correctly clear stale pixels and paint the new location. Additionally, recurse into child subsurfaces so that nested subsurface trees are properly damage-checked, with a depth limit of 32 to guard against cycles. Cached geometry is invalidated on map/unmap to avoid stale comparisons across surface lifecycle transitions. * clang-format --- src/desktop/view/Subsurface.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'src/desktop/view/Subsurface.cpp') diff --git a/src/desktop/view/Subsurface.cpp b/src/desktop/view/Subsurface.cpp index c601c00e..c3c985df 100644 --- a/src/desktop/view/Subsurface.cpp +++ b/src/desktop/view/Subsurface.cpp @@ -128,10 +128,32 @@ void CSubsurface::checkSiblingDamage() { } } -void CSubsurface::recheckDamageForSubsurfaces() { +void CSubsurface::recheckDamageForSubsurfaces(int depth) { + if (depth > 32) + return; + for (auto const& n : m_children) { const auto COORDS = n->coordsGlobal(); - g_pHyprRenderer->damageSurface(n->wlSurface()->resource(), COORDS.x, COORDS.y); + const auto SIZE = n->size(); + + const bool GEOMETRYUNCHANGED = n->m_hasLastRecheckGeometry && COORDS.x == n->m_lastRecheckGlobalPos.x && COORDS.y == n->m_lastRecheckGlobalPos.y && + SIZE.x == n->m_lastRecheckGlobalSize.x && SIZE.y == n->m_lastRecheckGlobalSize.y; + + if (!GEOMETRYUNCHANGED) { + // damage the old area to clear stale pixels + if (n->m_hasLastRecheckGeometry) + g_pHyprRenderer->damageBox(CBox{n->m_lastRecheckGlobalPos, n->m_lastRecheckGlobalSize}.expand(4)); + + n->m_lastRecheckGlobalPos = COORDS; + n->m_lastRecheckGlobalSize = SIZE; + n->m_hasLastRecheckGeometry = true; + + // damage the new area + g_pHyprRenderer->damageBox(CBox{COORDS, SIZE}.expand(4)); + } + + // recurse into children to handle nested subsurface trees + n->recheckDamageForSubsurfaces(depth + 1); } } @@ -194,8 +216,9 @@ void CSubsurface::onNewSubsurface(SP pSubsurface) { } void CSubsurface::onMap() { - m_lastSize = m_wlSurface->resource()->m_current.size; - m_lastPosition = m_subsurface->m_position; + m_lastSize = m_wlSurface->resource()->m_current.size; + m_lastPosition = m_subsurface->m_position; + m_hasLastRecheckGeometry = false; const auto COORDS = coordsGlobal(); CBox box{COORDS, m_lastSize}; @@ -209,6 +232,8 @@ void CSubsurface::onMap() { void CSubsurface::onUnmap() { damageLastArea(); + m_hasLastRecheckGeometry = false; + if (m_wlSurface->resource() == Desktop::focusState()->surface()) g_pInputManager->releaseAllMouseButtons(); -- cgit v1.2.3