Merge pull request #186 from yshui/malloc-blur-passes
Lift the MAX_BLUR_PASS limit
This commit is contained in:
commit
dc7050cb00
|
@ -388,7 +388,6 @@ bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur,
|
||||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, extent->x1, dst_y, width, height);
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, extent->x1, dst_y, width, height);
|
||||||
|
|
||||||
for (int i = 0; i < gd->npasses; ++i) {
|
for (int i = 0; i < gd->npasses; ++i) {
|
||||||
assert(i < MAX_BLUR_PASS - 1);
|
|
||||||
const gl_blur_shader_t *p = &gd->blur_shader[i];
|
const gl_blur_shader_t *p = &gd->blur_shader[i];
|
||||||
assert(p->prog);
|
assert(p->prog);
|
||||||
|
|
||||||
|
@ -668,6 +667,9 @@ static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (gd->npasses = 0; kernels[gd->npasses]; gd->npasses++);
|
||||||
|
gd->blur_shader = ccalloc(gd->npasses, gl_blur_shader_t);
|
||||||
|
|
||||||
char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL));
|
char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL));
|
||||||
// Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane
|
// Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane
|
||||||
// Thanks to hiciu for reporting.
|
// Thanks to hiciu for reporting.
|
||||||
|
@ -698,8 +700,7 @@ static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels) {
|
||||||
const char *shader_add = FRAG_SHADER_BLUR_ADD;
|
const char *shader_add = FRAG_SHADER_BLUR_ADD;
|
||||||
char *extension = strdup("");
|
char *extension = strdup("");
|
||||||
|
|
||||||
gl_blur_shader_t *passes = gd->blur_shader;
|
for (int i = 0; kernels[i]; i++) {
|
||||||
for (int i = 0; i < MAX_BLUR_PASS && kernels[i]; gd->npasses = ++i) {
|
|
||||||
auto kern = kernels[i];
|
auto kern = kernels[i];
|
||||||
// Build shader
|
// Build shader
|
||||||
int width = kern->w, height = kern->h;
|
int width = kern->w, height = kern->h;
|
||||||
|
@ -728,7 +729,7 @@ static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pass = passes + i;
|
auto pass = gd->blur_shader + i;
|
||||||
size_t shader_len = strlen(FRAG_SHADER_BLUR) + strlen(extension) +
|
size_t shader_len = strlen(FRAG_SHADER_BLUR) + strlen(extension) +
|
||||||
strlen(shader_body) + 10 /* sum */ +
|
strlen(shader_body) + 10 /* sum */ +
|
||||||
1 /* null terminator */;
|
1 /* null terminator */;
|
||||||
|
@ -812,10 +813,6 @@ const char *win_shader_glsl = GLSL(330,
|
||||||
|
|
||||||
bool gl_init(struct gl_data *gd, session_t *ps) {
|
bool gl_init(struct gl_data *gd, session_t *ps) {
|
||||||
// Initialize GLX data structure
|
// Initialize GLX data structure
|
||||||
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
|
||||||
gd->blur_shader[i] = (gl_blur_shader_t){.prog = 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
@ -833,7 +830,6 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
gd->npasses = 0;
|
|
||||||
gl_win_shader_from_string(vertex_shader, win_shader_glsl, &gd->win_shader);
|
gl_win_shader_from_string(vertex_shader, win_shader_glsl, &gd->win_shader);
|
||||||
if (!gl_init_blur(gd, ps->o.blur_kerns)) {
|
if (!gl_init_blur(gd, ps->o.blur_kerns)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -874,9 +870,10 @@ static inline void gl_free_blur_shader(gl_blur_shader_t *shader) {
|
||||||
|
|
||||||
void gl_deinit(struct gl_data *gd) {
|
void gl_deinit(struct gl_data *gd) {
|
||||||
// Free GLSL shaders/programs
|
// Free GLSL shaders/programs
|
||||||
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
for (int i = 0; i < gd->npasses; ++i) {
|
||||||
gl_free_blur_shader(&gd->blur_shader[i]);
|
gl_free_blur_shader(&gd->blur_shader[i]);
|
||||||
}
|
}
|
||||||
|
free(gd->blur_shader);
|
||||||
|
|
||||||
gl_free_prog_main(&gd->win_shader);
|
gl_free_prog_main(&gd->win_shader);
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ struct gl_data {
|
||||||
int npasses;
|
int npasses;
|
||||||
gl_win_shader_t win_shader;
|
gl_win_shader_t win_shader;
|
||||||
gl_fill_shader_t fill_shader;
|
gl_fill_shader_t fill_shader;
|
||||||
gl_blur_shader_t blur_shader[MAX_BLUR_PASS];
|
gl_blur_shader_t *blur_shader;
|
||||||
|
|
||||||
// Temporary textures used for blurring. They are always the same size as the
|
// Temporary textures used for blurring. They are always the same size as the
|
||||||
// target, so they are always big enough without resizing.
|
// target, so they are always big enough without resizing.
|
||||||
|
|
|
@ -60,9 +60,7 @@ typedef struct _xrender_data {
|
||||||
int target_width, target_height;
|
int target_width, target_height;
|
||||||
|
|
||||||
/// Blur kernels converted to X format
|
/// Blur kernels converted to X format
|
||||||
xcb_render_fixed_t *x_blur_kern[MAX_BLUR_PASS];
|
struct x_convolution_kernel **x_blur_kern;
|
||||||
/// Number of elements in each blur kernel
|
|
||||||
int x_blur_kern_size[MAX_BLUR_PASS];
|
|
||||||
|
|
||||||
xcb_special_event_t *present_event;
|
xcb_special_event_t *present_event;
|
||||||
} xrender_data;
|
} xrender_data;
|
||||||
|
@ -178,15 +176,13 @@ static bool blur(backend_t *backend_data, double opacity, const region_t *reg_bl
|
||||||
// back -(pass 1)-> tmp0 -(copy)-> target_buffer
|
// back -(pass 1)-> tmp0 -(copy)-> target_buffer
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; xd->x_blur_kern[i]; i++) {
|
for (i = 0; xd->x_blur_kern[i]; i++) {
|
||||||
assert(i < MAX_BLUR_PASS - 1);
|
|
||||||
|
|
||||||
// Copy from source picture to destination. The filter must
|
// Copy from source picture to destination. The filter must
|
||||||
// be applied on source picture, to get the nearby pixels outside the
|
// be applied on source picture, to get the nearby pixels outside the
|
||||||
// window.
|
// window.
|
||||||
// TODO cache converted blur_kerns
|
// TODO cache converted blur_kerns
|
||||||
xcb_render_set_picture_filter(
|
xcb_render_set_picture_filter(
|
||||||
c, src_pict, to_u16_checked(strlen(filter)), filter,
|
c, src_pict, to_u16_checked(strlen(filter)), filter,
|
||||||
to_u32_checked(xd->x_blur_kern_size[i]), xd->x_blur_kern[i]);
|
to_u32_checked(xd->x_blur_kern[i]->size), xd->x_blur_kern[i]->kernel);
|
||||||
|
|
||||||
if (xd->x_blur_kern[i + 1] || i == 0) {
|
if (xd->x_blur_kern[i + 1] || i == 0) {
|
||||||
// This is not the last pass, or this is the first pass
|
// This is not the last pass, or this is the first pass
|
||||||
|
@ -276,6 +272,7 @@ static void deinit(backend_t *backend_data) {
|
||||||
for (int i = 0; xd->x_blur_kern[i]; i++) {
|
for (int i = 0; xd->x_blur_kern[i]; i++) {
|
||||||
free(xd->x_blur_kern[i]);
|
free(xd->x_blur_kern[i]);
|
||||||
}
|
}
|
||||||
|
free(xd->x_blur_kern);
|
||||||
if (xd->present_event) {
|
if (xd->present_event) {
|
||||||
xcb_unregister_for_special_event(xd->base.c, xd->present_event);
|
xcb_unregister_for_special_event(xd->base.c, xd->present_event);
|
||||||
}
|
}
|
||||||
|
@ -377,8 +374,8 @@ static bool image_op(backend_t *base, enum image_operations op, void *image,
|
||||||
XCB_NONE, tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph);
|
XCB_NONE, tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph);
|
||||||
|
|
||||||
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_DIFFERENCE,
|
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_DIFFERENCE,
|
||||||
xd->white_pixel, XCB_NONE, img->pict, 0, 0, 0,
|
xd->white_pixel, XCB_NONE, img->pict, 0, 0,
|
||||||
0, 0, 0, tmpw, tmph);
|
0, 0, 0, 0, tmpw, tmph);
|
||||||
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_IN_REVERSE,
|
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_IN_REVERSE,
|
||||||
tmp_pict, XCB_NONE, img->pict, 0, 0, 0, 0, 0,
|
tmp_pict, XCB_NONE, img->pict, 0, 0, 0, 0, 0,
|
||||||
0, tmpw, tmph);
|
0, tmpw, tmph);
|
||||||
|
@ -549,10 +546,14 @@ backend_t *backend_xrender_init(session_t *ps) {
|
||||||
xd->root_pict = x_create_picture_with_visual_and_pixmap(
|
xd->root_pict = x_create_picture_with_visual_and_pixmap(
|
||||||
ps->c, ps->vis, root_pixmap, 0, NULL);
|
ps->c, ps->vis, root_pixmap, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int npasses = 0;
|
||||||
|
for (; ps->o.blur_kerns[npasses]; npasses++)
|
||||||
|
;
|
||||||
|
// +1 for null terminator
|
||||||
|
xd->x_blur_kern = ccalloc(npasses + 1, struct x_convolution_kernel *);
|
||||||
for (int i = 0; ps->o.blur_kerns[i]; i++) {
|
for (int i = 0; ps->o.blur_kerns[i]; i++) {
|
||||||
assert(i < MAX_BLUR_PASS - 1);
|
x_create_convolution_kernel(ps->o.blur_kerns[i], 1, &xd->x_blur_kern[i]);
|
||||||
xd->x_blur_kern_size[i] = x_picture_filter_from_conv(
|
|
||||||
ps->o.blur_kerns[i], 1, &xd->x_blur_kern[i], (size_t[]){0});
|
|
||||||
}
|
}
|
||||||
return &xd->base;
|
return &xd->base;
|
||||||
err:
|
err:
|
||||||
|
|
|
@ -224,7 +224,7 @@ typedef struct session {
|
||||||
/// ignore linked list.
|
/// ignore linked list.
|
||||||
ignore_t **ignore_tail;
|
ignore_t **ignore_tail;
|
||||||
// Cached blur convolution kernels.
|
// Cached blur convolution kernels.
|
||||||
xcb_render_fixed_t *blur_kerns_cache[MAX_BLUR_PASS];
|
struct x_convolution_kernel **blur_kerns_cache;
|
||||||
/// Reset program after next paint.
|
/// Reset program after next paint.
|
||||||
bool reset:1;
|
bool reset:1;
|
||||||
/// If compton should quit
|
/// If compton should quit
|
||||||
|
|
|
@ -2010,10 +2010,10 @@ static void session_destroy(session_t *ps) {
|
||||||
|
|
||||||
free(ps->o.write_pid_path);
|
free(ps->o.write_pid_path);
|
||||||
free(ps->o.logpath);
|
free(ps->o.logpath);
|
||||||
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
for (int i = 0; ps->o.blur_kerns[i]; ++i) {
|
||||||
free(ps->o.blur_kerns[i]);
|
free(ps->o.blur_kerns[i]);
|
||||||
free(ps->blur_kerns_cache[i]);
|
|
||||||
}
|
}
|
||||||
|
free(ps->o.blur_kerns);
|
||||||
free(ps->o.glx_fshader_win_str);
|
free(ps->o.glx_fshader_win_str);
|
||||||
free_xinerama_info(ps);
|
free_xinerama_info(ps);
|
||||||
|
|
||||||
|
|
47
src/config.c
47
src/config.c
|
@ -193,13 +193,10 @@ err1:
|
||||||
* Parse a list of convolution kernels.
|
* Parse a list of convolution kernels.
|
||||||
*
|
*
|
||||||
* @param[in] src string to parse
|
* @param[in] src string to parse
|
||||||
* @param[out] dest pointer to an array of kernels, must points to an array
|
|
||||||
* of `max` elements.
|
|
||||||
* @param[in] max maximum number of kernels supported
|
|
||||||
* @param[out] hasneg whether any of the kernels have negative values
|
* @param[out] hasneg whether any of the kernels have negative values
|
||||||
* @return if the `src` string is a valid kernel list string
|
* @return the kernels
|
||||||
*/
|
*/
|
||||||
bool parse_blur_kern_lst(const char *src, conv **dest, int max, bool *hasneg) {
|
struct conv **parse_blur_kern_lst(const char *src, bool *hasneg) {
|
||||||
// TODO just return a predefined kernels, not parse predefined strings...
|
// TODO just return a predefined kernels, not parse predefined strings...
|
||||||
static const struct {
|
static const struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -258,26 +255,33 @@ bool parse_blur_kern_lst(const char *src, conv **dest, int max, bool *hasneg) {
|
||||||
for (unsigned int i = 0;
|
for (unsigned int i = 0;
|
||||||
i < sizeof(CONV_KERN_PREDEF) / sizeof(CONV_KERN_PREDEF[0]); ++i) {
|
i < sizeof(CONV_KERN_PREDEF) / sizeof(CONV_KERN_PREDEF[0]); ++i) {
|
||||||
if (!strcmp(CONV_KERN_PREDEF[i].name, src))
|
if (!strcmp(CONV_KERN_PREDEF[i].name, src))
|
||||||
return parse_blur_kern_lst(CONV_KERN_PREDEF[i].kern_str, dest,
|
return parse_blur_kern_lst(CONV_KERN_PREDEF[i].kern_str, hasneg);
|
||||||
max, hasneg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nkernels = 1;
|
||||||
|
for (int i = 0; src[i]; i++) {
|
||||||
|
if (src[i] == ';') {
|
||||||
|
nkernels++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct conv **ret = ccalloc(nkernels+1, struct conv *); // +1 for NULL terminator
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
const char *pc = src;
|
const char *pc = src;
|
||||||
|
|
||||||
// Free old kernels
|
|
||||||
for (i = 0; i < max; ++i) {
|
|
||||||
free(dest[i]);
|
|
||||||
dest[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue parsing until the end of source string
|
// Continue parsing until the end of source string
|
||||||
i = 0;
|
i = 0;
|
||||||
while (pc && *pc && i < max - 1) {
|
while (pc && *pc) {
|
||||||
bool tmp_hasneg;
|
bool tmp_hasneg;
|
||||||
dest[i] = parse_blur_kern(pc, &pc, &tmp_hasneg);
|
assert(i < nkernels);
|
||||||
if (!dest[i]) {
|
ret[i] = parse_blur_kern(pc, &pc, &tmp_hasneg);
|
||||||
return false;
|
if (!ret[i]) {
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
free(ret[j]);
|
||||||
|
}
|
||||||
|
free(ret);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
*hasneg |= tmp_hasneg;
|
*hasneg |= tmp_hasneg;
|
||||||
|
@ -290,12 +294,7 @@ bool parse_blur_kern_lst(const char *src, conv **dest, int max, bool *hasneg) {
|
||||||
"removed in future releases");
|
"removed in future releases");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*pc) {
|
return ret;
|
||||||
log_error("Too many blur kernels!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -541,7 +540,7 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
|
||||||
.blur_background_frame = false,
|
.blur_background_frame = false,
|
||||||
.blur_background_fixed = false,
|
.blur_background_fixed = false,
|
||||||
.blur_background_blacklist = NULL,
|
.blur_background_blacklist = NULL,
|
||||||
.blur_kerns = {NULL},
|
.blur_kerns = NULL,
|
||||||
.inactive_dim = 0.0,
|
.inactive_dim = 0.0,
|
||||||
.inactive_dim_fixed = false,
|
.inactive_dim_fixed = false,
|
||||||
.invert_color_list = NULL,
|
.invert_color_list = NULL,
|
||||||
|
|
10
src/config.h
10
src/config.h
|
@ -64,12 +64,6 @@ typedef struct win_option {
|
||||||
|
|
||||||
typedef struct _c2_lptr c2_lptr_t;
|
typedef struct _c2_lptr c2_lptr_t;
|
||||||
|
|
||||||
// This macro is here because this is the maximum number
|
|
||||||
// of blur passes options_t can hold, not a limitation of
|
|
||||||
// rendering.
|
|
||||||
/// @brief Maximum passes for blur.
|
|
||||||
#define MAX_BLUR_PASS 5
|
|
||||||
|
|
||||||
/// Structure representing all options.
|
/// Structure representing all options.
|
||||||
typedef struct options {
|
typedef struct options {
|
||||||
// === Debugging ===
|
// === Debugging ===
|
||||||
|
@ -203,7 +197,7 @@ typedef struct options {
|
||||||
/// Background blur blacklist. A linked list of conditions.
|
/// Background blur blacklist. A linked list of conditions.
|
||||||
c2_lptr_t *blur_background_blacklist;
|
c2_lptr_t *blur_background_blacklist;
|
||||||
/// Blur convolution kernel.
|
/// Blur convolution kernel.
|
||||||
conv *blur_kerns[MAX_BLUR_PASS];
|
struct conv **blur_kerns;
|
||||||
/// How much to dim an inactive window. 0.0 - 1.0, 0 to disable.
|
/// How much to dim an inactive window. 0.0 - 1.0, 0 to disable.
|
||||||
double inactive_dim;
|
double inactive_dim;
|
||||||
/// Whether to use fixed inactive dim opacity, instead of deciding
|
/// Whether to use fixed inactive dim opacity, instead of deciding
|
||||||
|
@ -239,7 +233,7 @@ extern const char *const BACKEND_STRS[NUM_BKEND + 1];
|
||||||
|
|
||||||
bool must_use parse_long(const char *, long *);
|
bool must_use parse_long(const char *, long *);
|
||||||
bool must_use parse_int(const char *, int *);
|
bool must_use parse_int(const char *, int *);
|
||||||
bool must_use parse_blur_kern_lst(const char *, conv **, int, bool *hasneg);
|
struct conv **must_use parse_blur_kern_lst(const char *, bool *hasneg);
|
||||||
bool must_use parse_geometry(session_t *, const char *, region_t *);
|
bool must_use parse_geometry(session_t *, const char *, region_t *);
|
||||||
bool must_use parse_rule_opacity(c2_lptr_t **, const char *);
|
bool must_use parse_rule_opacity(c2_lptr_t **, const char *);
|
||||||
enum blur_method must_use parse_blur_method(const char *src);
|
enum blur_method must_use parse_blur_method(const char *src);
|
||||||
|
|
|
@ -379,11 +379,13 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||||
// --blur-background-fixed
|
// --blur-background-fixed
|
||||||
lcfg_lookup_bool(&cfg, "blur-background-fixed", &opt->blur_background_fixed);
|
lcfg_lookup_bool(&cfg, "blur-background-fixed", &opt->blur_background_fixed);
|
||||||
// --blur-kern
|
// --blur-kern
|
||||||
if (config_lookup_string(&cfg, "blur-kern", &sval) &&
|
if (config_lookup_string(&cfg, "blur-kern", &sval)) {
|
||||||
!parse_blur_kern_lst(sval, opt->blur_kerns, MAX_BLUR_PASS, conv_kern_hasneg)) {
|
opt->blur_kerns = parse_blur_kern_lst(sval, conv_kern_hasneg);
|
||||||
|
if (!opt->blur_kerns) {
|
||||||
log_fatal("Cannot parse \"blur-kern\"");
|
log_fatal("Cannot parse \"blur-kern\"");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// --resize-damage
|
// --resize-damage
|
||||||
config_lookup_int(&cfg, "resize-damage", &opt->resize_damage);
|
config_lookup_int(&cfg, "resize-damage", &opt->resize_damage);
|
||||||
// --glx-no-stencil
|
// --glx-no-stencil
|
||||||
|
@ -448,7 +450,6 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||||
}
|
}
|
||||||
|
|
||||||
config_setting_t *blur_cfg = config_lookup(&cfg, "blur");
|
config_setting_t *blur_cfg = config_lookup(&cfg, "blur");
|
||||||
// This is not a loop
|
|
||||||
if (blur_cfg) {
|
if (blur_cfg) {
|
||||||
if (config_setting_lookup_string(blur_cfg, "method", &sval)) {
|
if (config_setting_lookup_string(blur_cfg, "method", &sval)) {
|
||||||
enum blur_method method = parse_blur_method(sval);
|
enum blur_method method = parse_blur_method(sval);
|
||||||
|
@ -463,12 +464,9 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||||
config_setting_lookup_int(blur_cfg, "size", &opt->blur_radius);
|
config_setting_lookup_int(blur_cfg, "size", &opt->blur_radius);
|
||||||
|
|
||||||
if (config_setting_lookup_string(blur_cfg, "kernel", &sval)) {
|
if (config_setting_lookup_string(blur_cfg, "kernel", &sval)) {
|
||||||
struct conv *kerns[5];
|
opt->blur_kerns = parse_blur_kern_lst(sval, conv_kern_hasneg);
|
||||||
if (!parse_blur_kern_lst(sval, kerns, MAX_BLUR_PASS,
|
if (!opt->blur_kerns) {
|
||||||
conv_kern_hasneg)) {
|
|
||||||
log_warn("Failed to parse blur kernel: %s", sval);
|
log_warn("Failed to parse blur kernel: %s", sval);
|
||||||
} else {
|
|
||||||
memcpy(opt->blur_kerns, kerns, sizeof kerns);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
src/opengl.c
16
src/opengl.c
|
@ -24,9 +24,9 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
|
#include "uthash_extra.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "uthash_extra.h"
|
|
||||||
|
|
||||||
#include "opengl.h"
|
#include "opengl.h"
|
||||||
|
|
||||||
|
@ -89,7 +89,13 @@ bool glx_init(session_t *ps, bool need_render) {
|
||||||
ps->psglx = cmalloc(glx_session_t);
|
ps->psglx = cmalloc(glx_session_t);
|
||||||
memcpy(ps->psglx, &CGLX_SESSION_DEF, sizeof(glx_session_t));
|
memcpy(ps->psglx, &CGLX_SESSION_DEF, sizeof(glx_session_t));
|
||||||
|
|
||||||
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
int npasses;
|
||||||
|
for (npasses = 0; ps->o.blur_kerns[npasses]; npasses++)
|
||||||
|
;
|
||||||
|
// +1 for the zero terminator
|
||||||
|
ps->psglx->blur_passes = ccalloc(npasses + 1, glx_blur_pass_t);
|
||||||
|
|
||||||
|
for (int i = 0; ps->o.blur_kerns[i]; ++i) {
|
||||||
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
||||||
ppass->unifm_factor_center = -1;
|
ppass->unifm_factor_center = -1;
|
||||||
ppass->unifm_offset_x = -1;
|
ppass->unifm_offset_x = -1;
|
||||||
|
@ -230,13 +236,14 @@ void glx_destroy(session_t *ps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free GLSL shaders/programs
|
// Free GLSL shaders/programs
|
||||||
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
for (int i = 0; ps->psglx->blur_passes[i].prog; ++i) {
|
||||||
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
||||||
if (ppass->frag_shader)
|
if (ppass->frag_shader)
|
||||||
glDeleteShader(ppass->frag_shader);
|
glDeleteShader(ppass->frag_shader);
|
||||||
if (ppass->prog)
|
if (ppass->prog)
|
||||||
glDeleteProgram(ppass->prog);
|
glDeleteProgram(ppass->prog);
|
||||||
}
|
}
|
||||||
|
free(ps->psglx->blur_passes);
|
||||||
|
|
||||||
glx_free_prog_main(ps, &ps->glx_prog_win);
|
glx_free_prog_main(ps, &ps->glx_prog_win);
|
||||||
|
|
||||||
|
@ -324,7 +331,7 @@ bool glx_init_blur(session_t *ps) {
|
||||||
extension = strdup("");
|
extension = strdup("");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < MAX_BLUR_PASS && ps->o.blur_kerns[i]; ++i) {
|
for (int i = 0; ps->o.blur_kerns[i]; ++i) {
|
||||||
auto kern = ps->o.blur_kerns[i];
|
auto kern = ps->o.blur_kerns[i];
|
||||||
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
||||||
|
|
||||||
|
@ -783,7 +790,6 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
bool last_pass = false;
|
bool last_pass = false;
|
||||||
for (int i = 0; !last_pass; ++i) {
|
for (int i = 0; !last_pass; ++i) {
|
||||||
last_pass = !ps->psglx->blur_passes[i + 1].prog;
|
last_pass = !ps->psglx->blur_passes[i + 1].prog;
|
||||||
assert(i < MAX_BLUR_PASS - 1);
|
|
||||||
const glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
const glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
||||||
assert(ppass->prog);
|
assert(ppass->prog);
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ typedef struct glx_session {
|
||||||
bool has_texture_non_power_of_two;
|
bool has_texture_non_power_of_two;
|
||||||
/// Current GLX Z value.
|
/// Current GLX Z value.
|
||||||
int z;
|
int z;
|
||||||
glx_blur_pass_t blur_passes[MAX_BLUR_PASS];
|
glx_blur_pass_t *blur_passes;
|
||||||
} glx_session_t;
|
} glx_session_t;
|
||||||
|
|
||||||
/// @brief Wrapper of a binded GLX texture.
|
/// @brief Wrapper of a binded GLX texture.
|
||||||
|
|
|
@ -710,9 +710,10 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
||||||
break;
|
break;
|
||||||
case 301:
|
case 301:
|
||||||
// --blur-kern
|
// --blur-kern
|
||||||
if (!parse_blur_kern_lst(optarg, opt->blur_kerns,
|
opt->blur_kerns = parse_blur_kern_lst(optarg, &conv_kern_hasneg);
|
||||||
MAX_BLUR_PASS, &conv_kern_hasneg))
|
if (!opt->blur_kerns) {
|
||||||
exit(1);
|
exit(1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
P_CASEINT(302, resize_damage);
|
P_CASEINT(302, resize_damage);
|
||||||
case 303:
|
case 303:
|
||||||
|
@ -816,9 +817,10 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill default blur kernel
|
// Fill default blur kernel
|
||||||
if (opt->blur_method == BLUR_METHOD_KERNEL && !opt->blur_kerns[0]) {
|
if (opt->blur_method == BLUR_METHOD_KERNEL &&
|
||||||
CHECK(parse_blur_kern_lst("3x3box", opt->blur_kerns, MAX_BLUR_PASS,
|
(!opt->blur_kerns || !opt->blur_kerns[0])) {
|
||||||
&conv_kern_hasneg));
|
opt->blur_kerns = parse_blur_kern_lst("3x3box", &conv_kern_hasneg);
|
||||||
|
CHECK(opt->blur_kerns);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt->resize_damage < 0) {
|
if (opt->resize_damage < 0) {
|
||||||
|
|
42
src/render.c
42
src/render.c
|
@ -618,7 +618,7 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) {
|
||||||
*/
|
*/
|
||||||
static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x,
|
static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x,
|
||||||
int16_t y, uint16_t wid, uint16_t hei,
|
int16_t y, uint16_t wid, uint16_t hei,
|
||||||
xcb_render_fixed_t **blur_kerns, const region_t *reg_clip) {
|
struct x_convolution_kernel **blur_kerns, const region_t *reg_clip) {
|
||||||
assert(blur_kerns[0]);
|
assert(blur_kerns[0]);
|
||||||
|
|
||||||
// Directly copying from tgt_buffer to it does not work, so we create a
|
// Directly copying from tgt_buffer to it does not work, so we create a
|
||||||
|
@ -636,8 +636,7 @@ static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t
|
||||||
|
|
||||||
xcb_render_picture_t src_pict = tgt_buffer, dst_pict = tmp_picture;
|
xcb_render_picture_t src_pict = tgt_buffer, dst_pict = tmp_picture;
|
||||||
for (int i = 0; blur_kerns[i]; ++i) {
|
for (int i = 0; blur_kerns[i]; ++i) {
|
||||||
assert(i < MAX_BLUR_PASS - 1);
|
xcb_render_fixed_t *convolution_blur = blur_kerns[i]->kernel;
|
||||||
xcb_render_fixed_t *convolution_blur = blur_kerns[i];
|
|
||||||
// `x / 65536.0` converts from X fixed point to double
|
// `x / 65536.0` converts from X fixed point to double
|
||||||
int kwid = (int)((double)convolution_blur[0] / 65536.0),
|
int kwid = (int)((double)convolution_blur[0] / 65536.0),
|
||||||
khei = (int)((double)convolution_blur[1] / 65536.0);
|
khei = (int)((double)convolution_blur[1] / 65536.0);
|
||||||
|
@ -675,8 +674,8 @@ static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t
|
||||||
* Blur the background of a window.
|
* Blur the background of a window.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
win_blur_background(session_t *ps, struct managed_win *w,
|
win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t tgt_buffer,
|
||||||
xcb_render_picture_t tgt_buffer, const region_t *reg_paint) {
|
const region_t *reg_paint) {
|
||||||
const int16_t x = w->g.x;
|
const int16_t x = w->g.x;
|
||||||
const int16_t y = w->g.y;
|
const int16_t y = w->g.y;
|
||||||
const auto wid = to_u16_checked(w->widthb);
|
const auto wid = to_u16_checked(w->widthb);
|
||||||
|
@ -694,30 +693,22 @@ win_blur_background(session_t *ps, struct managed_win *w,
|
||||||
case BKEND_XRENDER:
|
case BKEND_XRENDER:
|
||||||
case BKEND_XR_GLX_HYBRID: {
|
case BKEND_XR_GLX_HYBRID: {
|
||||||
// Normalize blur kernels
|
// Normalize blur kernels
|
||||||
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
for (int i = 0; ps->o.blur_kerns[i]; ++i) {
|
||||||
// Note: `x * 65536` converts double `x` to a X fixed point
|
// Note: `x * 65536` converts double `x` to a X fixed point
|
||||||
// representation. `x / 65536` is the other way.
|
// representation. `x / 65536` is the other way.
|
||||||
auto kern_src = ps->o.blur_kerns[i];
|
auto kern_src = ps->o.blur_kerns[i];
|
||||||
xcb_render_fixed_t *kern_dst = ps->blur_kerns_cache[i];
|
auto kern_dst = ps->blur_kerns_cache[i];
|
||||||
assert(i < MAX_BLUR_PASS);
|
|
||||||
if (!kern_src) {
|
|
||||||
assert(!kern_dst);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(!kern_dst || (kern_src->w == kern_dst[0] / 65536 &&
|
assert(!kern_dst || (kern_src->w == kern_dst->kernel[0] / 65536 &&
|
||||||
kern_src->h == kern_dst[1] / 65536));
|
kern_src->h == kern_dst->kernel[1] / 65536));
|
||||||
|
|
||||||
// Skip for fixed factor_center if the cache exists already
|
// Skip for fixed factor_center if the cache exists already
|
||||||
if (ps->o.blur_background_fixed && kern_dst) {
|
if (ps->o.blur_background_fixed && kern_dst) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If kern_dst is allocated, it's always allocated to the right
|
x_create_convolution_kernel(kern_src, factor_center,
|
||||||
// size
|
&ps->blur_kerns_cache[i]);
|
||||||
size_t size = kern_dst ? (size_t)(kern_src->w * kern_src->h + 2) : 0;
|
|
||||||
x_picture_filter_from_conv(kern_src, factor_center, &kern_dst, &size);
|
|
||||||
ps->blur_kerns_cache[i] = kern_dst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Minimize the region we try to blur, if the window itself is not
|
// Minimize the region we try to blur, if the window itself is not
|
||||||
|
@ -1143,7 +1134,13 @@ bool init_render(session_t *ps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blur filter
|
// Blur filter
|
||||||
if (ps->o.blur_method || ps->o.blur_background_frame) {
|
if (ps->o.blur_method) {
|
||||||
|
int npasses;
|
||||||
|
for (npasses = 0; ps->o.blur_kerns[npasses]; npasses++)
|
||||||
|
;
|
||||||
|
|
||||||
|
// +1 for NULL terminator
|
||||||
|
ps->blur_kerns_cache = ccalloc(npasses+1, struct x_convolution_kernel *);
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (ps->o.backend == BKEND_GLX) {
|
if (ps->o.backend == BKEND_GLX) {
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
|
@ -1225,6 +1222,11 @@ void deinit_render(session_t *ps) {
|
||||||
glx_destroy(ps);
|
glx_destroy(ps);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
for (int i = 0; ps->blur_kerns_cache[i]; i++) {
|
||||||
|
free(ps->blur_kerns_cache[i]);
|
||||||
|
}
|
||||||
|
free(ps->blur_kerns_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: set ts=8 sw=8 noet :
|
// vim: set ts=8 sw=8 noet :
|
||||||
|
|
23
src/x.c
23
src/x.c
|
@ -13,6 +13,7 @@
|
||||||
#include <xcb/xcb_renderutil.h>
|
#include <xcb/xcb_renderutil.h>
|
||||||
#include <xcb/xfixes.h>
|
#include <xcb/xfixes.h>
|
||||||
|
|
||||||
|
#include "atom.h"
|
||||||
#include "backend/gl/glx.h"
|
#include "backend/gl/glx.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
@ -20,7 +21,6 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "atom.h"
|
|
||||||
#include "x.h"
|
#include "x.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -528,15 +528,23 @@ bool x_fence_sync(xcb_connection_t *c, xcb_sync_fence_t f) {
|
||||||
* @param[inout] size size of the array pointed to by `ret`, in number of elements
|
* @param[inout] size size of the array pointed to by `ret`, in number of elements
|
||||||
* @return number of elements filled into `*ret`
|
* @return number of elements filled into `*ret`
|
||||||
*/
|
*/
|
||||||
int x_picture_filter_from_conv(const conv *kernel, double center,
|
void x_create_convolution_kernel(const conv *kernel, double center,
|
||||||
xcb_render_fixed_t **ret, size_t *size) {
|
struct x_convolution_kernel **ret) {
|
||||||
if (*size < (size_t)(kernel->w * kernel->h + 2)) {
|
assert(ret);
|
||||||
*size = (size_t)(kernel->w * kernel->h + 2);
|
if (!*ret || (*ret)->capacity < kernel->w * kernel->h + 2) {
|
||||||
*ret = crealloc(*ret, *size);
|
free(*ret);
|
||||||
|
*ret =
|
||||||
|
cvalloc(sizeof(struct x_convolution_kernel) +
|
||||||
|
(size_t)(kernel->w * kernel->h + 2) * sizeof(xcb_render_fixed_t));
|
||||||
|
(*ret)->capacity = kernel->w * kernel->h + 2;
|
||||||
}
|
}
|
||||||
auto buf = *ret;
|
|
||||||
|
(*ret)->size = kernel->w * kernel->h + 2;
|
||||||
|
|
||||||
|
auto buf = (*ret)->kernel;
|
||||||
buf[0] = DOUBLE_TO_XFIXED(kernel->w);
|
buf[0] = DOUBLE_TO_XFIXED(kernel->w);
|
||||||
buf[1] = DOUBLE_TO_XFIXED(kernel->h);
|
buf[1] = DOUBLE_TO_XFIXED(kernel->h);
|
||||||
|
|
||||||
double sum = center;
|
double sum = center;
|
||||||
for (int i = 0; i < kernel->w * kernel->h; i++) {
|
for (int i = 0; i < kernel->w * kernel->h; i++) {
|
||||||
sum += kernel->data[i];
|
sum += kernel->data[i];
|
||||||
|
@ -551,7 +559,6 @@ int x_picture_filter_from_conv(const conv *kernel, double center,
|
||||||
|
|
||||||
buf[kernel->h / 2 * kernel->w + kernel->w / 2 + 2] =
|
buf[kernel->h / 2 * kernel->w + kernel->w / 2 + 2] =
|
||||||
DOUBLE_TO_XFIXED(center * factor);
|
DOUBLE_TO_XFIXED(center * factor);
|
||||||
return kernel->w * kernel->h + 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a search criteria for fbconfig from a X visual.
|
/// Generate a search criteria for fbconfig from a X visual.
|
||||||
|
|
10
src/x.h
10
src/x.h
|
@ -223,6 +223,12 @@ bool x_is_root_back_pixmap_atom(session_t *ps, xcb_atom_t atom);
|
||||||
|
|
||||||
bool x_fence_sync(xcb_connection_t *, xcb_sync_fence_t);
|
bool x_fence_sync(xcb_connection_t *, xcb_sync_fence_t);
|
||||||
|
|
||||||
|
struct x_convolution_kernel {
|
||||||
|
int size;
|
||||||
|
int capacity;
|
||||||
|
xcb_render_fixed_t kernel[];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a struct conv to a X picture convolution filter, normalizing the kernel
|
* Convert a struct conv to a X picture convolution filter, normalizing the kernel
|
||||||
* in the process. Allow the caller to specify the element at the center of the kernel,
|
* in the process. Allow the caller to specify the element at the center of the kernel,
|
||||||
|
@ -234,8 +240,8 @@ bool x_fence_sync(xcb_connection_t *, xcb_sync_fence_t);
|
||||||
* will be allocated, and `*ret` will be updated.
|
* will be allocated, and `*ret` will be updated.
|
||||||
* @param[inout] size size of the array pointed to by `ret`.
|
* @param[inout] size size of the array pointed to by `ret`.
|
||||||
*/
|
*/
|
||||||
int x_picture_filter_from_conv(const conv *kernel, double center,
|
void attr_nonnull(1, 3) x_create_convolution_kernel(const conv *kernel, double center,
|
||||||
xcb_render_fixed_t **ret, size_t *size);
|
struct x_convolution_kernel **ret);
|
||||||
|
|
||||||
/// Generate a search criteria for fbconfig from a X visual.
|
/// Generate a search criteria for fbconfig from a X visual.
|
||||||
/// Returns {-1, -1, -1, -1, -1, -1} on failure
|
/// Returns {-1, -1, -1, -1, -1, -1} on failure
|
||||||
|
|
Loading…
Reference in New Issue