diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 793d373a..d9b9bfcd 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -355,7 +355,7 @@ void CHyprOpenGLImpl::renderTextureInternal(const CTexture& tex, wlr_box* pBox, // but it works... well, I guess? // // Dual (or more) kawase blur -CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* pBox) { +CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* originalDamage) { glDisable(GL_BLEND); glDisable(GL_STENCIL_TEST); @@ -375,6 +375,12 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p const auto BLURSIZE = g_pConfigManager->getInt("decoration:blur_size"); const auto BLURPASSES = g_pConfigManager->getInt("decoration:blur_passes"); + // prep damage + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, originalDamage); + wlr_region_expand(&damage, &damage, BLURPASSES * BLURSIZE * 2); + // helper const auto PMIRRORFB = &m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB; const auto PMIRRORSWAPFB = &m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorSwapFB; @@ -437,23 +443,24 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p // damage region will be scaled, make a temp pixman_region32_t tempDamage; pixman_region32_init(&tempDamage); - wlr_region_scale(&tempDamage, m_RenderData.pDamage, 1.f / 2.f); // when DOWNscaling, we make the region twice as small because it's the TARGET + wlr_region_scale(&tempDamage, &damage, 1.f / 2.f); // when DOWNscaling, we make the region twice as small because it's the TARGET drawPass(&m_shBLUR1, &tempDamage); // and draw for (int i = 1; i < BLURPASSES; ++i) { - wlr_region_scale(&tempDamage, m_RenderData.pDamage, 1.f / (1 << (i + 1))); + wlr_region_scale(&tempDamage, &damage, 1.f / (1 << (i + 1))); drawPass(&m_shBLUR1, &tempDamage); // down } for (int i = BLURPASSES - 1; i >= 0; --i) { - wlr_region_scale(&tempDamage, m_RenderData.pDamage, 1.f / (1 << i)); // when upsampling we make the region twice as big + wlr_region_scale(&tempDamage, &damage, 1.f / (1 << i)); // when upsampling we make the region twice as big drawPass(&m_shBLUR2, &tempDamage); // up } // finish pixman_region32_fini(&tempDamage); + pixman_region32_fini(&damage); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -463,7 +470,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p return currentRenderToFB; } -void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, int round) { +void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); if (g_pConfigManager->getInt("decoration:blur") == 0) { @@ -476,11 +483,19 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, pixman_region32_init(&damage); pixman_region32_intersect_rect(&damage, m_RenderData.pDamage, pBox->x, pBox->y, pBox->width, pBox->height); // clip it to the box + // amazing hack: the surface has an opaque region! + pixman_region32_t inverseOpaque; + pixman_region32_init(&inverseOpaque); + pixman_box32_t monbox = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y}; + pixman_region32_inverse(&inverseOpaque, &pSurface->current.opaque, &monbox); + pixman_region32_intersect(&damage, &damage, &inverseOpaque); + pixman_region32_fini(&inverseOpaque); + if (!pixman_region32_not_empty(&damage)) return; // if its empty, reject. // blur the main FB, it will be rendered onto the mirror - const auto POUTFB = blurMainFramebufferWithDamage(a, pBox); + const auto POUTFB = blurMainFramebufferWithDamage(a, pBox, &damage); // bind primary m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.bind(); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index c19ba395..8affb39d 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -56,7 +56,7 @@ public: void renderRect(wlr_box*, const CColor&); void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0); void renderTexture(const CTexture&, wlr_box*, float a, int round = 0); - void renderTextureWithBlur(const CTexture&, wlr_box*, float a, int round = 0); + void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0); void renderBorder(wlr_box*, const CColor&, int thick = 1, int round = 0); void makeWindowSnapshot(CWindow*); @@ -102,7 +102,7 @@ private: void createBGTextureForMonitor(SMonitor*); // returns the out FB, can be either Mirror or MirrorSwap - CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox); + CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage); void renderTextureInternal(const CTexture&, wlr_box* pBox, float a, int round = 0, bool discardOpaque = false); void renderTextureWithBlurInternal(const CTexture&, wlr_box*, float a, int round = 0); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index f65a4be2..2d5ba2bf 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -20,7 +20,7 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { scaleBox(&windowBox, RDATA->output->scale); if (RDATA->surface && surface == RDATA->surface) - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding")); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding")); else g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding"));