mirror of https://github.com/yshui/picom.git
Use struct conv for blur kernel as well
Instead of storing them as an array of xfixed. Might cause some performance overhead for the new backend, because it is allocating a buffer to do the conversion every frame. Will fix later. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
ae9dee8a9a
commit
2e2e8e3ce0
|
@ -15,6 +15,7 @@
|
|||
#include "region.h"
|
||||
#include "string_utils.h"
|
||||
#include "utils.h"
|
||||
#include "kernel.h"
|
||||
|
||||
#include "backend/gl/gl_common.h"
|
||||
|
||||
|
@ -678,13 +679,10 @@ bool gl_create_blur_filters(session_t *ps, gl_blur_shader_t *passes, const gl_ca
|
|||
}
|
||||
|
||||
for (int i = 0; i < MAX_BLUR_PASS && ps->o.blur_kerns[i]; ++i) {
|
||||
xcb_render_fixed_t *kern = ps->o.blur_kerns[i];
|
||||
if (!kern)
|
||||
break;
|
||||
|
||||
auto kern = ps->o.blur_kerns[i];
|
||||
// Build shader
|
||||
int wid = XFIXED_TO_DOUBLE(kern[0]), hei = XFIXED_TO_DOUBLE(kern[1]);
|
||||
int nele = wid * hei - 1;
|
||||
int width = kern->w, height = kern->h;
|
||||
int nele = width * height - 1;
|
||||
unsigned int len =
|
||||
strlen(FRAG_SHADER_BLUR_PREFIX) + strlen(sampler_type) +
|
||||
strlen(extension) + (strlen(shader_add) + strlen(texture_func) + 42) * nele +
|
||||
|
@ -696,15 +694,16 @@ bool gl_create_blur_filters(session_t *ps, gl_blur_shader_t *passes, const gl_ca
|
|||
assert(strlen(shader_str) < len);
|
||||
|
||||
double sum = 0.0;
|
||||
for (int j = 0; j < hei; ++j) {
|
||||
for (int k = 0; k < wid; ++k) {
|
||||
if (hei / 2 == j && wid / 2 == k)
|
||||
for (int j = 0; j < height; ++j) {
|
||||
for (int k = 0; k < width; ++k) {
|
||||
if (height / 2 == j && width / 2 == k)
|
||||
continue;
|
||||
double val = XFIXED_TO_DOUBLE(kern[2 + j * wid + k]);
|
||||
if (0.0 == val)
|
||||
double val = kern->data[j * width + k];
|
||||
if (val == 0) {
|
||||
continue;
|
||||
}
|
||||
sum += val;
|
||||
sprintf(pc, shader_add, val, texture_func, k - wid / 2, j - hei / 2);
|
||||
sprintf(pc, shader_add, val, texture_func, k - width / 2, j - height / 2);
|
||||
pc += strlen(pc);
|
||||
assert(strlen(shader_str) < len);
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/present.h>
|
||||
#include <xcb/sync.h>
|
||||
#include <xcb/render.h>
|
||||
#include <xcb/composite.h>
|
||||
#include <xcb/present.h>
|
||||
#include <xcb/render.h>
|
||||
#include <xcb/sync.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "backend/backend_common.h"
|
||||
|
@ -154,19 +154,13 @@ static void compose(void *backend_data, session_t *ps, win *w, void *win_data, i
|
|||
0, dst_x, dst_y, w->widthb, w->heightb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset filter on a <code>Picture</code>.
|
||||
*/
|
||||
static inline void xrfilter_reset(session_t *ps, xcb_render_picture_t p) {
|
||||
const char *filter = "Nearest";
|
||||
xcb_render_set_picture_filter(ps->c, p, strlen(filter), filter, 0, NULL);
|
||||
}
|
||||
|
||||
static bool blur(void *backend_data, session_t *ps, double opacity, const region_t *reg_paint) {
|
||||
static bool
|
||||
blur(void *backend_data, session_t *ps, double opacity, const region_t *reg_paint) {
|
||||
struct _xrender_data *xd = backend_data;
|
||||
const pixman_box32_t *reg = pixman_region32_extents((region_t *)reg_paint);
|
||||
const int height = reg->y2 - reg->y1;
|
||||
const int width = reg->x2 - reg->x1;
|
||||
static const char *default_filter = "Nearest";
|
||||
|
||||
// Create a buffer for storing blurred picture, make it just big enough
|
||||
// for the blur region
|
||||
|
@ -202,20 +196,18 @@ static bool blur(void *backend_data, session_t *ps, double opacity, const region
|
|||
int i;
|
||||
for (i = 0; ps->o.blur_kerns[i]; i++) {
|
||||
assert(i < MAX_BLUR_PASS - 1);
|
||||
xcb_render_fixed_t *convolution_blur = ps->o.blur_kerns[i];
|
||||
int kwid = XFIXED_TO_DOUBLE(convolution_blur[0]),
|
||||
khei = XFIXED_TO_DOUBLE(convolution_blur[1]);
|
||||
|
||||
// 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);
|
||||
// TODO cache converted blur_kerns
|
||||
x_set_picture_convolution_kernel(ps->c, src_pict, ps->o.blur_kerns[i]);
|
||||
|
||||
if (ps->o.blur_kerns[i + 1] || i == 0) {
|
||||
// This is not the last pass, or this is the first pass
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE,
|
||||
dst_pict, src_x, src_y, 0, 0, 0, 0, width, height);
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, src_pict,
|
||||
XCB_NONE, dst_pict, src_x, src_y, 0, 0, 0, 0,
|
||||
width, height);
|
||||
} else {
|
||||
// This is the last pass, and this is also not the first
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, src_pict,
|
||||
|
@ -223,7 +215,9 @@ static bool blur(void *backend_data, session_t *ps, double opacity, const region
|
|||
reg->y1, width, height);
|
||||
}
|
||||
|
||||
xrfilter_reset(ps, src_pict);
|
||||
// reset filter
|
||||
xcb_render_set_picture_filter(ps->c, src_pict, strlen(default_filter),
|
||||
default_filter, 0, NULL);
|
||||
|
||||
src_pict = tmp_picture[current];
|
||||
dst_pict = tmp_picture[!current];
|
||||
|
@ -243,8 +237,8 @@ static bool blur(void *backend_data, session_t *ps, double opacity, const region
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
render_win(void *backend_data, session_t *ps, win *w, void *win_data, const region_t *reg_paint) {
|
||||
static void render_win(void *backend_data, session_t *ps, win *w, void *win_data,
|
||||
const region_t *reg_paint) {
|
||||
struct _xrender_data *xd = backend_data;
|
||||
struct _xrender_win_data *wd = win_data;
|
||||
|
||||
|
@ -278,8 +272,9 @@ render_win(void *backend_data, session_t *ps, win *w, void *win_data, const regi
|
|||
// Handle invert color
|
||||
x_set_picture_clip_region(ps->c, wd->rendered_pict, 0, 0, ®_paint_local);
|
||||
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_DIFFERENCE, xd->white_pixel, XCB_NONE,
|
||||
wd->rendered_pict, 0, 0, 0, 0, 0, 0, w->widthb, w->heightb);
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_DIFFERENCE,
|
||||
xd->white_pixel, XCB_NONE, wd->rendered_pict, 0, 0,
|
||||
0, 0, 0, 0, w->widthb, w->heightb);
|
||||
// We use an extra PictOpInReverse operation to get correct pixel
|
||||
// alpha. There could be a better solution.
|
||||
if (win_has_alpha(w))
|
||||
|
@ -305,8 +300,9 @@ render_win(void *backend_data, session_t *ps, win *w, void *win_data, const regi
|
|||
|
||||
// Step 2: multiply alpha value
|
||||
// XXX test
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, xd->white_pixel, alpha_pict,
|
||||
wd->rendered_pict, 0, 0, 0, 0, 0, 0, w->widthb, w->heightb);
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, xd->white_pixel,
|
||||
alpha_pict, wd->rendered_pict, 0, 0, 0, 0, 0, 0,
|
||||
w->widthb, w->heightb);
|
||||
}
|
||||
|
||||
if (w->dim) {
|
||||
|
@ -361,7 +357,8 @@ static void *prepare_win(void *backend_data, session_t *ps, win *w) {
|
|||
// leave this here until we have chance to re-think the backend API
|
||||
if (w->shadow) {
|
||||
xcb_pixmap_t pixmap;
|
||||
build_shadow(ps, 1, w->widthb, w->heightb, xd->shadow_pixel, &pixmap, &wd->shadow_pict);
|
||||
build_shadow(ps, 1, w->widthb, w->heightb, xd->shadow_pixel, &pixmap,
|
||||
&wd->shadow_pict);
|
||||
xcb_free_pixmap(ps->c, pixmap);
|
||||
}
|
||||
return wd;
|
||||
|
@ -389,12 +386,12 @@ static void *init(session_t *ps) {
|
|||
|
||||
xd->black_pixel = solid_picture(ps, true, 1, 0, 0, 0);
|
||||
xd->white_pixel = solid_picture(ps, true, 1, 1, 1, 1);
|
||||
xd->shadow_pixel =
|
||||
solid_picture(ps, true, 1, ps->o.shadow_red, ps->o.shadow_green, ps->o.shadow_blue);
|
||||
xd->shadow_pixel = solid_picture(ps, true, 1, ps->o.shadow_red,
|
||||
ps->o.shadow_green, ps->o.shadow_blue);
|
||||
|
||||
if (ps->overlay != XCB_NONE) {
|
||||
xd->target =
|
||||
x_create_picture_with_visual_and_pixmap(ps->c, ps->vis, ps->overlay, 0, NULL);
|
||||
xd->target = x_create_picture_with_visual_and_pixmap(
|
||||
ps->c, ps->vis, ps->overlay, 0, NULL);
|
||||
xd->target_win = ps->overlay;
|
||||
} else {
|
||||
xcb_render_create_picture_value_list_t pa = {
|
||||
|
@ -411,16 +408,17 @@ static void *init(session_t *ps) {
|
|||
abort();
|
||||
}
|
||||
|
||||
xd->back_pixmap =
|
||||
x_create_pixmap(ps->c, pictfmt->depth, ps->root, ps->root_width, ps->root_height);
|
||||
xd->back = x_create_picture_with_pictfmt_and_pixmap(ps->c, pictfmt, xd->back_pixmap, 0, NULL);
|
||||
xd->back_pixmap = x_create_pixmap(ps->c, pictfmt->depth, ps->root, ps->root_width,
|
||||
ps->root_height);
|
||||
xd->back = x_create_picture_with_pictfmt_and_pixmap(ps->c, pictfmt,
|
||||
xd->back_pixmap, 0, NULL);
|
||||
|
||||
xcb_pixmap_t root_pixmap = x_get_root_back_pixmap(ps);
|
||||
if (root_pixmap == XCB_NONE) {
|
||||
xd->root_pict = solid_picture(ps, false, 1, 0.5, 0.5, 0.5);
|
||||
} else {
|
||||
xd->root_pict =
|
||||
x_create_picture_with_visual_and_pixmap(ps->c, ps->vis, root_pixmap, 0, NULL);
|
||||
xd->root_pict = x_create_picture_with_visual_and_pixmap(
|
||||
ps->c, ps->vis, root_pixmap, 0, NULL);
|
||||
}
|
||||
|
||||
if (ps->present_exists) {
|
||||
|
@ -475,8 +473,9 @@ static void present(void *backend_data, session_t *ps) {
|
|||
// To make sure rendering won't get stuck if user toggles vsync on the
|
||||
// fly.
|
||||
xcb_sync_reset_fence(ps->c, xd->idle_fence);
|
||||
xcb_present_pixmap(ps->c, xd->target_win, xd->back_pixmap, 0, XCB_NONE, XCB_NONE,
|
||||
0, 0, XCB_NONE, XCB_NONE, xd->idle_fence, 0, 0, 1, 0, 0, NULL);
|
||||
xcb_present_pixmap(ps->c, xd->target_win, xd->back_pixmap, 0, XCB_NONE,
|
||||
XCB_NONE, 0, 0, XCB_NONE, XCB_NONE, xd->idle_fence, 0,
|
||||
0, 1, 0, 0, NULL);
|
||||
} else {
|
||||
// compose() sets clip region, so clear it first to make
|
||||
// sure we update the whole screen.
|
||||
|
@ -484,8 +483,9 @@ static void present(void *backend_data, session_t *ps) {
|
|||
|
||||
// TODO buffer-age-like optimization might be possible here.
|
||||
// but that will require a different backend API
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, xd->back, XCB_NONE, xd->target,
|
||||
0, 0, 0, 0, 0, 0, ps->root_width, ps->root_height);
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, xd->back, XCB_NONE,
|
||||
xd->target, 0, 0, 0, 0, 0, 0, ps->root_width,
|
||||
ps->root_height);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -127,10 +127,6 @@
|
|||
// Window opacity / dim state changed
|
||||
#define WFLAG_OPCT_CHANGE 0x0004
|
||||
|
||||
// xcb-render specific macros
|
||||
#define XFIXED_TO_DOUBLE(value) (((double) (value)) / 65536)
|
||||
#define DOUBLE_TO_XFIXED(value) ((xcb_render_fixed_t) (((double) (value)) * 65536))
|
||||
|
||||
// === Types ===
|
||||
typedef struct glx_fbconfig glx_fbconfig_t;
|
||||
|
||||
|
|
147
src/config.c
147
src/config.c
|
@ -17,6 +17,7 @@
|
|||
#include "log.h"
|
||||
#include "region.h"
|
||||
#include "types.h"
|
||||
#include "kernel.h"
|
||||
#include "win.h"
|
||||
|
||||
#include "config.h"
|
||||
|
@ -43,109 +44,116 @@ parse_long(const char *s, long *dest) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Parse a floating-point number in matrix.
|
||||
* Parse a floating-point number in from a string,
|
||||
* also strips the trailing space and comma after the number.
|
||||
*
|
||||
* @param[in] src string to parse
|
||||
* @param[out] dest return the number parsed from the string
|
||||
* @return pointer to the last character parsed
|
||||
*/
|
||||
const char *
|
||||
parse_matrix_readnum(const char *src, double *dest) {
|
||||
parse_readnum(const char *src, double *dest) {
|
||||
const char *pc = NULL;
|
||||
double val = strtod_simple(src, &pc);
|
||||
if (!pc || pc == src) {
|
||||
log_error("No number found: %s", src);
|
||||
return src;
|
||||
}
|
||||
|
||||
while (*pc && (isspace(*pc) || ',' == *pc))
|
||||
while (*pc && (isspace(*pc) || *pc == ',')) {
|
||||
++pc;
|
||||
|
||||
}
|
||||
*dest = val;
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a matrix.
|
||||
*
|
||||
* @param[in] src the blur kernel string
|
||||
* @param[out] endptr return where the end of kernel is in the string
|
||||
* @param[out] hasneg whether the kernel has negative values
|
||||
*/
|
||||
xcb_render_fixed_t *
|
||||
parse_matrix(const char *src, const char **endptr, bool *hasneg) {
|
||||
int wid = 0, hei = 0;
|
||||
conv *
|
||||
parse_blur_kern(const char *src, const char **endptr, bool *hasneg) {
|
||||
int width = 0, height = 0;
|
||||
*hasneg = false;
|
||||
|
||||
const char *pc = NULL;
|
||||
|
||||
// Get matrix width and height
|
||||
{
|
||||
double val = 0.0;
|
||||
if (src == (pc = parse_matrix_readnum(src, &val)))
|
||||
goto err1;
|
||||
src = pc;
|
||||
wid = val;
|
||||
if (src == (pc = parse_matrix_readnum(src, &val)))
|
||||
goto err1;
|
||||
src = pc;
|
||||
hei = val;
|
||||
}
|
||||
double val = 0.0;
|
||||
if (src == (pc = parse_readnum(src, &val)))
|
||||
goto err1;
|
||||
src = pc;
|
||||
width = val;
|
||||
if (src == (pc = parse_readnum(src, &val)))
|
||||
goto err1;
|
||||
src = pc;
|
||||
height = val;
|
||||
|
||||
// Validate matrix width and height
|
||||
if (wid <= 0 || hei <= 0) {
|
||||
log_error("Invalid matrix width/height.");
|
||||
if (width <= 0 || height <= 0) {
|
||||
log_error("Blue kernel width/height can't be negative.");
|
||||
goto err1;
|
||||
}
|
||||
if (!(wid % 2 && hei % 2)) {
|
||||
log_error("Width/height not odd.");
|
||||
if (!(width % 2 && height % 2)) {
|
||||
log_error("Blur kernel idth/height must be odd.");
|
||||
goto err1;
|
||||
}
|
||||
if (wid > 16 || hei > 16)
|
||||
log_warn("Matrix width/height too large, may slow down"
|
||||
if (width > 16 || height > 16)
|
||||
log_warn("Blur kernel width/height too large, may slow down"
|
||||
"rendering, and/or consume lots of memory");
|
||||
|
||||
// Allocate memory
|
||||
auto matrix = ccalloc(wid * hei + 2, xcb_render_fixed_t);
|
||||
conv *matrix = cvalloc(sizeof(conv) + width * height * sizeof(double));
|
||||
|
||||
// Read elements
|
||||
{
|
||||
int skip = hei / 2 * wid + wid / 2;
|
||||
for (int i = 0; i < wid * hei; ++i) {
|
||||
// Ignore the center element
|
||||
if (i == skip) {
|
||||
matrix[2 + i] = DOUBLE_TO_XFIXED(0);
|
||||
continue;
|
||||
}
|
||||
double val = 0;
|
||||
if (src == (pc = parse_matrix_readnum(src, &val)))
|
||||
goto err2;
|
||||
src = pc;
|
||||
if (val < 0) *hasneg = true;
|
||||
matrix[2 + i] = DOUBLE_TO_XFIXED(val);
|
||||
int skip = height / 2 * width + width / 2;
|
||||
for (int i = 0; i < width * height; ++i) {
|
||||
// Ignore the center element
|
||||
if (i == skip) {
|
||||
matrix->data[i] = 0;
|
||||
continue;
|
||||
}
|
||||
if (src == (pc = parse_readnum(src, &val))) {
|
||||
goto err2;
|
||||
}
|
||||
src = pc;
|
||||
if (val < 0) {
|
||||
*hasneg = true;
|
||||
}
|
||||
matrix->data[i] = val;
|
||||
}
|
||||
|
||||
// Detect trailing characters
|
||||
for ( ;*pc && ';' != *pc; ++pc)
|
||||
if (!isspace(*pc) && ',' != *pc) {
|
||||
log_error("Trailing characters in matrix string.");
|
||||
for (;*pc && *pc != ';'; pc++) {
|
||||
if (!isspace(*pc) && *pc != ',') {
|
||||
// TODO isspace is locale aware, be careful
|
||||
log_error("Trailing characters in blur kernel string.");
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
|
||||
// Jump over spaces after ';'
|
||||
if (';' == *pc) {
|
||||
++pc;
|
||||
while (*pc && isspace(*pc))
|
||||
if (*pc == ';') {
|
||||
pc++;
|
||||
while (*pc && isspace(*pc)) {
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
|
||||
// Require an end of string if endptr is not provided, otherwise
|
||||
// copy end pointer to endptr
|
||||
if (endptr)
|
||||
if (endptr) {
|
||||
*endptr = pc;
|
||||
else if (*pc) {
|
||||
log_error("Only one matrix expected.");
|
||||
} else if (*pc) {
|
||||
log_error("Only one blur kernel expected.");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
// Fill in width and height
|
||||
matrix[0] = DOUBLE_TO_XFIXED(wid);
|
||||
matrix[1] = DOUBLE_TO_XFIXED(hei);
|
||||
|
||||
matrix->w = width;
|
||||
matrix->h = height;
|
||||
return matrix;
|
||||
|
||||
err2:
|
||||
|
@ -154,25 +162,19 @@ err1:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a convolution kernel.
|
||||
*
|
||||
* Output:
|
||||
* hasneg: whether the convolution kernel has negative values
|
||||
*/
|
||||
xcb_render_fixed_t *
|
||||
parse_conv_kern(const char *src, const char **endptr, bool *hasneg) {
|
||||
return parse_matrix(src, endptr, hasneg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a list of convolution kernels.
|
||||
*
|
||||
* Output:
|
||||
* hasneg: whether any of the convolution kernel has negative values
|
||||
* @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
|
||||
*/
|
||||
bool
|
||||
parse_conv_kern_lst(const char *src, xcb_render_fixed_t **dest, int max, bool *hasneg) {
|
||||
parse_blur_kern_lst(const char *src, conv **dest, int max, bool *hasneg) {
|
||||
// TODO just return a predefined kernels, not parse predefined strings...
|
||||
static const struct {
|
||||
const char *name;
|
||||
const char *kern_str;
|
||||
|
@ -188,11 +190,11 @@ parse_conv_kern_lst(const char *src, xcb_render_fixed_t **dest, int max, bool *h
|
|||
};
|
||||
|
||||
*hasneg = false;
|
||||
|
||||
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))
|
||||
return parse_conv_kern_lst(CONV_KERN_PREDEF[i].kern_str, dest, max, hasneg);
|
||||
return parse_blur_kern_lst(CONV_KERN_PREDEF[i].kern_str, dest, max, hasneg);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
const char *pc = src;
|
||||
|
@ -207,8 +209,11 @@ parse_conv_kern_lst(const char *src, xcb_render_fixed_t **dest, int max, bool *h
|
|||
i = 0;
|
||||
while (pc && *pc && i < max - 1) {
|
||||
bool tmp_hasneg;
|
||||
if (!(dest[i++] = parse_conv_kern(pc, &pc, &tmp_hasneg)))
|
||||
dest[i] = parse_blur_kern(pc, &pc, &tmp_hasneg);
|
||||
if (!dest[i]) {
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
*hasneg |= tmp_hasneg;
|
||||
}
|
||||
|
||||
|
|
10
src/config.h
10
src/config.h
|
@ -24,6 +24,7 @@
|
|||
#include "compiler.h"
|
||||
#include "win.h"
|
||||
#include "types.h"
|
||||
#include "kernel.h"
|
||||
|
||||
typedef struct session session_t;
|
||||
|
||||
|
@ -207,7 +208,7 @@ typedef struct options_t {
|
|||
/// Background blur blacklist. A linked list of conditions.
|
||||
c2_lptr_t *blur_background_blacklist;
|
||||
/// Blur convolution kernel.
|
||||
xcb_render_fixed_t *blur_kerns[MAX_BLUR_PASS];
|
||||
conv *blur_kerns[MAX_BLUR_PASS];
|
||||
/// 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
|
||||
|
@ -245,13 +246,8 @@ extern const char *const VSYNC_STRS[NUM_VSYNC + 1];
|
|||
extern const char *const BACKEND_STRS[NUM_BKEND + 1];
|
||||
|
||||
attr_warn_unused_result bool parse_long(const char *, long *);
|
||||
attr_warn_unused_result const char *parse_matrix_readnum(const char *, double *);
|
||||
attr_warn_unused_result xcb_render_fixed_t *
|
||||
parse_matrix(const char *, const char **, bool *hasneg);
|
||||
attr_warn_unused_result xcb_render_fixed_t *
|
||||
parse_conv_kern(const char *, const char **, bool *hasneg);
|
||||
attr_warn_unused_result bool
|
||||
parse_conv_kern_lst(const char *, xcb_render_fixed_t **, int, bool *hasneg);
|
||||
parse_blur_kern_lst(const char *, conv **, int, bool *hasneg);
|
||||
attr_warn_unused_result bool parse_geometry(session_t *, const char *, region_t *);
|
||||
attr_warn_unused_result bool parse_rule_opacity(c2_lptr_t **, const char *);
|
||||
|
||||
|
|
|
@ -379,7 +379,7 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
|||
&opt->blur_background_fixed);
|
||||
// --blur-kern
|
||||
if (config_lookup_string(&cfg, "blur-kern", &sval) &&
|
||||
!parse_conv_kern_lst(sval, opt->blur_kerns, MAX_BLUR_PASS, conv_kern_hasneg)) {
|
||||
!parse_blur_kern_lst(sval, opt->blur_kerns, MAX_BLUR_PASS, conv_kern_hasneg)) {
|
||||
log_fatal("Cannot parse \"blur-kern\"");
|
||||
goto err;
|
||||
}
|
||||
|
|
23
src/opengl.c
23
src/opengl.c
|
@ -23,6 +23,7 @@
|
|||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "region.h"
|
||||
#include "kernel.h"
|
||||
#include "backend/gl/gl_common.h"
|
||||
#include "backend/gl/glx.h"
|
||||
|
||||
|
@ -357,16 +358,13 @@ glx_init_blur(session_t *ps) {
|
|||
}
|
||||
|
||||
for (int i = 0; i < MAX_BLUR_PASS && ps->o.blur_kerns[i]; ++i) {
|
||||
xcb_render_fixed_t *kern = ps->o.blur_kerns[i];
|
||||
if (!kern)
|
||||
break;
|
||||
|
||||
auto kern = ps->o.blur_kerns[i];
|
||||
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
||||
|
||||
// Build shader
|
||||
{
|
||||
int wid = XFIXED_TO_DOUBLE(kern[0]), hei = XFIXED_TO_DOUBLE(kern[1]);
|
||||
int nele = wid * hei - 1;
|
||||
int width = kern->w, height = kern->h;
|
||||
int nele = width * height - 1;
|
||||
unsigned int len = strlen(FRAG_SHADER_BLUR_PREFIX) +
|
||||
strlen(sampler_type) +
|
||||
strlen(extension) +
|
||||
|
@ -380,15 +378,16 @@ glx_init_blur(session_t *ps) {
|
|||
assert(strlen(shader_str) < len);
|
||||
|
||||
double sum = 0.0;
|
||||
for (int j = 0; j < hei; ++j) {
|
||||
for (int k = 0; k < wid; ++k) {
|
||||
if (hei / 2 == j && wid / 2 == k)
|
||||
for (int j = 0; j < height; ++j) {
|
||||
for (int k = 0; k < width; ++k) {
|
||||
if (height / 2 == j && width / 2 == k)
|
||||
continue;
|
||||
double val = XFIXED_TO_DOUBLE(kern[2 + j * wid + k]);
|
||||
if (0.0 == val)
|
||||
double val = kern->data[j * width + k];
|
||||
if (val == 0) {
|
||||
continue;
|
||||
}
|
||||
sum += val;
|
||||
sprintf(pc, shader_add, val, texture_func, k - wid / 2, j - hei / 2);
|
||||
sprintf(pc, shader_add, val, texture_func, k - width / 2, j - height / 2);
|
||||
pc += strlen(pc);
|
||||
assert(strlen(shader_str) < len);
|
||||
}
|
||||
|
|
|
@ -711,7 +711,7 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
|||
break;
|
||||
case 301:
|
||||
// --blur-kern
|
||||
if (!parse_conv_kern_lst(optarg, opt->blur_kerns,
|
||||
if (!parse_blur_kern_lst(optarg, opt->blur_kerns,
|
||||
MAX_BLUR_PASS, &conv_kern_hasneg))
|
||||
exit(1);
|
||||
break;
|
||||
|
@ -818,35 +818,18 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
|||
|
||||
// Fill default blur kernel
|
||||
if (opt->blur_background && !opt->blur_kerns[0]) {
|
||||
// Convolution filter parameter (box blur)
|
||||
// gaussian or binomial filters are definitely superior, yet looks
|
||||
// like they aren't supported as of xorg-server-1.13.0
|
||||
static const xcb_render_fixed_t convolution_blur[] = {
|
||||
// Must convert to XFixed with DOUBLE_TO_XFIXED()
|
||||
// Matrix size
|
||||
DOUBLE_TO_XFIXED(3),
|
||||
DOUBLE_TO_XFIXED(3),
|
||||
// Matrix
|
||||
DOUBLE_TO_XFIXED(1),
|
||||
DOUBLE_TO_XFIXED(1),
|
||||
DOUBLE_TO_XFIXED(1),
|
||||
DOUBLE_TO_XFIXED(1),
|
||||
DOUBLE_TO_XFIXED(1),
|
||||
DOUBLE_TO_XFIXED(1),
|
||||
DOUBLE_TO_XFIXED(1),
|
||||
DOUBLE_TO_XFIXED(1),
|
||||
DOUBLE_TO_XFIXED(1),
|
||||
};
|
||||
opt->blur_kerns[0] = ccalloc(ARR_SIZE(convolution_blur), xcb_render_fixed_t);
|
||||
memcpy(opt->blur_kerns[0], convolution_blur, sizeof(convolution_blur));
|
||||
bool ret = parse_blur_kern_lst("3x3box", opt->blur_kerns, MAX_BLUR_PASS, &conv_kern_hasneg);
|
||||
assert(ret);
|
||||
}
|
||||
|
||||
if (opt->resize_damage < 0)
|
||||
if (opt->resize_damage < 0) {
|
||||
log_warn("Negative --resize-damage will not work correctly.");
|
||||
}
|
||||
|
||||
if (opt->backend == BKEND_XRENDER && conv_kern_hasneg)
|
||||
if (opt->backend == BKEND_XRENDER && conv_kern_hasneg) {
|
||||
log_warn("A convolution kernel with negative values may not work "
|
||||
"properly under X Render backend.");
|
||||
}
|
||||
}
|
||||
|
||||
// vim: set noet sw=8 ts=8 :
|
||||
|
|
56
src/render.c
56
src/render.c
|
@ -318,7 +318,7 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) {
|
|||
const int r = extents.right;
|
||||
|
||||
#define COMP_BDR(cx, cy, cwid, chei) \
|
||||
paint_region(ps, w, (cx), (cy), (cwid), (chei), w->frame_opacity * w->opacity, \
|
||||
paint_region(ps, w, (cx), (cy), (cwid), (chei), w->frame_opacity * w->opacity, \
|
||||
reg_paint, pict)
|
||||
|
||||
// Sanitize the margins, in case some broken WM makes
|
||||
|
@ -582,18 +582,6 @@ static inline void win_paint_shadow(session_t *ps, win *w, region_t *reg_paint)
|
|||
w->shadow_paint.ptex, reg_paint, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a convolution kernel.
|
||||
*/
|
||||
static inline void normalize_conv_kern(int wid, int hei, xcb_render_fixed_t *kern) {
|
||||
double sum = 0.0;
|
||||
for (int i = 0; i < wid * hei; ++i)
|
||||
sum += XFIXED_TO_DOUBLE(kern[i]);
|
||||
double factor = 1.0 / sum;
|
||||
for (int i = 0; i < wid * hei; ++i)
|
||||
kern[i] = DOUBLE_TO_XFIXED(XFIXED_TO_DOUBLE(kern[i]) * factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Blur an area on a buffer.
|
||||
*
|
||||
|
@ -630,8 +618,9 @@ static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int x, i
|
|||
for (int i = 0; blur_kerns[i]; ++i) {
|
||||
assert(i < MAX_BLUR_PASS - 1);
|
||||
xcb_render_fixed_t *convolution_blur = blur_kerns[i];
|
||||
int kwid = XFIXED_TO_DOUBLE(convolution_blur[0]),
|
||||
khei = XFIXED_TO_DOUBLE(convolution_blur[1]);
|
||||
// `x / 65536.0` converts from X fixed point to double
|
||||
int kwid = ((double)convolution_blur[0]) / 65536.0,
|
||||
khei = ((double)convolution_blur[1]) / 65536.0;
|
||||
bool rd_from_tgt = (tgt_buffer == src_pict);
|
||||
|
||||
// Copy from source picture to destination. The filter must
|
||||
|
@ -685,7 +674,9 @@ static inline void win_blur_background(session_t *ps, win *w, xcb_render_picture
|
|||
case BKEND_XR_GLX_HYBRID: {
|
||||
// Normalize blur kernels
|
||||
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
||||
xcb_render_fixed_t *kern_src = ps->o.blur_kerns[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) {
|
||||
|
@ -693,30 +684,33 @@ static inline void win_blur_background(session_t *ps, win *w, xcb_render_picture
|
|||
break;
|
||||
}
|
||||
|
||||
assert(!kern_dst ||
|
||||
(kern_src[0] == kern_dst[0] && kern_src[1] == kern_dst[1]));
|
||||
assert(!kern_dst || (kern_src->w == kern_dst[0] / 65536 &&
|
||||
kern_src->h == kern_dst[1] / 65536));
|
||||
|
||||
// Skip for fixed factor_center if the cache exists already
|
||||
if (ps->o.blur_background_fixed && kern_dst)
|
||||
continue;
|
||||
|
||||
int kwid = XFIXED_TO_DOUBLE(kern_src[0]),
|
||||
khei = XFIXED_TO_DOUBLE(kern_src[1]);
|
||||
|
||||
// Allocate cache space if needed
|
||||
if (!kern_dst) {
|
||||
kern_dst = ccalloc(kwid * khei + 2, xcb_render_fixed_t);
|
||||
kern_dst = ccalloc(kern_src->w * kern_src->h + 2,
|
||||
xcb_render_fixed_t);
|
||||
ps->blur_kerns_cache[i] = kern_dst;
|
||||
}
|
||||
|
||||
double sum = factor_center;
|
||||
for (int j = 0; j < kern_src->w * kern_src->h; j++) {
|
||||
sum += kern_src->data[j];
|
||||
}
|
||||
// Copy src to dst, normalizing in the process
|
||||
for (int j = 0; j < kern_src->w * kern_src->h; j++) {
|
||||
kern_dst[j + 2] = kern_src->data[j] / sum * 65536;
|
||||
}
|
||||
// Modify the factor of the center pixel
|
||||
kern_src[2 + (khei / 2) * kwid + kwid / 2] =
|
||||
DOUBLE_TO_XFIXED(factor_center);
|
||||
|
||||
// Copy over
|
||||
memcpy(kern_dst, kern_src,
|
||||
(kwid * khei + 2) * sizeof(xcb_render_fixed_t));
|
||||
normalize_conv_kern(kwid, khei, kern_dst + 2);
|
||||
kern_dst[2 + (kern_src->h / 2) * kern_src->w + kern_src->w / 2] =
|
||||
factor_center / sum * 65536;
|
||||
kern_dst[0] = kern_src->w * 65536;
|
||||
kern_dst[1] = kern_src->h * 65536;
|
||||
}
|
||||
|
||||
// Minimize the region we try to blur, if the window itself is not
|
||||
|
@ -1017,8 +1011,8 @@ void paint_all(session_t *ps, win *const t, bool ignore_damage) {
|
|||
glFlush();
|
||||
glXWaitX();
|
||||
assert(ps->tgt_buffer.pixmap);
|
||||
paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height, false,
|
||||
ps->depth, ps->vis, !ps->o.glx_no_rebind_pixmap);
|
||||
paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height,
|
||||
false, ps->depth, ps->vis, !ps->o.glx_no_rebind_pixmap);
|
||||
if (ps->o.vsync_use_glfinish)
|
||||
glFinish();
|
||||
else
|
||||
|
|
27
src/x.c
27
src/x.c
|
@ -17,6 +17,7 @@
|
|||
#include "region.h"
|
||||
#include "compiler.h"
|
||||
#include "common.h"
|
||||
#include "kernel.h"
|
||||
#include "x.h"
|
||||
#include "log.h"
|
||||
#include "backend/gl/glx.h"
|
||||
|
@ -513,3 +514,29 @@ bool x_fence_sync(xcb_connection_t *c, xcb_sync_fence_t f) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// xcb-render specific macros
|
||||
#define XFIXED_TO_DOUBLE(value) (((double) (value)) / 65536)
|
||||
#define DOUBLE_TO_XFIXED(value) ((xcb_render_fixed_t) (((double) (value)) * 65536))
|
||||
|
||||
/**
|
||||
* Set the picture filter of a xrender picture to a convolution
|
||||
* kernel.
|
||||
*
|
||||
* @param c xcb connection
|
||||
* @param pict the picture
|
||||
* @param kern the convolution kernel
|
||||
*/
|
||||
void
|
||||
x_set_picture_convolution_kernel(xcb_connection_t *c,
|
||||
xcb_render_picture_t pict, conv *kernel) {
|
||||
auto buf = ccalloc(kernel->w * kernel->h + 2, xcb_render_fixed_t);
|
||||
static const char *filter = "convolution";
|
||||
buf[0] = DOUBLE_TO_XFIXED(kernel->w);
|
||||
buf[1] = DOUBLE_TO_XFIXED(kernel->h);
|
||||
for (int i = 0; i < kernel->w * kernel->h; i++) {
|
||||
buf[i + 2] = DOUBLE_TO_XFIXED(kernel->data[i]);
|
||||
}
|
||||
xcb_render_set_picture_filter(c, pict, sizeof(filter), filter, kernel->w * kernel->h + 2, buf);
|
||||
free(buf);
|
||||
}
|
||||
|
|
13
src/x.h
13
src/x.h
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "compiler.h"
|
||||
#include "region.h"
|
||||
#include "kernel.h"
|
||||
|
||||
typedef struct session session_t;
|
||||
|
||||
|
@ -167,3 +168,15 @@ xcb_pixmap_t x_get_root_back_pixmap(session_t *ps);
|
|||
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);
|
||||
|
||||
/**
|
||||
* Set the picture filter of a xrender picture to a convolution
|
||||
* kernel.
|
||||
*
|
||||
* @param c xcb connection
|
||||
* @param pict the picture
|
||||
* @param kern the convolution kernel
|
||||
*/
|
||||
void
|
||||
x_set_picture_convolution_kernel(xcb_connection_t *c,
|
||||
xcb_render_picture_t pict, conv *kernel);
|
||||
|
|
Loading…
Reference in New Issue