aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/render/OpenGL.cpp
diff options
context:
space:
mode:
authorVirt <[email protected]>2024-04-24 17:29:41 +0200
committerGitHub <[email protected]>2024-04-24 16:29:41 +0100
commit9fe409800ba5466017be8dfa16a55ca9833a416e (patch)
treebf3974d131f0a387588e938c29704085b2b70132 /src/render/OpenGL.cpp
parent8aecd4f253a102a2afa4edd3e502106eb3626d86 (diff)
downloadHyprland-9fe409800ba5466017be8dfa16a55ca9833a416e.tar.gz
Hyprland-9fe409800ba5466017be8dfa16a55ca9833a416e.zip
renderer: Fix mirrored displays when transformed and preserve aspect ratio (#5697)
* renderer: transform mirror buffer and preserve mirror aspect ratio * renderer: render mirrors directly from offloadFB * renderer: fix formatting * renderer: use monitorMirrorFB again, but properly damage mirrors * renderer: clean mirrors after reload and support cursor zoom mirroring
Diffstat (limited to 'src/render/OpenGL.cpp')
-rw-r--r--src/render/OpenGL.cpp52
1 files changed, 40 insertions, 12 deletions
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 981541b2..c4884245 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -152,6 +152,12 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) {
if (m_RenderData.mouseZoomFactor != 1.0 || g_pHyprRenderer->m_bCrashingInProgress)
return true;
+ // mirrors should not be offloaded (as we then would basically copy the same data twice)
+ // yes, this breaks mirrors of mirrors
+ if (pMonitor->isMirror())
+ return false;
+
+ // monitors that are mirrored however must be offloaded because we cannot copy from output FBs
if (!pMonitor->mirrors.empty())
return true;
@@ -336,14 +342,10 @@ void CHyprOpenGLImpl::end() {
TRACY_GPU_ZONE("RenderEnd");
- if (!m_RenderData.pMonitor->mirrors.empty() && !m_bFakeFrame)
- saveBufferForMirror(); // save with original damage region
-
// end the render, copy the data to the WLR framebuffer
if (m_bOffloadedFramebuffer) {
m_RenderData.damage = m_RenderData.finalDamage;
-
- m_RenderData.outFB->bind();
+ m_bEndFrame = true;
CBox monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
@@ -364,11 +366,16 @@ void CHyprOpenGLImpl::end() {
monbox.y = m_RenderData.pMonitor->vecTransformedSize.y - monbox.height;
}
- m_bEndFrame = true;
m_bApplyFinalShader = !m_RenderData.blockScreenShader;
if (m_RenderData.mouseZoomUseMouse)
m_RenderData.useNearestNeighbor = true;
+ // copy the damaged areas into the mirror buffer
+ // we can't use the offloadFB for mirroring, as it contains artifacts from blurring
+ if (!m_RenderData.pMonitor->mirrors.empty() && !m_bFakeFrame)
+ saveBufferForMirror(&monbox);
+
+ m_RenderData.outFB->bind();
blend(false);
if (m_sFinalScreenShader.program < 1 && !g_pHyprRenderer->m_bCrashingInProgress)
@@ -1971,18 +1978,16 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib);
}
-void CHyprOpenGLImpl::saveBufferForMirror() {
+void CHyprOpenGLImpl::saveBufferForMirror(CBox* box) {
if (!m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated())
m_RenderData.pCurrentMonData->monitorMirrorFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, m_RenderData.pMonitor->drmFormat);
m_RenderData.pCurrentMonData->monitorMirrorFB.bind();
- CBox monbox = {0, 0, m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y};
-
blend(false);
- renderTexture(m_RenderData.currentFB->m_cTex, &monbox, 1.f, 0, false, false);
+ renderTexture(m_RenderData.currentFB->m_cTex, box, 1.f, 0, false, false);
blend(true);
@@ -1990,14 +1995,37 @@ void CHyprOpenGLImpl::saveBufferForMirror() {
}
void CHyprOpenGLImpl::renderMirrored() {
- CBox monbox = {0, 0, m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y};
- const auto PFB = &m_mMonitorRenderResources[m_RenderData.pMonitor->pMirrorOf].monitorMirrorFB;
+ auto monitor = m_RenderData.pMonitor;
+ auto mirrored = monitor->pMirrorOf;
+
+ double scale = std::min(monitor->vecTransformedSize.x / mirrored->vecTransformedSize.x, monitor->vecTransformedSize.y / mirrored->vecTransformedSize.y);
+ CBox monbox = {0, 0, mirrored->vecTransformedSize.x * scale, mirrored->vecTransformedSize.y * scale};
+
+ // transform box as it will be drawn on a transformed projection
+ monbox.transform(mirrored->transform, mirrored->vecTransformedSize.x * scale, mirrored->vecTransformedSize.y * scale);
+
+ monbox.x = (monitor->vecTransformedSize.x - monbox.w) / 2;
+ monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2;
+ const auto PFB = &m_mMonitorRenderResources[mirrored].monitorMirrorFB;
if (!PFB->isAllocated() || PFB->m_cTex.m_iTexID <= 0)
return;
+ // replace monitor projection to undo the mirrored monitor's projection
+ wlr_matrix_identity(monitor->projMatrix.data());
+ wlr_matrix_translate(monitor->projMatrix.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0);
+ wlr_matrix_transform(monitor->projMatrix.data(), monitor->transform);
+ wlr_matrix_transform(monitor->projMatrix.data(), wlr_output_transform_invert(mirrored->transform));
+ wlr_matrix_translate(monitor->projMatrix.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0);
+
+ // clear stuff outside of mirrored area (e.g. when changing to mirrored)
+ clear(CColor(0, 0, 0, 0));
+
renderTexture(PFB->m_cTex, &monbox, 1.f, 0, false, false);
+
+ // reset matrix for further drawing
+ monitor->updateMatrix();
}
void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY, const Vector2D& size) {