diff options
author | Vaxry <[email protected]> | 2024-10-05 00:52:53 +0100 |
---|---|---|
committer | Vaxry <[email protected]> | 2024-10-05 01:01:21 +0100 |
commit | 595eb89f6e16df0e19916e3c02bf5ceac5a61c57 (patch) | |
tree | c3c08f6405838491ae195a5f29e9f6c260a72b80 | |
parent | a815b14bf1b69b92f82bd09f6845fbdbb2fbe516 (diff) | |
download | Hyprland-595eb89f6e16df0e19916e3c02bf5ceac5a61c57.tar.gz Hyprland-595eb89f6e16df0e19916e3c02bf5ceac5a61c57.zip |
renderer: Fix resize artifacts (stretching, bumps) (#7499)
-rw-r--r-- | src/desktop/WLSurface.cpp | 2 | ||||
-rw-r--r-- | src/render/OpenGL.cpp | 3 | ||||
-rw-r--r-- | src/render/Renderer.cpp | 42 | ||||
-rw-r--r-- | src/render/Renderer.hpp | 33 |
4 files changed, 46 insertions, 34 deletions
diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 45050e35..5e88f507 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -62,7 +62,7 @@ bool CWLSurface::small() const { const auto O = m_pWindowOwner.lock(); - return O->m_vReportedSize.x > m_pResource->current.bufferSize.x + 1 || O->m_vReportedSize.y > m_pResource->current.bufferSize.y + 1; + return O->m_vReportedSize.x > m_pResource->current.size.x + 1 || O->m_vReportedSize.y > m_pResource->current.size.y + 1; } Vector2D CWLSurface::correctSmallVec() const { diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 4f22d6aa..a16c2d62 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1423,6 +1423,9 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB glActiveTexture(GL_TEXTURE0); glBindTexture(tex->m_iTarget, tex->m_iTexID); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_S, 0x2900 /* GL_CLAMP */); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_T, 0x2900); + if (m_RenderData.useNearestNeighbor) { glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b081fd81..310d45af 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -150,7 +150,7 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da const auto& TEXTURE = surface->current.texture; const auto RDATA = (SRenderData*)data; - const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE; + const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow && g_pInputManager->dragMode == MBIND_RESIZE; // this is bad, probably has been logged elsewhere. Means the texture failed // uploading to the GPU. @@ -180,6 +180,7 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da // however, if surface buffer w / h < box, we need to adjust them const auto PWINDOW = PSURFACE ? PSURFACE->getWindow() : nullptr; + // center the surface if it's smaller than the viewport we assign it if (PSURFACE && !PSURFACE->m_bFillIgnoreSmall && PSURFACE->small() /* guarantees PWINDOW */) { const auto CORRECT = PSURFACE->correctSmallVec(); const auto SIZE = PSURFACE->getViewporterCorrectedSize(); @@ -195,17 +196,6 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da } } - if (!INTERACTIVERESIZEINPROGRESS && PSURFACE && PWINDOW && PWINDOW->m_vRealSize.goal().floor() > PWINDOW->m_vReportedSize && PWINDOW->m_vReportedSize > Vector2D{1, 1}) { - Vector2D size = - Vector2D{windowBox.w * (PWINDOW->m_vReportedSize.x / PWINDOW->m_vRealSize.value().x), windowBox.h * (PWINDOW->m_vReportedSize.y / PWINDOW->m_vRealSize.value().y)}; - Vector2D correct = Vector2D{windowBox.w, windowBox.h} - size; - - windowBox.translate(correct / 2.0); - - windowBox.w = size.x; - windowBox.h = size.y; - } - } else { // here we clamp to 2, these might be some tiny specks windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max((float)surface->current.size.x, 2.F), std::max((float)surface->current.size.y, 2.F)}; if (RDATA->pWindow && RDATA->pWindow->m_vRealSize.isBeingAnimated() && RDATA->surface && RDATA->surface != surface && RDATA->squishOversized /* subsurface */) { @@ -231,6 +221,8 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da return; // invisible } + const auto PROJSIZEUNSCALED = windowBox.size(); + windowBox.scale(RDATA->pMonitor->scale); windowBox.round(); @@ -239,7 +231,7 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da DELTALESSTHAN(windowBox.height, surface->current.bufferSize.y, 3) /* off by one-or-two */ && (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; - g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1); + g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->pMonitor->self.lock(), RDATA->surface == surface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1); // check for fractional scale surfaces misaligning the buffer size // in those cases it's better to just force nearest neighbor @@ -1083,7 +1075,8 @@ void CHyprRenderer::renderSessionLockMissing(CMonitor* pMonitor) { g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); } -void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { +void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, SP<CMonitor> pMonitor, bool main, const Vector2D& projSize, + const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) { if (!pWindow || !pWindow->m_bIsX11) { Vector2D uvTL; Vector2D uvBR = Vector2D(1, 1); @@ -1112,6 +1105,22 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour uvBR -= MISALIGNMENT * PIXELASUV; } + // if the surface is smaller than our viewport, extend its edges. + // this will break if later on xdg geometry is hit, but we really try + // to let the apps know to NOT add CSD. Also if source is there. + // there is no way to fix this if that's the case + const auto MONITOR_WL_SCALE = std::ceil(pMonitor->scale); + const bool SCALE_UNAWARE = MONITOR_WL_SCALE != pSurface->current.scale && !pSurface->current.viewport.hasDestination; + const auto EXPECTED_SIZE = + ((pSurface->current.viewport.hasDestination ? pSurface->current.viewport.destination : pSurface->current.bufferSize / pSurface->current.scale) * pMonitor->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; + uvBR = uvBR * FIX; + } + g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL; g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR; @@ -1127,7 +1136,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour CBox geom = pWindow->m_pXDGSurface->current.geometry; // ignore X and Y, adjust uv - if (geom.x != 0 || geom.y != 0 || geom.width > pWindow->m_vRealSize.value().x || geom.height > pWindow->m_vRealSize.value().y) { + if (geom.x != 0 || geom.y != 0 || geom.width > projSizeUnscaled.x || geom.height > projSizeUnscaled.y) { const auto XPERC = (double)geom.x / (double)pSurface->current.size.x; const auto YPERC = (double)geom.y / (double)pSurface->current.size.y; const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.size.x; @@ -1137,8 +1146,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour uvBR = uvBR - Vector2D((1.0 - WPERC) * (uvBR.x - uvTL.x), (1.0 - HPERC) * (uvBR.y - uvTL.y)); uvTL = uvTL + TOADDTL; - // TODO: make this passed to the func. Might break in the future. - auto maxSize = pWindow->m_vRealSize.value(); + auto maxSize = projSizeUnscaled; if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall) maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize(); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index b730d589..7d1ae4b1 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -49,22 +49,23 @@ class CHyprRenderer { CHyprRenderer(); ~CHyprRenderer(); - void renderMonitor(CMonitor* pMonitor); - void arrangeLayersForMonitor(const MONITORID&); - void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0); - void damageWindow(PHLWINDOW, bool forceFull = false); - void damageBox(CBox*, bool skipFrameSchedule = false); - void damageBox(const int& x, const int& y, const int& w, const int& h); - void damageRegion(const CRegion&); - void damageMonitor(CMonitor*); - void damageMirrorsWith(CMonitor*, const CRegion&); - bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false); - bool shouldRenderWindow(PHLWINDOW, CMonitor*); - bool shouldRenderWindow(PHLWINDOW); - void ensureCursorRenderingMode(); - bool shouldRenderCursor(); - void setCursorHidden(bool hide); - void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false); + void renderMonitor(CMonitor* pMonitor); + void arrangeLayersForMonitor(const MONITORID&); + void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0); + void damageWindow(PHLWINDOW, bool forceFull = false); + void damageBox(CBox*, bool skipFrameSchedule = false); + void damageBox(const int& x, const int& y, const int& w, const int& h); + void damageRegion(const CRegion&); + void damageMonitor(CMonitor*); + void damageMirrorsWith(CMonitor*, const CRegion&); + bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false); + bool shouldRenderWindow(PHLWINDOW, CMonitor*); + bool shouldRenderWindow(PHLWINDOW); + void ensureCursorRenderingMode(); + bool shouldRenderCursor(); + void setCursorHidden(bool hide); + void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, SP<CMonitor> pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {}, + bool fixMisalignedFSV1 = false); std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry); void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace); |