From 26cbc67385d95ba621fe0a125a5b121ffdd09335 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sun, 21 Sep 2025 19:27:56 +0200 Subject: [PATCH] renderer: fix uv calculations once and for all (#11770) fixes synchronization of ackd sizes, fixes wrong xdg stuff --- src/desktop/WLSurface.cpp | 8 ++-- src/desktop/Window.cpp | 27 +++++++++-- src/desktop/Window.hpp | 1 + src/events/Windows.cpp | 3 +- src/protocols/types/SurfaceState.cpp | 3 ++ src/protocols/types/SurfaceState.hpp | 4 ++ src/render/Renderer.cpp | 63 +++++++++++++------------- src/render/pass/SurfacePassElement.cpp | 24 ++++++---- 8 files changed, 85 insertions(+), 48 deletions(-) diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index d868e1a9..1a1bd293 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -62,9 +62,10 @@ bool CWLSurface::small() const { if (!m_resource->m_current.texture) return false; - const auto O = m_windowOwner.lock(); + const auto O = m_windowOwner.lock(); + const auto REPORTED_SIZE = O->getReportedSize(); - return O->m_reportedSize.x > m_resource->m_current.size.x + 1 || O->m_reportedSize.y > m_resource->m_current.size.y + 1; + return REPORTED_SIZE.x > m_resource->m_current.size.x + 1 || REPORTED_SIZE.y > m_resource->m_current.size.y + 1; } Vector2D CWLSurface::correctSmallVec() const { @@ -73,8 +74,9 @@ Vector2D CWLSurface::correctSmallVec() const { const auto SIZE = getViewporterCorrectedSize(); const auto O = m_windowOwner.lock(); + const auto REP = O->getReportedSize(); - return Vector2D{(O->m_reportedSize.x - SIZE.x) / 2, (O->m_reportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_realSize->value() / O->m_reportedSize); + return Vector2D{(REP.x - SIZE.x) / 2, (REP.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_realSize->value() / REP); } Vector2D CWLSurface::correctSmallVecBuf() const { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 71b78ded..ba0f09d5 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -16,6 +16,7 @@ #include "../managers/TokenManager.hpp" #include "../managers/animation/AnimationManager.hpp" #include "../managers/ANRManager.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/core/Subcompositor.hpp" @@ -576,7 +577,12 @@ void CWindow::onMap() { if (!m_isMapped || isX11OverrideRedirect()) return; - sendWindowSize(); + g_pEventLoopManager->doLater([this, self = m_self] { + if (!self) + return; + + sendWindowSize(); + }); }, false); @@ -1549,13 +1555,20 @@ std::string CWindow::fetchClass() { } void CWindow::onAck(uint32_t serial) { - const auto SERIAL = std::ranges::find_if(m_pendingSizeAcks | std::views::reverse, [serial](const auto& e) { return e.first == serial; }); + const auto SERIAL = std::ranges::find_if(m_pendingSizeAcks | std::views::reverse, [serial](const auto& e) { return e.first <= serial; }); if (SERIAL == m_pendingSizeAcks.rend()) return; m_pendingSizeAck = *SERIAL; std::erase_if(m_pendingSizeAcks, [&](const auto& el) { return el.first <= SERIAL->first; }); + + if (m_isX11) + return; + + m_wlSurface->resource()->m_pending.ackedSize = m_pendingSizeAck->second; // apply pending size. We pinged, the window ponged. + m_wlSurface->resource()->m_pending.updated.bits.acked = true; + m_pendingSizeAck.reset(); } void CWindow::onResourceChangeX11() { @@ -1805,7 +1818,7 @@ void CWindow::sendWindowSize(bool force) { if (m_isX11 && m_xwaylandSurface) m_xwaylandSurface->configure({REPORTPOS, REPORTSIZE}); else if (m_xdgSurface && m_xdgSurface->m_toplevel) - m_pendingSizeAcks.emplace_back(m_xdgSurface->m_toplevel->setSize(REPORTSIZE), REPORTPOS.floor()); + m_pendingSizeAcks.emplace_back(m_xdgSurface->m_toplevel->setSize(REPORTSIZE), REPORTSIZE.floor()); } NContentType::eContentType CWindow::getContentType() { @@ -1910,3 +1923,11 @@ SP CWindow::getSolitaryResource() { return nullptr; } + +Vector2D CWindow::getReportedSize() { + if (m_isX11) + return m_reportedSize; + if (m_wlSurface && m_wlSurface->resource()) + return m_wlSurface->resource()->m_current.ackedSize; + return m_reportedSize; +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 9d94baea..e08dd7af 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -416,6 +416,7 @@ class CWindow { PHLWINDOW parent(); bool priorityFocus(); SP getSolitaryResource(); + Vector2D getReportedSize(); CBox getWindowMainSurfaceBox() const { return {m_realPosition->value().x, m_realPosition->value().y, m_realSize->value().x, m_realSize->value().y}; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 7d3eb3eb..8f40c0e1 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -868,7 +868,8 @@ void Events::listener_commitWindow(void* owner, void* data) { if (!PWINDOW->m_isMapped || PWINDOW->isHidden()) return; - PWINDOW->m_reportedSize = PWINDOW->m_pendingReportedSize; // apply pending size. We pinged, the window ponged. + if (PWINDOW->m_isX11) + PWINDOW->m_reportedSize = PWINDOW->m_pendingReportedSize; if (!PWINDOW->m_isX11 && !PWINDOW->isFullscreen() && PWINDOW->m_isFloating) { const auto MINSIZE = PWINDOW->m_xdgSurface->m_toplevel->layoutMinSize(); diff --git a/src/protocols/types/SurfaceState.cpp b/src/protocols/types/SurfaceState.cpp index a1195439..a8838170 100644 --- a/src/protocols/types/SurfaceState.cpp +++ b/src/protocols/types/SurfaceState.cpp @@ -97,4 +97,7 @@ void SSurfaceState::updateFrom(SSurfaceState& ref) { if (ref.updated.bits.acquire) acquire = ref.acquire; + + if (ref.updated.bits.acked) + ackedSize = ref.ackedSize; } diff --git a/src/protocols/types/SurfaceState.hpp b/src/protocols/types/SurfaceState.hpp index e11692cf..eb50a988 100644 --- a/src/protocols/types/SurfaceState.hpp +++ b/src/protocols/types/SurfaceState.hpp @@ -20,6 +20,7 @@ struct SSurfaceState { bool offset : 1; bool viewport : 1; bool acquire : 1; + bool acked : 1; } bits; } updated; @@ -37,6 +38,9 @@ struct SSurfaceState { Vector2D size, bufferSize; Vector2D offset; + // for xdg_shell resizing + Vector2D ackedSize; + // viewporter protocol surface state struct { bool hasDestination = false; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 32b571b1..af983926 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1126,15 +1126,25 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPm_scale); const bool SCALE_UNAWARE = MONITOR_WL_SCALE != pSurface->m_current.scale && !pSurface->m_current.viewport.hasDestination; - const auto EXPECTED_SIZE = - ((pSurface->m_current.viewport.hasDestination ? pSurface->m_current.viewport.destination : pSurface->m_current.bufferSize / pSurface->m_current.scale) * - pMonitor->m_scale) - .round(); - if (!SCALE_UNAWARE && (EXPECTED_SIZE.x < projSize.x || EXPECTED_SIZE.y < projSize.y)) { - // this will not work with shm AFAIK, idk why. - // NOTE: this math is wrong if we have a source... or geom updates later, but I don't think we can do much - const auto FIX = (projSize / EXPECTED_SIZE).clamp(Vector2D{1, 1}, Vector2D{1000000, 1000000}); - uvBR = uvBR * FIX; + const auto EXPECTED_SIZE = ((pSurface->m_current.viewport.hasDestination ? + pSurface->m_current.viewport.destination : + (pSurface->m_current.viewport.hasSource ? pSurface->m_current.viewport.source.size() / pSurface->m_current.scale : projSize)) * + pMonitor->m_scale) + .round(); + + const auto RATIO = projSize / EXPECTED_SIZE; + if (!SCALE_UNAWARE) { + if (*PEXPANDEDGES && !SCALE_UNAWARE && (RATIO.x > 1 || RATIO.y > 1)) { + const auto FIX = RATIO.clamp(Vector2D{1, 1}, Vector2D{1000000, 1000000}); + uvBR = uvBR * FIX; + } + + // FIXME: probably do this for in anims on all views... + const auto SHOULD_SKIP = !pWindow || pWindow->m_animatingIn; + if (!SHOULD_SKIP && (RATIO.x < 1 || RATIO.y < 1)) { + const auto FIX = RATIO.clamp(Vector2D{0.0001, 0.0001}, Vector2D{1, 1}); + uvBR = uvBR * FIX; + } } } @@ -1150,32 +1160,21 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPm_xdgSurface->m_current.geometry; + // FIXME: this doesn't work. We always set MAXIMIZED anyways, so this doesn't need to work, but it's problematic. - // Adjust UV based on the xdg_surface geometry - if (geom.x != 0 || geom.y != 0 || geom.w != 0 || geom.h != 0) { - const auto XPERC = geom.x / pSurface->m_current.size.x; - const auto YPERC = geom.y / pSurface->m_current.size.y; - const auto WPERC = (geom.x + geom.w ? geom.w : pSurface->m_current.size.x) / pSurface->m_current.size.x; - const auto HPERC = (geom.y + geom.h ? geom.h : pSurface->m_current.size.y) / pSurface->m_current.size.y; + // CBox geom = pWindow->m_xdgSurface->m_current.geometry; - const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y)); - uvBR = uvBR - Vector2D((1.0 - WPERC) * (uvBR.x - uvTL.x), (1.0 - HPERC) * (uvBR.y - uvTL.y)); - uvTL = uvTL + TOADDTL; - } + // // Adjust UV based on the xdg_surface geometry + // if (geom.x != 0 || geom.y != 0 || geom.w != 0 || geom.h != 0) { + // const auto XPERC = geom.x / pSurface->m_current.size.x; + // const auto YPERC = geom.y / pSurface->m_current.size.y; + // const auto WPERC = (geom.x + geom.w ? geom.w : pSurface->m_current.size.x) / pSurface->m_current.size.x; + // const auto HPERC = (geom.y + geom.h ? geom.h : pSurface->m_current.size.y) / pSurface->m_current.size.y; - // Adjust UV based on our animation progress - if (pSurface->m_current.size.x > projSizeUnscaled.x || pSurface->m_current.size.y > projSizeUnscaled.y) { - auto maxSize = projSizeUnscaled; - - if (pWindow->m_wlSurface->small() && !pWindow->m_wlSurface->m_fillIgnoreSmall) - maxSize = pWindow->m_wlSurface->getViewporterCorrectedSize(); - - if (pSurface->m_current.size.x > maxSize.x) - uvBR.x = uvBR.x * (maxSize.x / pSurface->m_current.size.x); - if (pSurface->m_current.size.y > maxSize.y) - uvBR.y = uvBR.y * (maxSize.y / pSurface->m_current.size.y); - } + // const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y)); + // uvBR = uvBR - Vector2D((1.0 - WPERC) * (uvBR.x - uvTL.x), (1.0 - HPERC) * (uvBR.y - uvTL.y)); + // uvTL = uvTL + TOADDTL; + // } g_pHyprOpenGL->m_renderData.primarySurfaceUVTopLeft = uvTL; g_pHyprOpenGL->m_renderData.primarySurfaceUVBottomRight = uvBR; diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index 7dd423bd..47ace789 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -174,27 +174,33 @@ CBox CSurfacePassElement::getTexBox() { // center the surface if it's smaller than the viewport we assign it if (PSURFACE && !PSURFACE->m_fillIgnoreSmall && PSURFACE->small() /* guarantees PWINDOW */) { - const auto CORRECT = PSURFACE->correctSmallVec(); - const auto SIZE = PSURFACE->getViewporterCorrectedSize(); + const auto CORRECT = PSURFACE->correctSmallVec(); + const auto SIZE = PSURFACE->getViewporterCorrectedSize(); + const auto REPORTED = PWINDOW->getReportedSize(); if (!INTERACTIVERESIZEINPROGRESS) { windowBox.translate(CORRECT); - windowBox.width = SIZE.x * (PWINDOW->m_realSize->value().x / PWINDOW->m_reportedSize.x); - windowBox.height = SIZE.y * (PWINDOW->m_realSize->value().y / PWINDOW->m_reportedSize.y); + windowBox.width = SIZE.x * (PWINDOW->m_realSize->value().x / REPORTED.x); + windowBox.height = SIZE.y * (PWINDOW->m_realSize->value().y / REPORTED.y); } else { windowBox.width = SIZE.x; windowBox.height = SIZE.y; } } - } else { // here we clamp to 2, these might be some tiny specks - windowBox = {sc(outputX) + m_data.pos.x + m_data.localPos.x, sc(outputY) + m_data.pos.y + m_data.localPos.y, - std::max(sc(m_data.surface->m_current.size.x), 2.F), std::max(sc(m_data.surface->m_current.size.y), 2.F)}; + + const auto SURFSIZE = m_data.surface->m_current.size; + + windowBox = {sc(outputX) + m_data.pos.x + m_data.localPos.x, sc(outputY) + m_data.pos.y + m_data.localPos.y, std::max(sc(SURFSIZE.x), 2.F), + std::max(sc(SURFSIZE.y), 2.F)}; if (m_data.pWindow && m_data.pWindow->m_realSize->isBeingAnimated() && m_data.surface && !m_data.mainSurface && m_data.squishOversized /* subsurface */) { // adjust subsurfaces to the window - windowBox.width = (windowBox.width / m_data.pWindow->m_reportedSize.x) * m_data.pWindow->m_realSize->value().x; - windowBox.height = (windowBox.height / m_data.pWindow->m_reportedSize.y) * m_data.pWindow->m_realSize->value().y; + const auto REPORTED = m_data.pWindow->getReportedSize(); + if (REPORTED.x != 0 && REPORTED.y != 0) { + windowBox.width = (windowBox.width / REPORTED.x) * m_data.pWindow->m_realSize->value().x; + windowBox.height = (windowBox.height / REPORTED.y) * m_data.pWindow->m_realSize->value().y; + } } }