@@ -36,7 +36,7 @@ use wayland_client::{
3636} ;
3737
3838const TIMESPEC_NSEC_PER_SEC : u32 = 1_000_000_000 ;
39- const FPS_MEASURE_PERIOD_SEC : u64 = 5 ;
39+ const FPS_MEASURE_PERIOD_SEC : f64 = 5. ;
4040
4141pub struct ScreencastThread {
4242 node_id : u32 ,
@@ -85,7 +85,9 @@ struct FPSLimit {
8585 frame_last_time : Instant ,
8686 fps_last_time : Instant ,
8787 fps_frame_count : u32 ,
88+ delay_before_capture_frame_ns : u64 ,
8889 delay_til_next_frame_ns : u64 ,
90+ accumulated_frame_debt_ns : u64 ,
8991}
9092
9193impl FPSLimit {
@@ -94,7 +96,9 @@ impl FPSLimit {
9496 frame_last_time : Instant :: now ( ) ,
9597 fps_last_time : Instant :: now ( ) ,
9698 fps_frame_count : 0 ,
99+ delay_before_capture_frame_ns : 0 ,
97100 delay_til_next_frame_ns : 0 ,
101+ accumulated_frame_debt_ns : 0 ,
98102 }
99103 }
100104
@@ -110,35 +114,60 @@ impl FPSLimit {
110114 let now = Instant :: now ( ) ;
111115 self . fps_frame_count += 1 ;
112116 let elapsed_sec = ( now - self . fps_last_time ) . as_secs_f64 ( ) ;
113- if elapsed_sec < 1. {
117+
118+ if elapsed_sec < FPS_MEASURE_PERIOD_SEC {
114119 return ;
115120 }
116- // log::info!(
117- // "fps_limit: average FPS in the last {:.2} seconds: {:.2}",
118- // elapsed_sec,
119- // self.fps_frame_count
120- // );
121+ let avg_frames_per_sec = self . fps_frame_count as f64 / elapsed_sec;
122+
123+ log:: info!(
124+ "fps_limit: average FPS in the last {:.2} seconds: {:.2}" ,
125+ elapsed_sec,
126+ avg_frames_per_sec
127+ ) ;
121128 self . fps_frame_count = 0 ;
122129 self . fps_last_time = now;
123130 }
124131
125132 fn fps_limit_measure_end ( & mut self , max_fps : u32 ) {
126133 if max_fps <= 0 {
134+ self . delay_before_capture_frame_ns = 0 ;
127135 self . delay_til_next_frame_ns = 0 ;
136+ self . accumulated_frame_debt_ns = 0 ;
128137 return ;
129138 }
130139 self . measure_fps ( ) ;
131140
132- // Throttling will not be applied if the current FPS is unlikely to exceed the target frame rate.
133- if self . fps_frame_count < max_fps - 1 {
141+ let elapsed_ns = self . frame_last_time . elapsed ( ) . as_nanos ( ) ;
142+ let target_ns = ( TIMESPEC_NSEC_PER_SEC / max_fps) as u128 ;
143+
144+ // Wait for half of the target frame rate duration before requesting a frame capture.
145+ self . delay_before_capture_frame_ns = ( target_ns / 2 ) as u64 ;
146+
147+ // Throttle after the current frame has been captured:
148+ let total_elapsed_ns = elapsed_ns + self . accumulated_frame_debt_ns as u128 ;
149+ if target_ns > total_elapsed_ns {
150+ // If it is before the next frame capture time -> wait for the right time.
151+ self . delay_til_next_frame_ns = ( target_ns - total_elapsed_ns) as u64 ;
152+ } else {
153+ // If it is after the next frame capture time, Set value of `delay_til_next_frame_ns` to 0 and increase value of `accumulated_frame_debt_ns` by the amount of time it has been delayed.
134154 self . delay_til_next_frame_ns = 0 ;
135- return ;
155+ self . accumulated_frame_debt_ns = target_ns . abs_diff ( total_elapsed_ns ) as u64 ;
136156 }
137157
138- let elapsed_ns = self . frame_last_time . elapsed ( ) . as_nanos ( ) ;
139- let target_ns = ( TIMESPEC_NSEC_PER_SEC / max_fps) as u128 ;
140- self . delay_til_next_frame_ns =
141- target_ns. saturating_sub ( elapsed_ns + 3_000_000 /* safety margin */ ) as u64 ;
158+ // Set `delay_before_capture_frame_ns` to its current value minus the overrun time, if any.
159+ if self . accumulated_frame_debt_ns > self . delay_before_capture_frame_ns {
160+ self . accumulated_frame_debt_ns -= self . delay_before_capture_frame_ns ;
161+ self . delay_before_capture_frame_ns = 0 ;
162+ } else {
163+ self . delay_before_capture_frame_ns -= self . accumulated_frame_debt_ns ;
164+ self . accumulated_frame_debt_ns = 0 ;
165+ }
166+
167+ // Reset at the end of each capture cycle, this helps prevent `accumulated_frame_debt_ns` from increasing indefinitely.
168+ if self . fps_frame_count % max_fps == 0 {
169+ self . accumulated_frame_debt_ns = 0 ;
170+ }
142171 }
143172}
144173
@@ -368,15 +397,16 @@ impl StreamData {
368397 fn process ( & mut self , stream : & StreamRef ) {
369398 let buffer = unsafe { stream. dequeue_raw_buffer ( ) } ;
370399 if !buffer. is_null ( ) {
371- if self . fps_limit . delay_til_next_frame_ns != 0 {
400+ self . fps_limit . fps_limit_measure_start ( self . framerate ) ;
401+ if self . fps_limit . delay_before_capture_frame_ns != 0 {
372402 // log::info!(
373- // "fps_limit: wait {}ns til next frame",
374- // self.fps_limit.delay_til_next_frame_ns
403+ // "fps_limit: wait {}ns before capture frame",
404+ // self.fps_limit.delay_before_capture_frame_ns
375405 // );
376- std:: thread:: sleep ( Duration :: from_nanos ( self . fps_limit . delay_til_next_frame_ns ) ) ;
406+ std:: thread:: sleep ( Duration :: from_nanos (
407+ self . fps_limit . delay_before_capture_frame_ns ,
408+ ) ) ;
377409 }
378-
379- self . fps_limit . fps_limit_measure_start ( self . framerate ) ;
380410 let wl_buffer = unsafe { & * ( ( * buffer) . user_data as * const wl_buffer:: WlBuffer ) } ;
381411 let full_damage = & [ Rect {
382412 x : 0 ,
@@ -417,6 +447,14 @@ impl StreamData {
417447 }
418448 unsafe { stream. queue_raw_buffer ( buffer) } ;
419449 self . fps_limit . fps_limit_measure_end ( self . framerate ) ;
450+
451+ if self . fps_limit . delay_til_next_frame_ns != 0 {
452+ // log::info!(
453+ // "fps_limit: wait {}ns til next frame",
454+ // self.fps_limit.delay_til_next_frame_ns
455+ // );
456+ std:: thread:: sleep ( Duration :: from_nanos ( self . fps_limit . delay_til_next_frame_ns ) ) ;
457+ }
420458 }
421459 }
422460}
0 commit comments