mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-26 04:05:57 +01:00
renderer: Fix resize artifacts (stretching, bumps) (#7499)
This commit is contained in:
parent
a815b14bf1
commit
595eb89f6e
4 changed files with 46 additions and 34 deletions
|
@ -62,7 +62,7 @@ bool CWLSurface::small() const {
|
||||||
|
|
||||||
const auto O = m_pWindowOwner.lock();
|
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 {
|
Vector2D CWLSurface::correctSmallVec() const {
|
||||||
|
|
|
@ -1423,6 +1423,9 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(tex->m_iTarget, tex->m_iTexID);
|
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) {
|
if (m_RenderData.useNearestNeighbor) {
|
||||||
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
|
|
@ -150,7 +150,7 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
|
||||||
|
|
||||||
const auto& TEXTURE = surface->current.texture;
|
const auto& TEXTURE = surface->current.texture;
|
||||||
const auto RDATA = (SRenderData*)data;
|
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
|
// this is bad, probably has been logged elsewhere. Means the texture failed
|
||||||
// uploading to the GPU.
|
// 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
|
// however, if surface buffer w / h < box, we need to adjust them
|
||||||
const auto PWINDOW = PSURFACE ? PSURFACE->getWindow() : nullptr;
|
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 */) {
|
if (PSURFACE && !PSURFACE->m_bFillIgnoreSmall && PSURFACE->small() /* guarantees PWINDOW */) {
|
||||||
const auto CORRECT = PSURFACE->correctSmallVec();
|
const auto CORRECT = PSURFACE->correctSmallVec();
|
||||||
const auto SIZE = PSURFACE->getViewporterCorrectedSize();
|
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
|
} 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)};
|
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 */) {
|
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
|
return; // invisible
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto PROJSIZEUNSCALED = windowBox.size();
|
||||||
|
|
||||||
windowBox.scale(RDATA->pMonitor->scale);
|
windowBox.scale(RDATA->pMonitor->scale);
|
||||||
windowBox.round();
|
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 */ &&
|
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 */;
|
(!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
|
// check for fractional scale surfaces misaligning the buffer size
|
||||||
// in those cases it's better to just force nearest neighbor
|
// 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);
|
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) {
|
if (!pWindow || !pWindow->m_bIsX11) {
|
||||||
Vector2D uvTL;
|
Vector2D uvTL;
|
||||||
Vector2D uvBR = Vector2D(1, 1);
|
Vector2D uvBR = Vector2D(1, 1);
|
||||||
|
@ -1112,6 +1105,22 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
|
||||||
uvBR -= MISALIGNMENT * PIXELASUV;
|
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.primarySurfaceUVTopLeft = uvTL;
|
||||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR;
|
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR;
|
||||||
|
|
||||||
|
@ -1127,7 +1136,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
|
||||||
CBox geom = pWindow->m_pXDGSurface->current.geometry;
|
CBox geom = pWindow->m_pXDGSurface->current.geometry;
|
||||||
|
|
||||||
// ignore X and Y, adjust uv
|
// 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 XPERC = (double)geom.x / (double)pSurface->current.size.x;
|
||||||
const auto YPERC = (double)geom.y / (double)pSurface->current.size.y;
|
const auto YPERC = (double)geom.y / (double)pSurface->current.size.y;
|
||||||
const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.size.x;
|
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));
|
uvBR = uvBR - Vector2D((1.0 - WPERC) * (uvBR.x - uvTL.x), (1.0 - HPERC) * (uvBR.y - uvTL.y));
|
||||||
uvTL = uvTL + TOADDTL;
|
uvTL = uvTL + TOADDTL;
|
||||||
|
|
||||||
// TODO: make this passed to the func. Might break in the future.
|
auto maxSize = projSizeUnscaled;
|
||||||
auto maxSize = pWindow->m_vRealSize.value();
|
|
||||||
|
|
||||||
if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall)
|
if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall)
|
||||||
maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize();
|
maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize();
|
||||||
|
|
|
@ -64,7 +64,8 @@ class CHyprRenderer {
|
||||||
void ensureCursorRenderingMode();
|
void ensureCursorRenderingMode();
|
||||||
bool shouldRenderCursor();
|
bool shouldRenderCursor();
|
||||||
void setCursorHidden(bool hide);
|
void setCursorHidden(bool hide);
|
||||||
void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false);
|
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
|
std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min
|
||||||
void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry);
|
void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry);
|
||||||
void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace);
|
void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace);
|
||||||
|
|
Loading…
Reference in a new issue