From d170a627b515a1fe6b9dea7b43e0e8afb85876f8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 4 Apr 2026 19:01:50 +0100 Subject: render/decoration: improve extent calculations --- src/render/decorations/DecorationPositioner.cpp | 55 ++++++++++++++++++++----- src/render/decorations/DecorationPositioner.hpp | 11 +++-- 2 files changed, 52 insertions(+), 14 deletions(-) (limited to 'src/render') diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index 470b5bb7..27da0f4a 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -61,7 +61,8 @@ void CDecorationPositioner::uncacheDecoration(IHyprWindowDecoration* deco) { if (WIT == m_windowDatas.end()) return; - WIT->second.needsRecalc = true; + WIT->second.needsRecalc = true; + WIT->second.needsDamageExtents = true; } void CDecorationPositioner::repositionDeco(IHyprWindowDecoration* deco) { @@ -111,7 +112,27 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { if (WIT == m_windowDatas.end()) return; - const auto WINDOWDATA = &WIT->second; + auto* const WINDOWDATA = &WIT->second; + + // fast path: if size unchanged and no recalc needed, skip the expensive work below. + // needsReposition is only true for newly-added decoration entries, so if the deco count + // matches what we've cached, no new decos were added and we can skip the all_of scan too. + if (WINDOWDATA->lastWindowSize == pWindow->m_realSize->value() && !WINDOWDATA->needsRecalc) { + const auto expectedDecos = pWindow->m_windowDecorations.size(); + bool allCached = true; + size_t found = 0; + for (auto const& data : m_windowPositioningDatas) { + if (data->pWindow.lock() == pWindow) { + if (data->needsReposition) { + allCached = false; + break; + } + ++found; + } + } + if (allCached && found == expectedDecos) + return; + } sanitizeDatas(); @@ -124,13 +145,6 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { datas.push_back(getDataFor(wd.get(), pWindow)); } - if (WINDOWDATA->lastWindowSize == pWindow->m_realSize->value() /* position not changed */ - && std::ranges::all_of(m_windowPositioningDatas, [pWindow](const auto& data) { return pWindow != data->pWindow.lock() || !data->needsReposition; }) - /* all window datas are either not for this window or don't need a reposition */ - && !WINDOWDATA->needsRecalc /* window doesn't need recalc */ - ) - return; - for (auto const& wd : datas) { wd->positioningInfo = wd->pDecoration->getPositioningInfo(); } @@ -273,6 +287,9 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { WINDOWDATA->extents = {{stickyOffsetXL + reservedXL, stickyOffsetYT + reservedYT}, {stickyOffsetXR + reservedXR, stickyOffsetYB + reservedYB}}; pWindow->layoutTarget()->recalc(); } + + // update cached decoration extents for getWindowDecorationExtents + WINDOWDATA->needsDamageExtents = true; } void CDecorationPositioner::onWindowUnmap(PHLWINDOW pWindow) { @@ -291,7 +308,7 @@ SBoxExtents CDecorationPositioner::getWindowDecorationReserved(PHLWINDOWREF pWin } catch (std::out_of_range& e) { return {}; } } -SBoxExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOWREF pWindow, bool inputOnly) { +SBoxExtents CDecorationPositioner::computeWindowDecorationExtents(PHLWINDOWREF pWindow, bool inputOnly) { CBox const mainSurfaceBox = pWindow->getWindowMainSurfaceBox(); CBox accum = mainSurfaceBox; @@ -340,6 +357,24 @@ SBoxExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOWREF pWind return accum.extentsFrom(mainSurfaceBox); } +SBoxExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOWREF pWindow, bool inputOnly) { + // inputOnly is rare (input handling), skip the cache for it + if (inputOnly) + return computeWindowDecorationExtents(pWindow, true); + + const auto WIT = std::ranges::find_if(m_windowDatas, [&](const auto& other) { return other.first.lock() == pWindow; }); + if (WIT == m_windowDatas.end()) + return computeWindowDecorationExtents(pWindow, false); + + auto& wd = WIT->second; + if (wd.needsDamageExtents) { + wd.decorationExtents = computeWindowDecorationExtents(pWindow, false); + wd.needsDamageExtents = false; + } + + return wd.decorationExtents; +} + CBox CDecorationPositioner::getBoxWithIncludedDecos(PHLWINDOW pWindow) { CBox accum = pWindow->getWindowMainSurfaceBox(); diff --git a/src/render/decorations/DecorationPositioner.hpp b/src/render/decorations/DecorationPositioner.hpp index 8fbb44c7..ccd148dd 100644 --- a/src/render/decorations/DecorationPositioner.hpp +++ b/src/render/decorations/DecorationPositioner.hpp @@ -80,16 +80,19 @@ class CDecorationPositioner { }; struct SWindowData { - Vector2D lastWindowSize = {}; - SBoxExtents reserved = {}; - SBoxExtents extents = {}; - bool needsRecalc = false; + Vector2D lastWindowSize = {}; + SBoxExtents reserved = {}; + SBoxExtents extents = {}; + SBoxExtents decorationExtents = {}; + bool needsRecalc = false; + bool needsDamageExtents = true; }; std::map m_windowDatas; std::vector> m_windowPositioningDatas; SWindowPositioningData* getDataFor(IHyprWindowDecoration* pDecoration, PHLWINDOW pWindow); + SBoxExtents computeWindowDecorationExtents(PHLWINDOWREF pWindow, bool inputOnly); void onWindowUnmap(PHLWINDOW pWindow); void onWindowMap(PHLWINDOW pWindow); void sanitizeDatas(); -- cgit v1.2.3