From b56b81089692bded2c00d16136a93c215a6796ae Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Tue, 18 Feb 2025 16:28:15 +0100 Subject: [PATCH 1/7] Added initial WIP blur alpha logic --- include/scenefx/types/fx/blur_data.h | 2 +- render/fx_renderer/fx_pass.c | 25 ++++++++++++++++++++----- types/fx/blur_data.c | 2 +- types/scene/wlr_scene.c | 15 +++++---------- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/include/scenefx/types/fx/blur_data.h b/include/scenefx/types/fx/blur_data.h index 69c86f2..17e751d 100644 --- a/include/scenefx/types/fx/blur_data.h +++ b/include/scenefx/types/fx/blur_data.h @@ -6,7 +6,7 @@ struct blur_data { int num_passes; - int radius; + float radius; float noise; float brightness; float contrast; diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index 2aa7bd0..61c2b95 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -772,11 +773,23 @@ static void render_blur_effects(struct fx_gles_render_pass *pass, wlr_texture_destroy(options->texture); } +static void compute_blur_data(struct blur_data *blur_data, + struct blur_data *ref_blur_data, const float *alpha) { + const float slice = 1.0 / ref_blur_data->num_passes; + + // Lowering num_passes by one requires doubling the radius to keep the same + // blur + blur_data->num_passes = fmin(ceilf(*alpha / slice), ref_blur_data->num_passes); + blur_data->radius = ref_blur_data->radius * *alpha * pow(2, ref_blur_data->num_passes - blur_data->num_passes); +} + // Blurs the main_buffer content and returns the blurred framebuffer 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 blur_data blur_data = *fx_options->blur_data; + compute_blur_data(&blur_data, fx_options->blur_data, fx_options->tex_options.base.alpha); + fx_options->blur_data = &blur_data; struct wlr_box monitor_box = get_monitor_box(pass->output); pixman_region32_t damage; @@ -785,7 +798,7 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p 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; @@ -804,13 +817,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); @@ -819,7 +832,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); @@ -901,6 +914,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, } // Draw the blurred texture + const float blur_alpha = 1.0; tex_options->base.dst_box = get_monitor_box(pass->output); tex_options->base.src_box = (struct wlr_fbox) { .x = 0, @@ -909,6 +923,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, .height = buffer->buffer->height, }; tex_options->base.texture = &blur_texture->wlr_texture; + tex_options->base.alpha = &blur_alpha; fx_render_pass_add_texture(pass, tex_options); wlr_texture_destroy(&blur_texture->wlr_texture); diff --git a/types/fx/blur_data.c b/types/fx/blur_data.c index ea3c0ff..4e528ff 100644 --- a/types/fx/blur_data.c +++ b/types/fx/blur_data.c @@ -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, diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 68937b2..76f7ff0 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1595,11 +1595,6 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren scene_node_opaque_region(node, x, y, &opaque_region); scale_output_damage(&opaque_region, data->scale); - /* TODO: should this be configurable? Borked when not 1.0, probably due to - lack of premultiplication in the frag shader - */ - float blur_alpha = 1.0; - struct fx_render_blur_pass_options blur_options = { .tex_options = { .base = (struct wlr_render_texture_options) { @@ -1608,7 +1603,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .dst_box = dst_box, .transform = WL_OUTPUT_TRANSFORM_NORMAL, .clip = &render_region, - .alpha = &blur_alpha, + .alpha = &scene_rect->color[3], .filter_mode = WLR_SCALE_FILTER_BILINEAR, .blend_mode = WLR_RENDER_BLEND_MODE_PREMULTIPLIED, }, @@ -1764,8 +1759,6 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren pixman_region32_translate(&opaque_region, -scene_buffer->src_box.x, -scene_buffer->src_box.y); - // TODO: should I be configurable? We should probably move blur to a node - float blur_alpha = 1.0; struct fx_render_blur_pass_options blur_options = { .tex_options = { .base = (struct wlr_render_texture_options) { @@ -1774,7 +1767,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .dst_box = dst_box, .transform = WL_OUTPUT_TRANSFORM_NORMAL, .clip = &render_region, // Render with the smaller region, clipping CSD - .alpha = &blur_alpha, + .alpha = &scene_buffer->opacity, .filter_mode = WLR_SCALE_FILTER_BILINEAR, }, .clip_box = &dst_box, @@ -1794,6 +1787,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren pixman_region32_fini(&opaque_region); } + float testing_fixed_alpha = 1.0; struct fx_render_texture_options tex_options = { .base = (struct wlr_render_texture_options){ .texture = texture, @@ -1801,7 +1795,8 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .dst_box = dst_box, .transform = transform, .clip = &render_region, // Render with the smaller region, clipping CSD - .alpha = &scene_buffer->opacity, + // .alpha = &scene_buffer->opacity, + .alpha = &testing_fixed_alpha, // TODO: Remove, only for testing .filter_mode = scene_buffer->filter_mode, .blend_mode = !data->output->scene->calculate_visibility || pixman_region32_not_empty(&opaque) ? From 88059d147a321deac79fe725fe4f737859f6d0f5 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Fri, 21 Feb 2025 20:10:26 +0100 Subject: [PATCH 2/7] Calculate the new blur size from the new smaller blur size --- include/scenefx/types/fx/blur_data.h | 2 ++ render/fx_renderer/fx_pass.c | 16 ++++------------ types/fx/blur_data.c | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/include/scenefx/types/fx/blur_data.h b/include/scenefx/types/fx/blur_data.h index 17e751d..5b6710f 100644 --- a/include/scenefx/types/fx/blur_data.h +++ b/include/scenefx/types/fx/blur_data.h @@ -23,4 +23,6 @@ bool blur_data_cmp(struct blur_data *a, struct blur_data *b); int blur_data_calc_size(struct blur_data *blur_data); +void blur_data_apply_alpha(struct blur_data *blur_data, float alpha); + #endif diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index 61c2b95..fb12e06 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -773,24 +773,16 @@ static void render_blur_effects(struct fx_gles_render_pass *pass, wlr_texture_destroy(options->texture); } -static void compute_blur_data(struct blur_data *blur_data, - struct blur_data *ref_blur_data, const float *alpha) { - const float slice = 1.0 / ref_blur_data->num_passes; - - // Lowering num_passes by one requires doubling the radius to keep the same - // blur - blur_data->num_passes = fmin(ceilf(*alpha / slice), ref_blur_data->num_passes); - blur_data->radius = ref_blur_data->radius * *alpha * pow(2, ref_blur_data->num_passes - blur_data->num_passes); -} - // Blurs the main_buffer content and returns the blurred framebuffer 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 wlr_box monitor_box = get_monitor_box(pass->output); + + // We don't want to affect the reference blur_data struct blur_data blur_data = *fx_options->blur_data; - compute_blur_data(&blur_data, fx_options->blur_data, fx_options->tex_options.base.alpha); fx_options->blur_data = &blur_data; - struct wlr_box monitor_box = get_monitor_box(pass->output); + blur_data_apply_alpha(&blur_data, *fx_options->tex_options.base.alpha); pixman_region32_t damage; pixman_region32_init(&damage); diff --git a/types/fx/blur_data.c b/types/fx/blur_data.c index 4e528ff..cf32bdf 100644 --- a/types/fx/blur_data.c +++ b/types/fx/blur_data.c @@ -34,3 +34,20 @@ bool blur_data_cmp(struct blur_data *a, struct blur_data *b) { int blur_data_calc_size(struct blur_data *blur_data) { return pow(2, blur_data->num_passes + 1) * blur_data->radius; } + +void blur_data_apply_alpha(struct blur_data *blur_data, float alpha) { + if (alpha >= 1.0f) { + return; + } else if (alpha <= 0.0f) { + blur_data->num_passes = 0; + blur_data->radius = 0.0f; + return; + } + + // 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 + struct blur_data ref_blur_data = *blur_data; + int new_size = blur_data_calc_size(&ref_blur_data) * alpha; + 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))); +} From afa390a2f5a65d4d8e089980843f6115237d1c50 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Fri, 21 Feb 2025 20:15:41 +0100 Subject: [PATCH 3/7] Remove fixed testing buffer alpha --- types/scene/wlr_scene.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 76f7ff0..e46a8e9 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1787,7 +1787,6 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren pixman_region32_fini(&opaque_region); } - float testing_fixed_alpha = 1.0; struct fx_render_texture_options tex_options = { .base = (struct wlr_render_texture_options){ .texture = texture, @@ -1795,8 +1794,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .dst_box = dst_box, .transform = transform, .clip = &render_region, // Render with the smaller region, clipping CSD - // .alpha = &scene_buffer->opacity, - .alpha = &testing_fixed_alpha, // TODO: Remove, only for testing + .alpha = &scene_buffer->opacity, .filter_mode = scene_buffer->filter_mode, .blend_mode = !data->output->scene->calculate_visibility || pixman_region32_not_empty(&opaque) ? @@ -2535,7 +2533,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, // No need to compensate for blur artifacts when the damage spans // the whole output whole_output_blur_damaged = true; - }else { + } else { // Expand the original damage to compensate for surrounding // blurred views to avoid sharp edges between damage regions wlr_region_expand(damage, damage, blur_data_calc_size(blur_data)); From 8e23ecc0b1d058e158fb87f01af4e3a1814eecaf Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Fri, 21 Feb 2025 20:32:56 +0100 Subject: [PATCH 4/7] NULL-check the tex alpha --- include/scenefx/types/fx/blur_data.h | 2 +- render/fx_renderer/fx_pass.c | 2 +- types/fx/blur_data.c | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/scenefx/types/fx/blur_data.h b/include/scenefx/types/fx/blur_data.h index 5b6710f..49fea64 100644 --- a/include/scenefx/types/fx/blur_data.h +++ b/include/scenefx/types/fx/blur_data.h @@ -23,6 +23,6 @@ bool blur_data_cmp(struct blur_data *a, struct blur_data *b); int blur_data_calc_size(struct blur_data *blur_data); -void blur_data_apply_alpha(struct blur_data *blur_data, float alpha); +void blur_data_apply_alpha(struct blur_data *blur_data, const float *alpha); #endif diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index fb12e06..6fb919b 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -782,7 +782,7 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p // We don't want to affect the reference blur_data struct blur_data blur_data = *fx_options->blur_data; fx_options->blur_data = &blur_data; - blur_data_apply_alpha(&blur_data, *fx_options->tex_options.base.alpha); + blur_data_apply_alpha(&blur_data, fx_options->tex_options.base.alpha); pixman_region32_t damage; pixman_region32_init(&damage); diff --git a/types/fx/blur_data.c b/types/fx/blur_data.c index cf32bdf..1731657 100644 --- a/types/fx/blur_data.c +++ b/types/fx/blur_data.c @@ -35,7 +35,12 @@ int blur_data_calc_size(struct blur_data *blur_data) { return pow(2, blur_data->num_passes + 1) * blur_data->radius; } -void blur_data_apply_alpha(struct blur_data *blur_data, float alpha) { +void blur_data_apply_alpha(struct blur_data *blur_data, const float *a) { + if (!a) { + return; + } + float alpha = *a; + if (alpha >= 1.0f) { return; } else if (alpha <= 0.0f) { From 8948634b71fd640a3d1faeb3d1800a29e6e0f65a Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Fri, 21 Feb 2025 20:35:41 +0100 Subject: [PATCH 5/7] Added alpha support to optimized blur --- .../fx_renderer/fx_effect_framebuffers.h | 3 +++ render/fx_renderer/fx_pass.c | 20 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/scenefx/render/fx_renderer/fx_effect_framebuffers.h b/include/scenefx/render/fx_renderer/fx_effect_framebuffers.h index 0938db4..f9ca2dd 100644 --- a/include/scenefx/render/fx_renderer/fx_effect_framebuffers.h +++ b/include/scenefx/render/fx_renderer/fx_effect_framebuffers.h @@ -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 diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index 6fb919b..1c1aad1 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -875,8 +875,10 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, goto damage_finish; } + const float *tex_alpha = fx_options->tex_options.base.alpha; + bool has_alpha = tex_alpha && *tex_alpha < 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_alpha) { if (!buffer) { wlr_log(WLR_ERROR, "Warning: Failed to use optimized blur"); } @@ -886,7 +888,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_alpha + // 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 = @@ -953,6 +963,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; } @@ -961,6 +973,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; From 38c0629d9affb700305095341554c8a41262af55 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Wed, 26 Feb 2025 17:05:53 +0100 Subject: [PATCH 6/7] Added blur_strength and blur_alpha to rect and scene_buffer --- include/scenefx/render/pass.h | 1 + include/scenefx/types/fx/blur_data.h | 4 +-- include/scenefx/types/wlr_scene.h | 47 ++++++++++++++++++++++++++ render/fx_renderer/fx_pass.c | 12 +++---- types/fx/blur_data.c | 32 +++++++++--------- types/scene/wlr_scene.c | 49 ++++++++++++++++++++++++++-- 6 files changed, 116 insertions(+), 29 deletions(-) diff --git a/include/scenefx/render/pass.h b/include/scenefx/render/pass.h index bd00b77..8697561 100644 --- a/include/scenefx/render/pass.h +++ b/include/scenefx/render/pass.h @@ -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; }; /** diff --git a/include/scenefx/types/fx/blur_data.h b/include/scenefx/types/fx/blur_data.h index 49fea64..7cfaf62 100644 --- a/include/scenefx/types/fx/blur_data.h +++ b/include/scenefx/types/fx/blur_data.h @@ -21,8 +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); -void blur_data_apply_alpha(struct blur_data *blur_data, const float *alpha); +struct blur_data blur_data_apply_strength(const struct blur_data *blur_data, float strength); #endif diff --git a/include/scenefx/types/wlr_scene.h b/include/scenefx/types/wlr_scene.h index b4df998..2261c5b 100644 --- a/include/scenefx/types/wlr_scene.h +++ b/include/scenefx/types/wlr_scene.h @@ -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; @@ -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; @@ -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. */ @@ -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. */ diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index 1c1aad1..b07a256 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -780,9 +780,8 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p 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 = *fx_options->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; - blur_data_apply_alpha(&blur_data, fx_options->tex_options.base.alpha); pixman_region32_t damage; pixman_region32_init(&damage); @@ -875,10 +874,9 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, goto damage_finish; } - const float *tex_alpha = fx_options->tex_options.base.alpha; - bool has_alpha = tex_alpha && *tex_alpha < 1.0; + 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 || has_alpha) { + if (!buffer || !fx_options->use_optimized_blur || has_strength) { if (!buffer) { wlr_log(WLR_ERROR, "Warning: Failed to use optimized blur"); } @@ -888,7 +886,7 @@ 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; - if (fx_options->use_optimized_blur && has_alpha + 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. @@ -916,7 +914,6 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, } // Draw the blurred texture - const float blur_alpha = 1.0; tex_options->base.dst_box = get_monitor_box(pass->output); tex_options->base.src_box = (struct wlr_fbox) { .x = 0, @@ -925,7 +922,6 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, .height = buffer->buffer->height, }; tex_options->base.texture = &blur_texture->wlr_texture; - tex_options->base.alpha = &blur_alpha; fx_render_pass_add_texture(pass, tex_options); wlr_texture_destroy(&blur_texture->wlr_texture); diff --git a/types/fx/blur_data.c b/types/fx/blur_data.c index 1731657..f6eb99d 100644 --- a/types/fx/blur_data.c +++ b/types/fx/blur_data.c @@ -31,28 +31,26 @@ 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; } -void blur_data_apply_alpha(struct blur_data *blur_data, const float *a) { - if (!a) { - return; - } - float alpha = *a; - - if (alpha >= 1.0f) { - return; - } else if (alpha <= 0.0f) { - blur_data->num_passes = 0; - blur_data->radius = 0.0f; - return; +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) { + return blur_data; + } else if (strength <= 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 - struct blur_data ref_blur_data = *blur_data; - int new_size = blur_data_calc_size(&ref_blur_data) * alpha; - 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))); + 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))); + + return blur_data; } diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index e46a8e9..1b15e37 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -694,6 +694,8 @@ struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent, scene_rect->clipped_region = clipped_region_get_default(); scene_rect->backdrop_blur = false; scene_rect->backdrop_blur_optimized = false; + scene_rect->backdrop_blur_strength = 1.0f; + scene_rect->backdrop_blur_alpha = 1.0f; scene_node_update(&scene_rect->node, NULL); @@ -737,6 +739,25 @@ void wlr_scene_rect_set_backdrop_blur_optimized(struct wlr_scene_rect *rect, scene_node_update(&rect->node, NULL); } +void wlr_scene_rect_set_backdrop_blur_strength(struct wlr_scene_rect *rect, + float strength) { + if (rect->backdrop_blur_strength == strength) { + return; + } + rect->backdrop_blur_strength = strength; + scene_node_update(&rect->node, NULL); +} + +void wlr_scene_rect_set_backdrop_blur_alpha(struct wlr_scene_rect *rect, + float alpha) { + if (rect->backdrop_blur_alpha == alpha) { + return; + } + + rect->backdrop_blur_alpha = alpha; + scene_node_update(&rect->node, NULL); +} + static void scene_buffer_handle_buffer_release(struct wl_listener *listener, void *data) { struct wlr_scene_buffer *scene_buffer = @@ -986,6 +1007,8 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, scene_buffer->backdrop_blur = false; scene_buffer->backdrop_blur_optimized = false; scene_buffer->backdrop_blur_ignore_transparent = true; + scene_buffer->backdrop_blur_strength = 1.0f; + scene_buffer->backdrop_blur_alpha = 1.0f; scene_buffer->corners = CORNER_LOCATION_NONE; scene_buffer_set_buffer(scene_buffer, buffer); @@ -1244,6 +1267,25 @@ void wlr_scene_buffer_set_backdrop_blur_ignore_transparent( scene_node_update(&scene_buffer->node, NULL); } +void wlr_scene_buffer_set_backdrop_blur_strength(struct wlr_scene_buffer *scene_buffer, + float strength) { + if (scene_buffer->backdrop_blur_strength == strength) { + return; + } + scene_buffer->backdrop_blur_strength = strength; + scene_node_update(&scene_buffer->node, NULL); +} + +void wlr_scene_buffer_set_backdrop_blur_alpha(struct wlr_scene_buffer *scene_buffer, + float alpha) { + if (scene_buffer->backdrop_blur_alpha == alpha) { + return; + } + + scene_buffer->backdrop_blur_alpha = alpha; + scene_node_update(&scene_buffer->node, NULL); +} + static struct wlr_texture *scene_buffer_get_texture( struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { if (scene_buffer->buffer == NULL || scene_buffer->texture != NULL) { @@ -1603,7 +1645,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .dst_box = dst_box, .transform = WL_OUTPUT_TRANSFORM_NORMAL, .clip = &render_region, - .alpha = &scene_rect->color[3], + .alpha = &scene_rect->backdrop_blur_alpha, .filter_mode = WLR_SCALE_FILTER_BILINEAR, .blend_mode = WLR_RENDER_BLEND_MODE_PREMULTIPLIED, }, @@ -1616,6 +1658,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .use_optimized_blur = scene_rect->backdrop_blur_optimized, .blur_data = &scene->blur_data, .ignore_transparent = false, + .blur_strength = scene_rect->backdrop_blur_strength, }; // Render the actual blur behind the surface fx_render_pass_add_blur(data->render_pass, &blur_options); @@ -1687,6 +1730,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .discard_transparent = false, }, .blur_data = &scene->blur_data, + .blur_strength = 1.0f, }; bool result = fx_render_pass_add_optimized_blur(data->render_pass, &blur_options); if (result) { @@ -1767,7 +1811,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .dst_box = dst_box, .transform = WL_OUTPUT_TRANSFORM_NORMAL, .clip = &render_region, // Render with the smaller region, clipping CSD - .alpha = &scene_buffer->opacity, + .alpha = &scene_buffer->backdrop_blur_alpha, .filter_mode = WLR_SCALE_FILTER_BILINEAR, }, .clip_box = &dst_box, @@ -1779,6 +1823,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .use_optimized_blur = scene_buffer->backdrop_blur_optimized, .blur_data = &scene->blur_data, .ignore_transparent = scene_buffer->backdrop_blur_ignore_transparent, + .blur_strength = scene_buffer->backdrop_blur_strength, }; // Render the actual blur behind the surface fx_render_pass_add_blur(data->render_pass, &blur_options); From 7289eeec8239849385b87f127aae8fe0bd82b8e4 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Wed, 26 Feb 2025 17:06:17 +0100 Subject: [PATCH 7/7] Adjust all the blur post effect strengths --- types/fx/blur_data.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/types/fx/blur_data.c b/types/fx/blur_data.c index f6eb99d..5154f79 100644 --- a/types/fx/blur_data.c +++ b/types/fx/blur_data.c @@ -35,12 +35,25 @@ 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; @@ -52,5 +65,7 @@ struct blur_data blur_data_apply_strength(const struct blur_data *ref_blur_data, 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; }