From fa8faaf91d9a7c6dedd5ec221de1bd8c181b1ea0 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 7 Jun 2019 21:53:23 +0100 Subject: [PATCH] Remember the number of blur kernels Don't count the number of blur kernels everytime. Fixes #188 Signed-off-by: Yuxuan Shui --- src/backend/gl/gl_common.c | 10 +++++----- src/backend/xrender/xrender.c | 28 ++++++++++++++-------------- src/compton.c | 2 +- src/config.c | 10 +++++++--- src/config.h | 4 +++- src/config_libconfig.c | 6 ++++-- src/opengl.c | 21 ++++++++++----------- src/options.c | 7 +++++-- src/render.c | 23 +++++++++++------------ 9 files changed, 60 insertions(+), 51 deletions(-) diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index a58f205..10092a9 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -662,12 +662,12 @@ void *gl_copy(backend_t *base, const void *image_data, const region_t *reg_visib /** * Initialize GL blur filters. */ -static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels) { - if (!kernels[0]) { +static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels, int nkernels) { + if (!nkernels) { return true; } - for (gd->npasses = 0; kernels[gd->npasses]; gd->npasses++); + gd->npasses = nkernels; gd->blur_shader = ccalloc(gd->npasses, gl_blur_shader_t); char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL)); @@ -700,7 +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(""); - for (int i = 0; kernels[i]; i++) { + for (int i = 0; i < nkernels; i++) { auto kern = kernels[i]; // Build shader int width = kern->w, height = kern->h; @@ -831,7 +831,7 @@ bool gl_init(struct gl_data *gd, session_t *ps) { glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 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, ps->o.blur_kernel_count)) { return false; } gd->fill_shader.prog = gl_create_program_from_str(fill_vert, fill_frag); diff --git a/src/backend/xrender/xrender.c b/src/backend/xrender/xrender.c index 6137dca..defe0d3 100644 --- a/src/backend/xrender/xrender.c +++ b/src/backend/xrender/xrender.c @@ -60,7 +60,10 @@ typedef struct _xrender_data { int target_width, target_height; /// Blur kernels converted to X format - struct x_convolution_kernel **x_blur_kern; + struct x_convolution_kernel **x_blur_kernel; + + /// Number of blur kernels + int x_blur_kernel_count; xcb_special_event_t *present_event; } xrender_data; @@ -175,16 +178,16 @@ static bool blur(backend_t *backend_data, double opacity, const region_t *reg_bl // For 1 pass, we do // back -(pass 1)-> tmp0 -(copy)-> target_buffer int i; - for (i = 0; xd->x_blur_kern[i]; i++) { + for (i = 0; i < xd->x_blur_kernel_count; i++) { // 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[i]->size), xd->x_blur_kern[i]->kernel); + to_u32_checked(xd->x_blur_kernel[i]->size), xd->x_blur_kernel[i]->kernel); - if (xd->x_blur_kern[i + 1] || i == 0) { + if (i < xd->x_blur_kernel_count - 1 || i == 0) { // This is not the last pass, or this is the first pass xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, dst_pict, src_x, src_y, 0, 0, 0, 0, @@ -269,10 +272,10 @@ static void deinit(backend_t *backend_data) { xcb_render_free_picture(xd->base.c, xd->back[i]); xcb_free_pixmap(xd->base.c, xd->back_pixmap[i]); } - for (int i = 0; xd->x_blur_kern[i]; i++) { - free(xd->x_blur_kern[i]); + for (int i = 0; i < xd->x_blur_kernel_count; i++) { + free(xd->x_blur_kernel[i]); } - free(xd->x_blur_kern); + free(xd->x_blur_kernel); if (xd->present_event) { xcb_unregister_for_special_event(xd->base.c, xd->present_event); } @@ -547,14 +550,11 @@ backend_t *backend_xrender_init(session_t *ps) { 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++) { - x_create_convolution_kernel(ps->o.blur_kerns[i], 1, &xd->x_blur_kern[i]); + xd->x_blur_kernel = ccalloc(ps->o.blur_kernel_count, struct x_convolution_kernel *); + for (int i = 0; i < ps->o.blur_kernel_count; i++) { + x_create_convolution_kernel(ps->o.blur_kerns[i], 1, &xd->x_blur_kernel[i]); } + xd->x_blur_kernel_count = ps->o.blur_kernel_count; return &xd->base; err: deinit(&xd->base); diff --git a/src/compton.c b/src/compton.c index 64f3829..89b7d4e 100644 --- a/src/compton.c +++ b/src/compton.c @@ -2010,7 +2010,7 @@ static void session_destroy(session_t *ps) { free(ps->o.write_pid_path); free(ps->o.logpath); - for (int i = 0; ps->o.blur_kerns[i]; ++i) { + for (int i = 0; i < ps->o.blur_kernel_count; ++i) { free(ps->o.blur_kerns[i]); } free(ps->o.blur_kerns); diff --git a/src/config.c b/src/config.c index 69f5556..1f46df9 100644 --- a/src/config.c +++ b/src/config.c @@ -196,7 +196,7 @@ err1: * @param[out] hasneg whether any of the kernels have negative values * @return the kernels */ -struct conv **parse_blur_kern_lst(const char *src, bool *hasneg) { +struct conv **parse_blur_kern_lst(const char *src, bool *hasneg, int *count) { // TODO just return a predefined kernels, not parse predefined strings... static const struct { const char *name; @@ -251,11 +251,12 @@ struct conv **parse_blur_kern_lst(const char *src, bool *hasneg) { "000000,"}, }; + *count = 0; *hasneg = false; 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, hasneg); + return parse_blur_kern_lst(CONV_KERN_PREDEF[i].kern_str, hasneg, count); } int nkernels = 1; @@ -265,7 +266,7 @@ struct conv **parse_blur_kern_lst(const char *src, bool *hasneg) { } } - struct conv **ret = ccalloc(nkernels+1, struct conv *); // +1 for NULL terminator + struct conv **ret = ccalloc(nkernels, struct conv *); int i = 0; const char *pc = src; @@ -294,6 +295,8 @@ struct conv **parse_blur_kern_lst(const char *src, bool *hasneg) { "removed in future releases"); } + *count = i; + return ret; } @@ -541,6 +544,7 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable, .blur_background_fixed = false, .blur_background_blacklist = NULL, .blur_kerns = NULL, + .blur_kernel_count = 0, .inactive_dim = 0.0, .inactive_dim_fixed = false, .invert_color_list = NULL, diff --git a/src/config.h b/src/config.h index 66bb5f7..f359a33 100644 --- a/src/config.h +++ b/src/config.h @@ -198,6 +198,8 @@ typedef struct options { c2_lptr_t *blur_background_blacklist; /// Blur convolution kernel. struct conv **blur_kerns; + /// Number of convolution kernels + int blur_kernel_count; /// 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 @@ -233,7 +235,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 *); -struct conv **must_use parse_blur_kern_lst(const char *, bool *hasneg); +struct conv **must_use parse_blur_kern_lst(const char *, bool *hasneg, int *count); 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 48d8335..4a6bbb5 100644 --- a/src/config_libconfig.c +++ b/src/config_libconfig.c @@ -380,7 +380,8 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad lcfg_lookup_bool(&cfg, "blur-background-fixed", &opt->blur_background_fixed); // --blur-kern if (config_lookup_string(&cfg, "blur-kern", &sval)) { - opt->blur_kerns = parse_blur_kern_lst(sval, conv_kern_hasneg); + opt->blur_kerns = + parse_blur_kern_lst(sval, conv_kern_hasneg, &opt->blur_kernel_count); if (!opt->blur_kerns) { log_fatal("Cannot parse \"blur-kern\""); goto err; @@ -464,7 +465,8 @@ 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)) { - opt->blur_kerns = parse_blur_kern_lst(sval, conv_kern_hasneg); + opt->blur_kerns = parse_blur_kern_lst(sval, conv_kern_hasneg, + &opt->blur_kernel_count); if (!opt->blur_kerns) { log_warn("Failed to parse blur kernel: %s", sval); } diff --git a/src/opengl.c b/src/opengl.c index dc50c84..7e96af1 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -89,13 +89,10 @@ 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)); - 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); + ps->psglx->blur_passes = ccalloc(ps->o.blur_kernel_count, glx_blur_pass_t); - for (int i = 0; ps->o.blur_kerns[i]; ++i) { + for (int i = 0; i < ps->o.blur_kernel_count; ++i) { glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i]; ppass->unifm_factor_center = -1; ppass->unifm_offset_x = -1; @@ -236,7 +233,7 @@ void glx_destroy(session_t *ps) { } // Free GLSL shaders/programs - for (int i = 0; ps->psglx->blur_passes[i].prog; ++i) { + for (int i = 0; i < ps->o.blur_kernel_count; ++i) { glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i]; if (ppass->frag_shader) glDeleteShader(ppass->frag_shader); @@ -277,10 +274,12 @@ void glx_on_root_change(session_t *ps) { * Initialize GLX blur filter. */ bool glx_init_blur(session_t *ps) { + assert(ps->o.blur_kernel_count > 0); + assert(ps->o.blur_kerns); assert(ps->o.blur_kerns[0]); // Allocate PBO if more than one blur kernel is present - if (ps->o.blur_kerns[1]) { + if (ps->o.blur_kernel_count > 1) { // Try to generate a framebuffer GLuint fbo = 0; glGenFramebuffers(1, &fbo); @@ -331,7 +330,7 @@ bool glx_init_blur(session_t *ps) { extension = strdup(""); } - for (int i = 0; ps->o.blur_kerns[i]; ++i) { + for (int i = 0; i < ps->o.blur_kernel_count; ++i) { auto kern = ps->o.blur_kerns[i]; glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i]; @@ -695,7 +694,7 @@ static inline void glx_copy_region_to_tex(session_t *ps, GLenum tex_tgt, int bas bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc) { assert(ps->psglx->blur_passes[0].prog); - const bool more_passes = ps->psglx->blur_passes[1].prog; + const bool more_passes = ps->o.blur_kernel_count > 1; const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST); const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); bool ret = false; @@ -788,8 +787,8 @@ 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; + for (int i = 0; i < ps->o.blur_kernel_count; ++i) { + last_pass = (i == ps->o.blur_kernel_count - 1); const glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i]; assert(ppass->prog); diff --git a/src/options.c b/src/options.c index 5b8df81..f005929 100644 --- a/src/options.c +++ b/src/options.c @@ -710,7 +710,8 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, break; case 301: // --blur-kern - opt->blur_kerns = parse_blur_kern_lst(optarg, &conv_kern_hasneg); + opt->blur_kerns = parse_blur_kern_lst(optarg, &conv_kern_hasneg, + &opt->blur_kernel_count); if (!opt->blur_kerns) { exit(1); } @@ -819,8 +820,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 || !opt->blur_kerns[0])) { - opt->blur_kerns = parse_blur_kern_lst("3x3box", &conv_kern_hasneg); + opt->blur_kerns = parse_blur_kern_lst("3x3box", &conv_kern_hasneg, + &opt->blur_kernel_count); CHECK(opt->blur_kerns); + CHECK(opt->blur_kernel_count); } if (opt->resize_damage < 0) { diff --git a/src/render.c b/src/render.c index 2eab89e..c6acf58 100644 --- a/src/render.c +++ b/src/render.c @@ -616,9 +616,10 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) { * * @return true if successful, false otherwise */ -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, - struct x_convolution_kernel **blur_kerns, const region_t *reg_clip) { +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, struct x_convolution_kernel **blur_kerns, + int nkernels, const region_t *reg_clip) { + assert(blur_kerns); assert(blur_kerns[0]); // Directly copying from tgt_buffer to it does not work, so we create a @@ -635,7 +636,7 @@ static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x_set_picture_clip_region(ps->c, tmp_picture, 0, 0, reg_clip); xcb_render_picture_t src_pict = tgt_buffer, dst_pict = tmp_picture; - for (int i = 0; blur_kerns[i]; ++i) { + for (int i = 0; i < nkernels; ++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), @@ -693,7 +694,7 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t case BKEND_XRENDER: case BKEND_XR_GLX_HYBRID: { // Normalize blur kernels - for (int i = 0; ps->o.blur_kerns[i]; ++i) { + for (int i = 0; i < ps->o.blur_kernel_count; 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]; @@ -724,7 +725,8 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t } // Translate global coordinates to local ones pixman_region32_translate(®_blur, -x, -y); - xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache, ®_blur); + xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache, + ps->o.blur_kernel_count, ®_blur); pixman_region32_clear(®_blur); } break; #ifdef CONFIG_OPENGL @@ -1135,12 +1137,9 @@ bool init_render(session_t *ps) { // Blur filter if (ps->o.blur_method) { - int npasses; - for (npasses = 0; ps->o.blur_kerns[npasses]; npasses++) - ; + ps->blur_kerns_cache = + ccalloc(ps->o.blur_kernel_count, struct x_convolution_kernel *); - // +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 @@ -1223,7 +1222,7 @@ void deinit_render(session_t *ps) { } #endif - for (int i = 0; ps->blur_kerns_cache[i]; i++) { + for (int i = 0; i < ps->o.blur_kernel_count; i++) { free(ps->blur_kerns_cache[i]); } free(ps->blur_kerns_cache);