From 9e277ed1ff7c88719d8fdee6533d479627623e43 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Fri, 18 Aug 2023 20:22:08 +0200 Subject: [PATCH] Improved the blur shaders to run faster at higher resolutions and to look identical regardless of display resolution Also improved the blur shaders rendering quality when rotating the screen 90 or 270 degrees --- es-app/src/MediaViewer.cpp | 26 +++----- es-app/src/Screensaver.cpp | 27 +++------ es-core/src/Window.cpp | 21 ++----- es-core/src/renderers/Renderer.h | 5 ++ es-core/src/renderers/RendererOpenGL.cpp | 11 ++-- es-core/src/renderers/ShaderOpenGL.cpp | 8 +++ es-core/src/renderers/ShaderOpenGL.h | 2 + resources/shaders/glsl/blur_horizontal.glsl | 67 ++++++++++++--------- resources/shaders/glsl/blur_vertical.glsl | 67 ++++++++++++--------- 9 files changed, 123 insertions(+), 111 deletions(-) diff --git a/es-app/src/MediaViewer.cpp b/es-app/src/MediaViewer.cpp index acb5d052b..9c364df24 100644 --- a/es-app/src/MediaViewer.cpp +++ b/es-app/src/MediaViewer.cpp @@ -199,26 +199,16 @@ void MediaViewer::render(const glm::mat4& /*parentTrans*/) if (Settings::getInstance()->getBool("MediaViewerVideoScanlines")) shaders = Renderer::Shader::SCANLINES; if (Settings::getInstance()->getBool("MediaViewerVideoBlur")) { - shaders |= Renderer::Shader::BLUR_HORIZONTAL; - const float resolutionModifier {mRenderer->getScreenResolutionModifier()}; - // clang-format off - if (resolutionModifier < 1) - videoParameters.blurPasses = 2; // Below 1080 - else if (resolutionModifier >= 4) - videoParameters.blurPasses = 12; // 8K - else if (resolutionModifier >= 2.9) - videoParameters.blurPasses = 10; // 6K - else if (resolutionModifier >= 2.6) - videoParameters.blurPasses = 8; // 5K - else if (resolutionModifier >= 2) - videoParameters.blurPasses = 5; // 4K - else if (resolutionModifier >= 1.3) - videoParameters.blurPasses = 3; // 1440 - else if (resolutionModifier >= 1) - videoParameters.blurPasses = 2; // 1080 - // clang-format on + if (mRenderer->getScreenRotation() == 90 || mRenderer->getScreenRotation() == 270) + shaders |= Renderer::Shader::BLUR_VERTICAL; + else + shaders |= Renderer::Shader::BLUR_HORIZONTAL; } + // We run two passes to make the blur smoother. + videoParameters.blurPasses = 2; + videoParameters.blurStrength = 1.35f; + if (shaders != 0) mRenderer->shaderPostprocessing(shaders, videoParameters); } diff --git a/es-app/src/Screensaver.cpp b/es-app/src/Screensaver.cpp index cc065902f..ba731faae 100644 --- a/es-app/src/Screensaver.cpp +++ b/es-app/src/Screensaver.cpp @@ -324,26 +324,17 @@ void Screensaver::renderScreensaver() if (Settings::getInstance()->getBool("ScreensaverVideoScanlines")) shaders = Renderer::Shader::SCANLINES; if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) { - shaders |= Renderer::Shader::BLUR_HORIZONTAL; - const float resolutionModifier {mRenderer->getScreenResolutionModifier()}; - // clang-format off - if (resolutionModifier < 1) - videoParameters.blurPasses = 2; // Below 1080 - else if (resolutionModifier >= 4) - videoParameters.blurPasses = 12; // 8K - else if (resolutionModifier >= 2.9) - videoParameters.blurPasses = 10; // 6K - else if (resolutionModifier >= 2.6) - videoParameters.blurPasses = 8; // 5K - else if (resolutionModifier >= 2) - videoParameters.blurPasses = 5; // 4K - else if (resolutionModifier >= 1.3) - videoParameters.blurPasses = 3; // 1440 - else if (resolutionModifier >= 1) - videoParameters.blurPasses = 2; // 1080 - // clang-format on + if (mRenderer->getScreenRotation() == 90 || + mRenderer->getScreenRotation() == 270) + shaders |= Renderer::Shader::BLUR_VERTICAL; + else + shaders |= Renderer::Shader::BLUR_HORIZONTAL; } + // We run two passes to make the blur smoother. + videoParameters.blurPasses = 2; + videoParameters.blurStrength = 1.35f; + if (shaders != 0) mRenderer->shaderPostprocessing(shaders, videoParameters); diff --git a/es-core/src/Window.cpp b/es-core/src/Window.cpp index 637a8b2c1..fbc054be7 100644 --- a/es-core/src/Window.cpp +++ b/es-core/src/Window.cpp @@ -513,23 +513,10 @@ void Window::render() // degrees. if (Settings::getInstance()->getBool("MenuBlurBackground") || mRenderer->getScreenRotation() == 90 || mRenderer->getScreenRotation() == 270) { - const float resolutionModifier {mRenderer->getScreenResolutionModifier()}; - // clang-format off - if (resolutionModifier < 1) - backgroundParameters.blurPasses = 2; // Below 1080 - else if (resolutionModifier >= 4) - backgroundParameters.blurPasses = 12; // 8K - else if (resolutionModifier >= 2.9) - backgroundParameters.blurPasses = 10; // 6K - else if (resolutionModifier >= 2.6) - backgroundParameters.blurPasses = 8; // 5K - else if (resolutionModifier >= 2) - backgroundParameters.blurPasses = 5; // 4K - else if (resolutionModifier >= 1.3) - backgroundParameters.blurPasses = 3; // 1440 - else if (resolutionModifier >= 1) - backgroundParameters.blurPasses = 2; // 1080 - // clang-format on + + // We run two passes to make the blur smoother. + backgroundParameters.blurPasses = 2; + backgroundParameters.blurStrength = 1.35f; // Also dim the background slightly. if (Settings::getInstance()->getString("MenuColorScheme") == "light") diff --git a/es-core/src/renderers/Renderer.h b/es-core/src/renderers/Renderer.h index e1dd749b2..a66586337 100644 --- a/es-core/src/renderers/Renderer.h +++ b/es-core/src/renderers/Renderer.h @@ -67,6 +67,7 @@ public: float saturation; float dimming; float reflectionsFalloff; + float blurStrength; unsigned int shaders; unsigned int shaderFlags; @@ -76,6 +77,7 @@ public: , saturation {1.0f} , dimming {1.0f} , reflectionsFalloff {0.0f} + , blurStrength {0.0f} , shaders {0} , shaderFlags {0} { @@ -94,6 +96,7 @@ public: , saturation {1.0f} , dimming {1.0f} , reflectionsFalloff {0.0f} + , blurStrength {0.0f} , shaders {0} , shaderFlags {0} { @@ -104,6 +107,7 @@ public: float opacity; float saturation; float dimming; + float blurStrength; unsigned int blurPasses; unsigned int shaders; @@ -111,6 +115,7 @@ public: : opacity {1.0f} , saturation {1.0f} , dimming {1.0f} + , blurStrength {0.0f} , blurPasses {1} , shaders {0} { diff --git a/es-core/src/renderers/RendererOpenGL.cpp b/es-core/src/renderers/RendererOpenGL.cpp index 8eb2ceb5c..e62da151e 100644 --- a/es-core/src/renderers/RendererOpenGL.cpp +++ b/es-core/src/renderers/RendererOpenGL.cpp @@ -294,9 +294,9 @@ bool RendererOpenGL::createContext() textureHeight = static_cast(getScreenWidth()); } - mPostProcTexture1 = createTexture(TextureType::BGRA, false, false, false, false, textureWidth, + mPostProcTexture1 = createTexture(TextureType::BGRA, false, true, false, false, textureWidth, textureHeight, nullptr); - mPostProcTexture2 = createTexture(TextureType::BGRA, false, false, false, false, textureWidth, + mPostProcTexture2 = createTexture(TextureType::BGRA, false, true, false, false, textureWidth, textureHeight, nullptr); // Attach textures to the shader framebuffers. @@ -522,7 +522,8 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices, mBlurHorizontalShader->setAttribPointers(); GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_DYNAMIC_DRAW)); - mBlurHorizontalShader->setTextureSize({width, height}); + mBlurHorizontalShader->setBlurStrength((vertices->blurStrength / getScreenWidth()) * + getScreenResolutionModifier()); mBlurHorizontalShader->setFlags(vertices->shaderFlags); GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); mLastShader = mBlurHorizontalShader; @@ -540,7 +541,8 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices, mBlurVerticalShader->setAttribPointers(); GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_DYNAMIC_DRAW)); - mBlurVerticalShader->setTextureSize({width, height}); + mBlurVerticalShader->setBlurStrength((vertices->blurStrength / getScreenHeight()) * + getScreenResolutionModifier()); mBlurVerticalShader->setFlags(vertices->shaderFlags); GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); mLastShader = mBlurVerticalShader; @@ -621,6 +623,7 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders, vertices->opacity = parameters.opacity; vertices->saturation = parameters.saturation; vertices->dimming = parameters.dimming; + vertices->blurStrength = parameters.blurStrength; vertices->shaderFlags = ShaderFlags::POST_PROCESSING | ShaderFlags::PREMULTIPLIED; if (screenRotation == 90 || screenRotation == 270) diff --git a/es-core/src/renderers/ShaderOpenGL.cpp b/es-core/src/renderers/ShaderOpenGL.cpp index 7d04d8c71..2b34aca58 100644 --- a/es-core/src/renderers/ShaderOpenGL.cpp +++ b/es-core/src/renderers/ShaderOpenGL.cpp @@ -24,6 +24,7 @@ ShaderOpenGL::ShaderOpenGL() , mShaderSaturation {0} , mShaderDimming {0} , mShaderReflectionsFalloff {0} + , mBlurStrength {0} , mShaderFlags {0} { } @@ -128,6 +129,7 @@ void ShaderOpenGL::getVariableLocations(GLuint programID) mShaderSaturation = glGetUniformLocation(mProgramID, "saturation"); mShaderDimming = glGetUniformLocation(mProgramID, "dimming"); mShaderReflectionsFalloff = glGetUniformLocation(mProgramID, "reflectionsFalloff"); + mBlurStrength = glGetUniformLocation(mProgramID, "blurStrength"); mShaderFlags = glGetUniformLocation(mProgramID, "shaderFlags"); } @@ -198,6 +200,12 @@ void ShaderOpenGL::setReflectionsFalloff(GLfloat falloff) GL_CHECK_ERROR(glUniform1f(mShaderReflectionsFalloff, falloff)); } +void ShaderOpenGL::setBlurStrength(GLfloat blurStrength) +{ + if (mBlurStrength != -1) + GL_CHECK_ERROR(glUniform1f(mBlurStrength, blurStrength)); +} + void ShaderOpenGL::setFlags(GLuint flags) { if (mShaderFlags != -1) diff --git a/es-core/src/renderers/ShaderOpenGL.h b/es-core/src/renderers/ShaderOpenGL.h index f8f594d3e..d50d6268f 100644 --- a/es-core/src/renderers/ShaderOpenGL.h +++ b/es-core/src/renderers/ShaderOpenGL.h @@ -74,6 +74,7 @@ public: void setSaturation(GLfloat saturation); void setDimming(GLfloat dimming); void setReflectionsFalloff(GLfloat falloff); + void setBlurStrength(GLfloat blurStrength); void setFlags(GLuint flags); // Sets the shader program to use the loaded shaders. void activateShaders(); @@ -101,6 +102,7 @@ private: GLint mShaderSaturation; GLint mShaderDimming; GLint mShaderReflectionsFalloff; + GLint mBlurStrength; GLint mShaderFlags; }; diff --git a/resources/shaders/glsl/blur_horizontal.glsl b/resources/shaders/glsl/blur_horizontal.glsl index a4b3a2945..4428bb308 100644 --- a/resources/shaders/glsl/blur_horizontal.glsl +++ b/resources/shaders/glsl/blur_horizontal.glsl @@ -1,14 +1,11 @@ +// SPDX-License-Identifier: MIT // -// Implementation based on the article "Efficient Gaussian blur with linear sampling" -// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ -// A version for MasterEffect Reborn, a standalone version, and a custom shader version for SweetFX -// can be found at http://reshade.me/forum/shader-presentation/27-gaussian-blur-bloom-unsharpmask +// EmulationStation Desktop Edition +// blur_horizontal.glsl // -// Taken from the RetroArch project and modified for ES-DE. +// Horizontal gaussian blur. // -#define HW 1.00 - // Vertex section of code: #if defined(VERTEX) @@ -31,8 +28,8 @@ precision mediump float; #endif uniform uint shaderFlags; -uniform vec2 textureSize; uniform sampler2D textureSampler; +uniform float blurStrength; in vec2 texCoord; out vec4 FragColor; @@ -45,32 +42,48 @@ out vec4 FragColor; void main() { - vec4 SourceSize; - vec2 PIXEL_SIZE; + vec4 color = vec4(0.0); + float hstep = 1.0f; + float vstep = 0.0f; + vec2 tc; if (0x0u != (shaderFlags & 0x10u)) { - SourceSize = vec4(textureSize.yx, 1.0 / textureSize.xy); - PIXEL_SIZE = vec2(SourceSize.w, SourceSize.z); + // Screen rotated 90 or 270 degrees. + tc = texCoord.yx; } else { - SourceSize = vec4(textureSize.xy, 1.0 / textureSize.xy); - PIXEL_SIZE = vec2(SourceSize.z, SourceSize.w); + tc = texCoord.xy; } - float sampleOffsets[5] = float[5](0.0, 1.4347826, 3.3478260, 5.2608695, 7.1739130); - float sampleWeights[5] = - float[5](0.16818994, 0.27276957, 0.11690125, 0.024067905, 0.0021112196); + // 9-tap filter. + color += texture(textureSampler, + vec2(tc.x - 4.0 * blurStrength * hstep, tc.y - 4.0 * blurStrength * vstep)) * + 0.0162162162; + color += texture(textureSampler, + vec2(tc.x - 3.0 * blurStrength * hstep, tc.y - 3.0 * blurStrength * vstep)) * + 0.0540540541; + color += texture(textureSampler, + vec2(tc.x - 2.0 * blurStrength * hstep, tc.y - 2.0 * blurStrength * vstep)) * + 0.1216216216; + color += texture(textureSampler, + vec2(tc.x - 1.0 * blurStrength * hstep, tc.y - 1.0 * blurStrength * vstep)) * + 0.1945945946; - vec4 color = texture(textureSampler, texCoord) * sampleWeights[0]; - for (int i = 1; i < 5; i++) { - color += - texture(textureSampler, texCoord + vec2(sampleOffsets[i] * HW * PIXEL_SIZE.x, 0.0)) * - sampleWeights[i]; - color += - texture(textureSampler, texCoord - vec2(sampleOffsets[i] * HW * PIXEL_SIZE.x, 0.0)) * - sampleWeights[i]; - } + color += texture(textureSampler, vec2(tc.x, tc.y)) * 0.2270270270; - FragColor = vec4(color); + color += texture(textureSampler, + vec2(tc.x + 1.0 * blurStrength * hstep, tc.y + 1.0 * blurStrength * vstep)) * + 0.1945945946; + color += texture(textureSampler, + vec2(tc.x + 2.0 * blurStrength * hstep, tc.y + 2.0 * blurStrength * vstep)) * + 0.1216216216; + color += texture(textureSampler, + vec2(tc.x + 3.0 * blurStrength * hstep, tc.y + 3.0 * blurStrength * vstep)) * + 0.0540540541; + color += texture(textureSampler, + vec2(tc.x + 4.0 * blurStrength * hstep, tc.y + 4.0 * blurStrength * vstep)) * + 0.0162162162; + + FragColor = vec4(color.rgb, 1.0); } #endif diff --git a/resources/shaders/glsl/blur_vertical.glsl b/resources/shaders/glsl/blur_vertical.glsl index 69f89e21a..ce7e551d7 100644 --- a/resources/shaders/glsl/blur_vertical.glsl +++ b/resources/shaders/glsl/blur_vertical.glsl @@ -1,14 +1,11 @@ +// SPDX-License-Identifier: MIT // -// Implementation based on the article "Efficient Gaussian blur with linear sampling" -// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ -// A version for MasterEffect Reborn, a standalone version, and a custom shader version for SweetFX -// can be found at http://reshade.me/forum/shader-presentation/27-gaussian-blur-bloom-unsharpmask +// EmulationStation Desktop Edition +// blur_vertical.glsl // -// Taken from the RetroArch project and modified for ES-DE. +// Vertical gaussian blur. // -#define VW 1.00 - // Vertex section of code: #if defined(VERTEX) @@ -31,8 +28,8 @@ precision mediump float; #endif uniform uint shaderFlags; -uniform vec2 textureSize; uniform sampler2D textureSampler; +uniform float blurStrength; in vec2 texCoord; out vec4 FragColor; @@ -45,32 +42,48 @@ out vec4 FragColor; void main() { - vec4 SourceSize; - vec2 PIXEL_SIZE; + vec4 color = vec4(0.0); + float hstep = 0.0f; + float vstep = 1.0f; + vec2 tc; if (0x0u != (shaderFlags & 0x10u)) { - SourceSize = vec4(textureSize.xy, 1.0 / textureSize.yx); - PIXEL_SIZE = vec2(SourceSize.w, SourceSize.z); + // Screen rotated 90 or 270 degrees. + tc = texCoord.yx; } else { - SourceSize = vec4(textureSize.xy, 1.0 / textureSize.xy); - PIXEL_SIZE = vec2(SourceSize.z, SourceSize.w); + tc = texCoord.xy; } - float sampleOffsets[5] = float[5](0.0, 1.4347826, 3.3478260, 5.2608695, 7.1739130); - float sampleWeights[5] = - float[5](0.16818994, 0.27276957, 0.11690125, 0.024067905, 0.0021112196); + // 9-tap filter. + color += texture(textureSampler, + vec2(tc.x - 4.0 * blurStrength * hstep, tc.y - 4.0 * blurStrength * vstep)) * + 0.0162162162; + color += texture(textureSampler, + vec2(tc.x - 3.0 * blurStrength * hstep, tc.y - 3.0 * blurStrength * vstep)) * + 0.0540540541; + color += texture(textureSampler, + vec2(tc.x - 2.0 * blurStrength * hstep, tc.y - 2.0 * blurStrength * vstep)) * + 0.1216216216; + color += texture(textureSampler, + vec2(tc.x - 1.0 * blurStrength * hstep, tc.y - 1.0 * blurStrength * vstep)) * + 0.1945945946; - vec4 color = texture(textureSampler, texCoord) * sampleWeights[0]; - for (int i = 1; i < 5; i++) { - color += - texture(textureSampler, texCoord + vec2(0.0, sampleOffsets[i] * VW * PIXEL_SIZE.y)) * - sampleWeights[i]; - color += - texture(textureSampler, texCoord - vec2(0.0, sampleOffsets[i] * VW * PIXEL_SIZE.y)) * - sampleWeights[i]; - } + color += texture(textureSampler, vec2(tc.x, tc.y)) * 0.2270270270; - FragColor = vec4(color); + color += texture(textureSampler, + vec2(tc.x + 1.0 * blurStrength * hstep, tc.y + 1.0 * blurStrength * vstep)) * + 0.1945945946; + color += texture(textureSampler, + vec2(tc.x + 2.0 * blurStrength * hstep, tc.y + 2.0 * blurStrength * vstep)) * + 0.1216216216; + color += texture(textureSampler, + vec2(tc.x + 3.0 * blurStrength * hstep, tc.y + 3.0 * blurStrength * vstep)) * + 0.0540540541; + color += texture(textureSampler, + vec2(tc.x + 4.0 * blurStrength * hstep, tc.y + 4.0 * blurStrength * vstep)) * + 0.0162162162; + + FragColor = vec4(color.rgb, 1.0); } #endif