11use std:: {
22 borrow:: { Borrow , BorrowMut } ,
33 sync:: {
4- Arc , Mutex ,
4+ Arc , LazyLock , Mutex ,
55 atomic:: { AtomicBool , Ordering } ,
66 } ,
77} ;
@@ -27,6 +27,7 @@ use smithay::{
2727 } ,
2828 wayland:: compositor:: SurfaceData ,
2929} ;
30+ use tracing:: info;
3031
3132use crate :: {
3233 backend:: render:: { element:: AsGlowRenderer , wayland:: clipped_surface:: ClippingShader } ,
@@ -36,9 +37,50 @@ use crate::{
3637pub static BLUR_DOWNSAMPLE_SHADER : & str = include_str ! ( "../shaders/blur_downsample.frag" ) ;
3738pub static BLUR_UPSAMPLE_SHADER : & str = include_str ! ( "../shaders/blur_upsample.frag" ) ;
3839
39- const PASSES : usize = 3 ;
40- const OFFSET : f64 = 1.1 ;
4140const NOISE : f32 = 0.03 ;
41+ const MAX_STEPS : usize = 15 ;
42+
43+ #[ derive( Debug , Clone , Copy , PartialEq ) ]
44+ struct BlurParameters {
45+ passes : usize ,
46+ offset : f64 ,
47+ extended_radius : i32 ,
48+ }
49+
50+ static BLUR_PARAMS : LazyLock < Vec < BlurParameters > > = LazyLock :: new ( || {
51+ let mut params = Vec :: new ( ) ;
52+
53+ let mut remaining_steps = MAX_STEPS as isize ;
54+ let offsets = [
55+ // min offset, max offset, extended radius to avoid artifacts
56+ ( 1.0 , 2.0 , 10 ) ,
57+ ( 2.0 , 3.0 , 20 ) ,
58+ ( 2.0 , 5.0 , 50 ) ,
59+ ( 3.0 , 8.0 , 150 ) ,
60+ ] ;
61+
62+ let sum = offsets. iter ( ) . map ( |( min, max, _) | * max - * min) . sum :: < f64 > ( ) ;
63+ for ( i, ( min, max, extended_radius) ) in offsets. into_iter ( ) . enumerate ( ) {
64+ let mut iter_num = f64:: ceil ( ( max - min) / sum * ( MAX_STEPS as f64 ) ) as usize ;
65+ remaining_steps -= iter_num as isize ;
66+
67+ if remaining_steps < 0 {
68+ iter_num = iter_num. saturating_add_signed ( remaining_steps) ;
69+ }
70+
71+ let diff = max - min;
72+ for j in 1 ..=iter_num {
73+ params. push ( BlurParameters {
74+ passes : i + 1 ,
75+ offset : min + ( diff / iter_num as f64 ) * j as f64 ,
76+ extended_radius,
77+ } ) ;
78+ }
79+ }
80+
81+ info ! ( "Computed blur values: {:#?}" , & params) ;
82+ params
83+ } ) ;
4284
4385#[ derive( Debug , Clone ) ]
4486pub struct BlurShaders {
@@ -125,6 +167,7 @@ impl BlurElement {
125167 geometry : Rectangle < f64 , Logical > ,
126168 output_scale : f64 ,
127169 radii : [ u8 ; 4 ] ,
170+ strength : usize ,
128171 ) -> Result < Option < Self > , R :: Error > {
129172 let mut blur_region_state = states. cached_state . get :: < ComputedBlurRegionCachedState > ( ) ;
130173 let Some ( region) = blur_region_state. current ( ) . blur_region . as_ref ( ) else {
@@ -133,7 +176,7 @@ impl BlurElement {
133176
134177 let geo = geometry. to_physical_precise_round ( output_scale) ;
135178 let mut extended_geo = geo;
136- let radius = OFFSET * 2.0f64 . powf ( PASSES as f64 ) ;
179+ let radius = BLUR_PARAMS [ strength . min ( MAX_STEPS - 1 ) ] . extended_radius as f64 ;
137180 extended_geo. loc -= Point :: < f64 , Physical > :: new ( radius, radius) ;
138181 extended_geo. size += Size :: < f64 , Physical > :: new ( radius, radius) . upscale ( 2. ) ;
139182
@@ -187,6 +230,7 @@ impl BlurElement {
187230 output_scale,
188231 & mut * state. lock ( ) . unwrap ( ) ,
189232 uniforms,
233+ strength,
190234 ) ?) )
191235 }
192236
@@ -197,19 +241,24 @@ impl BlurElement {
197241 output_scale : f64 ,
198242 state : & mut BlurState ,
199243 uniforms : Vec < Uniform < ' static > > ,
244+ strength : usize ,
200245 ) -> Result < Self , R :: Error > {
201246 let renderer_id = renderer. glow_renderer ( ) . context_id ( ) ;
202247 let src = geometry. size . to_buffer ( output_scale, Transform :: Normal ) ;
248+ let params = & BLUR_PARAMS [ strength. min ( MAX_STEPS - 1 ) ] ;
203249
204250 let dirty = !( state
205251 . renderer_id
206252 . as_ref ( )
207253 . is_some_and ( |id| id == & renderer_id)
254+ && state. offset == params. offset
255+ && state. passes == params. passes
208256 && & state. region == region
209257 && state. src == src) ;
258+
210259 state. renderer_id = Some ( renderer_id) ;
211- state. offset = OFFSET * output_scale ; // we want the blur result to be stable across scaling ;
212- state. passes = PASSES ;
260+ state. offset = params . offset ;
261+ state. passes = params . passes ;
213262 state. region = region. clone ( ) ;
214263 state. src = src;
215264 if dirty {
0 commit comments