feat: blur tweaks (#258)

This commit is contained in:
ozwaldorf 2024-01-03 12:38:44 -05:00 committed by GitHub
parent 1c5c60d928
commit 04b657b58c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 305 additions and 2 deletions

View file

@ -30,6 +30,10 @@ Sway is an incredible window manager, and certainly one of the most well establi
- `blur_xray enable|disable`: this will set floating windows to blur based on the background, not the windows below. You probably want to set this to `disable` :)
- `blur_passes <integer value 0 - 10>`
- `blur_radius <integer value 0 - 10>`
- `blur_noise <float value 0 - 1>` (**Note**: git only, percentage of noise to add)
- `blur_brightness <float value 0 - 2>` (**Note**: git only, percentage of original brightness to adjust)
- `blur_contrast <float value 0 - 2>` (**Note**: git only, percentage of original contrast to adjust)
- `blur_saturation <float value 0 - 2>` (**Note**: git only, percentage of original saturation to adjust)
+ Corner radius: `corner_radius <val>`
+ Window shadows:
- `shadows enable|disable`

View file

@ -115,8 +115,12 @@ sway_cmd cmd_bindgesture;
sway_cmd cmd_bindswitch;
sway_cmd cmd_bindsym;
sway_cmd cmd_blur;
sway_cmd cmd_blur_brightness;
sway_cmd cmd_blur_contrast;
sway_cmd cmd_blur_noise;
sway_cmd cmd_blur_passes;
sway_cmd cmd_blur_radius;
sway_cmd cmd_blur_saturation;
sway_cmd cmd_blur_xray;
sway_cmd cmd_border;
sway_cmd cmd_client_noop;

View file

