Skip to content

Commit bef564e

Browse files
authored
Merge pull request #1518 from anthonyde/blur-noise
Add noise to blur shaders
2 parents e5bbe67 + 6ecf0ff commit bef564e

15 files changed

Lines changed: 188 additions & 47 deletions

File tree

include/picom/backend.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,30 @@ enum shader_attributes {
5454
SHADER_ATTRIBUTE_ANIMATED = 1,
5555
};
5656

57+
struct blur_args {
58+
int noise_radius;
59+
double noise_scale;
60+
};
61+
5762
struct gaussian_blur_args {
63+
struct blur_args base;
5864
int size;
5965
double deviation;
6066
};
6167

6268
struct box_blur_args {
69+
struct blur_args base;
6370
int size;
6471
};
6572

6673
struct kernel_blur_args {
74+
struct blur_args base;
6775
struct conv **kernels;
6876
int kernel_count;
6977
};
7078

7179
struct dual_kawase_blur_args {
80+
struct blur_args base;
7281
int size;
7382
int strength;
7483
};
@@ -433,7 +442,7 @@ struct backend_operations {
433442
/// Create a blur context that can be used to call `blur` for images with a
434443
/// specific format.
435444
void *(*create_blur_context)(backend_t *base, enum blur_method,
436-
enum backend_image_format format, void *args);
445+
enum backend_image_format format, struct blur_args *args);
437446
/// Destroy a blur context
438447
void (*destroy_blur_context)(backend_t *base, void *ctx);
439448
/// Get how many pixels outside of the blur area is needed for blur

man/picom.1.adoc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ OPTIONS
178178
*--blur-method*, *--blur-size*, *--blur-deviation*, *--blur-strength*::
179179
Parameters for background blurring, see the xref:_blur[*BLUR*] section for more information.
180180

181+
*--blur-noise-radius*, *--blur-noise-scale*::
182+
Parameters for blur noise. See the xref:_blur[*BLUR*] section for more information.
183+
181184
*--blur-background*::
182185
Blur background of semi-transparent / ARGB windows. Bad in performance, with driver-dependent behavior. The name of the switch may change without prior notifications.
183186

@@ -917,6 +920,14 @@ Available options of the _blur_ section are: ::
917920
*kernel*:::
918921
A string. The kernel to use for the _kernel_ blur method, specified in the same format as the *--blur-kern* option. Corresponds to the *--blur-kern* command line option.
919922
923+
If blur is enabled, noise can be configured with the following options: ::
924+
925+
*noise-radius*:::
926+
An integer. The maximum displacement of background pixels when applying noise. Corresponds to the *--blur-noise-radius* command line option. If set to zero, noise is disabled (default: 0).
927+
928+
*noise-scale*:::
929+
A floating point number. The size of noise features. Corresponds to the *--blur-noise-scale* command line option. If negative or zero, noise is disabled (default: 0.005).
930+
920931
SIGNALS
921932
-------
922933

