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 +++++++++++++++++++++++++++++---- src/desktop/view/Subsurface.hpp | 5 ++++- 2 files changed, 33 insertions(+), 5 deletions(-) (limited to 'src/desktop') 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(); diff --git a/src/desktop/view/Subsurface.hpp b/src/desktop/view/Subsurface.hpp index ab74f48c..bb2f6780 100644 --- a/src/desktop/view/Subsurface.hpp +++ b/src/desktop/view/Subsurface.hpp @@ -40,7 +40,7 @@ namespace Desktop::View { void onMap(); void onUnmap(); - void recheckDamageForSubsurfaces(); + void recheckDamageForSubsurfaces(int depth = 0); WP m_self; @@ -58,6 +58,9 @@ namespace Desktop::View { WP m_subsurface; Vector2D m_lastSize = {}; Vector2D m_lastPosition = {}; + Vector2D m_lastRecheckGlobalPos; + Vector2D m_lastRecheckGlobalSize; + bool m_hasLastRecheckGeometry = false; // if nullptr, means it's a dummy node WP m_parent; -- cgit v1.2.3