From abb089e605ac9795c63d85625a601430e7295441 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Thu, 6 Jun 2019 07:37:48 +0100 Subject: [PATCH] Lift the MAX_BLUR_PASS limit Signed-off-by: Yuxuan Shui --- src/backend/gl/gl_common.c | 17 ++++++------- src/backend/gl/gl_common.h | 2 +- src/backend/xrender/xrender.c | 23 +++++++++-------- src/common.h | 2 +- src/compton.c | 4 +-- src/config.c | 47 +++++++++++++++++------------------ src/config.h | 10 ++------ src/config_libconfig.c | 18 ++++++-------- src/opengl.c | 16 ++++++++---- src/opengl.h | 2 +- src/options.c | 12 +++++---- src/render.c | 42 ++++++++++++++++--------------- src/x.c | 23 +++++++++++------ src/x.h | 10 ++++++-- 14 files changed, 120 insertions(+), 108 deletions(-) diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index a56a934d..a58f2053 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -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); for (int i = 0; i < gd->npasses; ++i) { - assert(i < MAX_BLUR_PASS - 1); const gl_blur_shader_t *p = &gd->blur_shader[i]; assert(p->prog); @@ -668,6 +667,9 @@ static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels) { 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)); // Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane // 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; char *extension = strdup(""); - gl_blur_shader_t *passes = gd->blur_shader; - for (int i = 0; i < MAX_BLUR_PASS && kernels[i]; gd->npasses = ++i) { + for (int i = 0; kernels[i]; i++) { auto kern = kernels[i]; // Build shader 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) + strlen(shader_body) + 10 /* sum */ + 1 /* null terminator */; @@ -812,10 +813,6 @@ const char *win_shader_glsl = GLSL(330, bool gl_init(struct gl_data *gd, session_t *ps) { // 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); 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); 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); if (!gl_init_blur(gd, ps->o.blur_kerns)) { 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) { // 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]); } + free(gd->blur_shader); gl_free_prog_main(&gd->win_shader); diff --git a/src/backend/gl/gl_common.h b/src/backend/gl/gl_common.h index bd483075..edf5c27f 100644 --- a/src/backend/gl/gl_common.h +++ b/src/backend/gl/gl_common.h @@ -69,7 +69,7 @@ struct gl_data { int npasses; gl_win_shader_t win_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 // target, so they are always big enough without resizing. diff --git a/src/backend/xrender/xrender.c b/src/backend/xrender/xrender.c index 28d882f9..6137dca8 100644 --- a/src/backend/xrender/xrender.c +++ b/src/backend/xrender/xrender.c @@ -60,9 +60,7 @@ typedef struct _xrender_data { int target_width, target_height; /// Blur kernels converted to X format - xcb_render_fixed_t *x_blur_kern[MAX_BLUR_PASS]; - /// Number of elements in each blur kernel - int x_blur_kern_size[MAX_BLUR_PASS]; + struct x_convolution_kernel **x_blur_kern; xcb_special_event_t *present_event; } 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 int 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 // be applied on source picture, to get the nearby pixels outside the // window. // TODO cache converted blur_kerns xcb_render_set_picture_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) { // 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++) { free(xd->x_blur_kern[i]); } + free(xd->x_blur_kern); if (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_render_composite(base->c, XCB_RENDER_PICT_OP_DIFFERENCE, - xd->white_pixel, XCB_NONE, img->pict, 0, 0, 0, - 0, 0, 0, tmpw, tmph); + xd->white_pixel, XCB_NONE, img->pict, 0, 0, + 0, 0, 0, 0, tmpw, tmph); xcb_render_composite(base->c, XCB_RENDER_PICT_OP_IN_REVERSE, tmp_pict, XCB_NONE, img->pict, 0, 0, 0, 0, 0, 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( 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++) { - assert(i < MAX_BLUR_PASS - 1); - 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}); + x_create_convolution_kernel(ps->o.blur_kerns[i], 1, &xd->x_blur_kern[i]); } return &xd->base; err: diff --git a/src/common.h b/src/common.h index 6df57c6b..5e7af632 100644 --- a/src/common.h +++ b/src/common.h @@ -224,7 +224,7 @@ typedef struct session { /// ignore linked list. ignore_t **ignore_tail; // 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. bool reset:1; /// If compton should quit diff --git a/src/compton.c b/src/compton.c index a07266b7..64f38296 100644 --- a/src/compton.c +++ b/src/compton.c @@ -2010,10 +2010,10 @@ static void session_destroy(session_t *ps) { free(ps->o.write_pid_path); 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->blur_kerns_cache[i]); } + free(ps->o.blur_kerns); free(ps->o.glx_fshader_win_str); free_xinerama_info(ps); diff --git a/src/config.c b/src/config.c index f22fd564..69f55561 100644 --- a/src/config.c +++ b/src/config.c @@ -193,13 +193,10 @@ err1: * Parse a list of convolution kernels. * * @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 - * @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... static const struct { 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; i < sizeof(CONV_KERN_PREDEF) / sizeof(CONV_KERN_PREDEF[0]); ++i) { if (!strcmp(CONV_KERN_PREDEF[i].name, src)) - return parse_blur_kern_lst(CONV_KERN_PREDEF[i].kern_str, dest, - max, hasneg); + return parse_blur_kern_lst(CONV_KERN_PREDEF[i].kern_str, 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; 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 i = 0; - while (pc && *pc && i < max - 1) { + while (pc && *pc) { bool tmp_hasneg; - dest[i] = parse_blur_kern(pc, &pc, &tmp_hasneg); - if (!dest[i]) { - return false; + assert(i < nkernels); + ret[i] = parse_blur_kern(pc, &pc, &tmp_hasneg); + if (!ret[i]) { + for (int j = 0; j < i; j++) { + free(ret[j]); + } + free(ret); + return NULL; } i++; *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"); } - if (*pc) { - log_error("Too many blur kernels!"); - return false; - } - - return true; + return ret; } /** @@ -541,7 +540,7 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable, .blur_background_frame = false, .blur_background_fixed = false, .blur_background_blacklist = NULL, - .blur_kerns = {NULL}, + .blur_kerns = NULL, .inactive_dim = 0.0, .inactive_dim_fixed = false, .invert_color_list = NULL, diff --git a/src/config.h b/src/config.h index 256df778..66bb5f7f 100644 --- a/src/config.h +++ b/src/config.h @@ -64,12 +64,6 @@ typedef struct win_option { 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. typedef struct options { // === Debugging === @@ -203,7 +197,7 @@ typedef struct options { /// Background blur blacklist. A linked list of conditions. c2_lptr_t *blur_background_blacklist; /// 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. double inactive_dim; /// 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_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_rule_opacity(c2_lptr_t **, const char *); enum blur_method must_use parse_blur_method(const char *src); diff --git a/src/config_libconfig.c b/src/config_libconfig.c index 95eb08c7..48d83357 100644 --- a/src/config_libconfig.c +++ b/src/config_libconfig.c @@ -379,10 +379,12 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad // --blur-background-fixed lcfg_lookup_bool(&cfg, "blur-background-fixed", &opt->blur_background_fixed); // --blur-kern - if (config_lookup_string(&cfg, "blur-kern", &sval) && - !parse_blur_kern_lst(sval, opt->blur_kerns, MAX_BLUR_PASS, conv_kern_hasneg)) { - log_fatal("Cannot parse \"blur-kern\""); - goto err; + if (config_lookup_string(&cfg, "blur-kern", &sval)) { + opt->blur_kerns = parse_blur_kern_lst(sval, conv_kern_hasneg); + if (!opt->blur_kerns) { + log_fatal("Cannot parse \"blur-kern\""); + goto err; + } } // --resize-damage config_lookup_int(&cfg, "resize-damage", &opt->resize_damage); @@ -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"); - // This is not a loop if (blur_cfg) { if (config_setting_lookup_string(blur_cfg, "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); if (config_setting_lookup_string(blur_cfg, "kernel", &sval)) { - struct conv *kerns[5]; - if (!parse_blur_kern_lst(sval, kerns, MAX_BLUR_PASS, - conv_kern_hasneg)) { + opt->blur_kerns = parse_blur_kern_lst(sval, conv_kern_hasneg); + if (!opt->blur_kerns) { log_warn("Failed to parse blur kernel: %s", sval); - } else { - memcpy(opt->blur_kerns, kerns, sizeof kerns); } } diff --git a/src/opengl.c b/src/opengl.c index 839adfc8..dc50c840 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -24,9 +24,9 @@ #include "log.h" #include "region.h" #include "string_utils.h" +#include "uthash_extra.h" #include "utils.h" #include "win.h" -#include "uthash_extra.h" #include "opengl.h" @@ -89,7 +89,13 @@ bool glx_init(session_t *ps, bool need_render) { ps->psglx = cmalloc(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]; ppass->unifm_factor_center = -1; ppass->unifm_offset_x = -1; @@ -230,13 +236,14 @@ void glx_destroy(session_t *ps) { } // 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]; if (ppass->frag_shader) glDeleteShader(ppass->frag_shader); if (ppass->prog) glDeleteProgram(ppass->prog); } + free(ps->psglx->blur_passes); glx_free_prog_main(ps, &ps->glx_prog_win); @@ -324,7 +331,7 @@ bool glx_init_blur(session_t *ps) { 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]; 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; for (int i = 0; !last_pass; ++i) { 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]; assert(ppass->prog); diff --git a/src/opengl.h b/src/opengl.h index fa1c12f7..9008b8b2 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -48,7 +48,7 @@ typedef struct glx_session { bool has_texture_non_power_of_two; /// Current GLX Z value. int z; - glx_blur_pass_t blur_passes[MAX_BLUR_PASS]; + glx_blur_pass_t *blur_passes; } glx_session_t; /// @brief Wrapper of a binded GLX texture. diff --git a/src/options.c b/src/options.c index d2237ad2..5b8df813 100644 --- a/src/options.c +++ b/src/options.c @@ -710,9 +710,10 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, break; case 301: // --blur-kern - if (!parse_blur_kern_lst(optarg, opt->blur_kerns, - MAX_BLUR_PASS, &conv_kern_hasneg)) + opt->blur_kerns = parse_blur_kern_lst(optarg, &conv_kern_hasneg); + if (!opt->blur_kerns) { exit(1); + } break; P_CASEINT(302, resize_damage); case 303: @@ -816,9 +817,10 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, } // Fill default blur kernel - if (opt->blur_method == BLUR_METHOD_KERNEL && !opt->blur_kerns[0]) { - CHECK(parse_blur_kern_lst("3x3box", opt->blur_kerns, MAX_BLUR_PASS, - &conv_kern_hasneg)); + if (opt->blur_method == BLUR_METHOD_KERNEL && + (!opt->blur_kerns || !opt->blur_kerns[0])) { + opt->blur_kerns = parse_blur_kern_lst("3x3box", &conv_kern_hasneg); + CHECK(opt->blur_kerns); } if (opt->resize_damage < 0) { diff --git a/src/render.c b/src/render.c index e33568b7..2eab89ec 100644 --- a/src/render.c +++ b/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, 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]); // 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; for (int i = 0; blur_kerns[i]; ++i) { - assert(i < MAX_BLUR_PASS - 1); - xcb_render_fixed_t *convolution_blur = blur_kerns[i]; + xcb_render_fixed_t *convolution_blur = blur_kerns[i]->kernel; // `x / 65536.0` converts from X fixed point to double int kwid = (int)((double)convolution_blur[0] / 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. */ static inline void -win_blur_background(session_t *ps, struct managed_win *w, - xcb_render_picture_t tgt_buffer, const region_t *reg_paint) { +win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t tgt_buffer, + const region_t *reg_paint) { const int16_t x = w->g.x; const int16_t y = w->g.y; 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_XR_GLX_HYBRID: { // 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 // representation. `x / 65536` is the other way. auto kern_src = ps->o.blur_kerns[i]; - xcb_render_fixed_t *kern_dst = ps->blur_kerns_cache[i]; - assert(i < MAX_BLUR_PASS); - if (!kern_src) { - assert(!kern_dst); - break; - } + auto kern_dst = ps->blur_kerns_cache[i]; - assert(!kern_dst || (kern_src->w == kern_dst[0] / 65536 && - kern_src->h == kern_dst[1] / 65536)); + assert(!kern_dst || (kern_src->w == kern_dst->kernel[0] / 65536 && + kern_src->h == kern_dst->kernel[1] / 65536)); // Skip for fixed factor_center if the cache exists already if (ps->o.blur_background_fixed && kern_dst) { continue; } - // If kern_dst is allocated, it's always allocated to the right - // size - 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; + x_create_convolution_kernel(kern_src, factor_center, + &ps->blur_kerns_cache[i]); } // 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 - 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; if (ps->o.backend == BKEND_GLX) { #ifdef CONFIG_OPENGL @@ -1225,6 +1222,11 @@ void deinit_render(session_t *ps) { glx_destroy(ps); } #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 : diff --git a/src/x.c b/src/x.c index a2cbce13..79719b3b 100644 --- a/src/x.c +++ b/src/x.c @@ -13,6 +13,7 @@ #include #include +#include "atom.h" #include "backend/gl/glx.h" #include "common.h" #include "compiler.h" @@ -20,7 +21,6 @@ #include "log.h" #include "region.h" #include "utils.h" -#include "atom.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 * @return number of elements filled into `*ret` */ -int x_picture_filter_from_conv(const conv *kernel, double center, - xcb_render_fixed_t **ret, size_t *size) { - if (*size < (size_t)(kernel->w * kernel->h + 2)) { - *size = (size_t)(kernel->w * kernel->h + 2); - *ret = crealloc(*ret, *size); +void x_create_convolution_kernel(const conv *kernel, double center, + struct x_convolution_kernel **ret) { + assert(ret); + if (!*ret || (*ret)->capacity < kernel->w * kernel->h + 2) { + 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[1] = DOUBLE_TO_XFIXED(kernel->h); + double sum = center; for (int i = 0; i < kernel->w * kernel->h; 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] = DOUBLE_TO_XFIXED(center * factor); - return kernel->w * kernel->h + 2; } /// Generate a search criteria for fbconfig from a X visual. diff --git a/src/x.h b/src/x.h index 5c08e392..72e0dfea 100644 --- a/src/x.h +++ b/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); +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 * 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. * @param[inout] size size of the array pointed to by `ret`. */ -int x_picture_filter_from_conv(const conv *kernel, double center, - xcb_render_fixed_t **ret, size_t *size); +void attr_nonnull(1, 3) x_create_convolution_kernel(const conv *kernel, double center, + struct x_convolution_kernel **ret); /// Generate a search criteria for fbconfig from a X visual. /// Returns {-1, -1, -1, -1, -1, -1} on failure