diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index f90702dcf..7ef54da0e 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1149,7 +1149,7 @@ bool CWindow::opaque() { if (m_wlSurface->small() && !m_wlSurface->m_fillIgnoreSmall) return false; - if (PWORKSPACE->m_alpha->value() != 1.f) + if (PWORKSPACE && PWORKSPACE->m_alpha->value() != 1.f) return false; if (m_isX11 && m_xwaylandSurface && m_xwaylandSurface->m_surface && m_xwaylandSurface->m_surface->m_current.texture) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 48cf78d52..4bf54ca86 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -754,7 +754,8 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); // Allow the renderer to catch the last frame. - g_pHyprRenderer->makeWindowSnapshot(PWINDOW); + if (g_pHyprRenderer->shouldRenderWindow(PWINDOW)) + g_pHyprRenderer->makeWindowSnapshot(PWINDOW); // swallowing if (valid(PWINDOW->m_swallowed)) { diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 9cbf091bd..19d03fef8 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1813,13 +1813,16 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, const CBox& box, CFra // // Dual (or more) kawase blur CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* originalDamage) { - if (!m_renderData.currentFB->getTexture()) { Debug::log(ERR, "BUG THIS: null fb texture while attempting to blur main fb?! (introspection off?!)"); return &m_renderData.pCurrentMonData->mirrorFB; // return something to sample from at least } - TRACY_GPU_ZONE("RenderBlurMainFramebufferWithDamage"); + return blurFramebufferWithDamage(a, originalDamage, *m_renderData.currentFB); +} + +CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* originalDamage, CFramebuffer& source) { + TRACY_GPU_ZONE("RenderBlurFramebufferWithDamage"); const auto BLENDBEFORE = m_blend; blend(false); @@ -1859,7 +1862,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - auto currentTex = m_renderData.currentFB->getTexture(); + auto currentTex = source.getTexture(); glBindTexture(currentTex->m_target, currentTex->m_texID); @@ -2226,7 +2229,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, const CBox& box, f // amazing hack: the surface has an opaque region! CRegion inverseOpaque; - if (a >= 1.f && std::round(pSurface->m_current.size.x * m_renderData.pMonitor->m_scale) == box.w && + if (a >= 1.f && pSurface && std::round(pSurface->m_current.size.x * m_renderData.pMonitor->m_scale) == box.w && std::round(pSurface->m_current.size.y * m_renderData.pMonitor->m_scale) == box.h) { pixman_box32_t surfbox = {0, 0, pSurface->m_current.size.x * pSurface->m_current.scale, pSurface->m_current.size.y * pSurface->m_current.scale}; inverseOpaque = pSurface->m_current.opaque; @@ -2249,7 +2252,6 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, const CBox& box, f inverseOpaque.translate(box.pos()); m_renderData.renderModif.applyToRegion(inverseOpaque); inverseOpaque.intersect(texDamage); - POUTFB = blurMainFramebufferWithDamage(a, &inverseOpaque); } else POUTFB = &m_renderData.pCurrentMonData->blurFB; diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 3c7a31697..17fe7f85d 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -114,11 +114,12 @@ struct SMonitorRenderData { }; struct SCurrentRenderData { - PHLMONITORREF pMonitor; - Mat3x3 projection; - Mat3x3 savedProjection; - Mat3x3 monitorProjection; + PHLMONITORREF pMonitor; + Mat3x3 projection; + Mat3x3 savedProjection; + Mat3x3 monitorProjection; + // FIXME: raw pointer galore! SMonitorRenderData* pCurrentMonData = nullptr; CFramebuffer* currentFB = nullptr; // current rendering to CFramebuffer* mainFB = nullptr; // main to render to @@ -333,6 +334,7 @@ class CHyprOpenGLImpl { // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); + CFramebuffer* blurFramebufferWithDamage(float a, CRegion* damage, CFramebuffer& source); void passCMUniforms(const SShader&, const NColorManagement::SImageDescription& imageDescription, const NColorManagement::SImageDescription& targetImageDescription, bool modifySDR = false); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 343276c97..3abeb7bd4 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -493,7 +493,6 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T // whether to use m_fMovingToWorkspaceAlpha, only if fading out into an invisible ws const bool USE_WORKSPACE_FADE_ALPHA = pWindow->m_monitorMovedFrom != -1 && (!PWORKSPACE || !PWORKSPACE->isVisible()); - const bool DONT_BLUR = pWindow->m_windowData.noBlur.valueOrDefault() || pWindow->m_windowData.RGBX.valueOrDefault() || pWindow->opaque(); renderdata.surface = pWindow->m_wlSurface->resource(); renderdata.dontRound = pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN) || pWindow->m_windowData.noRounding.valueOrDefault(); @@ -503,7 +502,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T renderdata.decorate = decorate && !pWindow->m_X11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); renderdata.rounding = standalone || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->m_scale; renderdata.roundingPower = standalone || renderdata.dontRound ? 2.0f : pWindow->roundingPower(); - renderdata.blur = !standalone && *PBLUR && !DONT_BLUR; + renderdata.blur = !standalone && shouldBlur(pWindow); renderdata.pWindow = pWindow; if (standalone) { @@ -572,7 +571,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T if ((pWindow->m_isX11 && *PXWLUSENN) || pWindow->m_windowData.nearestNeighbor.valueOrDefault()) renderdata.useNearestNeighbor = true; - if (!pWindow->m_windowData.noBlur.valueOrDefault() && pWindow->m_wlSurface->small() && !pWindow->m_wlSurface->m_fillIgnoreSmall && renderdata.blur && *PBLUR) { + if (pWindow->m_wlSurface->small() && !pWindow->m_wlSurface->m_fillIgnoreSmall && renderdata.blur) { CBox wb = {renderdata.pos.x - pMonitor->m_position.x, renderdata.pos.y - pMonitor->m_position.y, renderdata.w, renderdata.h}; wb.scale(pMonitor->m_scale).round(); CRectPassElement::SRectData data; @@ -712,8 +711,6 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, const Time::s return; } - static auto PBLUR = CConfigValue("decoration:blur:enabled"); - TRACY_GPU_ZONE("RenderLayer"); const auto REALPOS = pLayer->m_realPosition->value(); @@ -721,7 +718,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, const Time::s CSurfacePassElement::SRenderData renderdata = {pMonitor, time, REALPOS}; renderdata.fadeAlpha = pLayer->m_alpha->value(); - renderdata.blur = pLayer->m_forceBlur && *PBLUR; + renderdata.blur = shouldBlur(pLayer); renderdata.surface = pLayer->m_surface->resource(); renderdata.decorate = false; renderdata.w = REALSIZ.x; @@ -874,12 +871,15 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA for (auto const& ls : pMonitor->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { renderLayer(ls.lock(), pMonitor, time); } + for (auto const& ls : pMonitor->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { renderLayer(ls.lock(), pMonitor, time); } + for (auto const& ls : pMonitor->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { renderLayer(ls.lock(), pMonitor, time); } + for (auto const& ls : pMonitor->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { renderLayer(ls.lock(), pMonitor, time); } @@ -896,6 +896,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA for (auto const& ls : pMonitor->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { renderLayer(ls.lock(), pMonitor, time); } + for (auto const& ls : pMonitor->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { renderLayer(ls.lock(), pMonitor, time); } @@ -940,9 +941,9 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA // special for (auto const& ws : g_pCompositor->m_workspaces) { if (ws->m_alpha->value() > 0.f && ws->m_isSpecialWorkspace) { - if (ws->m_hasFullscreenWindow) + if (ws->m_hasFullscreenWindow) { renderWorkspaceWindowsFullscreen(pMonitor, ws, time); - else + } else renderWorkspaceWindows(pMonitor, ws, time); } } @@ -2448,21 +2449,8 @@ void CHyprRenderer::makeWindowSnapshot(PHLWINDOW pWindow) { g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 0)); // JIC - // this is a hack but it works :P - // we need to disable blur or else we will get a black background, as the shader - // will try to copy the bg to apply blur. - // this isn't entirely correct, but like, oh well. - // small todo: maybe make this correct? :P - static auto* const PBLUR = (Hyprlang::INT* const*)(g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")); - const auto BLURVAL = **PBLUR; - **PBLUR = 0; - - g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 0)); // JIC - renderWindow(pWindow, PMONITOR, Time::steadyNow(), !pWindow->m_X11DoesntWantBorders, RENDER_PASS_ALL); - **PBLUR = BLURVAL; - endRender(); m_bRenderingSnapshot = false; @@ -2492,14 +2480,9 @@ void CHyprRenderer::makeLayerSnapshot(PHLLS pLayer) { g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 0)); // JIC - const auto BLURLSSTATUS = pLayer->m_forceBlur; - pLayer->m_forceBlur = false; - // draw the layer renderLayer(pLayer, PMONITOR, Time::steadyNow()); - pLayer->m_forceBlur = BLURLSSTATUS; - endRender(); m_bRenderingSnapshot = false; @@ -2534,7 +2517,6 @@ void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) { CRegion fakeDamage{0, 0, PMONITOR->m_transformedSize.x, PMONITOR->m_transformedSize.y}; if (*PDIMAROUND && pWindow->m_windowData.dimAround.valueOrDefault()) { - CRectPassElement::SRectData data; data.box = {0, 0, g_pHyprOpenGL->m_renderData.pMonitor->m_pixelSize.x, g_pHyprOpenGL->m_renderData.pMonitor->m_pixelSize.y}; @@ -2544,6 +2526,19 @@ void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) { damageMonitor(PMONITOR); } + if (shouldBlur(pWindow)) { + CRectPassElement::SRectData data; + data.box = CBox{pWindow->m_realPosition->value(), pWindow->m_realSize->value()}.translate(-PMONITOR->m_position).scale(PMONITOR->m_scale).round(); + data.color = CHyprColor{0, 0, 0, 0}; + data.blur = true; + data.blurA = sqrt(pWindow->m_alpha->value()); // sqrt makes the blur fadeout more realistic. + data.round = pWindow->rounding(); + data.roundingPower = pWindow->roundingPower(); + data.xray = pWindow->m_windowData.xray.valueOr(false); + + m_renderPass.add(makeShared(data)); + } + CTexPassElement::SRenderData data; data.flipEndFrame = true; data.tex = FBDATA->getTexture(); @@ -2580,12 +2575,35 @@ void CHyprRenderer::renderSnapshot(PHLLS pLayer) { CRegion fakeDamage{0, 0, PMONITOR->m_transformedSize.x, PMONITOR->m_transformedSize.y}; + const bool SHOULD_BLUR = shouldBlur(pLayer); + CTexPassElement::SRenderData data; data.flipEndFrame = true; data.tex = FBDATA->getTexture(); data.box = layerBox; data.a = pLayer->m_alpha->value(); data.damage = fakeDamage; + data.blur = SHOULD_BLUR; + data.blurA = sqrt(pLayer->m_alpha->value()); // sqrt makes the blur fadeout more realistic. + if (SHOULD_BLUR) + data.ignoreAlpha = pLayer->m_ignoreAlpha ? pLayer->m_ignoreAlphaValue : 0.01F /* ignore the alpha 0 regions */; m_renderPass.add(makeShared(data)); } + +bool CHyprRenderer::shouldBlur(PHLLS ls) { + if (m_bRenderingSnapshot) + return false; + + static auto PBLUR = CConfigValue("decoration:blur:enabled"); + return *PBLUR && ls->m_forceBlur; +} + +bool CHyprRenderer::shouldBlur(PHLWINDOW w) { + if (m_bRenderingSnapshot) + return false; + + static auto PBLUR = CConfigValue("decoration:blur:enabled"); + const bool DONT_BLUR = w->m_windowData.noBlur.valueOrDefault() || w->m_windowData.RGBX.valueOrDefault() || w->opaque(); + return *PBLUR && !DONT_BLUR; +} diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 29d7464b7..77e1fcf0c 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -45,6 +45,11 @@ struct SExplicitSyncSettings { bool explicitEnabled = false, explicitKMSEnabled = false; }; +struct SRenderWorkspaceUntilData { + PHLLS ls; + PHLWINDOW w; +}; + class CHyprRenderer { public: CHyprRenderer(); @@ -117,20 +122,23 @@ class CHyprRenderer { private: void arrangeLayerArray(PHLMONITOR, const std::vector&, bool, CBox*); + void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry); void renderWorkspaceWindowsFullscreen(PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special) void renderWorkspaceWindows(PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) + void renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); void renderWindow(PHLWINDOW, PHLMONITOR, const Time::steady_tp&, bool, eRenderPassMode, bool ignorePosition = false, bool standalone = false); void renderLayer(PHLLS, PHLMONITOR, const Time::steady_tp&, bool popups = false, bool lockscreen = false); void renderSessionLockSurface(WP, PHLMONITOR, const Time::steady_tp&); void renderDragIcon(PHLMONITOR, const Time::steady_tp&); void renderIMEPopup(CInputPopup*, PHLMONITOR, const Time::steady_tp&); - void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry); void sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now); // sends frame displayed events but doesn't actually render anything - void renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); void renderSessionLockMissing(PHLMONITOR pMonitor); bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor); + bool shouldBlur(PHLLS ls); + bool shouldBlur(PHLWINDOW w); + bool m_cursorHidden = false; bool m_cursorHasSurface = false; SP m_currentRenderbuffer = nullptr; diff --git a/src/render/pass/TexPassElement.cpp b/src/render/pass/TexPassElement.cpp index b27f1032c..e6f4d052b 100644 --- a/src/render/pass/TexPassElement.cpp +++ b/src/render/pass/TexPassElement.cpp @@ -11,10 +11,14 @@ CTexPassElement::CTexPassElement(const CTexPassElement::SRenderData& data_) : m_ void CTexPassElement::draw(const CRegion& damage) { g_pHyprOpenGL->m_endFrame = m_data.flipEndFrame; - CScopeGuard x = {[]() { + CScopeGuard x = {[this]() { // g_pHyprOpenGL->m_endFrame = false; g_pHyprOpenGL->m_renderData.clipBox = {}; + if (m_data.replaceProjection) + g_pHyprOpenGL->m_renderData.monitorProjection = g_pHyprOpenGL->m_renderData.pMonitor->m_projMatrix; + if (m_data.ignoreAlpha.has_value()) + g_pHyprOpenGL->m_renderData.discardMode = 0; }}; if (!m_data.clipBox.empty()) @@ -22,9 +26,16 @@ void CTexPassElement::draw(const CRegion& damage) { if (m_data.replaceProjection) g_pHyprOpenGL->m_renderData.monitorProjection = *m_data.replaceProjection; - g_pHyprOpenGL->renderTextureInternalWithDamage(m_data.tex, m_data.box, m_data.a, m_data.damage.empty() ? damage : m_data.damage, m_data.round, m_data.roundingPower); - if (m_data.replaceProjection) - g_pHyprOpenGL->m_renderData.monitorProjection = g_pHyprOpenGL->m_renderData.pMonitor->m_projMatrix; + + if (m_data.ignoreAlpha.has_value()) { + g_pHyprOpenGL->m_renderData.discardMode = DISCARD_ALPHA; + g_pHyprOpenGL->m_renderData.discardOpacity = *m_data.ignoreAlpha; + } + + if (m_data.blur) + g_pHyprOpenGL->renderTextureWithBlur(m_data.tex, m_data.box, m_data.a, nullptr, m_data.round, m_data.roundingPower, false, m_data.blurA, 1.F); + else + g_pHyprOpenGL->renderTextureInternalWithDamage(m_data.tex, m_data.box, m_data.a, m_data.damage.empty() ? damage : m_data.damage, m_data.round, m_data.roundingPower); } bool CTexPassElement::needsLiveBlur() { diff --git a/src/render/pass/TexPassElement.hpp b/src/render/pass/TexPassElement.hpp index e98edd606..a9206d2d0 100644 --- a/src/render/pass/TexPassElement.hpp +++ b/src/render/pass/TexPassElement.hpp @@ -11,13 +11,16 @@ class CTexPassElement : public IPassElement { struct SRenderData { SP tex; CBox box; - float a = 1.F; + float a = 1.F; + float blurA = 1.F; CRegion damage; int round = 0; float roundingPower = 2.0f; bool flipEndFrame = false; std::optional replaceProjection; CBox clipBox; + bool blur = false; + std::optional ignoreAlpha; }; CTexPassElement(const SRenderData& data);