Skip to content

Commit

Permalink
Merge pull request #382 from tryone144/feature/dual_kawase
Browse files Browse the repository at this point in the history
dual-kawase blur algorithm for new OpenGL backend
  • Loading branch information
yshui authored Aug 31, 2020
2 parents ceb9b7f + 5e0215a commit 731bd61
Show file tree
Hide file tree
Showing 13 changed files with 650 additions and 146 deletions.
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

0 comments on commit 731bd61

Please sign in to comment.