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")) if (Settings::getInstance()->getBool("MediaViewerVideoScanlines"))
shaders = Renderer::Shader::SCANLINES; shaders = Renderer::Shader::SCANLINES;
if (Settings::getInstance()->getBool("MediaViewerVideoBlur")) { if (Settings::getInstance()->getBool("MediaViewerVideoBlur")) {
shaders |= Renderer::Shader::BLUR_HORIZONTAL; if (mRenderer->getScreenRotation() == 90 || mRenderer->getScreenRotation() == 270)
const float resolutionModifier {mRenderer->getScreenResolutionModifier()}; shaders |= Renderer::Shader::BLUR_VERTICAL;
// clang-format off else
if (resolutionModifier < 1) shaders |= Renderer::Shader::BLUR_HORIZONTAL;
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) if (shaders != 0)
mRenderer->shaderPostprocessing(shaders, videoParameters); mRenderer->shaderPostprocessing(shaders, videoParameters);
} }

View file

@ -324,26 +324,17 @@ void Screensaver::renderScreensaver()
if (Settings::getInstance()->getBool("ScreensaverVideoScanlines")) if (Settings::getInstance()->getBool("ScreensaverVideoScanlines"))
shaders = Renderer::Shader::SCANLINES; shaders = Renderer::Shader::SCANLINES;
if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) { if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) {
shaders |= Renderer::Shader::BLUR_HORIZONTAL; if (mRenderer->getScreenRotation() == 90 ||
const float resolutionModifier {mRenderer->getScreenResolutionModifier()}; mRenderer->getScreenRotation() == 270)
// clang-format off shaders |= Renderer::Shader::BLUR_VERTICAL;
if (resolutionModifier < 1) else
videoParameters.blurPasses = 2; // Below 1080 shaders |= Renderer::Shader::BLUR_HORIZONTAL;
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) if (shaders != 0)
mRenderer->shaderPostprocessing(shaders, videoParameters); mRenderer->shaderPostprocessing(shaders, videoParameters);

View file

@ -513,23 +513,10 @@ void Window::render()
// degrees. // degrees.
if (Settings::getInstance()->getBool("MenuBlurBackground") || if (Settings::getInstance()->getBool("MenuBlurBackground") ||
mRenderer->getScreenRotation() == 90 || mRenderer->getScreenRotation() == 270) { mRenderer->getScreenRotation() == 90 || mRenderer->getScreenRotation() == 270) {
const float resolutionModifier {mRenderer->getScreenResolutionModifier()};
// clang-format off // We run two passes to make the blur smoother.
if (resolutionModifier < 1) backgroundParameters.blurPasses = 2;
backgroundParameters.blurPasses = 2; // Below 1080 backgroundParameters.blurStrength = 1.35f;
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
// Also dim the background slightly. // Also dim the background slightly.
if (Settings::getInstance()->getString("MenuColorScheme") == "light") if (Settings::getInstance()->getString("MenuColorScheme") == "light")

View file

@ -67,6 +67,7 @@ public:
float saturation; float saturation;
float dimming; float dimming;
float reflectionsFalloff; float reflectionsFalloff;
float blurStrength;
unsigned int shaders; unsigned int shaders;
unsigned int shaderFlags; unsigned int shaderFlags;
@ -76,6 +77,7 @@ public:
, saturation {1.0f} , saturation {1.0f}
, dimming {1.0f} , dimming {1.0f}
, reflectionsFalloff {0.0f} , reflectionsFalloff {0.0f}
, blurStrength {0.0f}
, shaders {0} , shaders {0}
, shaderFlags {0} , shaderFlags {0}
{ {
@ -94,6 +96,7 @@ public:
, saturation {1.0f} , saturation {1.0f}
, dimming {1.0f} , dimming {1.0f}
, reflectionsFalloff {0.0f} , reflectionsFalloff {0.0f}
, blurStrength {0.0f}
, shaders {0} , shaders {0}
, shaderFlags {0} , shaderFlags {0}
{ {
@ -104,6 +107,7 @@ public:
float opacity; float opacity;
float saturation; float saturation;
float dimming; float dimming;
float blurStrength;
unsigned int blurPasses; unsigned int blurPasses;
unsigned int shaders; unsigned int shaders;
@ -111,6 +115,7 @@ public:
: opacity {1.0f} : opacity {1.0f}
, saturation {1.0f} , saturation {1.0f}
, dimming {1.0f} , dimming {1.0f}
, blurStrength {0.0f}
, blurPasses {1} , blurPasses {1}
, shaders {0} , shaders {0}
{ {

View file

@ -294,9 +294,9 @@ bool RendererOpenGL::createContext()
textureHeight = static_cast<unsigned int>(getScreenWidth()); 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); textureHeight, nullptr);
mPostProcTexture2 = createTexture(TextureType::BGRA, false, false, false, false, textureWidth, mPostProcTexture2 = createTexture(TextureType::BGRA, false, true, false, false, textureWidth,
textureHeight, nullptr); textureHeight, nullptr);
// Attach textures to the shader framebuffers. // Attach textures to the shader framebuffers.
@ -522,7 +522,8 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
mBlurHorizontalShader->setAttribPointers(); mBlurHorizontalShader->setAttribPointers();
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW)); GL_DYNAMIC_DRAW));
mBlurHorizontalShader->setTextureSize({width, height}); mBlurHorizontalShader->setBlurStrength((vertices->blurStrength / getScreenWidth()) *
getScreenResolutionModifier());
mBlurHorizontalShader->setFlags(vertices->shaderFlags); mBlurHorizontalShader->setFlags(vertices->shaderFlags);
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
mLastShader = mBlurHorizontalShader; mLastShader = mBlurHorizontalShader;
@ -540,7 +541,8 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
mBlurVerticalShader->setAttribPointers(); mBlurVerticalShader->setAttribPointers();
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW)); GL_DYNAMIC_DRAW));
mBlurVerticalShader->setTextureSize({width, height}); mBlurVerticalShader->setBlurStrength((vertices->blurStrength / getScreenHeight()) *
getScreenResolutionModifier());
mBlurVerticalShader->setFlags(vertices->shaderFlags); mBlurVerticalShader->setFlags(vertices->shaderFlags);
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
mLastShader = mBlurVerticalShader; mLastShader = mBlurVerticalShader;
@ -621,6 +623,7 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
vertices->opacity = parameters.opacity; vertices->opacity = parameters.opacity;
vertices->saturation = parameters.saturation; vertices->saturation = parameters.saturation;
vertices->dimming = parameters.dimming; vertices->dimming = parameters.dimming;
vertices->blurStrength = parameters.blurStrength;
vertices->shaderFlags = ShaderFlags::POST_PROCESSING | ShaderFlags::PREMULTIPLIED; vertices->shaderFlags = ShaderFlags::POST_PROCESSING | ShaderFlags::PREMULTIPLIED;
if (screenRotation == 90 || screenRotation == 270) if (screenRotation == 90 || screenRotation == 270)

