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
This commit is contained in:
Leon Styhre 2023-08-18 20:22:08 +02:00
parent a8d20549a5
commit 9e277ed1ff
9 changed files with 123 additions and 111 deletions

View file

@ -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")) {
if (mRenderer->getScreenRotation() == 90 || mRenderer->getScreenRotation() == 270)
shaders |= Renderer::Shader::BLUR_VERTICAL;
else
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
}
// We run two passes to make the blur smoother.
videoParameters.blurPasses = 2;
videoParameters.blurStrength = 1.35f;
if (shaders != 0)
mRenderer->shaderPostprocessing(shaders, videoParameters);
}

View file

@ -324,26 +324,17 @@ void Screensaver::renderScreensaver()
if (Settings::getInstance()->getBool("ScreensaverVideoScanlines"))
shaders = Renderer::Shader::SCANLINES;
if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) {
if (mRenderer->getScreenRotation() == 90 ||
mRenderer->getScreenRotation() == 270)
shaders |= Renderer::Shader::BLUR_VERTICAL;
else
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
}
// We run two passes to make the blur smoother.
videoParameters.blurPasses = 2;
videoParameters.blurStrength = 1.35f;
if (shaders != 0)
mRenderer->shaderPostprocessing(shaders, videoParameters);

View file

@ -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")

View file

@ -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}
{

View file

@ -294,9 +294,9 @@ bool RendererOpenGL::createContext()
textureHeight = static_cast<unsigned int>(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)

View file

@ -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)

View file

@ -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;
};

View file

@ -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

View file

@ -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