diff --git a/src/backend/backend_common.c b/src/backend/backend_common.c index 9500308f..883238c7 100644 --- a/src/backend/backend_common.c +++ b/src/backend/backend_common.c @@ -47,7 +47,7 @@ solid_picture(session_t *ps, bool argb, double a, double r, double g, double b) } xcb_image_t *make_shadow(xcb_connection_t *c, const conv *kernel, - const double *shadow_sum, double opacity, int width, int height) { + double opacity, int width, int height) { /* * We classify shadows into 4 kinds of regions * r = shadow radius @@ -62,6 +62,7 @@ xcb_image_t *make_shadow(xcb_connection_t *c, const conv *kernel, * height+r +-----+---------+-----+ */ xcb_image_t *ximage; + const double *shadow_sum = kernel->rsum; int d = kernel->size, r = d / 2; int swidth = width + r * 2, sheight = height + r * 2; @@ -181,7 +182,7 @@ bool build_shadow(session_t *ps, double opacity, const int width, const int heig xcb_gcontext_t gc = None; shadow_image = - make_shadow(ps->c, ps->gaussian_map, ps->shadow_sum, opacity, width, height); + make_shadow(ps->c, ps->gaussian_map, opacity, width, height); if (!shadow_image) { log_error("Failed to make shadow"); return false; diff --git a/src/backend/backend_common.h b/src/backend/backend_common.h index e7691089..f3d3ffdc 100644 --- a/src/backend/backend_common.h +++ b/src/backend/backend_common.h @@ -19,5 +19,5 @@ solid_picture(session_t *ps, bool argb, double a, double r, double g, double b); void paint_all_new(session_t *ps, region_t *region, win *const t); -xcb_image_t *make_shadow(xcb_connection_t *c, const conv *kernel, - const double *shadow_sum, double opacity, int width, int height); +xcb_image_t * +make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width, int height); diff --git a/src/common.h b/src/common.h index 8ae784f2..c611738b 100644 --- a/src/common.h +++ b/src/common.h @@ -531,8 +531,6 @@ typedef struct session { /// Gaussian map of shadow. conv *gaussian_map; // for shadow precomputation - /// Pre-computed table for shadow. - double *shadow_sum; /// A region in which shadow is not painted on. region_t shadow_exclude_reg; diff --git a/src/compton.c b/src/compton.c index 412b49ef..5edc2c72 100644 --- a/src/compton.c +++ b/src/compton.c @@ -2640,7 +2640,6 @@ session_init(session_t *ps_old, int argc, char **argv) { .cshadow_picture = XCB_NONE, .white_picture = XCB_NONE, .gaussian_map = NULL, - .shadow_sum = NULL, .refresh_rate = 0, .refresh_intv = 0UL, diff --git a/src/kernel.c b/src/kernel.c index faf60caf..f4badbec 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Yuxuan Shui +#include #include #include "kernel.h" @@ -28,9 +29,20 @@ double sum_kernel(const conv *map, int x, int y, int width, int height) { if (yend > map->size) yend = map->size; + assert(yend > 0 && xend > 0); + + int d = map->size; + if (map->rsum) { + double v1 = xstart ? map->rsum[(yend - 1) * d + xstart - 1] : 0; + double v2 = ystart ? map->rsum[(ystart - 1) * d + xend - 1] : 0; + double v3 = + (xstart && ystart) ? map->rsum[(ystart - 1) * d + xstart - 1] : 0; + return map->rsum[(yend - 1) * d + xend - 1] - v1 - v2 + v3; + } + for (int yi = ystart; yi < yend; yi++) { for (int xi = xstart; xi < xend; xi++) { - ret += map->data[yi * map->size + xi]; + ret += map->data[yi * d + xi]; } } @@ -65,6 +77,7 @@ conv *gaussian_kernel(double r) { c = cvalloc(sizeof(conv) + size * size * sizeof(double)); c->size = size; + c->rsum = NULL; t = 0.0; for (int y = 0; y < size; y++) { @@ -86,13 +99,13 @@ conv *gaussian_kernel(double r) { /// preprocess kernels to make shadow generation faster /// shadow_sum[x*d+y] is the sum of the kernel from (0, 0) to (x, y), inclusive -void shadow_preprocess(conv *map, double **shadow_sum) { +void shadow_preprocess(conv *map) { const int d = map->size; - if (*shadow_sum) - free(*shadow_sum); + if (map->rsum) + free(map->rsum); - auto sum = *shadow_sum = ccalloc(d * d, double); + auto sum = map->rsum = ccalloc(d * d, double); sum[0] = map->data[0]; for (int x = 1; x < d; x++) { diff --git a/src/kernel.h b/src/kernel.h index 4ec016db..fdb60764 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -2,12 +2,14 @@ // Copyright (c) Yuxuan Shui #pragma once +#include #include "compiler.h" /// Code for generating convolution kernels typedef struct conv { int size; + double *rsum; double data[]; } conv; @@ -21,4 +23,9 @@ conv *gaussian_kernel(double r); /// preprocess kernels to make shadow generation faster /// shadow_sum[x*d+y] is the sum of the kernel from (0, 0) to (x, y), inclusive -void shadow_preprocess(conv *map, double **shadow_sum); +void shadow_preprocess(conv *map); + +static inline void free_conv(conv *k) { + free(k->rsum); + free(k); +} diff --git a/src/render.c b/src/render.c index c107c2f4..6959c866 100644 --- a/src/render.c +++ b/src/render.c @@ -451,7 +451,7 @@ static bool win_build_shadow(session_t *ps, win *w, double opacity) { xcb_gcontext_t gc = XCB_NONE; shadow_image = - make_shadow(ps->c, ps->gaussian_map, ps->shadow_sum, opacity, width, height); + make_shadow(ps->c, ps->gaussian_map, opacity, width, height); if (!shadow_image) { log_error("failed to make shadow"); return XCB_NONE; @@ -1058,7 +1058,7 @@ bool init_render(session_t *ps) { } ps->gaussian_map = gaussian_kernel(ps->o.shadow_radius); - shadow_preprocess(ps->gaussian_map, &ps->shadow_sum); + shadow_preprocess(ps->gaussian_map); ps->black_picture = solid_picture(ps, true, 1, 0, 0, 0); ps->white_picture = solid_picture(ps, true, 1, 1, 1, 1); @@ -1116,8 +1116,7 @@ void deinit_render(session_t *ps) { free_picture(ps->c, &ps->black_picture); free_picture(ps->c, &ps->white_picture); - free(ps->shadow_sum); - free(ps->gaussian_map); + free_conv(ps->gaussian_map); // Free other X resources free_root_tile(ps);