src/backend/backend_common.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -252,20 +252,23 @@ generate_gaussian_blur_kernel(struct gaussian_blur_args *args, int *kernel_count
252252

253253
/// Generate blur kernels for gaussian and box blur methods. Generated kernel is not
254254
/// normalized, and the center element will always be 1.
255-
struct conv **generate_blur_kernel(enum blur_method method, void *args, int *kernel_count) {
255+
struct conv **
256+
generate_blur_kernel(enum blur_method method, struct blur_args *args, int *kernel_count) {
256257
switch (method) {
257-
case BLUR_METHOD_BOX: return generate_box_blur_kernel(args, kernel_count);
258+
case BLUR_METHOD_BOX:
259+
return generate_box_blur_kernel((struct box_blur_args *)args, kernel_count);
258260
case BLUR_METHOD_GAUSSIAN:
259-
return generate_gaussian_blur_kernel(args, kernel_count);
261+
return generate_gaussian_blur_kernel((struct gaussian_blur_args *)args,
262+
kernel_count);
260263
default: break;
261264
}
262265
return NULL;
263266
}
264267

265268
/// Generate kernel parameters for dual-kawase blur method. Falls back on approximating
266269
/// standard gauss radius if strength is zero or below.
267-
struct dual_kawase_params *generate_dual_kawase_params(void *args) {
268-
struct dual_kawase_blur_args *blur_args = args;
270+
struct dual_kawase_params *generate_dual_kawase_params(struct blur_args *args) {
271+
auto blur_args = (struct dual_kawase_blur_args *)args;
269272
static const struct {
270273
int iterations; /// Number of down- and upsample iterations
271274
float offset; /// Sample offset in half-pixels

src/backend/backend_common.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ struct conv;
1515
struct backend_base;
1616
struct backend_operations;
1717
struct x_connection;
18+
struct blur_args;
1819

1920
struct dual_kawase_params {
2021
/// Number of downsample passes
@@ -33,7 +34,8 @@ solid_picture(struct x_connection *, bool argb, double a, double r, double g, do
3334

3435
void init_backend_base(struct backend_base *base, session_t *ps);
3536

36-
struct conv **generate_blur_kernel(enum blur_method method, void *args, int *kernel_count);
37-
struct dual_kawase_params *generate_dual_kawase_params(void *args);
37+
struct conv **
38+
generate_blur_kernel(enum blur_method method, struct blur_args *args, int *kernel_count);
39+
struct dual_kawase_params *generate_dual_kawase_params(struct blur_args *args);
3840

3941
uint32_t backend_no_quirks(struct backend_base *base attr_unused);

src/backend/dummy/dummy.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ image_handle dummy_back_buffer(struct backend_base *base) {
179179
void *dummy_create_blur_context(struct backend_base *base attr_unused,
180180
enum blur_method method attr_unused,
181181
enum backend_image_format format attr_unused,
182-
void *args attr_unused) {
182+
struct blur_args *args attr_unused) {
183183
static int dummy_context;
184184
return &dummy_context;
185185
}

src/backend/gl/blur.c

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ struct gl_blur_context {
3737
/// How much do we need to resize the damaged region for blurring.
3838
int resize_width, resize_height;
3939

40+
int noise_radius;
41+
float noise_scale;
42+
4043
int npasses;
4144

4245
enum backend_image_format format;
@@ -82,12 +85,8 @@ gl_kernel_blur(double opacity, struct gl_blur_context *bctx,
8285
glBindTexture(GL_TEXTURE_2D, src_texture);
8386
glBindSampler(0, blur_sampler);
8487
glUseProgram(p->prog);
85-
if (p->uniform_bitmask & (1 << UNIFORM_PIXEL_NORM_LOC)) {
86-
// If the last pass is a trivial blend pass, it will not have
87-
// pixel_norm.
88-
glUniform2f(UNIFORM_PIXEL_NORM_LOC, 1.0F / (GLfloat)tex_width,
89-
1.0F / (GLfloat)tex_height);
90-
}
88+
glUniform2f(UNIFORM_PIXEL_NORM_LOC, 1.0F / (GLfloat)tex_width,
89+
1.0F / (GLfloat)tex_height);
9190

9291
glActiveTexture(GL_TEXTURE1);
9392
glBindTexture(GL_TEXTURE_2D, default_mask);
@@ -118,6 +117,8 @@ gl_kernel_blur(double opacity, struct gl_blur_context *bctx,
118117
}
119118

120119
glUniform1f(UNIFORM_OPACITY_LOC, 1.0F);
120+
glUniform1i(UNIFORM_BLUR_NOISE_RADIUS_LOC, 0);
121+
glUniform1f(UNIFORM_BLUR_NOISE_SCALE_LOC, 0.0F);
121122
} else {
122123
// last pass, draw directly into the back buffer, with origin
123124
// regions. And apply mask if requested
@@ -139,6 +140,8 @@ gl_kernel_blur(double opacity, struct gl_blur_context *bctx,
139140
glBindFramebuffer(GL_FRAMEBUFFER, target_fbo);
140141

141142
glUniform1f(UNIFORM_OPACITY_LOC, (float)opacity);
143+
glUniform1i(UNIFORM_BLUR_NOISE_RADIUS_LOC, bctx->noise_radius);
144+
glUniform1f(UNIFORM_BLUR_NOISE_SCALE_LOC, bctx->noise_scale);
142145
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
143146
}
144147

@@ -224,6 +227,8 @@ bool gl_dual_kawase_blur(double opacity, struct gl_blur_context *bctx,
224227
glUniform1f(UNIFORM_MASK_CORNER_RADIUS_LOC, 0.0F);
225228
glUniform2f(UNIFORM_MASK_SCALE_LOC, 1.0F, 1.0F);
226229
glUniform1f(UNIFORM_OPACITY_LOC, 1.0F);
230+
glUniform1i(UNIFORM_BLUR_NOISE_RADIUS_LOC, 0);
231+
glUniform1f(UNIFORM_BLUR_NOISE_SCALE_LOC, 0.0F);
227232

228233
for (int i = iterations - 1; i >= 0; --i) {
229234
// Scale output width / height back by two in each iteration
@@ -267,6 +272,8 @@ bool gl_dual_kawase_blur(double opacity, struct gl_blur_context *bctx,
267272
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target_fbo);
268273

269274
glUniform1f(UNIFORM_OPACITY_LOC, (GLfloat)opacity);
275+
glUniform1i(UNIFORM_BLUR_NOISE_RADIUS_LOC, bctx->noise_radius);
276+
glUniform1f(UNIFORM_BLUR_NOISE_SCALE_LOC, bctx->noise_scale);
270277
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
271278
}
272279

@@ -534,18 +541,22 @@ bool gl_create_kernel_blur_context(void *blur_context, GLfloat *projection,
534541

535542
// clang-format off
536543
static const char *FRAG_SHADER_BLUR = GLSL(330,
537-
%s\n // other extension pragmas
538544
layout(location = UNIFORM_TEX_SRC_LOC)
539545
uniform sampler2D tex_src;
540546
layout(location = UNIFORM_PIXEL_NORM_LOC)
541547
uniform vec2 pixel_norm;
542548
layout(location = UNIFORM_OPACITY_LOC)
543549
uniform float opacity;
550+
layout(location = UNIFORM_BLUR_NOISE_RADIUS_LOC)
551+
uniform int noise_radius;
552+
layout(location = UNIFORM_BLUR_NOISE_SCALE_LOC)
553+
uniform float noise_scale;
544554
in vec2 texcoord;
545555
out vec4 out_color;
546556
float mask_factor();
557+
vec2 perturb(vec2, float, float);
547558
void main() {
548-
vec2 uv = texcoord * pixel_norm;
559+
vec2 uv = perturb(texcoord, noise_radius, noise_scale) * pixel_norm;
549560
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
550561
%s //body of the convolution
551562
out_color = sum / float(%.7g) * opacity * mask_factor();
@@ -557,7 +568,6 @@ bool gl_create_kernel_blur_context(void *blur_context, GLfloat *projection,
557568
// clang-format on
558569

559570
const char *shader_add = FRAG_SHADER_BLUR_ADD;
560-
char *extension = strdup("");
561571

562572
for (int i = 0; i < nkernels; i++) {
563573
auto kern = kernels[i];
@@ -628,27 +638,25 @@ bool gl_create_kernel_blur_context(void *blur_context, GLfloat *projection,
628638
}
629639

630640
auto pass = ctx->blur_shader + i;
631-
size_t shader_len = strlen(FRAG_SHADER_BLUR) + strlen(extension) +
632-
strlen(shader_body) + 10 /* sum */ +
633-
1 /* null terminator */;
641+
size_t shader_len = strlen(FRAG_SHADER_BLUR) + strlen(shader_body) +
642+
10 /* sum */ + 1 /* null terminator */;
634643
char *shader_str = ccalloc(shader_len, char);
635-
auto real_shader_len = snprintf(shader_str, shader_len, FRAG_SHADER_BLUR,
636-
extension, shader_body, sum);
644+
auto real_shader_len =
645+
snprintf(shader_str, shader_len, FRAG_SHADER_BLUR, shader_body, sum);
637646
CHECK(real_shader_len >= 0);
638647
CHECK((size_t)real_shader_len < shader_len);
639648
free(shader_body);
640649

641650
// Build program
642651
pass->prog = gl_create_program_from_strv(
643652
(const char *[]){vertex_shader, NULL},
644-
(const char *[]){shader_str, scaled_masking_glsl, NULL});
653+
(const char *[]){shader_str, scaled_masking_glsl, perturb_glsl, NULL});
645654
free(shader_str);
646655
if (!pass->prog) {
647656
log_error("Failed to create GLSL program.");
648657
success = false;
649658
goto out;
650659
}
651-
pass->uniform_bitmask = 1 << UNIFORM_PIXEL_NORM_LOC;
652660
glBindFragDataLocation(pass->prog, 0, "out_color");
653661

654662
// Setup projection matrix
@@ -666,7 +674,8 @@ bool gl_create_kernel_blur_context(void *blur_context, GLfloat *projection,
666674
auto pass = &ctx->blur_shader[1];
667675
pass->prog = gl_create_program_from_strv(
668676
(const char *[]){vertex_shader, NULL},
669-
(const char *[]){blend_with_mask_frag, scaled_masking_glsl, NULL});
677+
(const char *[]){blend_with_mask_frag, scaled_masking_glsl,
678+
perturb_glsl, NULL});
670679

671680
// Setup projection matrix
672681
glUseProgram(pass->prog);
@@ -688,7 +697,6 @@ bool gl_create_kernel_blur_context(void *blur_context, GLfloat *projection,
688697
free(kernels);
689698
}
690699

691-
free(extension);
692700
// Restore LC_NUMERIC
693701
setlocale(LC_NUMERIC, lc_numeric_old);
694702
free(lc_numeric_old);
@@ -784,12 +792,17 @@ bool gl_create_dual_kawase_blur_context(void *blur_context, GLfloat *projection,
784792
uniform vec2 pixel_norm;
785793
layout(location = UNIFORM_OPACITY_LOC)
786794
uniform float opacity;
795+
layout(location = UNIFORM_BLUR_NOISE_RADIUS_LOC)
796+
uniform int noise_radius;
797+
layout(location = UNIFORM_BLUR_NOISE_SCALE_LOC)
798+
uniform float noise_scale;
787799
in vec2 texcoord;
788800
out vec4 out_color;
789801
float mask_factor();
802+
vec2 perturb(vec2, float, float);
790803
void main() {
791804
vec2 offset = %.7g * pixel_norm;
792-
vec2 uv = texcoord * pixel_norm / (2 * scale);
805+
vec2 uv = perturb(texcoord, noise_radius, noise_scale) * pixel_norm / (2 * scale);
793806
vec4 sum = texture2D(tex_src, uv + vec2(-1.0, 0.0) * offset);
794807
sum += texture2D(tex_src, uv + vec2(-0.5, 0.5) * offset) * 2.0;
795808
sum += texture2D(tex_src, uv + vec2(0.0, 1.0) * offset);
@@ -815,7 +828,7 @@ bool gl_create_dual_kawase_blur_context(void *blur_context, GLfloat *projection,
815828
// Build program
816829
up_pass->prog = gl_create_program_from_strv(
817830
(const char *[]){vertex_shader, NULL},
818-
(const char *[]){shader_str, scaled_masking_glsl, NULL});
831+
(const char *[]){shader_str, scaled_masking_glsl, perturb_glsl, NULL});
819832
free(shader_str);
820833
if (!up_pass->prog) {
821834
log_error("Failed to create GLSL program.");
@@ -834,10 +847,6 @@ bool gl_create_dual_kawase_blur_context(void *blur_context, GLfloat *projection,
834847
out:
835848
free(blur_params);
836849

837-
if (!success) {
838-
ctx = NULL;
839-
}
840-
841850
// Restore LC_NUMERIC
842851
setlocale(LC_NUMERIC, lc_numeric_old);
843852
free(lc_numeric_old);
@@ -846,7 +855,7 @@ bool gl_create_dual_kawase_blur_context(void *blur_context, GLfloat *projection,
846855
}
847856

848857
void *gl_create_blur_context(backend_t *base, enum blur_method method,
849-
enum backend_image_format format, void *args) {
858+
enum backend_image_format format, struct blur_args *args) {
850859
bool success;
851860
auto gd = (struct gl_data *)base;
852861

@@ -878,6 +887,12 @@ void *gl_create_blur_context(backend_t *base, enum blur_method method,
878887
goto out;
879888
}
880889

890+
ctx->noise_radius = args->noise_radius;
891+
ctx->noise_scale = (float)args->noise_scale;
892+
// Expand the blur region to account for noise samples
893+
ctx->resize_width = max2(ctx->resize_width, ctx->noise_radius);
894+
ctx->resize_height = max2(ctx->resize_height, ctx->noise_radius);
895+
881896
// Texture size will be defined by gl_blur
882897
ctx->blur_textures = ccalloc(ctx->blur_texture_count, GLuint);
883898
ctx->texture_sizes = ccalloc(ctx->blur_texture_count, struct texture_size);

src/backend/gl/gl_common.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ struct gl_blur_context;
4040
// Added in backend API 2.0
4141
#define UNIFORM_TINT_LOC 22
4242
#define UNIFORM_MASK_SCALE_LOC 23
43-
#define NUMBER_OF_UNIFORMS (UNIFORM_TINT_LOC + 1)
43+
#define UNIFORM_BLUR_NOISE_RADIUS_LOC 24
44+
#define UNIFORM_BLUR_NOISE_SCALE_LOC 25
45+
#define NUMBER_OF_UNIFORMS (UNIFORM_BLUR_NOISE_SCALE_LOC + 1)
4446

4547
struct gl_shader {
4648
GLuint prog;
@@ -173,7 +175,7 @@ image_handle gl_back_buffer(struct backend_base *base);
173175
uint32_t gl_image_capabilities(backend_t *base, image_handle img);
174176
bool gl_is_format_supported(backend_t *base, enum backend_image_format format);
175177
void *gl_create_blur_context(backend_t *base, enum blur_method,
176-
enum backend_image_format format, void *args);
178+
enum backend_image_format format, struct blur_args *args);
177179
void gl_destroy_blur_context(backend_t *base, void *ctx);
178180
void gl_get_blur_size(void *blur_context, int *width, int *height);
179181

@@ -311,4 +313,4 @@ static const GLuint vert_in_texcoord_loc = 1;
311313
extern const char vertex_shader[], blend_with_mask_frag[], masking_glsl[],
312314
scaled_masking_glsl[], copy_area_frag[], copy_area_with_dither_frag[], fill_frag[],
313315
fill_vert[], interpolating_frag[], interpolating_vert[], blit_shader_glsl[],
314-
blit_shader_default[], present_vertex_shader[], dither_glsl[];
316+
blit_shader_default[], present_vertex_shader[], dither_glsl[], perturb_glsl[];

0 commit comments

Comments
 (0)