diff --git a/src/backend/backend_common.c b/src/backend/backend_common.c index 8132155..221f350 100644 --- a/src/backend/backend_common.c +++ b/src/backend/backend_common.c @@ -2,8 +2,8 @@ #include "backend.h" #include "backend_common.h" -#include "x.h" #include "common.h" +#include "x.h" /** * Generate a 1x1 Picture of a particular color. @@ -46,20 +46,31 @@ solid_picture(session_t *ps, bool argb, double a, double r, double g, double b) return picture; } -static xcb_image_t *make_shadow(session_t *ps, double opacity, int width, int height) { +static xcb_image_t * +make_shadow(xcb_connection_t *c, const conv *kernel, const double *shadow_sum, + double opacity, int width, int height) { + /* + * We classify shadows into 4 kinds of regions + * r = shadow radius + * (0, 0) is the top left of the window itself + * -r r width-r width+r + * -r +-----+---------+-----+ + * | 1 | 2 | 1 | + * r +-----+---------+-----+ + * | 2 | 3 | 2 | + * height-r +-----+---------+-----+ + * | 1 | 2 | 1 | + * height+r +-----+---------+-----+ + */ xcb_image_t *ximage; - int ylimit, xlimit; - int swidth = width + ps->cgsize; - int sheight = height + ps->cgsize; - int center = ps->cgsize / 2; - int x, y; - unsigned char d; - int x_diff; - int opacity_int = (int)(opacity * 25); + int d = kernel->size, r = d / 2; + int swidth = width + r * 2, sheight = height + r * 2; - ximage = xcb_image_create_native(ps->c, swidth, sheight, - XCB_IMAGE_FORMAT_Z_PIXMAP, 8, 0, 0, NULL); + assert(d % 2 == 1); + assert(d > 0); + ximage = xcb_image_create_native(c, swidth, sheight, XCB_IMAGE_FORMAT_Z_PIXMAP, 8, + 0, 0, NULL); if (!ximage) { log_error("failed to create an X image"); return 0; @@ -68,92 +79,91 @@ static xcb_image_t *make_shadow(session_t *ps, double opacity, int width, int he unsigned char *data = ximage->data; uint32_t sstride = ximage->stride; - /* - * Build the gaussian in sections - */ - - /* - * center (fill the complete data array) - */ - - // XXX If the center part of the shadow would be entirely covered by - // the body of the window, we shouldn't need to fill the center here. - // XXX In general, we want to just fill the part that is not behind - // the window, in order to reduce CPU load and make transparent window - // look correct - if (ps->cgsize > 0) { - d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + ps->cgsize]; - } else { - d = (unsigned char)(sum_kernel(ps->gaussian_map, center, center, width, - height) * - opacity * 255.0); - } - memset(data, d, sheight * swidth); - - /* - * corners - */ - - ylimit = ps->cgsize; - if (ylimit > sheight / 2) - ylimit = (sheight + 1) / 2; - - xlimit = ps->cgsize; - if (xlimit > swidth / 2) - xlimit = (swidth + 1) / 2; - - for (y = 0; y < ylimit; y++) { - for (x = 0; x < xlimit; x++) { - if (xlimit == ps->cgsize && ylimit == ps->cgsize) { - d = ps->shadow_corner[opacity_int * (ps->cgsize + 1) * - (ps->cgsize + 1) + - y * (ps->cgsize + 1) + x]; - } else { - d = (unsigned char)(sum_kernel(ps->gaussian_map, x - center, - y - center, width, height) * - opacity * 255.0); + // If the window body is smaller than the kernel, we do convolution directly + if (width < r * 2 && height < r * 2) { + for (int y = 0; y < sheight; y++) { + for (int x = 0; x < swidth; x++) { + double sum = sum_kernel_normalized( + kernel, d - x - 1, d - y - 1, width, height); + data[y * sstride + x] = sum * 255.0; } - data[y * sstride + x] = d; - data[(sheight - y - 1) * sstride + x] = d; - data[(sheight - y - 1) * sstride + (swidth - x - 1)] = d; - data[y * sstride + (swidth - x - 1)] = d; } + return ximage; } - /* - * top/bottom - */ - - x_diff = swidth - (ps->cgsize * 2); - if (x_diff > 0 && ylimit > 0) { - for (y = 0; y < ylimit; y++) { - if (ylimit == ps->cgsize) { - d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + y]; - } else { - d = (unsigned char)(sum_kernel(ps->gaussian_map, center, - y - center, width, height) * - opacity * 255.0); + if (height < r * 2) { + // If the window height is smaller than the kernel, we divide + // the window like this: + // -r r width-r width+r + // +------+-------------+------+ + // | | | | + // +------+-------------+------+ + for (int y = 0; y < sheight; y++) { + for (int x = 0; x < r * 2; x++) { + double sum = sum_kernel_normalized(kernel, d - x - 1, + d - y - 1, d, height) * + 255.0; + data[y * sstride + x] = sum; + data[y * sstride + swidth - x - 1] = sum; } - memset(&data[y * sstride + ps->cgsize], d, x_diff); - memset(&data[(sheight - y - 1) * sstride + ps->cgsize], d, x_diff); + } + for (int y = 0; y < sheight; y++) { + double sum = + sum_kernel_normalized(kernel, 0, d - y - 1, d, height) * 255.0; + memset(&data[y * sstride + r * 2], sum, width - 2 * r); + } + return ximage; + } + if (width < r * 2) { + // Similarly, for width smaller than kernel + for (int y = 0; y < r * 2; y++) { + for (int x = 0; x < swidth; x++) { + double sum = sum_kernel_normalized(kernel, d - x - 1, + d - y - 1, width, d) * + 255.0; + data[y * sstride + x] = sum; + data[(sheight - y - 1) * sstride + x] = sum; + } + } + for (int x = 0; x < swidth; x++) { + double sum = + sum_kernel_normalized(kernel, d - x - 1, 0, width, d) * 255.0; + for (int y = r * 2; y < height; y++) { + data[y * sstride + x] = sum; + } + } + return ximage; + } + + // Fill part 3 + for (int y = r; y < height + r; y++) { + memset(data + sstride * y + r, 255, width); + } + + // Part 1 + for (int y = 0; y < r * 2; y++) { + for (int x = 0; x < r * 2; x++) { + double tmpsum = shadow_sum[y * d + x] * opacity * 255.0; + data[y * sstride + x] = tmpsum; + data[(sheight - y - 1) * sstride + x] = tmpsum; + data[(sheight - y - 1) * sstride + (swidth - x - 1)] = tmpsum; + data[y * sstride + (swidth - x - 1)] = tmpsum; } } - /* - * sides - */ + // Part 2, top/bottom + for (int y = 0; y < r * 2; y++) { + double tmpsum = shadow_sum[d * y + d - 1] * opacity * 255.0; + memset(&data[y * sstride + r * 2], tmpsum, width - r * 2); + memset(&data[(sheight - y - 1) * sstride + r * 2], tmpsum, width - r * 2); + } - for (x = 0; x < xlimit; x++) { - if (xlimit == ps->cgsize) { - d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + x]; - } else { - d = (unsigned char)(sum_kernel(ps->gaussian_map, x - center, - center, width, height) * - opacity * 255.0); - } - for (y = ps->cgsize; y < sheight - ps->cgsize; y++) { - data[y * sstride + x] = d; - data[y * sstride + (swidth - x - 1)] = d; + // Part 2, left/right + for (int x = 0; x < r * 2; x++) { + double tmpsum = shadow_sum[d * (d - 1) + x] * opacity * 255.0; + for (int y = r * 2; y < height; y++) { + data[y * sstride + x] = tmpsum; + data[y * sstride + (swidth - x - 1)] = tmpsum; } } @@ -171,7 +181,8 @@ bool build_shadow(session_t *ps, double opacity, const int width, const int heig xcb_render_picture_t shadow_picture = None, shadow_picture_argb = None; xcb_gcontext_t gc = None; - shadow_image = make_shadow(ps, opacity, width, height); + shadow_image = + make_shadow(ps->c, ps->gaussian_map, ps->shadow_sum, opacity, width, height); if (!shadow_image) { log_error("Failed to make shadow"); return false; diff --git a/src/common.h b/src/common.h index 09d0980..8ae784f 100644 --- a/src/common.h +++ b/src/common.h @@ -531,12 +531,8 @@ typedef struct session { /// Gaussian map of shadow. conv *gaussian_map; // for shadow precomputation - /// Shadow depth on one side. - int cgsize; - /// Pre-computed color table for corners of shadow. - unsigned char *shadow_corner; - /// Pre-computed color table for a side of shadow. - unsigned char *shadow_top; + /// 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 4c66de7..412b49e 100644 --- a/src/compton.c +++ b/src/compton.c @@ -2640,9 +2640,7 @@ session_init(session_t *ps_old, int argc, char **argv) { .cshadow_picture = XCB_NONE, .white_picture = XCB_NONE, .gaussian_map = NULL, - .cgsize = 0, - .shadow_corner = NULL, - .shadow_top = NULL, + .shadow_sum = NULL, .refresh_rate = 0, .refresh_intv = 0UL, diff --git a/src/kernel.c b/src/kernel.c index 58ec248..faf60ca 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -6,75 +6,46 @@ #include "kernel.h" #include "utils.h" -/* - * A picture will help - * - * -center 0 width width+center - * -center +-----+-------------------+-----+ - * | | | | - * | | | | - * 0 +-----+-------------------+-----+ - * | | | | - * | | | | - * | | | | - * height +-----+-------------------+-----+ - * | | | | - * height+ | | | | - * center +-----+-------------------+-----+ - */ - -double sum_kernel(const conv *map, int x, int y, int width, - int height) { - int fx, fy; - const double *g_data; - const double *g_line = map->data; - int g_size = map->size; - int center = g_size / 2; - int fx_start, fx_end; - int fy_start, fy_end; - double v; - +/// Sum a region convolution kernel. Region is defined by a width x height rectangle whose +/// top left corner is at (x, y) +double sum_kernel(const conv *map, int x, int y, int width, int height) { + double ret = 0; /* - * Compute set of filter values which are "in range", - * that's the set with: - * 0 <= x + (fx-center) && x + (fx-center) < width && - * 0 <= y + (fy-center) && y + (fy-center) < height - * - * 0 <= x + (fx - center) x + fx - center < width - * center - x <= fx fx < width + center - x + * Compute set of filter values which are "in range" */ - fx_start = center - x; - if (fx_start < 0) - fx_start = 0; - fx_end = width + center - x; - if (fx_end > g_size) - fx_end = g_size; + int xstart = x; + if (xstart < 0) + xstart = 0; + int xend = width + x; + if (xend > map->size) + xend = map->size; - fy_start = center - y; - if (fy_start < 0) - fy_start = 0; - fy_end = height + center - y; - if (fy_end > g_size) - fy_end = g_size; + int ystart = y; + if (ystart < 0) + ystart = 0; + int yend = height + y; + if (yend > map->size) + yend = map->size; - g_line = g_line + fy_start * g_size + fx_start; - - v = 0; - - for (fy = fy_start; fy < fy_end; fy++) { - g_data = g_line; - g_line += g_size; - - for (fx = fx_start; fx < fx_end; fx++) { - v += *g_data++; + for (int yi = ystart; yi < yend; yi++) { + for (int xi = xstart; xi < xend; xi++) { + ret += map->data[yi * map->size + xi]; } } - if (v > 1) - v = 1; + return ret; +} - return v; +double sum_kernel_normalized(const conv *map, int x, int y, int width, int height) { + double ret = sum_kernel(map, x, y, width, height); + if (ret < 0) { + ret = 0; + } + if (ret > 1) { + ret = 1; + } + return ret; } static double attr_const gaussian(double r, double x, double y) { @@ -113,4 +84,29 @@ conv *gaussian_kernel(double r) { return c; } +/// 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) { + const int d = map->size; + + if (*shadow_sum) + free(*shadow_sum); + + auto sum = *shadow_sum = ccalloc(d * d, double); + sum[0] = map->data[0]; + + for (int x = 1; x < d; x++) { + sum[x] = sum[x - 1] + map->data[x]; + } + + for (int y = 1; y < d; y++) { + sum[y * d] = sum[(y - 1) * d] + map->data[y * d]; + for (int x = 1; x < d; x++) { + double tmp = sum[(y - 1) * d + x] + sum[y * d + x - 1] - + sum[(y - 1) * d + x - 1]; + sum[y * d + x] = tmp + map->data[y * d + x]; + } + } +} + // vim: set noet sw=8 ts=8 : diff --git a/src/kernel.h b/src/kernel.h index 7864619..4ec016d 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -14,6 +14,11 @@ typedef struct conv { /// Calculate the sum of a rectangle part of the convolution kernel /// the rectangle is defined by top left (x, y), and a size (width x height) double attr_const sum_kernel(const conv *map, int x, int y, int width, int height); +double attr_const sum_kernel_normalized(const conv *map, int x, int y, int width, int height); /// Create a kernel with gaussian distribution of radius r 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); diff --git a/src/render.c b/src/render.c index 4b99386..9935161 100644 --- a/src/render.c +++ b/src/render.c @@ -99,9 +99,8 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, doubl if (alpha_step != 0) { int op = ((!argb && !alpha_pict) ? XCB_RENDER_PICT_OP_SRC : XCB_RENDER_PICT_OP_OVER); - xcb_render_composite(ps->c, op, pict, alpha_pict, - ps->tgt_buffer.pict, x, y, 0, 0, dx, dy, wid, - hei); + xcb_render_composite(ps->c, op, pict, alpha_pict, ps->tgt_buffer.pict, + x, y, 0, 0, dx, dy, wid, hei); } break; } @@ -221,14 +220,14 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) { xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, pict, XCB_NONE, newpict, 0, 0, 0, 0, 0, 0, wid, hei); xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_DIFFERENCE, - ps->white_picture, XCB_NONE, newpict, 0, 0, 0, 0, - 0, 0, wid, hei); + ps->white_picture, XCB_NONE, newpict, 0, 0, + 0, 0, 0, 0, wid, hei); // We use an extra PictOpInReverse operation to get correct // pixel alpha. There could be a better solution. if (win_has_alpha(w)) xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_IN_REVERSE, - pict, XCB_NONE, newpict, 0, 0, 0, 0, 0, - 0, wid, hei); + pict, XCB_NONE, newpict, 0, 0, 0, 0, + 0, 0, wid, hei); pict = newpict; } } @@ -256,9 +255,8 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) { // top int body_height = hei; // ctop = checked top - int ctop = min_i( - body_height, - t); // Make sure top margin is smaller than height + // Make sure top margin is smaller than height + int ctop = min_i(body_height, t); if (ctop > 0) COMP_BDR(0, 0, wid, ctop); @@ -268,13 +266,13 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) { // bottom // cbot = checked bottom - int cbot = - min_i(body_height, - b); // Make sure bottom margin is not too large + // Make sure bottom margin is not too large + int cbot = min_i(body_height, b); if (cbot > 0) COMP_BDR(0, hei - cbot, wid, cbot); - body_height -= cbot; // Height of window exclude the margin + // Height of window exclude the margin + body_height -= cbot; if (body_height <= 0) break; @@ -438,20 +436,31 @@ static void paint_root(session_t *ps, const region_t *reg_paint) { ps->root_tile_paint.pict); } -static xcb_image_t *make_shadow(session_t *ps, double opacity, int width, int height) { +static xcb_image_t * +make_shadow(xcb_connection_t *c, const conv *kernel, const double *shadow_sum, + double opacity, int width, int height) { + /* + * We classify shadows into 4 kinds of regions + * r = shadow radius + * (0, 0) is the top left of the window itself + * -r r width-r width+r + * -r +-----+---------+-----+ + * | 1 | 2 | 1 | + * r +-----+---------+-----+ + * | 2 | 3 | 2 | + * height-r +-----+---------+-----+ + * | 1 | 2 | 1 | + * height+r +-----+---------+-----+ + */ xcb_image_t *ximage; - int ylimit, xlimit; - int swidth = width + ps->cgsize; - int sheight = height + ps->cgsize; - int center = ps->cgsize / 2; - int x, y; - unsigned char d; - int x_diff; - int opacity_int = (int)(opacity * 25); + int d = kernel->size, r = d / 2; + int swidth = width + r * 2, sheight = height + r * 2; - ximage = xcb_image_create_native(ps->c, swidth, sheight, - XCB_IMAGE_FORMAT_Z_PIXMAP, 8, 0, 0, NULL); + assert(d % 2 == 1); + assert(d > 0); + ximage = xcb_image_create_native(c, swidth, sheight, XCB_IMAGE_FORMAT_Z_PIXMAP, 8, + 0, 0, NULL); if (!ximage) { log_error("failed to create an X image"); return 0; @@ -460,92 +469,91 @@ static xcb_image_t *make_shadow(session_t *ps, double opacity, int width, int he unsigned char *data = ximage->data; uint32_t sstride = ximage->stride; - /* - * Build the gaussian in sections - */ - - /* - * center (fill the complete data array) - */ - - // XXX If the center part of the shadow would be entirely covered by - // the body of the window, we shouldn't need to fill the center here. - // XXX In general, we want to just fill the part that is not behind - // the window, in order to reduce CPU load and make transparent window - // look correct - if (ps->cgsize > 0) { - d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + ps->cgsize]; - } else { - d = (unsigned char)(sum_kernel(ps->gaussian_map, center, center, width, - height) * - opacity * 255.0); - } - memset(data, d, sheight * swidth); - - /* - * corners - */ - - ylimit = ps->cgsize; - if (ylimit > sheight / 2) - ylimit = (sheight + 1) / 2; - - xlimit = ps->cgsize; - if (xlimit > swidth / 2) - xlimit = (swidth + 1) / 2; - - for (y = 0; y < ylimit; y++) { - for (x = 0; x < xlimit; x++) { - if (xlimit == ps->cgsize && ylimit == ps->cgsize) { - d = ps->shadow_corner[opacity_int * (ps->cgsize + 1) * - (ps->cgsize + 1) + - y * (ps->cgsize + 1) + x]; - } else { - d = (unsigned char)(sum_kernel(ps->gaussian_map, x - center, - y - center, width, height) * - opacity * 255.0); + // If the window body is smaller than the kernel, we do convolution directly + if (width < r * 2 && height < r * 2) { + for (int y = 0; y < sheight; y++) { + for (int x = 0; x < swidth; x++) { + double sum = sum_kernel_normalized( + kernel, d - x - 1, d - y - 1, width, height); + data[y * sstride + x] = sum * 255.0; } - data[y * sstride + x] = d; - data[(sheight - y - 1) * sstride + x] = d; - data[(sheight - y - 1) * sstride + (swidth - x - 1)] = d; - data[y * sstride + (swidth - x - 1)] = d; } + return ximage; } - /* - * top/bottom - */ - - x_diff = swidth - (ps->cgsize * 2); - if (x_diff > 0 && ylimit > 0) { - for (y = 0; y < ylimit; y++) { - if (ylimit == ps->cgsize) { - d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + y]; - } else { - d = (unsigned char)(sum_kernel(ps->gaussian_map, center, - y - center, width, height) * - opacity * 255.0); + if (height < r * 2) { + // If the window height is smaller than the kernel, we divide + // the window like this: + // -r r width-r width+r + // +------+-------------+------+ + // | | | | + // +------+-------------+------+ + for (int y = 0; y < sheight; y++) { + for (int x = 0; x < r * 2; x++) { + double sum = sum_kernel_normalized(kernel, d - x - 1, + d - y - 1, d, height) * + 255.0; + data[y * sstride + x] = sum; + data[y * sstride + swidth - x - 1] = sum; } - memset(&data[y * sstride + ps->cgsize], d, x_diff); - memset(&data[(sheight - y - 1) * sstride + ps->cgsize], d, x_diff); + } + for (int y = 0; y < sheight; y++) { + double sum = + sum_kernel_normalized(kernel, 0, d - y - 1, d, height) * 255.0; + memset(&data[y * sstride + r * 2], sum, width - 2 * r); + } + return ximage; + } + if (width < r * 2) { + // Similarly, for width smaller than kernel + for (int y = 0; y < r * 2; y++) { + for (int x = 0; x < swidth; x++) { + double sum = sum_kernel_normalized(kernel, d - x - 1, + d - y - 1, width, d) * + 255.0; + data[y * sstride + x] = sum; + data[(sheight - y - 1) * sstride + x] = sum; + } + } + for (int x = 0; x < swidth; x++) { + double sum = + sum_kernel_normalized(kernel, d - x - 1, 0, width, d) * 255.0; + for (int y = r * 2; y < height; y++) { + data[y * sstride + x] = sum; + } + } + return ximage; + } + + // Fill part 3 + for (int y = r; y < height + r; y++) { + memset(data + sstride * y + r, 255, width); + } + + // Part 1 + for (int y = 0; y < r * 2; y++) { + for (int x = 0; x < r * 2; x++) { + double tmpsum = shadow_sum[y * d + x] * opacity * 255.0; + data[y * sstride + x] = tmpsum; + data[(sheight - y - 1) * sstride + x] = tmpsum; + data[(sheight - y - 1) * sstride + (swidth - x - 1)] = tmpsum; + data[y * sstride + (swidth - x - 1)] = tmpsum; } } - /* - * sides - */ + // Part 2, top/bottom + for (int y = 0; y < r * 2; y++) { + double tmpsum = shadow_sum[d * y + d - 1] * opacity * 255.0; + memset(&data[y * sstride + r * 2], tmpsum, width - r * 2); + memset(&data[(sheight - y - 1) * sstride + r * 2], tmpsum, width - r * 2); + } - for (x = 0; x < xlimit; x++) { - if (xlimit == ps->cgsize) { - d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + x]; - } else { - d = (unsigned char)(sum_kernel(ps->gaussian_map, x - center, - center, width, height) * - opacity * 255.0); - } - for (y = ps->cgsize; y < sheight - ps->cgsize; y++) { - data[y * sstride + x] = d; - data[y * sstride + (swidth - x - 1)] = d; + // Part 2, left/right + for (int x = 0; x < r * 2; x++) { + double tmpsum = shadow_sum[d * (d - 1) + x] * opacity * 255.0; + for (int y = r * 2; y < height; y++) { + data[y * sstride + x] = tmpsum; + data[y * sstride + (swidth - x - 1)] = tmpsum; } } @@ -565,7 +573,8 @@ static bool win_build_shadow(session_t *ps, win *w, double opacity) { xcb_render_picture_t shadow_picture = XCB_NONE, shadow_picture_argb = XCB_NONE; xcb_gcontext_t gc = XCB_NONE; - shadow_image = make_shadow(ps, opacity, width, height); + shadow_image = + make_shadow(ps->c, ps->gaussian_map, ps->shadow_sum, opacity, width, height); if (!shadow_image) { log_error("failed to make shadow"); return XCB_NONE; @@ -698,9 +707,9 @@ xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int x, int y, int wi // Copy from source picture to destination. The filter must // be applied on source picture, to get the nearby pixels outside the // window. - xcb_render_set_picture_filter( - ps->c, src_pict, strlen(XRFILTER_CONVOLUTION), XRFILTER_CONVOLUTION, - kwid * khei + 2, convolution_blur); + xcb_render_set_picture_filter(ps->c, src_pict, strlen(XRFILTER_CONVOLUTION), + XRFILTER_CONVOLUTION, kwid * khei + 2, + convolution_blur); xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, dst_pict, (rd_from_tgt ? x : 0), (rd_from_tgt ? y : 0), 0, 0, (rd_from_tgt ? 0 : x), @@ -726,9 +735,8 @@ xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int x, int y, int wi /** * Blur the background of a window. */ -static inline void -win_blur_background(session_t *ps, win *w, xcb_render_picture_t tgt_buffer, - const region_t *reg_paint) { +static inline void win_blur_background(session_t *ps, win *w, xcb_render_picture_t tgt_buffer, + const region_t *reg_paint) { const int x = w->g.x; const int y = w->g.y; const int wid = w->widthb; @@ -794,8 +802,7 @@ win_blur_background(session_t *ps, win *w, xcb_render_picture_t tgt_buffer, } // 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, ®_blur); pixman_region32_clear(®_blur); } break; #ifdef CONFIG_OPENGL @@ -815,7 +822,8 @@ win_blur_background(session_t *ps, win *w, xcb_render_picture_t tgt_buffer, void paint_all(session_t *ps, region_t *region, const region_t *region_real, win *const t) { if (ps->o.xrender_sync_fence) { if (!x_fence_sync(ps, ps->sync_fence)) { - log_error("x_fence_sync failed, xrender-sync-fence will be disabled from now on."); + log_error("x_fence_sync failed, xrender-sync-fence will be " + "disabled from now on."); xcb_sync_destroy_fence(ps->c, ps->sync_fence); ps->sync_fence = XCB_NONE; ps->o.xrender_sync_fence = false; @@ -997,15 +1005,15 @@ void paint_all(session_t *ps, region_t *region, const region_t *region_real, win xcb_render_picture_t new_pict = x_create_picture_with_pictfmt( ps, ps->root_width, ps->root_height, pictfmt, 0, NULL); xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, - ps->tgt_buffer.pict, XCB_NONE, new_pict, 0, 0, 0, - 0, 0, 0, ps->root_width, ps->root_height); + ps->tgt_buffer.pict, XCB_NONE, new_pict, 0, 0, + 0, 0, 0, 0, ps->root_width, ps->root_height); // Next, we set the region of paint and highlight it x_set_picture_clip_region(ps, new_pict, 0, 0, region_real); - xcb_render_composite( - ps->c, XCB_RENDER_PICT_OP_OVER, ps->white_picture, - ps->alpha_picts[MAX_ALPHA / 2], new_pict, 0, 0, 0, 0, 0, 0, - ps->root_width, ps->root_height); + xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, + ps->white_picture, + ps->alpha_picts[MAX_ALPHA / 2], new_pict, 0, 0, + 0, 0, 0, 0, ps->root_width, ps->root_height); // Finally, clear clip region and put the whole thing on screen x_set_picture_clip_region(ps, new_pict, 0, 0, &ps->screen_reg); @@ -1015,9 +1023,9 @@ void paint_all(session_t *ps, region_t *region, const region_t *region_real, win xcb_render_free_picture(ps->c, new_pict); } else xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, - ps->tgt_buffer.pict, XCB_NONE, ps->tgt_picture, - 0, 0, 0, 0, 0, 0, ps->root_width, - ps->root_height); + ps->tgt_buffer.pict, XCB_NONE, + ps->tgt_picture, 0, 0, 0, 0, 0, 0, + ps->root_width, ps->root_height); break; #ifdef CONFIG_OPENGL case BKEND_XR_GLX_HYBRID: @@ -1091,8 +1099,7 @@ static bool xr_init_blur(session_t *ps) { char *name = xcb_str_name(iter.data); // Check for the convolution filter if (strlen(XRFILTER_CONVOLUTION) == len && - !memcmp(XRFILTER_CONVOLUTION, name, - strlen(XRFILTER_CONVOLUTION))) + !memcmp(XRFILTER_CONVOLUTION, name, strlen(XRFILTER_CONVOLUTION))) ps->xrfilter_convolution_exists = true; } free(pf); @@ -1165,49 +1172,6 @@ static bool init_alpha_picts(session_t *ps) { return true; } -/// precompute shadow corners and sides to save time for large windows -static void presum_gaussian(session_t *ps, conv *map) { - ps->cgsize = map->size; - - const int center = map->size / 2; - const int r = ps->cgsize + 1; // radius of the kernel - const int width = ps->cgsize * 2, height = ps->cgsize * 2; - - if (ps->shadow_corner) - free(ps->shadow_corner); - if (ps->shadow_top) - free(ps->shadow_top); - - // clang-format off - ps->shadow_corner = cvalloc(r*r*26); - ps->shadow_top = cvalloc(r*26); - - for (int x = 0; x < r; x++) { - double sum = sum_kernel(map, x-center, center, width, height); - int tmp = ps->shadow_top[25*r+x] = (unsigned char)(sum*255.0); - - for (int opacity = 0; opacity < 25; opacity++) { - ps->shadow_top[opacity*r+x] = tmp*opacity/25; - } - } - - for (int x = 0; x < r; x++) { - for (int y = 0; y <= x; y++) { - double sum = - sum_kernel(map, x-center, y-center, width, height); - ps->shadow_corner[25*r*r+y*r+x] = (unsigned char)(sum*255.0); - ps->shadow_corner[25*r*r+x*r+y] = ps->shadow_corner[25*r*r+y*r+x]; - - for (int opacity = 0; opacity < 25; opacity++) { - ps->shadow_corner[opacity*r*r+y*r+x] = - ps->shadow_corner[opacity*r*r+x*r+y] = - ps->shadow_corner[25*r*r+y*r+x]*opacity/25; - } - } - } - // clang-format on -} - bool init_render(session_t *ps) { // Initialize OpenGL as early as possible if (bkend_use_glx(ps)) { @@ -1228,8 +1192,7 @@ bool init_render(session_t *ps) { // Initialize window GL shader if (BKEND_GLX == ps->o.backend && ps->o.glx_fshader_win_str) { #ifdef CONFIG_OPENGL - if (!glx_load_prog_main(ps, NULL, ps->o.glx_fshader_win_str, - &ps->glx_prog_win)) + if (!glx_load_prog_main(ps, NULL, ps->o.glx_fshader_win_str, &ps->glx_prog_win)) return false; #else log_error("GLSL supported not compiled in, can't load " @@ -1259,7 +1222,7 @@ bool init_render(session_t *ps) { } ps->gaussian_map = gaussian_kernel(ps->o.shadow_radius); - presum_gaussian(ps, ps->gaussian_map); + shadow_preprocess(ps->gaussian_map, &ps->shadow_sum); ps->black_picture = solid_picture(ps, true, 1, 0, 0, 0); ps->white_picture = solid_picture(ps, true, 1, 1, 1, 1); @@ -1317,8 +1280,7 @@ void deinit_render(session_t *ps) { free_picture(ps->c, &ps->black_picture); free_picture(ps->c, &ps->white_picture); - free(ps->shadow_corner); - free(ps->shadow_top); + free(ps->shadow_sum); free(ps->gaussian_map); // Free other X resources