@@ -146,6 +146,17 @@ pub struct SurfaceThreadState {
146146
147147 #[ cfg( feature = "debug" ) ]
148148 egui : EguiState ,
149+
150+ last_sequence : Option < u32 > ,
151+ /// Tracy frame that goes from vblank to vblank.
152+ vblank_frame : Option < tracy_client:: Frame > ,
153+ /// Frame name for the VBlank frame.
154+ vblank_frame_name : tracy_client:: FrameName ,
155+ /// Plot name for the time since presentation plot.
156+ time_since_presentation_plot_name : tracy_client:: PlotName ,
157+ /// Plot name for the presentation misprediction plot.
158+ presentation_misprediction_plot_name : tracy_client:: PlotName ,
159+ sequence_delta_plot_name : tracy_client:: PlotName ,
149160}
150161
151162pub type GbmDrmOutput = DrmOutput <
@@ -154,6 +165,7 @@ pub type GbmDrmOutput = DrmOutput<
154165 Option < (
155166 OutputPresentationFeedback ,
156167 Receiver < ( ScreencopyFrame , Vec < Rectangle < i32 , BufferCoords > > ) > ,
168+ Duration ,
157169 ) > ,
158170 DrmDeviceFd ,
159171> ;
@@ -469,7 +481,8 @@ fn surface_thread(
469481 thread_receiver : Channel < ThreadCommand > ,
470482 startup_done : Arc < AtomicBool > ,
471483) -> Result < ( ) > {
472- profiling:: register_thread!( & format!( "Surface Thread {}" , output. name( ) ) ) ;
484+ let name = output. name ( ) ;
485+ profiling:: register_thread!( & format!( "Surface Thread {}" , name) ) ;
473486
474487 let mut event_loop = EventLoop :: try_new ( ) . unwrap ( ) ;
475488
@@ -492,6 +505,14 @@ fn surface_thread(
492505 state
493506 } ;
494507
508+ let vblank_frame_name = tracy_client:: FrameName :: new_leak ( format ! ( "vblank on {name}" ) ) ;
509+ let time_since_presentation_plot_name =
510+ tracy_client:: PlotName :: new_leak ( format ! ( "{name} time since presentation, ms" ) ) ;
511+ let presentation_misprediction_plot_name =
512+ tracy_client:: PlotName :: new_leak ( format ! ( "{name} presentation misprediction, ms" ) ) ;
513+ let sequence_delta_plot_name =
514+ tracy_client:: PlotName :: new_leak ( format ! ( "{name} sequence delta" ) ) ;
515+
495516 let mut state = SurfaceThreadState {
496517 api,
497518 primary_node,
@@ -516,6 +537,13 @@ fn surface_thread(
516537 clock : Clock :: new ( ) ,
517538 #[ cfg( feature = "debug" ) ]
518539 egui,
540+
541+ last_sequence : None ,
542+ vblank_frame : None ,
543+ vblank_frame_name,
544+ time_since_presentation_plot_name,
545+ presentation_misprediction_plot_name,
546+ sequence_delta_plot_name,
519547 } ;
520548
521549 let signal = event_loop. get_signal ( ) ;
@@ -716,9 +744,46 @@ impl SurfaceThreadState {
716744 } ;
717745 let sequence = metadata. as_ref ( ) . map ( |data| data. sequence ) . unwrap_or ( 0 ) ;
718746
747+ // finish tracy frame
748+ let _ = self . vblank_frame . take ( ) ;
749+
719750 // mark last frame completed
720- if let Ok ( Some ( Some ( ( mut feedback, frames) ) ) ) = compositor. frame_submitted ( ) {
751+ if let Ok ( Some ( Some ( ( mut feedback, frames, estimated_presentation_time) ) ) ) =
752+ compositor. frame_submitted ( )
753+ {
721754 if self . mirroring . is_none ( ) {
755+ let name = self . output . name ( ) ;
756+ let message = if let Some ( presentation_time) = presentation_time {
757+ let misprediction_s =
758+ presentation_time. as_secs_f64 ( ) - estimated_presentation_time. as_secs_f64 ( ) ;
759+ tracy_client:: Client :: running ( ) . unwrap ( ) . plot (
760+ self . presentation_misprediction_plot_name ,
761+ misprediction_s * 1000. ,
762+ ) ;
763+
764+ let now = Duration :: from ( now) ;
765+ if presentation_time > now {
766+ let diff = presentation_time - now;
767+ tracy_client:: Client :: running ( ) . unwrap ( ) . plot (
768+ self . time_since_presentation_plot_name ,
769+ -diff. as_secs_f64 ( ) * 1000. ,
770+ ) ;
771+ format ! ( "vblank on {name}, presentation is {diff:?} later" )
772+ } else {
773+ let diff = now - presentation_time;
774+ tracy_client:: Client :: running ( ) . unwrap ( ) . plot (
775+ self . time_since_presentation_plot_name ,
776+ diff. as_secs_f64 ( ) * 1000. ,
777+ ) ;
778+ format ! ( "vblank on {name}, presentation was {diff:?} ago" )
779+ }
780+ } else {
781+ format ! ( "vblank on {name}, presentation time unknown" )
782+ } ;
783+ tracy_client:: Client :: running ( )
784+ . unwrap ( )
785+ . message ( & message, 0 ) ;
786+
722787 let ( clock, flags) = if let Some ( tp) = presentation_time {
723788 (
724789 tp. into ( ) ,
@@ -751,6 +816,14 @@ impl SurfaceThreadState {
751816 None => Refresh :: Unknown ,
752817 } ;
753818
819+ if let Some ( last_sequence) = self . last_sequence {
820+ let delta = sequence as f64 - last_sequence as f64 ;
821+ tracy_client:: Client :: running ( )
822+ . unwrap ( )
823+ . plot ( self . sequence_delta_plot_name , delta) ;
824+ }
825+ self . last_sequence = Some ( sequence) ;
826+
754827 feedback. presented ( clock, refresh, sequence as u64 , flags) ;
755828
756829 self . timings . presented ( clock) ;
@@ -770,6 +843,11 @@ impl SurfaceThreadState {
770843 } ;
771844
772845 if redraw_needed || self . shell . read ( ) . unwrap ( ) . animations_going ( ) {
846+ let vblank_frame = tracy_client:: Client :: running ( )
847+ . unwrap ( )
848+ . non_continuous_frame ( self . vblank_frame_name ) ;
849+ self . vblank_frame = Some ( vblank_frame) ;
850+
773851 self . queue_redraw ( false ) ;
774852 } else {
775853 self . send_frame_callbacks ( ) ;
@@ -1332,6 +1410,7 @@ impl SurfaceThreadState {
13321410 . unwrap ( )
13331411 . take_presentation_feedback ( & self . output , & frame_result. states ) ,
13341412 rx,
1413+ estimated_presentation,
13351414 ) )
13361415 } else {
13371416 None
@@ -1628,6 +1707,9 @@ impl SurfaceThreadState {
16281707 self . send_frame_callbacks ( ) ;
16291708 }
16301709 } else {
1710+ // we don't expect a vblank
1711+ let _ = self . vblank_frame . take ( ) ;
1712+
16311713 self . queue_estimated_vblank (
16321714 estimated_presentation,
16331715 // Make sure we redraw to reevaluate, if we intentionally missed content
0 commit comments