Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dual-kawase blur algorithm for new OpenGL backend #382

Merged
merged 5 commits into from
Aug 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions man/picom.1.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ OPTIONS
*--detect-client-leader*::
Use 'WM_CLIENT_LEADER' to group windows, and consider windows in the same group focused at the same time. 'WM_TRANSIENT_FOR' has higher priority if *--detect-transient* is enabled, too.

*--blur-method*, *--blur-size*, *--blur-deviation*::
*--blur-method*, *--blur-size*, *--blur-deviation*, *--blur-strength*::
Parameters for background blurring, see the *BLUR* section for more information.

*--blur-background*::
Expand Down Expand Up @@ -397,8 +397,8 @@ Available options of the 'blur' section are: ::

*method*:::
A string. Controls the blur method. Corresponds to the *--blur-method* command line option. Available choices are:
'none' to disable blurring; 'gaussian' for gaussian blur; 'box' for box blur; 'kernel' for convolution blur with a custom kernel.
Note: 'gaussian' and 'box' blur methods are only supported by the experimental backends.
'none' to disable blurring; 'gaussian' for gaussian blur; 'box' for box blur; 'kernel' for convolution blur with a custom kernel; 'dual_kawase' for dual-filter kawase blur.
Note: 'gaussian', 'box' and 'dual_kawase' blur methods are only supported by the experimental backends.
(default: none)

*size*:::
Expand All @@ -407,6 +407,9 @@ Available options of the 'blur' section are: ::
*deviation*:::
A floating point number. The standard deviation for the 'gaussian' blur method. Corresponds to the *--blur-deviation* command line option (default: 0.84089642).

*strength*:::
An integer in the range 0-20. The strength of the 'dual_kawase' blur method. Corresponds to the *--blur-strength* command line option. If set to zero, the value requested by *--blur-size* is approximated (default: 5).

*kernel*:::
A string. The kernel to use for the 'kernel' blur method, specified in the same format as the *--blur-kerns* option. Corresponds to the *--blur-kerns* command line option.

Expand Down
2 changes: 2 additions & 0 deletions picom.sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ focus-exclude = [ "class_g = 'Cairo-clock'" ];
# blur-size = 12
#
# blur-deviation = false
#
# blur-strength = 5

# Blur background of semi-transparent / ARGB windows.
# Bad in performance, with driver-dependent behavior.
Expand Down
7 changes: 6 additions & 1 deletion src/backend/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

#include <stdbool.h>

#include "config.h"
#include "compiler.h"
#include "config.h"
#include "driver.h"
#include "kernel.h"
#include "region.h"
Expand Down Expand Up @@ -65,6 +65,11 @@ struct kernel_blur_args {
int kernel_count;
};

struct dual_kawase_blur_args {
int size;
int strength;
};

struct backend_operations {
// =========== Initialization ===========

Expand Down
63 changes: 63 additions & 0 deletions src/backend/backend_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,69 @@ struct conv **generate_blur_kernel(enum blur_method method, void *args, int *ker
return NULL;
}

/// Generate kernel parameters for dual-kawase blur method. Falls back on approximating
/// standard gauss radius if strength is zero or below.
struct dual_kawase_params *generate_dual_kawase_params(void *args) {
struct dual_kawase_blur_args *blur_args = args;
static const struct {
int iterations; /// Number of down- and upsample iterations
float offset; /// Sample offset in half-pixels
int min_radius; /// Approximate gauss-blur with at least this
/// radius and std-deviation
} strength_levels[20] = {
{.iterations = 1, .offset = 1.25f, .min_radius = 1}, // LVL 1
{.iterations = 1, .offset = 2.25f, .min_radius = 6}, // LVL 2
{.iterations = 2, .offset = 2.00f, .min_radius = 11}, // LVL 3
{.iterations = 2, .offset = 3.00f, .min_radius = 17}, // LVL 4
{.iterations = 2, .offset = 4.25f, .min_radius = 24}, // LVL 5
{.iterations = 3, .offset = 2.50f, .min_radius = 32}, // LVL 6
{.iterations = 3, .offset = 3.25f, .min_radius = 40}, // LVL 7
{.iterations = 3, .offset = 4.25f, .min_radius = 51}, // LVL 8
{.iterations = 3, .offset = 5.50f, .min_radius = 67}, // LVL 9
{.iterations = 4, .offset = 3.25f, .min_radius = 83}, // LVL 10
{.iterations = 4, .offset = 4.00f, .min_radius = 101}, // LVL 11
{.iterations = 4, .offset = 5.00f, .min_radius = 123}, // LVL 12
{.iterations = 4, .offset = 6.00f, .min_radius = 148}, // LVL 13
{.iterations = 4, .offset = 7.25f, .min_radius = 178}, // LVL 14
{.iterations = 4, .offset = 8.25f, .min_radius = 208}, // LVL 15
{.iterations = 5, .offset = 4.50f, .min_radius = 236}, // LVL 16
{.iterations = 5, .offset = 5.25f, .min_radius = 269}, // LVL 17
{.iterations = 5, .offset = 6.25f, .min_radius = 309}, // LVL 18
{.iterations = 5, .offset = 7.25f, .min_radius = 357}, // LVL 19
{.iterations = 5, .offset = 8.50f, .min_radius = 417}, // LVL 20
};

auto params = ccalloc(1, struct dual_kawase_params);
params->iterations = 0;
params->offset = 1.0f;

if (blur_args->strength <= 0 && blur_args->size) {
// find highest level that approximates blur-strength with the selected
// gaussian blur-radius
int lvl = 1;
while (strength_levels[lvl - 1].min_radius < blur_args->size && lvl < 20) {
++lvl;
}
blur_args->strength = lvl;
}
if (blur_args->strength <= 0) {
// default value
blur_args->strength = 5;
}

assert(blur_args->strength > 0 && blur_args->strength <= 20);
params->iterations = strength_levels[blur_args->strength - 1].iterations;
params->offset = strength_levels[blur_args->strength - 1].offset;

// Expand sample area to cover the smallest texture / highest selected iteration:
// - Smallest texture dimensions are halved `iterations`-times
// - Upsample needs pixels two-times `offset` away from the border
// - Plus one for interpolation differences
params->expand = (1 << params->iterations) * 2 * (int)ceil(params->offset) + 1;

return params;
}

void init_backend_base(struct backend_base *base, session_t *ps) {
base->c = ps->c;
base->loop = ps->loop;
Expand Down
10 changes: 10 additions & 0 deletions src/backend/backend_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ typedef struct conv conv;
typedef struct backend_base backend_t;
struct backend_operations;

struct dual_kawase_params {
/// Number of downsample passes
int iterations;
/// Pixel offset for down- and upsample
float offset;
/// Save area around blur target (@ref resize_width, @ref resize_height)
int expand;
};

bool build_shadow(xcb_connection_t *, xcb_drawable_t, double opacity, int width,
int height, const conv *kernel, xcb_render_picture_t shadow_pixel,
xcb_pixmap_t *pixmap, xcb_render_picture_t *pict);
Expand All @@ -41,3 +50,4 @@ default_backend_render_shadow(backend_t *backend_data, int width, int height,
void init_backend_base(struct backend_base *base, session_t *ps);

struct conv **generate_blur_kernel(enum blur_method method, void *args, int *kernel_count);
struct dual_kawase_params *generate_dual_kawase_params(void *args);
Loading