diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 2b3dce49..139c5b3f 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -404,6 +404,13 @@ void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixm RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); + wlr_box newBox = *box; + scaleBox(&newBox, m_RenderData.renderModif.scale); + newBox.x += m_RenderData.renderModif.translate.x; + newBox.y += m_RenderData.renderModif.translate.y; + + box = &newBox; + float matrix[9]; wlr_matrix_project_box(matrix, box, wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here @@ -497,12 +504,17 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b if (!pixman_region32_not_empty(m_RenderData.pDamage)) return; + wlr_box newBox = *pBox; + scaleBox(&newBox, m_RenderData.renderModif.scale); + newBox.x += m_RenderData.renderModif.translate.x; + newBox.y += m_RenderData.renderModif.translate.y; + static auto* const PDIMINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:dim_inactive")->intValue; // get transform const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); float matrix[9]; - wlr_matrix_project_box(matrix, pBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix); + wlr_matrix_project_box(matrix, &newBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -579,7 +591,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b } wlr_box transformedBox; - wlr_box_transform(&transformedBox, pBox, wlr_output_transform_invert(m_RenderData.pMonitor->transform), m_RenderData.pMonitor->vecTransformedSize.x, + wlr_box_transform(&transformedBox, &newBox, wlr_output_transform_invert(m_RenderData.pMonitor->transform), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); @@ -847,6 +859,9 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { void CHyprOpenGLImpl::preBlurForCurrentMonitor() { + const auto SAVEDRENDERMODIF = m_RenderData.renderModif; + m_RenderData.renderModif = {}; // fix shit + // make the fake dmg pixman_region32_t fakeDamage; pixman_region32_init_rect(&fakeDamage, 0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); @@ -868,6 +883,8 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() { m_RenderData.pCurrentMonData->primaryFB.bind(); m_RenderData.pCurrentMonData->blurFBDirty = false; + + m_RenderData.renderModif = SAVEDRENDERMODIF; } void CHyprOpenGLImpl::preWindowPass() { @@ -969,8 +986,11 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, // render our great blurred FB static auto* const PBLURIGNOREOPACITY = &g_pConfigManager->getConfigValuePtr("decoration:blur_ignore_opacity")->intValue; m_bEndFrame = true; // fix transformed + const auto SAVEDRENDERMODIF = m_RenderData.renderModif; + m_RenderData.renderModif = {}; // fix shit renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 1.f : a, &damage, 0, false, false, false); - m_bEndFrame = false; + m_bEndFrame = false; + m_RenderData.renderModif = SAVEDRENDERMODIF; // render the window, but clear stencil glClearStencil(0); @@ -1003,10 +1023,17 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CGradientValueData& grad, static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; static auto* const PMULTISAMPLE = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue; + wlr_box newBox = *box; + scaleBox(&newBox, m_RenderData.renderModif.scale); + newBox.x += m_RenderData.renderModif.translate.x; + newBox.y += m_RenderData.renderModif.translate.y; + + box = &newBox; + if (*PBORDERSIZE < 1) return; - int scaledBorderSize = *PBORDERSIZE * m_RenderData.pMonitor->scale; + int scaledBorderSize = *PBORDERSIZE * m_RenderData.pMonitor->scale * m_RenderData.renderModif.scale; // adjust box box->x -= scaledBorderSize; @@ -1088,12 +1115,6 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CGradientValueData& grad, glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - // fix back box - box->x += scaledBorderSize; - box->y += scaledBorderSize; - box->width -= 2 * scaledBorderSize; - box->height -= 2 * scaledBorderSize; } void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFramebuffer) { @@ -1363,6 +1384,13 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl if (!pixman_region32_not_empty(m_RenderData.pDamage)) return; + wlr_box newBox = *box; + scaleBox(&newBox, m_RenderData.renderModif.scale); + newBox.x += m_RenderData.renderModif.translate.x; + newBox.y += m_RenderData.renderModif.translate.y; + + box = &newBox; + static auto* const PSHADOWPOWER = &g_pConfigManager->getConfigValuePtr("decoration:shadow_render_power")->intValue; const auto SHADOWPOWER = std::clamp((int)*PSHADOWPOWER, 1, 4); @@ -1594,3 +1622,16 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { wlr_output_rollback(pMonitor->output); } + +void CHyprOpenGLImpl::saveMatrix() { + memcpy(m_RenderData.savedProjection, m_RenderData.projection, 9 * sizeof(float)); +} + +void CHyprOpenGLImpl::setMatrixScaleTranslate(const Vector2D& translate, const float& scale) { + wlr_matrix_scale(m_RenderData.projection, scale, scale); + wlr_matrix_translate(m_RenderData.projection, translate.x, translate.y); +} + +void CHyprOpenGLImpl::restoreMatrix() { + memcpy(m_RenderData.projection, m_RenderData.savedProjection, 9 * sizeof(float)); +} diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 3c563946..6f54ea35 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -23,11 +23,17 @@ inline const float fullVerts[] = { }; inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f}; -enum eDiscardMode { +enum eDiscardMode +{ DISCARD_OPAQUE = 1, DISCARD_ALPHAZERO = 1 << 1 }; +struct SRenderModifData { + Vector2D translate = {}; + float scale = 1.f; +}; + struct SMonitorRenderData { CFramebuffer primaryFB; CFramebuffer mirrorFB; // these are used for some effects, @@ -61,11 +67,14 @@ struct SMonitorRenderData { struct SCurrentRenderData { CMonitor* pMonitor = nullptr; float projection[9]; + float savedProjection[9]; SMonitorRenderData* pCurrentMonData = nullptr; pixman_region32_t* pDamage = nullptr; + SRenderModifData renderModif; + Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); @@ -91,6 +100,10 @@ class CHyprOpenGLImpl { void renderRoundedShadow(wlr_box*, int round, int range, float a = 1.0); void renderBorder(wlr_box*, const CGradientValueData&, int round, float a = 1.0); + void saveMatrix(); + void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); + void restoreMatrix(); + void makeWindowSnapshot(CWindow*); void makeRawWindowSnapshot(CWindow*, CFramebuffer*); void makeLayerSnapshot(SLayerSurface*); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b6a8499c..bba94ee4 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -411,11 +411,12 @@ void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMon wlr_surface_for_each_surface(pSurface->pWlrLockSurface->surface, renderSurface, &renderdata); } -void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(ID); - static auto* const PDIMSPECIAL = &g_pConfigManager->getConfigValuePtr("decoration:dim_special")->floatValue; +void CHyprRenderer::renderAllClientsForMonitor(CMonitor* pMonitor, timespec* time, const Vector2D& translate, const float& scale) { + static auto* const PDIMSPECIAL = &g_pConfigManager->getConfigValuePtr("decoration:dim_special")->floatValue; - if (!PMONITOR) + const SRenderModifData RENDERMODIFDATA = {translate, scale}; + + if (!pMonitor) return; if (!g_pCompositor->m_sSeat.exclusiveClient && g_pSessionLockManager->isSessionLocked()) { @@ -425,12 +426,17 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { return; } + // todo: matrices are buggy atm for some reason, but probably would be preferable in the long run + // g_pHyprOpenGL->saveMatrix(); + // g_pHyprOpenGL->setMatrixScaleTranslate(translate, scale); + g_pHyprOpenGL->m_RenderData.renderModif = RENDERMODIFDATA; + // Render layer surfaces below windows for monitor - for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { - renderLayer(ls.get(), PMONITOR, time); + for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { + renderLayer(ls.get(), pMonitor, time); } - for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { - renderLayer(ls.get(), PMONITOR, time); + for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { + renderLayer(ls.get(), pMonitor, time); } // pre window pass @@ -438,10 +444,10 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { // if there is a fullscreen window, render it and then do not render anymore. // fullscreen window will hide other windows and top layers - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace); if (PWORKSPACE->m_bHasFullscreenWindow) { - renderWorkspaceWithFullscreenWindow(PMONITOR, PWORKSPACE, time); + renderWorkspaceWithFullscreenWindow(pMonitor, PWORKSPACE, time); return; } @@ -458,7 +464,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) continue; // special are in the third pass - if (!shouldRenderWindow(w.get(), PMONITOR)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; // render active window after all others of this pass @@ -468,11 +474,11 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { } // render the bad boy - renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_MAIN); + renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_MAIN); } if (lastWindow) - renderWindow(lastWindow, PMONITOR, time, true, RENDER_PASS_MAIN); + renderWindow(lastWindow, pMonitor, time, true, RENDER_PASS_MAIN); // Non-floating popup for (auto& w : g_pCompositor->m_vWindows) { @@ -485,11 +491,11 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) continue; // special are in the third pass - if (!shouldRenderWindow(w.get(), PMONITOR)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; // render the bad boy - renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_POPUP); + renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_POPUP); } // floating on top @@ -503,11 +509,11 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) continue; - if (!shouldRenderWindow(w.get(), PMONITOR)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; // render the bad boy - renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_ALL); + renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL); } // pinned always above @@ -521,11 +527,11 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) continue; - if (!shouldRenderWindow(w.get(), PMONITOR)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; // render the bad boy - renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_ALL); + renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL); } // and then special @@ -537,7 +543,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { if (!g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) continue; - if (!shouldRenderWindow(w.get(), PMONITOR)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; if (!renderedSpecialBG) { @@ -547,9 +553,9 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { const auto SPECIALANIMPROGRS = PSPECIALWORKSPACE->m_vRenderOffset.isBeingAnimated() ? PSPECIALWORKSPACE->m_vRenderOffset.getCurveValue() : PSPECIALWORKSPACE->m_fAlpha.getCurveValue(); - const bool ANIMOUT = !PMONITOR->specialWorkspaceID; + const bool ANIMOUT = !pMonitor->specialWorkspaceID; - wlr_box monbox = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y}; + wlr_box monbox = {translate.x, translate.y, pMonitor->vecTransformedSize.x * scale, pMonitor->vecTransformedSize.y * scale}; g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMSPECIAL * (ANIMOUT ? (1.0 - SPECIALANIMPROGRS) : SPECIALANIMPROGRS))); } @@ -557,34 +563,39 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { } // render the bad boy - renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_ALL); + renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL); } // Render surfaces above windows for monitor - for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { - renderLayer(ls.get(), PMONITOR, time); + for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + renderLayer(ls.get(), pMonitor, time); } // Render IME popups for (auto& imep : g_pInputManager->m_sIMERelay.m_lIMEPopups) { - renderIMEPopup(&imep, PMONITOR, time); + renderIMEPopup(&imep, pMonitor, time); } - for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { - renderLayer(ls.get(), PMONITOR, time); + for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { + renderLayer(ls.get(), pMonitor, time); } - renderDragIcon(PMONITOR, time); + renderDragIcon(pMonitor, time); + //g_pHyprOpenGL->restoreMatrix(); + g_pHyprOpenGL->m_RenderData.renderModif = {}; +} + +void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now) { if (g_pSessionLockManager->isSessionLocked()) { - const auto PSLS = g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID); + const auto PSLS = g_pSessionLockManager->getSessionLockSurfaceForMonitor(pMonitor->ID); if (!PSLS) { // locked with no surface, fill with red wlr_box boxe = {0, 0, INT16_MAX, INT16_MAX}; g_pHyprOpenGL->renderRect(&boxe, CColor(1.0, 0.2, 0.2, 1.0)); } else { - renderSessionLockSurface(PSLS, PMONITOR, time); + renderSessionLockSurface(PSLS, pMonitor, now); } } } @@ -892,7 +903,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { g_pHyprOpenGL->clear(CColor(17.0 / 255.0, 17.0 / 255.0, 17.0 / 255.0, 1.0)); g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper" - renderAllClientsForMonitor(pMonitor->ID, &now); + renderWorkspace(pMonitor, g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace), &now, {0, 0, (int)pMonitor->vecPixelSize.x, (int)pMonitor->vecPixelSize.y}); + + renderLockscreen(pMonitor, &now); if (pMonitor == g_pCompositor->m_pLastMonitor) { g_pHyprNotificationOverlay->draw(pMonitor); @@ -981,6 +994,20 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } } +void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* now, const wlr_box& geometry) { + + Vector2D translate = {geometry.x, geometry.y}; + float scale = (float)geometry.width / pMonitor->vecPixelSize.x; + + if (DELTALESSTHAN((double)geometry.width / (double)geometry.height, pMonitor->vecPixelSize.x / pMonitor->vecPixelSize.y, 0.01)) { + Debug::log(ERR, "Ignoring geometry in renderWorkspace: aspect ratio mismatch"); + scale = 1.f; + translate = Vector2D{}; + } + + renderAllClientsForMonitor(pMonitor, now, translate, scale); +} + void CHyprRenderer::setWindowScanoutMode(CWindow* pWindow) { if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked()) return; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 7b0f47fd..b076c07c 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -10,14 +10,16 @@ struct SMonitorRule; // TODO: add fuller damage tracking for updating only parts of a window -enum DAMAGETRACKINGMODES { +enum DAMAGETRACKINGMODES +{ DAMAGE_TRACKING_INVALID = -1, DAMAGE_TRACKING_NONE = 0, DAMAGE_TRACKING_MONITOR, DAMAGE_TRACKING_FULL }; -enum eRenderPassMode { +enum eRenderPassMode +{ RENDER_PASS_ALL = 0, RENDER_PASS_MAIN, RENDER_PASS_POPUP @@ -30,7 +32,6 @@ struct SSessionLockSurface; class CHyprRenderer { public: void renderMonitor(CMonitor* pMonitor); - void renderAllClientsForMonitor(const int&, timespec*); void outputMgrApplyTest(wlr_output_configuration_v1*, bool); void arrangeLayersForMonitor(const int&); void damageSurface(wlr_surface*, double, double); @@ -47,6 +48,7 @@ class CHyprRenderer { bool shouldRenderCursor(); void calculateUVForSurface(CWindow*, wlr_surface*, bool main = false); std::tuple getRenderTimes(CMonitor* pMonitor); // avg max min + void renderLockscreen(CMonitor* pMonitor, timespec* now); bool m_bWindowRequestedCursorHide = false; bool m_bBlockSurfaceFeedback = false; @@ -74,6 +76,8 @@ class CHyprRenderer { void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*); void renderDragIcon(CMonitor*, timespec*); void renderIMEPopup(SIMEPopup*, CMonitor*, timespec*); + void renderWorkspace(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* now, const wlr_box& geometry); + void renderAllClientsForMonitor(CMonitor* pMonitor, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); bool m_bHasARenderedCursor = true;