renderer: added new customization options to the blur shaders (#3650)

Adds to `decoration:blur:` `vibrancy` and `vibrancy_darkness`
This commit is contained in:
Visual-Dawg 2023-11-06 20:49:03 +02:00 committed by GitHub
parent a1b7a5a53d
commit 29e0a7112e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 266 additions and 80 deletions

View file

@ -63,6 +63,8 @@ decoration {
enabled = true
size = 3
passes = 1
vibrancy = 0.1696
}
drop_shadow = true

View file

@ -160,9 +160,11 @@ void CConfigManager::setDefaultVars() {
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:blur:brightness"].floatValue = 1.0;
configValues["decoration:blur:vibrancy"].floatValue = 0.1696;
configValues["decoration:blur:vibrancy_darkness"].floatValue = 0.0;
configValues["decoration:blur:noise"].floatValue = 0.0117;
configValues["decoration:blur:special"].intValue = 0;
configValues["decoration:active_opacity"].floatValue = 1;
configValues["decoration:inactive_opacity"].floatValue = 1;

View file

@ -316,6 +316,9 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shBLUR1.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shBLUR1.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel = glGetUniformLocation(prog, "halfpixel");
m_RenderData.pCurrentMonData->m_shBLUR1.passes = glGetUniformLocation(prog, "passes");
m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy = glGetUniformLocation(prog, "vibrancy");
m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy_darkness = glGetUniformLocation(prog, "vibrancy_darkness");
prog = createProgram(TEXVERTSRC, FRAGBLUR2);
m_RenderData.pCurrentMonData->m_shBLUR2.program = prog;
@ -327,15 +330,23 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shBLUR2.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shBLUR2.halfpixel = glGetUniformLocation(prog, "halfpixel");
prog = createProgram(TEXVERTSRC, FRAGBLURPREPARE);
m_RenderData.pCurrentMonData->m_shBLURPREPARE.program = prog;
m_RenderData.pCurrentMonData->m_shBLURPREPARE.tex = glGetUniformLocation(prog, "tex");
m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast = glGetUniformLocation(prog, "contrast");
m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness = glGetUniformLocation(prog, "brightness");
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");
m_RenderData.pCurrentMonData->m_shBLURFINISH.noise = glGetUniformLocation(prog, "noise");
prog = createProgram(QUADVERTSRC, FRAGSHADOW);
m_RenderData.pCurrentMonData->m_shSHADOW.program = prog;
@ -914,6 +925,8 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
// 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 PBLURVIBRANCY = &g_pConfigManager->getConfigValuePtr("decoration:blur:vibrancy")->floatValue;
static auto* const PBLURVIBRANCYDARKNESS = &g_pConfigManager->getConfigValuePtr("decoration:blur:vibrancy_darkness")->floatValue;
// prep damage
CRegion damage{*originalDamage};
@ -927,7 +940,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
CFramebuffer* currentRenderToFB = PMIRRORFB;
// begin with color adjustments
// Begin with base color adjustments - global brightness and contrast
// TODO: make this a part of the first pass maybe to save on a drawcall?
{
static auto* const PBLURCONTRAST = &g_pConfigManager->getConfigValuePtr("decoration:blur:contrast")->floatValue;
@ -941,24 +954,23 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glTexParameteri(m_RenderData.pCurrentMonData->primaryFB.m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program);
glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program);
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.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.brightness, *PBLURBRIGHTNESS);
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST);
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS);
glUniform1i(m_RenderData.pCurrentMonData->m_shBLURPREPARE.tex, 0);
glUniform1i(m_RenderData.pCurrentMonData->m_shBLURFINISH.tex, 0);
glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
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);
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib);
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib);
if (!damage.empty()) {
for (auto& RECT : damage.getRects()) {
@ -967,8 +979,8 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
}
}
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib);
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib);
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib);
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib);
currentRenderToFB = PMIRRORSWAPFB;
}
@ -996,10 +1008,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a
if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1)
if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1) {
glUniform2f(m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f),
0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f));
else
glUniform1i(m_RenderData.pCurrentMonData->m_shBLUR1.passes, *PBLURPASSES);
glUniform1f(m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy, *PBLURVIBRANCY);
glUniform1f(m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy_darkness, *PBLURVIBRANCYDARKNESS);
} else
glUniform2f(m_RenderData.pCurrentMonData->m_shBLUR2.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f),
0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f));
glUniform1i(pShader->tex, 0);
@ -1045,9 +1060,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up
}
// finalize with noise
// finalize the image
{
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();
@ -1069,6 +1085,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE);
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness, *PBLURBRIGHTNESS);
glUniform1i(m_RenderData.pCurrentMonData->m_shBLURFINISH.tex, 0);