View file

@ -24,6 +24,7 @@ ShaderOpenGL::ShaderOpenGL()
, mShaderSaturation {0} , mShaderSaturation {0}
, mShaderDimming {0} , mShaderDimming {0}
, mShaderReflectionsFalloff {0} , mShaderReflectionsFalloff {0}
, mBlurStrength {0}
, mShaderFlags {0} , mShaderFlags {0}
{ {
} }
@ -128,6 +129,7 @@ void ShaderOpenGL::getVariableLocations(GLuint programID)
mShaderSaturation = glGetUniformLocation(mProgramID, "saturation"); mShaderSaturation = glGetUniformLocation(mProgramID, "saturation");
mShaderDimming = glGetUniformLocation(mProgramID, "dimming"); mShaderDimming = glGetUniformLocation(mProgramID, "dimming");
mShaderReflectionsFalloff = glGetUniformLocation(mProgramID, "reflectionsFalloff"); mShaderReflectionsFalloff = glGetUniformLocation(mProgramID, "reflectionsFalloff");
mBlurStrength = glGetUniformLocation(mProgramID, "blurStrength");
mShaderFlags = glGetUniformLocation(mProgramID, "shaderFlags"); mShaderFlags = glGetUniformLocation(mProgramID, "shaderFlags");
} }
@ -198,6 +200,12 @@ void ShaderOpenGL::setReflectionsFalloff(GLfloat falloff)
GL_CHECK_ERROR(glUniform1f(mShaderReflectionsFalloff, 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) void ShaderOpenGL::setFlags(GLuint flags)
{ {
if (mShaderFlags != -1) if (mShaderFlags != -1)

View file

@ -74,6 +74,7 @@ public:
void setSaturation(GLfloat saturation); void setSaturation(GLfloat saturation);
void setDimming(GLfloat dimming); void setDimming(GLfloat dimming);
void setReflectionsFalloff(GLfloat falloff); void setReflectionsFalloff(GLfloat falloff);
void setBlurStrength(GLfloat blurStrength);
void setFlags(GLuint flags); void setFlags(GLuint flags);
// Sets the shader program to use the loaded shaders. // Sets the shader program to use the loaded shaders.
void activateShaders(); void activateShaders();
@ -101,6 +102,7 @@ private:
GLint mShaderSaturation; GLint mShaderSaturation;
GLint mShaderDimming; GLint mShaderDimming;
GLint mShaderReflectionsFalloff; GLint mShaderReflectionsFalloff;
GLint mBlurStrength;
GLint mShaderFlags; GLint mShaderFlags;
}; };

View file

@ -1,14 +1,11 @@
// SPDX-License-Identifier: MIT
// //
// Implementation based on the article "Efficient Gaussian blur with linear sampling" // EmulationStation Desktop Edition
// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ // blur_horizontal.glsl
// 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
// //
// Taken from the RetroArch project and modified for ES-DE. // Horizontal gaussian blur.
// //
#define HW 1.00
// Vertex section of code: // Vertex section of code:
#if defined(VERTEX) #if defined(VERTEX)
@ -31,8 +28,8 @@ precision mediump float;
#endif #endif
uniform uint shaderFlags; uniform uint shaderFlags;
uniform vec2 textureSize;
uniform sampler2D textureSampler; uniform sampler2D textureSampler;
uniform float blurStrength;
in vec2 texCoord; in vec2 texCoord;
out vec4 FragColor; out vec4 FragColor;
@ -45,32 +42,48 @@ out vec4 FragColor;
void main() void main()
{ {
vec4 SourceSize; vec4 color = vec4(0.0);
vec2 PIXEL_SIZE; float hstep = 1.0f;
float vstep = 0.0f;
vec2 tc;
if (0x0u != (shaderFlags & 0x10u)) { if (0x0u != (shaderFlags & 0x10u)) {
SourceSize = vec4(textureSize.yx, 1.0 / textureSize.xy); // Screen rotated 90 or 270 degrees.
PIXEL_SIZE = vec2(SourceSize.w, SourceSize.z); tc = texCoord.yx;
} }
else { else {
SourceSize = vec4(textureSize.xy, 1.0 / textureSize.xy); tc = texCoord.xy;
PIXEL_SIZE = vec2(SourceSize.z, SourceSize.w);
} }
float sampleOffsets[5] = float[5](0.0, 1.4347826, 3.3478260, 5.2608695, 7.1739130); // 9-tap filter.
float sampleWeights[5] = color += texture(textureSampler,
float[5](0.16818994, 0.27276957, 0.11690125, 0.024067905, 0.0021112196); 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]; color += texture(textureSampler, vec2(tc.x, tc.y)) * 0.2270270270;
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];
}
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 #endif

View file

@ -1,14 +1,11 @@
// SPDX-License-Identifier: MIT
// //
// Implementation based on the article "Efficient Gaussian blur with linear sampling" // EmulationStation Desktop Edition
// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ // blur_vertical.glsl
// 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
// //
// Taken from the RetroArch project and modified for ES-DE. // Vertical gaussian blur.
// //
#define VW 1.00
// Vertex section of code: // Vertex section of code:
#if defined(VERTEX) #if defined(VERTEX)
@ -31,8 +28,8 @@ precision mediump float;
#endif #endif
uniform uint shaderFlags; uniform uint shaderFlags;
uniform vec2 textureSize;
uniform sampler2D textureSampler; uniform sampler2D textureSampler;
uniform float blurStrength;
in vec2 texCoord; in vec2 texCoord;
out vec4 FragColor; out vec4 FragColor;
@ -45,32 +42,48 @@ out vec4 FragColor;
void main() void main()
{ {
vec4 SourceSize; vec4 color = vec4(0.0);
vec2 PIXEL_SIZE; float hstep = 0.0f;
float vstep = 1.0f;
vec2 tc;
if (0x0u != (shaderFlags & 0x10u)) { if (0x0u != (shaderFlags & 0x10u)) {
SourceSize = vec4(textureSize.xy, 1.0 / textureSize.yx); // Screen rotated 90 or 270 degrees.
PIXEL_SIZE = vec2(SourceSize.w, SourceSize.z); tc = texCoord.yx;
} }
else { else {
SourceSize = vec4(textureSize.xy, 1.0 / textureSize.xy); tc = texCoord.xy;
PIXEL_SIZE = vec2(SourceSize.z, SourceSize.w);
} }
float sampleOffsets[5] = float[5](0.0, 1.4347826, 3.3478260, 5.2608695, 7.1739130); // 9-tap filter.
float sampleWeights[5] = color += texture(textureSampler,
float[5](0.16818994, 0.27276957, 0.11690125, 0.024067905, 0.0021112196); 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]; color += texture(textureSampler, vec2(tc.x, tc.y)) * 0.2270270270;
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];
}
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 #endif