Improvement: Dynamic blur strength & improved frame blur performance
- Remove the region expansion design in win_blur_background(). I must be sleep-walking when I wrote that! - Improve performance of blurring when a window is opaque but its frame is transparent. - Adjust blur strength according to window opacity. --blur-background-fixed restores the old behavior. - Add "use_offset" parameter to a few functions for convenience. Code clean-up.
This commit is contained in:
parent
22cabf7c89
commit
1bfe21efb5
|
@ -24,6 +24,7 @@ alpha-step = 0.06;
|
||||||
# inactive-dim-fixed = true;
|
# inactive-dim-fixed = true;
|
||||||
# blur-background = true;
|
# blur-background = true;
|
||||||
# blur-background-frame = true;
|
# blur-background-frame = true;
|
||||||
|
blur-background-fixed = false;
|
||||||
|
|
||||||
# Fading
|
# Fading
|
||||||
fading = true;
|
fading = true;
|
||||||
|
|
|
@ -545,7 +545,7 @@ win_rounded_corners(session_t *ps, win *w) {
|
||||||
|
|
||||||
// Fetch its bounding region
|
// Fetch its bounding region
|
||||||
if (!w->border_size)
|
if (!w->border_size)
|
||||||
w->border_size = border_size(ps, w);
|
w->border_size = border_size(ps, w, true);
|
||||||
|
|
||||||
// Quit if border_size() returns None
|
// Quit if border_size() returns None
|
||||||
if (!w->border_size)
|
if (!w->border_size)
|
||||||
|
@ -991,11 +991,11 @@ paint_root(session_t *ps, Picture tgt_buffer) {
|
||||||
* Get a rectangular region a window occupies, excluding shadow.
|
* Get a rectangular region a window occupies, excluding shadow.
|
||||||
*/
|
*/
|
||||||
static XserverRegion
|
static XserverRegion
|
||||||
win_get_region(session_t *ps, win *w) {
|
win_get_region(session_t *ps, win *w, bool use_offset) {
|
||||||
XRectangle r;
|
XRectangle r;
|
||||||
|
|
||||||
r.x = w->a.x;
|
r.x = (use_offset ? w->a.x: 0);
|
||||||
r.y = w->a.y;
|
r.y = (use_offset ? w->a.y: 0);
|
||||||
r.width = w->widthb;
|
r.width = w->widthb;
|
||||||
r.height = w->heightb;
|
r.height = w->heightb;
|
||||||
|
|
||||||
|
@ -1006,11 +1006,11 @@ win_get_region(session_t *ps, win *w) {
|
||||||
* Get a rectangular region a window occupies, excluding frame and shadow.
|
* Get a rectangular region a window occupies, excluding frame and shadow.
|
||||||
*/
|
*/
|
||||||
static XserverRegion
|
static XserverRegion
|
||||||
win_get_region_noframe(session_t *ps, win *w) {
|
win_get_region_noframe(session_t *ps, win *w, bool use_offset) {
|
||||||
XRectangle r;
|
XRectangle r;
|
||||||
|
|
||||||
r.x = w->a.x + w->a.border_width + w->left_width;
|
r.x = (use_offset ? w->a.x: 0) + w->a.border_width + w->left_width;
|
||||||
r.y = w->a.y + w->a.border_width + w->top_width;
|
r.y = (use_offset ? w->a.y: 0) + w->a.border_width + w->top_width;
|
||||||
r.width = max_i(w->a.width - w->left_width - w->right_width, 0);
|
r.width = max_i(w->a.width - w->left_width - w->right_width, 0);
|
||||||
r.height = max_i(w->a.height - w->top_width - w->bottom_width, 0);
|
r.height = max_i(w->a.height - w->top_width - w->bottom_width, 0);
|
||||||
|
|
||||||
|
@ -1069,9 +1069,9 @@ win_extents(session_t *ps, win *w) {
|
||||||
* Retrieve the bounding shape of a window.
|
* Retrieve the bounding shape of a window.
|
||||||
*/
|
*/
|
||||||
static XserverRegion
|
static XserverRegion
|
||||||
border_size(session_t *ps, win *w) {
|
border_size(session_t *ps, win *w, bool use_offset) {
|
||||||
// Start with the window rectangular region
|
// Start with the window rectangular region
|
||||||
XserverRegion fin = win_get_region(ps, w);
|
XserverRegion fin = win_get_region(ps, w, use_offset);
|
||||||
|
|
||||||
// Only request for a bounding region if the window is shaped
|
// Only request for a bounding region if the window is shaped
|
||||||
if (w->bounding_shaped) {
|
if (w->bounding_shaped) {
|
||||||
|
@ -1089,10 +1089,12 @@ border_size(session_t *ps, win *w) {
|
||||||
if (!border)
|
if (!border)
|
||||||
return fin;
|
return fin;
|
||||||
|
|
||||||
// Translate the region to the correct place
|
if (use_offset) {
|
||||||
XFixesTranslateRegion(ps->dpy, border,
|
// Translate the region to the correct place
|
||||||
w->a.x + w->a.border_width,
|
XFixesTranslateRegion(ps->dpy, border,
|
||||||
w->a.y + w->a.border_width);
|
w->a.x + w->a.border_width,
|
||||||
|
w->a.y + w->a.border_width);
|
||||||
|
}
|
||||||
|
|
||||||
// Intersect the bounding region we got with the window rectangle, to
|
// Intersect the bounding region we got with the window rectangle, to
|
||||||
// make sure the bounding region is not bigger than the window
|
// make sure the bounding region is not bigger than the window
|
||||||
|
@ -1249,7 +1251,7 @@ paint_preprocess(session_t *ps, win *list) {
|
||||||
if (to_paint) {
|
if (to_paint) {
|
||||||
// Fetch bounding region
|
// Fetch bounding region
|
||||||
if (!w->border_size) {
|
if (!w->border_size) {
|
||||||
w->border_size = border_size(ps, w);
|
w->border_size = border_size(ps, w, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch window extents
|
// Fetch window extents
|
||||||
|
@ -1326,10 +1328,10 @@ paint_preprocess(session_t *ps, win *list) {
|
||||||
if (w->border_size)
|
if (w->border_size)
|
||||||
w->reg_ignore = copy_region(ps, w->border_size);
|
w->reg_ignore = copy_region(ps, w->border_size);
|
||||||
else
|
else
|
||||||
w->reg_ignore = win_get_region(ps, w);
|
w->reg_ignore = win_get_region(ps, w, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
w->reg_ignore = win_get_region_noframe(ps, w);
|
w->reg_ignore = win_get_region_noframe(ps, w, true);
|
||||||
if (w->border_size)
|
if (w->border_size)
|
||||||
XFixesIntersectRegion(ps->dpy, w->reg_ignore, w->reg_ignore,
|
XFixesIntersectRegion(ps->dpy, w->reg_ignore, w->reg_ignore,
|
||||||
w->border_size);
|
w->border_size);
|
||||||
|
@ -1428,20 +1430,20 @@ win_paint_shadow(session_t *ps, win *w, Picture tgt_buffer) {
|
||||||
static inline void
|
static inline void
|
||||||
win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
|
win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
|
||||||
XserverRegion reg_paint) {
|
XserverRegion reg_paint) {
|
||||||
|
const static int convolution_blur_size = 3;
|
||||||
// Convolution filter parameter (box blur)
|
// Convolution filter parameter (box blur)
|
||||||
// gaussian or binomial filters are definitely superior, yet looks
|
// gaussian or binomial filters are definitely superior, yet looks
|
||||||
// like they aren't supported as of xorg-server-1.13.0
|
// like they aren't supported as of xorg-server-1.13.0
|
||||||
const static XFixed convolution_blur[] = {
|
XFixed convolution_blur[] = {
|
||||||
// Must convert to XFixed with XDoubleToFixed()
|
// Must convert to XFixed with XDoubleToFixed()
|
||||||
// Matrix size
|
// Matrix size
|
||||||
XDoubleToFixed(3), XDoubleToFixed(3),
|
XDoubleToFixed(convolution_blur_size),
|
||||||
|
XDoubleToFixed(convolution_blur_size),
|
||||||
// Matrix
|
// Matrix
|
||||||
XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1),
|
XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1),
|
||||||
XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1),
|
XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1),
|
||||||
XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1),
|
XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1),
|
||||||
};
|
};
|
||||||
// Extra pixels we have to get for the blur to work correctly.
|
|
||||||
const static int expand = 1;
|
|
||||||
|
|
||||||
Pixmap tmp_pixmap = None;
|
Pixmap tmp_pixmap = None;
|
||||||
Picture tmp_picture = None;
|
Picture tmp_picture = None;
|
||||||
|
@ -1451,15 +1453,9 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
|
||||||
int wid = w->widthb;
|
int wid = w->widthb;
|
||||||
int hei = w->heightb;
|
int hei = w->heightb;
|
||||||
|
|
||||||
int xe = x - expand;
|
|
||||||
int ye = y - expand;
|
|
||||||
int wide = wid + expand * 2;
|
|
||||||
int heie = hei + expand * 2;
|
|
||||||
|
|
||||||
// Directly copying from tgt_buffer does not work, so we create a
|
// Directly copying from tgt_buffer does not work, so we create a
|
||||||
// Picture in the middle. We expand the region slightly, to make sure
|
// Picture in the middle.
|
||||||
// the blur on border pixels work correctly.
|
tmp_pixmap = XCreatePixmap(ps->dpy, ps->root, wid, hei, ps->depth);
|
||||||
tmp_pixmap = XCreatePixmap(ps->dpy, ps->root, wide, heie, ps->depth);
|
|
||||||
if (!tmp_pixmap)
|
if (!tmp_pixmap)
|
||||||
goto win_blur_background_err;
|
goto win_blur_background_err;
|
||||||
|
|
||||||
|
@ -1468,14 +1464,31 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
|
||||||
if (!tmp_picture)
|
if (!tmp_picture)
|
||||||
goto win_blur_background_err;
|
goto win_blur_background_err;
|
||||||
|
|
||||||
// Copy the content to tmp_picture, then copy back.
|
// Adjust blur strength according to window opacity, to make it appear
|
||||||
// We lift the PictureClipRegion here, to get the expanded pixels.
|
// better during fading
|
||||||
XFixesSetPictureClipRegion(ps->dpy, tgt_buffer, 0, 0, None);
|
if (!ps->o.blur_background_fixed) {
|
||||||
XRenderComposite(ps->dpy, PictOpSrc, tgt_buffer, None, tmp_picture, xe, ye, 0, 0, 0, 0, wide, heie);
|
double pct = 1.0 - get_opacity_percent(w) * (1.0 - 1.0 / 9.0);
|
||||||
XFixesSetPictureClipRegion(ps->dpy, tgt_buffer, 0, 0, reg_paint);
|
convolution_blur[2 + convolution_blur_size + ((convolution_blur_size - 1) / 2)] = XDoubleToFixed(pct * 8.0 / (1.1 - pct));
|
||||||
XRenderSetPictureFilter(ps->dpy, tmp_picture, XRFILTER_CONVOLUTION, (XFixed *) convolution_blur, sizeof(convolution_blur) / sizeof(XFixed));
|
}
|
||||||
XRenderComposite(ps->dpy, PictOpSrc, tmp_picture, None, tgt_buffer, expand, expand, 0, 0, x, y, wid, hei);
|
|
||||||
xrfilter_reset(ps, tmp_picture);
|
// Minimize the region we try to blur, if the window itself is not
|
||||||
|
// opaque, only the frame is.
|
||||||
|
if (WINDOW_SOLID == w->mode && w->frame_opacity) {
|
||||||
|
XserverRegion reg_all = border_size(ps, w, false);
|
||||||
|
XserverRegion reg_noframe = win_get_region_noframe(ps, w, false);
|
||||||
|
XFixesSubtractRegion(ps->dpy, reg_noframe, reg_all, reg_noframe);
|
||||||
|
XFixesSetPictureClipRegion(ps->dpy, tmp_picture, reg_noframe, 0, 0);
|
||||||
|
free_region(ps, ®_all);
|
||||||
|
free_region(ps, ®_noframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the content to tmp_picture, then copy back. The filter must
|
||||||
|
// be applied on tgt_buffer, to get the nearby pixels outside the
|
||||||
|
// window.
|
||||||
|
XRenderSetPictureFilter(ps->dpy, tgt_buffer, XRFILTER_CONVOLUTION, (XFixed *) convolution_blur, sizeof(convolution_blur) / sizeof(XFixed));
|
||||||
|
XRenderComposite(ps->dpy, PictOpSrc, tgt_buffer, None, tmp_picture, x, y, 0, 0, 0, 0, wid, hei);
|
||||||
|
xrfilter_reset(ps, tgt_buffer);
|
||||||
|
XRenderComposite(ps->dpy, PictOpSrc, tmp_picture, None, tgt_buffer, 0, 0, 0, 0, x, y, wid, hei);
|
||||||
|
|
||||||
win_blur_background_err:
|
win_blur_background_err:
|
||||||
free_pixmap(ps, &tmp_pixmap);
|
free_pixmap(ps, &tmp_pixmap);
|
||||||
|
@ -3492,7 +3505,7 @@ ev_shape_notify(session_t *ps, XShapeEvent *ev) {
|
||||||
// Mark the old border_size as damaged
|
// Mark the old border_size as damaged
|
||||||
add_damage(ps, w->border_size);
|
add_damage(ps, w->border_size);
|
||||||
|
|
||||||
w->border_size = border_size(ps, w);
|
w->border_size = border_size(ps, w, true);
|
||||||
|
|
||||||
// Mark the new border_size as damaged
|
// Mark the new border_size as damaged
|
||||||
add_damage(ps, copy_region(ps, w->border_size));
|
add_damage(ps, copy_region(ps, w->border_size));
|
||||||
|
@ -3763,6 +3776,9 @@ usage(void) {
|
||||||
" Blur background of windows when the window frame is not opaque.\n"
|
" Blur background of windows when the window frame is not opaque.\n"
|
||||||
" Implies --blur-background. Bad in performance. The switch name\n"
|
" Implies --blur-background. Bad in performance. The switch name\n"
|
||||||
" may change.\n"
|
" may change.\n"
|
||||||
|
"--blur-background-fixed\n"
|
||||||
|
" Use fixed blur strength instead of adjusting according to window\n"
|
||||||
|
" opacity.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Format of a condition:\n"
|
"Format of a condition:\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -4174,6 +4190,9 @@ parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) {
|
||||||
// --blur-background-frame
|
// --blur-background-frame
|
||||||
lcfg_lookup_bool(&cfg, "blur-background-frame",
|
lcfg_lookup_bool(&cfg, "blur-background-frame",
|
||||||
&ps->o.blur_background_frame);
|
&ps->o.blur_background_frame);
|
||||||
|
// --blur-background-fixed
|
||||||
|
lcfg_lookup_bool(&cfg, "blur-background-fixed",
|
||||||
|
&ps->o.blur_background_fixed);
|
||||||
// Wintype settings
|
// Wintype settings
|
||||||
{
|
{
|
||||||
wintype_t i;
|
wintype_t i;
|
||||||
|
@ -4235,6 +4254,7 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
||||||
{ "detect-client-leader", no_argument, NULL, 282 },
|
{ "detect-client-leader", no_argument, NULL, 282 },
|
||||||
{ "blur-background", no_argument, NULL, 283 },
|
{ "blur-background", no_argument, NULL, 283 },
|
||||||
{ "blur-background-frame", no_argument, NULL, 284 },
|
{ "blur-background-frame", no_argument, NULL, 284 },
|
||||||
|
{ "blur-background-fixed", no_argument, NULL, 285 },
|
||||||
// Must terminate with a NULL entry
|
// Must terminate with a NULL entry
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
@ -4460,6 +4480,10 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
||||||
// --blur-background-frame
|
// --blur-background-frame
|
||||||
ps->o.blur_background_frame = true;
|
ps->o.blur_background_frame = true;
|
||||||
break;
|
break;
|
||||||
|
case 285:
|
||||||
|
// --blur-background-fixed
|
||||||
|
ps->o.blur_background_fixed = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
@ -5029,6 +5053,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
.alpha_step = 0.03,
|
.alpha_step = 0.03,
|
||||||
.blur_background = false,
|
.blur_background = false,
|
||||||
.blur_background_frame = false,
|
.blur_background_frame = false,
|
||||||
|
.blur_background_fixed = false,
|
||||||
|
|
||||||
.wintype_focus = { false },
|
.wintype_focus = { false },
|
||||||
.use_ewmh_active_win = false,
|
.use_ewmh_active_win = false,
|
||||||
|
|
|
@ -335,6 +335,9 @@ typedef struct {
|
||||||
/// Whether to blur background when the window frame is not opaque.
|
/// Whether to blur background when the window frame is not opaque.
|
||||||
/// Implies blur_background.
|
/// Implies blur_background.
|
||||||
bool blur_background_frame;
|
bool blur_background_frame;
|
||||||
|
/// Whether to use fixed blur strength instead of adjusting according
|
||||||
|
/// to window opacity.
|
||||||
|
bool blur_background_fixed;
|
||||||
|
|
||||||
// === Focus related ===
|
// === Focus related ===
|
||||||
/// Consider windows of specific types to be always focused.
|
/// Consider windows of specific types to be always focused.
|
||||||
|
@ -1493,11 +1496,17 @@ root_tile_f(session_t *ps);
|
||||||
static void
|
static void
|
||||||
paint_root(session_t *ps, Picture tgt_buffer);
|
paint_root(session_t *ps, Picture tgt_buffer);
|
||||||
|
|
||||||
|
static XserverRegion
|
||||||
|
win_get_region(session_t *ps, win *w, bool use_offset);
|
||||||
|
|
||||||
|
static XserverRegion
|
||||||
|
win_get_region_noframe(session_t *ps, win *w, bool use_offset);
|
||||||
|
|
||||||
static XserverRegion
|
static XserverRegion
|
||||||
win_extents(session_t *ps, win *w);
|
win_extents(session_t *ps, win *w);
|
||||||
|
|
||||||
static XserverRegion
|
static XserverRegion
|
||||||
border_size(session_t *ps, win *w);
|
border_size(session_t *ps, win *w, bool use_offset);
|
||||||
|
|
||||||
static Window
|
static Window
|
||||||
find_client_win(session_t *ps, Window w);
|
find_client_win(session_t *ps, Window w);
|
||||||
|
|
Loading…
Reference in New Issue