Skip to content

Blur strength #107

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions include/scenefx/render/fx_renderer/fx_effect_framebuffers.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ struct fx_effect_framebuffers {

// Contains the blurred background for tiled windows
struct fx_framebuffer *optimized_blur_buffer;
// Contains the non-blurred background for tiled windows. Used for blurring
// optimized surfaces with an alpha. Just as inefficient as the regular blur.
struct fx_framebuffer *optimized_no_blur_buffer;
// Contains the original pixels to draw over the areas where artifact are visible
struct fx_framebuffer *blur_saved_pixels_buffer;
// Blur swaps between the two effects buffers everytime it scales the image
Expand Down
1 change: 1 addition & 0 deletions include/scenefx/render/pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ struct fx_render_blur_pass_options {
struct blur_data *blur_data;
bool use_optimized_blur;
bool ignore_transparent;
float blur_strength;
};

/**
Expand Down
6 changes: 4 additions & 2 deletions include/scenefx/types/fx/blur_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

struct blur_data {
int num_passes;
int radius;
float radius;
float noise;
float brightness;
float contrast;
Expand All @@ -21,6 +21,8 @@ bool blur_data_should_parameters_blur_effects(struct blur_data *blur_data);

bool blur_data_cmp(struct blur_data *a, struct blur_data *b);

int blur_data_calc_size(struct blur_data *blur_data);
int blur_data_calc_size(const struct blur_data *blur_data);

struct blur_data blur_data_apply_strength(const struct blur_data *blur_data, float strength);

#endif
47 changes: 47 additions & 0 deletions include/scenefx/types/wlr_scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ struct wlr_scene_rect {
enum corner_location corners;
bool backdrop_blur;
bool backdrop_blur_optimized;
float backdrop_blur_strength;
float backdrop_blur_alpha;

bool accepts_input;
struct clipped_region clipped_region;
Expand Down Expand Up @@ -212,6 +214,8 @@ struct wlr_scene_buffer {
bool backdrop_blur;
bool backdrop_blur_optimized;
bool backdrop_blur_ignore_transparent;
float backdrop_blur_strength;
float backdrop_blur_alpha;
enum corner_location corners;

float opacity;
Expand Down Expand Up @@ -455,6 +459,27 @@ void wlr_scene_rect_set_backdrop_blur(struct wlr_scene_rect *rect,
void wlr_scene_rect_set_backdrop_blur_optimized(struct wlr_scene_rect *rect,
bool enabled);

/**
* Sets the blur strength from 1.0f -> 0.0f. This adjusts how strong the blur is
* relative to the base 1.0 value.
*
* Can be used combined with backdrop_blur_alpha to create a good looking
* fade-out effect.
*/
void wlr_scene_rect_set_backdrop_blur_strength(struct wlr_scene_rect *rect,
float strength);

/**
* Sets the blur alpha from 1.0f -> 0.0f. This adjusts the actual alpha of the blur.
* Default is 1.0f.
*
* Lower values without also adjusting the backdrop_blur_strength will look off.
*
* Can be used combined with backdrop_blur_strength to create a good looking
* fade-out effect.
*/
void wlr_scene_rect_set_backdrop_blur_alpha(struct wlr_scene_rect *rect,
float alpha);
/**
* Add a node displaying a shadow to the scene-graph.
*/
Expand Down Expand Up @@ -619,6 +644,28 @@ void wlr_scene_buffer_set_backdrop_blur_optimized(struct wlr_scene_buffer *scene
void wlr_scene_buffer_set_backdrop_blur_ignore_transparent(
struct wlr_scene_buffer *scene_buffer, bool enabled);

/**
* Sets the blur strength from 1.0f -> 0.0f. This adjusts how strong the blur is
* relative to the base 1.0 value.
*
* Can be used combined with backdrop_blur_alpha to create a good looking
* fade-out effect.
*/
void wlr_scene_buffer_set_backdrop_blur_strength(struct wlr_scene_buffer *scene_buffer,
float strength);

/**
* Sets the blur alpha from 1.0f -> 0.0f. This adjusts the actual alpha of the blur.
* Default is 1.0f.
*
* Lower values without also adjusting the backdrop_blur_strength will look off.
*
* Can be used combined with backdrop_blur_strength to create a good looking
* fade-out effect.
*/
void wlr_scene_buffer_set_backdrop_blur_alpha(struct wlr_scene_buffer *scene_buffer,
float alpha);

/**
* Calls the buffer's frame_done signal.
*/
Expand Down
33 changes: 26 additions & 7 deletions render/fx_renderer/fx_pass.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
Expand Down Expand Up @@ -776,16 +777,19 @@ static void render_blur_effects(struct fx_gles_render_pass *pass,
static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *pass,
struct fx_render_blur_pass_options *fx_options) {
struct fx_renderer *renderer = pass->buffer->renderer;
struct blur_data *blur_data = fx_options->blur_data;
struct wlr_box monitor_box = get_monitor_box(pass->output);

// We don't want to affect the reference blur_data
struct blur_data blur_data = blur_data_apply_strength(fx_options->blur_data, fx_options->blur_strength);
fx_options->blur_data = &blur_data;

pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_copy(&damage, fx_options->tex_options.base.clip);
wlr_region_transform(&damage, &damage, fx_options->tex_options.base.transform,
monitor_box.width, monitor_box.height);

wlr_region_expand(&damage, &damage, blur_data_calc_size(fx_options->blur_data));
wlr_region_expand(&damage, &damage, blur_data_calc_size(&blur_data));

// damage region will be scaled, make a temp
pixman_region32_t scaled_damage;
Expand All @@ -804,13 +808,13 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p
fx_options->tex_options.base.filter_mode = WLR_SCALE_FILTER_BILINEAR;

// Downscale
for (int i = 0; i < blur_data->num_passes; ++i) {
for (int i = 0; i < blur_data.num_passes; ++i) {
wlr_region_scale(&scaled_damage, &damage, 1.0f / (1 << (i + 1)));
render_blur_segments(pass, fx_options, &renderer->shaders.blur1);
}

// Upscale
for (int i = blur_data->num_passes - 1; i >= 0; --i) {
for (int i = blur_data.num_passes - 1; i >= 0; --i) {
// when upsampling we make the region twice as big
wlr_region_scale(&scaled_damage, &damage, 1.0f / (1 << i));
render_blur_segments(pass, fx_options, &renderer->shaders.blur2);
Expand All @@ -819,7 +823,7 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p
pixman_region32_fini(&scaled_damage);

// Render additional blur effects like saturation, noise, contrast, etc...
if (blur_data_should_parameters_blur_effects(blur_data)
if (blur_data_should_parameters_blur_effects(&blur_data)
&& pixman_region32_not_empty(&damage)) {
if (fx_options->current_buffer == pass->fx_effect_framebuffers->effects_buffer) {
fx_framebuffer_bind(pass->fx_effect_framebuffers->effects_buffer_swapped);
Expand Down Expand Up @@ -870,8 +874,9 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass,
goto damage_finish;
}

const bool has_strength = fx_options->blur_strength < 1.0;
struct fx_framebuffer *buffer = pass->fx_effect_framebuffers->optimized_blur_buffer;
if (!buffer || !fx_options->use_optimized_blur) {
if (!buffer || !fx_options->use_optimized_blur || has_strength) {
if (!buffer) {
wlr_log(WLR_ERROR, "Warning: Failed to use optimized blur");
}
Expand All @@ -881,7 +886,15 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass,
// Render the blur into its own buffer
struct fx_render_blur_pass_options blur_options = *fx_options;
blur_options.tex_options.base.clip = &translucent_region;
blur_options.current_buffer = pass->buffer;
if (fx_options->use_optimized_blur && has_strength
// If the optimized blur hasn't been rendered yet
&& pass->fx_effect_framebuffers->optimized_no_blur_buffer) {
// Re-blur the saved non-blurred version of the optimized blur.
// Isn't as efficient as just using the optimized blur buffer
blur_options.current_buffer = pass->fx_effect_framebuffers->optimized_no_blur_buffer;
} else {
blur_options.current_buffer = pass->buffer;
}
buffer = get_main_buffer_blur(pass, &blur_options);
}
struct wlr_texture *wlr_texture =
Expand Down Expand Up @@ -946,6 +959,8 @@ bool fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass,
bool failed = false;
fx_framebuffer_get_or_create_custom(renderer, pass->output, NULL,
&pass->fx_effect_framebuffers->optimized_blur_buffer, &failed);
fx_framebuffer_get_or_create_custom(renderer, pass->output, NULL,
&pass->fx_effect_framebuffers->optimized_no_blur_buffer, &failed);
if (failed) {
goto finish;
}
Expand All @@ -954,6 +969,10 @@ bool fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass,
fx_renderer_read_to_buffer(pass, &clip,
pass->fx_effect_framebuffers->optimized_blur_buffer, buffer, false);

// Save the current scene pass state
fx_renderer_read_to_buffer(pass, &clip,
pass->fx_effect_framebuffers->optimized_no_blur_buffer, pass->buffer, false);

finish:
pixman_region32_fini(&clip);
return !failed;
Expand Down
39 changes: 37 additions & 2 deletions types/fx/blur_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

struct blur_data blur_data_get_default(void) {
return (struct blur_data) {
.radius = 5,
.radius = 5.0f,
.num_passes = 3,
.noise = 0.02,
.brightness = 0.9,
Expand Down Expand Up @@ -31,6 +31,41 @@ bool blur_data_cmp(struct blur_data *a, struct blur_data *b) {
a->saturation == b->saturation;
}

int blur_data_calc_size(struct blur_data *blur_data) {
int blur_data_calc_size(const struct blur_data *blur_data) {
return pow(2, blur_data->num_passes + 1) * blur_data->radius;
}

static float lerp(float a, float b, float f) {
return (a * (1.0 - f)) + (b * f);
}

static void adjust_post_effects(struct blur_data *blur_data, float strength) {
blur_data->brightness = lerp(1.0, blur_data->brightness, strength);
blur_data->contrast = lerp(1.0, blur_data->contrast, strength);
blur_data->noise = lerp(0.0, blur_data->noise, strength);
blur_data->saturation = lerp(1.0, blur_data->saturation, strength);
}

struct blur_data blur_data_apply_strength(const struct blur_data *ref_blur_data, float strength) {
struct blur_data blur_data = *ref_blur_data;

if (strength >= 1.0f) {
adjust_post_effects(&blur_data, 1.0f);
return blur_data;
} else if (strength <= 0.0f) {
adjust_post_effects(&blur_data, 0.0f);
blur_data.num_passes = 0;
blur_data.radius = 0.0f;
return blur_data;
}

// Calculate the new blur strength from the new alpha multiplied blur size
// Also make sure that the values are never larger than the initial values
int new_size = blur_data_calc_size(ref_blur_data) * strength;
blur_data.num_passes = fmax(0, fmin(ref_blur_data->num_passes, ceilf(log2(new_size / ref_blur_data->radius))));
blur_data.radius = fmax(0, fmin(ref_blur_data->radius, new_size / pow(2, blur_data.num_passes + 1)));

adjust_post_effects(&blur_data, strength);

return blur_data;
}
Loading