@ -473,6 +473,10 @@ enum xwayland_mode {
struct blur_parameters {
int num_passes;
int radius;
float noise;
float brightness;
float contrast;
float saturation;
};
/**

View file

@ -47,6 +47,18 @@ struct blur_shader {
GLint halfpixel;
};
struct effects_shader {
GLuint program;
GLint proj;
GLint tex;
GLint pos_attrib;
GLint tex_attrib;
GLfloat noise;
GLfloat brightness;
GLfloat contrast;
GLfloat saturation;
};
struct box_shadow_shader {
GLuint program;
GLint proj;
@ -153,6 +165,7 @@ struct fx_renderer {
struct box_shadow_shader box_shadow;
struct blur_shader blur1;
struct blur_shader blur2;
struct effects_shader blur_effects;
struct corner_shader corner;
struct quad_shader quad;
struct rounded_quad_shader rounded_quad;
@ -211,7 +224,11 @@ void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *bo
const float matrix[static 9], int corner_radius, float blur_sigma);
void fx_render_blur(struct fx_renderer *renderer, const float matrix[static 9],
struct fx_framebuffer **buffer, struct blur_shader *shader, const struct wlr_box *box,
int blur_radius);
struct fx_framebuffer **buffer, struct blur_shader *shader,
const struct wlr_box *box, int blur_radius);
void fx_render_blur_effects(struct fx_renderer *renderer, const float matrix[static 9],
struct fx_framebuffer **buffer, float blur_noise, float blur_brightness,
float blur_contrast, float blur_saturation);
#endif

View file

@ -50,8 +50,12 @@ static const struct cmd_handler handlers[] = {
{ "bindswitch", cmd_bindswitch },
{ "bindsym", cmd_bindsym },
{ "blur", cmd_blur },
{ "blur_brightness", cmd_blur_brightness },
{ "blur_contrast", cmd_blur_contrast },
{ "blur_noise", cmd_blur_noise },
{ "blur_passes", cmd_blur_passes },
{ "blur_radius", cmd_blur_radius },
{ "blur_saturation", cmd_blur_saturation },
{ "blur_xray", cmd_blur_xray },
{ "client.background", cmd_client_noop },
{ "client.focused", cmd_client_focused },

View file

@ -0,0 +1,28 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"
struct cmd_results *cmd_blur_brightness(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "blur_brightness", EXPECTED_EQUAL_TO, 1))) {
return error;
}
char *inv;
float value = strtof(argv[0], &inv);
if (*inv != '\0' || value < 0 || value > 2) {
return cmd_results_new(CMD_FAILURE, "Invalid brightness specified");
}
config->blur_params.brightness = value;
struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) {
output->renderer->blur_buffer_dirty = true;
output_damage_whole(output);
}
}
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -0,0 +1,28 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"
struct cmd_results *cmd_blur_contrast(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "blur_contrast", EXPECTED_EQUAL_TO, 1))) {
return error;
}
char *inv;
float value = strtof(argv[0], &inv);
if (*inv != '\0' || value < 0 || value > 2) {
return cmd_results_new(CMD_FAILURE, "Invalid brightness specified");
}
config->blur_params.contrast = value;
struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) {
output->renderer->blur_buffer_dirty = true;
output_damage_whole(output);
}
}
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -0,0 +1,28 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"
struct cmd_results *cmd_blur_noise(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "blur_noise", EXPECTED_EQUAL_TO, 1))) {
return error;
}
char *inv;
float value = strtof(argv[0], &inv);
if (*inv != '\0' || value < 0 || value > 1) {
return cmd_results_new(CMD_FAILURE, "Invalid noise specified");
}
config->blur_params.noise = value;
struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) {
output->renderer->blur_buffer_dirty = true;
output_damage_whole(output);
}
}
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -0,0 +1,29 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"
struct cmd_results *cmd_blur_saturation(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "blur_saturation", EXPECTED_EQUAL_TO, 1))) {
return error;
}
char *inv;
float value = strtof(argv[0], &inv);
if (*inv != '\0' || value < 0 || value > 2) {
return cmd_results_new(CMD_FAILURE, "Invalid saturation specified");
}
config->blur_params.saturation = value;
struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) {
output->renderer->blur_buffer_dirty = true;
output_damage_whole(output);
}
}
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -360,6 +360,10 @@ static void config_defaults(struct sway_config *config) {
config->blur_xray = false;
config->blur_params.num_passes = 2;
config->blur_params.radius = 5;
config->blur_params.noise = 0.02;
config->blur_params.brightness = 0.9;
config->blur_params.contrast = 0.9;
config->blur_params.saturation = 1.1;
config->titlebar_separator = true;
config->scratchpad_minimize = false;

View file

@ -23,6 +23,7 @@
// shaders
#include "blur1_frag_src.h"
#include "blur2_frag_src.h"
#include "blur_effects_frag_src.h"
#include "box_shadow_frag_src.h"
#include "common_vert_src.h"
#include "corner_frag_src.h"
@ -107,6 +108,25 @@ static bool link_blur_program(struct blur_shader *shader, const char *shader_pro
return true;
}
static bool link_blur_effects_program(struct effects_shader *shader, const char *shader_program) {
GLuint prog;
shader->program = prog = link_program(shader_program);
if (!shader->program) {
return false;
}
shader->proj = glGetUniformLocation(prog, "proj");
shader->tex = glGetUniformLocation(prog, "tex");
shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->tex_attrib = glGetAttribLocation(prog, "texcoord");
shader->noise = glGetUniformLocation(prog, "noise");
shader->brightness = glGetUniformLocation(prog, "brightness");
shader->contrast = glGetUniformLocation(prog, "contrast");
shader->saturation = glGetUniformLocation(prog, "saturation");
return true;
}
static bool link_box_shadow_program(struct box_shadow_shader *shader) {
GLuint prog;
shader->program = prog = link_program(box_shadow_frag_src);
@ -305,6 +325,10 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl, struct wlr_output *w
if (!link_blur_program(&renderer->shaders.blur2, blur2_frag_src)) {
goto error;
}
// effects shader
if (!link_blur_effects_program(&renderer->shaders.blur_effects, blur_effects_frag_src)) {
goto error;
}
// box shadow shader
if (!link_box_shadow_program(&renderer->shaders.box_shadow)) {
goto error;
@ -365,6 +389,7 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl, struct wlr_output *w
error:
glDeleteProgram(renderer->shaders.blur1.program);
glDeleteProgram(renderer->shaders.blur2.program);
glDeleteProgram(renderer->shaders.blur_effects.program);
glDeleteProgram(renderer->shaders.box_shadow.program);
glDeleteProgram(renderer->shaders.corner.program);
glDeleteProgram(renderer->shaders.quad.program);
@ -899,3 +924,39 @@ void fx_render_blur(struct fx_renderer *renderer, const float matrix[static 9],
glDisableVertexAttribArray(shader->tex_attrib);
}
void fx_render_blur_effects(struct fx_renderer *renderer, const float matrix[static 9],
struct fx_framebuffer **buffer, float blur_noise, float blur_brightness,
float blur_contrast, float blur_saturation) {
struct effects_shader shader = renderer->shaders.blur_effects;
glEnable(GL_BLEND);
glActiveTexture(GL_TEXTURE0);
glBindTexture((*buffer)->texture.target, (*buffer)->texture.id);
glTexParameteri((*buffer)->texture.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(shader.program);
// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
// to GL_FALSE
float gl_matrix[9];
wlr_matrix_transpose(gl_matrix, matrix);
glUniformMatrix3fv(shader.proj, 1, GL_FALSE, gl_matrix);
glUniform1i(shader.tex, 0);
glUniform1f(shader.noise, blur_noise);
glUniform1f(shader.brightness, blur_brightness);
glUniform1f(shader.contrast, blur_contrast);
glUniform1f(shader.saturation, blur_saturation);
glVertexAttribPointer(shader.pos_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
glVertexAttribPointer(shader.tex_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
glEnableVertexAttribArray(shader.pos_attrib);
glEnableVertexAttribArray(shader.tex_attrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(shader.pos_attrib);
glDisableVertexAttribArray(shader.tex_attrib);
}

View file

@ -0,0 +1,54 @@
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D tex;
uniform float noise;
uniform float brightness;
uniform float contrast;
uniform float saturation;
mat4 brightnessMatrix() {
float b = brightness - 1.0;
return mat4(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
b, b, b, 1);
}
mat4 contrastMatrix() {
float t = (1.0 - contrast) / 2.0;
return mat4(contrast, 0, 0, 0,
0, contrast, 0, 0,
0, 0, contrast, 0,
t, t, t, 1);
}
mat4 saturationMatrix() {
vec3 luminance = vec3(0.3086, 0.6094, 0.0820);
float oneMinusSat = 1.0 - saturation;
vec3 red = vec3(luminance.x * oneMinusSat);
red+= vec3(saturation, 0, 0);
vec3 green = vec3(luminance.y * oneMinusSat);
green += vec3(0, saturation, 0);
vec3 blue = vec3(luminance.z * oneMinusSat);
blue += vec3(0, 0, saturation);
return mat4(red, 0,
green, 0,
blue, 0,
0, 0, 0, 1);
}
// Fast generative noise function
float hash(vec2 p) {
return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
}
void main() {
vec4 color = texture2D(tex, v_texcoord);
color *= brightnessMatrix() * contrastMatrix() * saturationMatrix();
float noiseHash = hash(v_texcoord);
float noiseAmount = (mod(noiseHash, 1.0) - 0.5);
color.rgb += noiseAmount * noise;
gl_FragColor = color;
}

View file

@ -3,6 +3,7 @@ embed = find_program('./embed.sh', native: true)
shaders = [
'blur1.frag',
'blur2.frag',
'blur_effects.frag',
'box_shadow.frag',
'common.vert',
'corner.frag',

View file

@ -258,6 +258,23 @@ struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct
&renderer->shaders.blur2, box, blur_radius);
}
float blur_noise = config->blur_params.noise;
float blur_brightness = config->blur_params.brightness;
float blur_contrast = config->blur_params.contrast;
float blur_saturation = config->blur_params.saturation;
if (pixman_region32_not_empty(&damage)) {
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; ++i) {
const pixman_box32_t box = rects[i];
struct wlr_box new_box = { box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1 };
fx_renderer_scissor(&new_box);
fx_render_blur_effects(renderer, gl_matrix, &current_buffer, blur_noise,
blur_brightness, blur_contrast, blur_saturation);
}
}
pixman_region32_fini(&tempDamage);
pixman_region32_fini(&damage);

View file

@ -53,9 +53,13 @@ sway_sources = files(
'commands/bar.c',
'commands/bind.c',
'commands/blur.c',
'commands/blur_brightness.c',
'commands/blur_contrast.c',
'commands/blur_passes.c',
'commands/blur_radius.c',
'commands/blur_xray.c',
'commands/blur_noise.c',
'commands/blur_saturation.c',
'commands/border.c',
'commands/client.c',
'commands/corner_radius.c',

View file

@ -707,6 +707,22 @@ The default colors are:
Adjusts the blur radius of windows between 0 (disabled) and 10
while 5 is the default value.
*blur_noise* <value>
Adjusts the percentage of noise applied to the blur between 0 and 1
while 0.02 (2%) is the default value.
*blur_brightness* <value>
Adjusts the percentage of brightness for the blur between 0 and 2
while 0.9 (90%) is the default value.
*blur_contrast* <value>
Adjusts the percentage of contrast for the blur between 0 and 2
while 0.9 (90%) is the default value.
*blur_saturation* <value>
Adjusts the percentage of saturation for the blur between 0 and 2
while 1.1 (110%) is the default value.
*default_border* normal|none|pixel [<n>]
Set default border style for new tiled windows.