From d96f8ff0fe44f874700c8c132086a206132635c5 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 3 Aug 2023 15:11:10 +0200 Subject: [PATCH] renderer: Various Blur Improvements (#2877) * move blur to its own category * blur improvements, contrast, brightness, noise --- src/config/ConfigManager.cpp | 15 +++-- src/render/OpenGL.cpp | 97 +++++++++++++++++++++++++++------ src/render/OpenGL.hpp | 1 + src/render/Renderer.cpp | 6 +- src/render/Shader.hpp | 4 ++ src/render/shaders/Textures.hpp | 30 ++++++++++ 6 files changed, 127 insertions(+), 26 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 820e81af..50132d13 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -126,12 +126,15 @@ void CConfigManager::setDefaultVars() { configValues["debug:manual_crash"].intValue = 0; configValues["decoration:rounding"].intValue = 0; - configValues["decoration:blur"].intValue = 1; - configValues["decoration:blur_size"].intValue = 8; - configValues["decoration:blur_passes"].intValue = 1; - configValues["decoration:blur_ignore_opacity"].intValue = 0; - configValues["decoration:blur_new_optimizations"].intValue = 1; - configValues["decoration:blur_xray"].intValue = 0; + configValues["decoration:blur:enabled"].intValue = 1; + configValues["decoration:blur:size"].intValue = 8; + configValues["decoration:blur:passes"].intValue = 1; + configValues["decoration:blur:ignore_opacity"].intValue = 0; + configValues["decoration:blur:new_optimizations"].intValue = 1; + configValues["decoration:blur:xray"].intValue = 0; + configValues["decoration:blur:noise"].floatValue = 0.0117; + configValues["decoration:blur:contrast"].floatValue = 0.8916; + configValues["decoration:blur:brightness"].floatValue = 0.8172; configValues["decoration:active_opacity"].floatValue = 1; configValues["decoration:inactive_opacity"].floatValue = 1; configValues["decoration:fullscreen_opacity"].floatValue = 1; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 81401727..1040aa86 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -321,6 +321,16 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shBLUR2.radius = glGetUniformLocation(prog, "radius"); m_RenderData.pCurrentMonData->m_shBLUR2.halfpixel = glGetUniformLocation(prog, "halfpixel"); + prog = createProgram(TEXVERTSRC, FRAGBLURFINISH); + m_RenderData.pCurrentMonData->m_shBLURFINISH.program = prog; + m_RenderData.pCurrentMonData->m_shBLURFINISH.tex = glGetUniformLocation(prog, "tex"); + m_RenderData.pCurrentMonData->m_shBLURFINISH.proj = glGetUniformLocation(prog, "proj"); + m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib = glGetAttribLocation(prog, "pos"); + m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib = glGetAttribLocation(prog, "texcoord"); + m_RenderData.pCurrentMonData->m_shBLURFINISH.noise = glGetUniformLocation(prog, "noise"); + m_RenderData.pCurrentMonData->m_shBLURFINISH.contrast = glGetUniformLocation(prog, "contrast"); + m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness = glGetUniformLocation(prog, "brightness"); + prog = createProgram(QUADVERTSRC, FRAGSHADOW); m_RenderData.pCurrentMonData->m_shSHADOW.program = prog; m_RenderData.pCurrentMonData->m_shSHADOW.proj = glGetUniformLocation(prog, "proj"); @@ -801,8 +811,8 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); // get the config settings - static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue; - static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue; + static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur:size")->intValue; + static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur:passes")->intValue; // prep damage CRegion damage{*originalDamage}; @@ -891,6 +901,59 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up } + // finalize with effects + { + static auto* const PBLURCONTRAST = &g_pConfigManager->getConfigValuePtr("decoration:blur:contrast")->floatValue; + static auto* const PBLURNOISE = &g_pConfigManager->getConfigValuePtr("decoration:blur:noise")->floatValue; + static auto* const PBLURBRIGHTNESS = &g_pConfigManager->getConfigValuePtr("decoration:blur:brightness")->floatValue; + + if (currentRenderToFB == PMIRRORFB) + PMIRRORSWAPFB->bind(); + else + PMIRRORFB->bind(); + + glActiveTexture(GL_TEXTURE0); + + glBindTexture(currentRenderToFB->m_cTex.m_iTarget, currentRenderToFB->m_cTex.m_iTexID); + + glTexParameteri(currentRenderToFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program); + +#ifndef GLES2 + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix); +#else + wlr_matrix_transpose(glMatrix, glMatrix); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix); +#endif + glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.contrast, *PBLURCONTRAST); + glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE); + glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness, *PBLURBRIGHTNESS); + + glUniform1i(m_RenderData.pCurrentMonData->m_shBLURFINISH.tex, 0); + + glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + + glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib); + glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib); + + if (!damage.empty()) { + for (auto& RECT : damage.getRects()) { + scissor(&RECT, false /* this region is already transformed */); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + } + + glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib); + glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib); + + if (currentRenderToFB != PMIRRORFB) + currentRenderToFB = PMIRRORFB; + else + currentRenderToFB = PMIRRORSWAPFB; + } + // finish glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -914,9 +977,9 @@ void CHyprOpenGLImpl::markBlurDirtyForMonitor(CMonitor* pMonitor) { } void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { - static auto* const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue; - static auto* const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur_xray")->intValue; - static auto* const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue; + static auto* const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur:new_optimizations")->intValue; + static auto* const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur:xray")->intValue; + static auto* const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue; if (!*PBLURNEWOPTIMIZE || !m_mMonitorRenderResources[pMonitor].blurFBDirty || !*PBLUR) return; @@ -1012,8 +1075,8 @@ void CHyprOpenGLImpl::preWindowPass() { } bool CHyprOpenGLImpl::preBlurQueued() { - static auto* const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue; - static auto* const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue; + static auto* const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur:new_optimizations")->intValue; + static auto* const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue; return !(!m_RenderData.pCurrentMonData->blurFBDirty || !*PBLURNEWOPTIMIZE || !*PBLUR || !m_RenderData.pCurrentMonData->blurFBShouldRender); } @@ -1021,10 +1084,10 @@ bool CHyprOpenGLImpl::preBlurQueued() { void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round, bool blockBlurOptimization) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); - static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue; + static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue; static auto* const PNOBLUROVERSIZED = &g_pConfigManager->getConfigValuePtr("decoration:no_blur_on_oversized")->intValue; - static auto* const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue; - static auto* const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur_xray")->intValue; + static auto* const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur:new_optimizations")->intValue; + static auto* const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur:xray")->intValue; TRACY_GPU_ZONE("RenderTextureWithBlur"); @@ -1098,7 +1161,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, // stencil done. Render everything. wlr_box MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; // render our great blurred FB - static auto* const PBLURIGNOREOPACITY = &g_pConfigManager->getConfigValuePtr("decoration:blur_ignore_opacity")->intValue; + 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 @@ -1252,8 +1315,8 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFra // 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 - const auto BLURVAL = g_pConfigManager->getInt("decoration:blur"); - g_pConfigManager->setInt("decoration:blur", 0); + const auto BLURVAL = g_pConfigManager->getInt("decoration:blur:enabled"); + g_pConfigManager->setInt("decoration:blur:enabled", 0); // TODO: how can we make this the size of the window? setting it to window's size makes the entire screen render with the wrong res forever more. odd. glViewport(0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); @@ -1268,7 +1331,7 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFra g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, false, RENDER_PASS_ALL, true); - g_pConfigManager->setInt("decoration:blur", BLURVAL); + g_pConfigManager->setInt("decoration:blur:enabled", BLURVAL); // restore original fb #ifndef GLES2 @@ -1309,8 +1372,8 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { // 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 - const auto BLURVAL = g_pConfigManager->getInt("decoration:blur"); - g_pConfigManager->setInt("decoration:blur", 0); + const auto BLURVAL = g_pConfigManager->getInt("decoration:blur:enabled"); + g_pConfigManager->setInt("decoration:blur:enabled", 0); glViewport(0, 0, m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y); @@ -1326,7 +1389,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, !pWindow->m_bX11DoesntWantBorders, RENDER_PASS_ALL); - g_pConfigManager->setInt("decoration:blur", BLURVAL); + g_pConfigManager->setInt("decoration:blur:enabled", BLURVAL); // restore original fb #ifndef GLES2 diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 9080c90b..d38f54ae 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -61,6 +61,7 @@ struct SMonitorRenderData { CShader m_shEXT; CShader m_shBLUR1; CShader m_shBLUR2; + CShader m_shBLURFINISH; CShader m_shSHADOW; CShader m_shBORDER1; CShader m_shGLITCH; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index bb1ab511..cf6877f3 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -969,13 +969,13 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { damage = {0, 0, (int)pMonitor->vecTransformedSize.x * 10, (int)pMonitor->vecTransformedSize.y * 10}; pMonitor->lastFrameDamage = damage; } else { - static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue; + static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue; // if we use blur we need to expand the damage for proper blurring if (*PBLURENABLED == 1) { // TODO: can this be optimized? - static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue; - static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue; + static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur:size")->intValue; + static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur:passes")->intValue; const auto BLURRADIUS = *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think. diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp index c43147ab..01d35209 100644 --- a/src/render/Shader.hpp +++ b/src/render/Shader.hpp @@ -43,6 +43,10 @@ class CShader { GLint distort = -1; GLint output = -1; + GLint noise = -1; + GLint contrast = -1; + GLint brightness = -1; + GLint getUniformLocation(const std::string&); void destroy(); diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp index 0928487f..98cd8907 100644 --- a/src/render/shaders/Textures.hpp +++ b/src/render/shaders/Textures.hpp @@ -225,6 +225,36 @@ void main() { } )#"; +inline const std::string FRAGBLURFINISH = R"#( +precision mediump float; +varying vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; + +uniform float contrast; +uniform float noise; +uniform float brightness; + +float hash(vec2 p) { + return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); +} + +void main() { + vec4 pixColor = texture2D(tex, v_texcoord); + + // contrast + pixColor.rgb = (pixColor.rgb - 0.5) * contrast + 0.5; + + // brightness + pixColor.rgb *= brightness; + + // noise + float noiseHash = hash(v_texcoord); + float noiseAmount = (mod(noiseHash, 1.0) - 0.5); + pixColor.rgb += noiseAmount * noise; + + gl_FragColor = pixColor; +})#"; + inline const std::string TEXFRAGSRCEXT = R"#( #extension GL_OES_EGL_image_external : require