View file

@ -64,6 +64,7 @@ struct SMonitorRenderData {
CShader m_shEXT;
CShader m_shBLUR1;
CShader m_shBLUR2;
CShader m_shBLURPREPARE;
CShader m_shBLURFINISH;
CShader m_shSHADOW;
CShader m_shBORDER1;

View file

@ -46,9 +46,17 @@ class CShader {
GLint distort = -1;
GLint output = -1;
GLint noise = -1;
// Blur prepare
GLint contrast = -1;
// Blur
GLint passes = -1; // Used by `vibrancy`
GLint vibrancy = -1;
GLint vibrancy_darkness = -1;
// Blur finish
GLint brightness = -1;
GLint noise = -1;
GLint getUniformLocation(const std::string&);

View file

@ -186,6 +186,110 @@ uniform sampler2D tex;
uniform float radius;
uniform vec2 halfpixel;
uniform int passes;
uniform float vibrancy;
uniform float vibrancy_darkness;
// see http://alienryderflex.com/hsp.html
const float Pr = 0.299;
const float Pg = 0.587;
const float Pb = 0.114;
// Y is "v" ( brightness ). X is "s" ( saturation )
// see https://www.desmos.com/3d/a88652b9a4
// Determines if high brightness or high saturation is more important
const float a = 0.93;
const float b = 0.11;
const float c = 0.66; // Determines the smoothness of the transition of unboosted to boosted colors
//
// http://www.flong.com/archive/texts/code/shapers_circ/
float doubleCircleSigmoid(float x, float a) {
float min_param_a = 0.0;
float max_param_a = 1.0;
a = max(min_param_a, min(max_param_a, a));
float y = .0;
if (x <= a) {
y = a - sqrt(a * a - x * x);
} else {
y = a + sqrt(pow(1. - a, 2.) - pow(x - 1., 2.));
}
return y;
}
vec3 rgb2hsl(vec3 col) {
float red = col.r;
float green = col.g;
float blue = col.b;
float minc = min(col.r, min(col.g, col.b));
float maxc = max(col.r, max(col.g, col.b));
float delta = maxc - minc;
float lum = (minc + maxc) * 0.5;
float sat = 0.0;
float hue = 0.0;
if (lum > 0.0 && lum < 1.0) {
float mul = (lum < 0.5) ? (lum) : (1.0 - lum);
sat = delta / (mul * 2.0);
}
vec3 masks = vec3((maxc == red && maxc != green) ? 1.0 : 0.0, (maxc == green && maxc != blue) ? 1.0 : 0.0, (maxc == blue && maxc != red) ? 1.0 : 0.0);
vec3 adds = vec3(((green - blue) / delta), 2.0 + ((blue - red) / delta), 4.0 + ((red - green) / delta));
float deltaGtz = (delta > 0.0) ? 1.0 : 0.0;
hue += dot(adds, masks);
hue *= deltaGtz;
hue /= 6.0;
if (hue < 0.0)
hue += 1.0;
return vec3(hue, sat, lum);
}
vec3 hsl2rgb(vec3 col) {
const float onethird = 1.0 / 3.0;
const float twothird = 2.0 / 3.0;
const float rcpsixth = 6.0;
float hue = col.x;
float sat = col.y;
float lum = col.z;
vec3 xt = vec3(rcpsixth * (hue - twothird), 0.0, rcpsixth * (1.0 - hue));
if (hue < twothird) {
xt.r = 0.0;
xt.g = rcpsixth * (twothird - hue);
xt.b = rcpsixth * (hue - onethird);
}
if (hue < onethird) {
xt.r = rcpsixth * (onethird - hue);
xt.g = rcpsixth * hue;
xt.b = 0.0;
}
xt = min(xt, 1.0);
float sat2 = 2.0 * sat;
float satinv = 1.0 - sat;
float luminv = 1.0 - lum;
float lum2m1 = (2.0 * lum) - 1.0;
vec3 ct = (sat2 * xt) + satinv;
vec3 rgb;
if (lum >= 0.5)
rgb = (luminv * ct) + lum2m1;
else
rgb = lum * ct;
return rgb;
}
void main() {
vec2 uv = v_texcoord * 2.0;
@ -196,7 +300,28 @@ void main() {
sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius);
sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius);
gl_FragColor = sum / 8.0;
vec4 color = sum / 8.0;
if (vibrancy == 0.0) {
gl_FragColor = color;
} else {
// Invert it so that it correctly maps to the config setting
float vibrancy_darkness1 = 1.0 - vibrancy_darkness;
// Decrease the RGB components based on their perceived brightness, to prevent visually dark colors from overblowing the rest.
vec3 hsl = rgb2hsl(color.rgb);
// Calculate perceived brightness, as not boost visually dark colors like deep blue as much as equally saturated yellow
float perceivedBrightness = doubleCircleSigmoid(sqrt(color.r * color.r * Pr + color.g * color.g * Pg + color.b * color.b * Pb), 0.8 * vibrancy_darkness1);
float b1 = b * vibrancy_darkness1;
float boostBase = hsl[1] > 0.0 ? smoothstep(b1 - c * 0.5, b1 + c * 0.5, 1.0 - (pow(1.0 - hsl[1] * cos(a), 2.0) + pow(1.0 - perceivedBrightness * sin(a), 2.0))) : 0.0;
float saturation = clamp(hsl[1] + (boostBase * vibrancy) / float(passes), 0.0, 1.0);
vec3 newColor = hsl2rgb(vec3(hsl[0], saturation, hsl[2]));
gl_FragColor = vec4(newColor, color[3]);
}
}
)#";
@ -226,12 +351,43 @@ void main() {
}
)#";
inline const std::string FRAGBLURFINISH = R"#(
inline const std::string FRAGBLURPREPARE = R"#(
precision mediump float;
varying vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
uniform float contrast;
uniform float brightness;
float gain(float x, float k) {
float a = 0.5 * pow(2.0 * ((x < 0.5) ? x : 1.0 - x), k);
return (x < 0.5) ? a : 1.0 - a;
}
void main() {
vec4 pixColor = texture2D(tex, v_texcoord);
// contrast
if (contrast != 1.0) {
pixColor.r = gain(pixColor.r, contrast);
pixColor.g = gain(pixColor.g, contrast);
pixColor.b = gain(pixColor.b, contrast);
}
// brightness
if (brightness > 1.0) {
pixColor.rgb *= brightness;
}
gl_FragColor = pixColor;
}
)#";
inline const std::string FRAGBLURFINISH = R"#(
precision mediump float;
varying vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
uniform float noise;
uniform float brightness;
@ -242,19 +398,19 @@ float hash(vec2 p) {
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;
// brightness
if (brightness < 1.0) {
pixColor.rgb *= brightness;
}
gl_FragColor = pixColor;
})#";
}
)#";
inline const std::string TEXFRAGSRCEXT = R"#(
#extension GL_OES_EGL_image_external : require