Add GdkFrameHistory and GdkFrameTimings, handle _NET_WM_FRAME_TIMINGS
In order to be able to track statistics about how well we are drawing, and in order to be able to do sophisticated things with frame timing like predicting per-frame latencies and synchronizing audio with video, we need to be able to track exactly when previous frames were drawn to the screen. Information about each frame is stored in a new GdkFrameTimings object. A new GdkFrameHistory object is added which keeps a queue of recent GdkFrameTimings (this is added to avoid further complicating the implementation of GdkFrameClock.) https://bugzilla.gnome.org/show_bug.cgi?id=685460
This commit is contained in:
		| @ -1056,6 +1056,26 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, | ||||
|   return return_val; | ||||
| } | ||||
|  | ||||
| static GdkFrameTimings * | ||||
| find_frame_timings (GdkFrameClock *clock, | ||||
|                     guint64        serial) | ||||
| { | ||||
|   GdkFrameHistory *history = gdk_frame_clock_get_history (clock); | ||||
|   gint64 start_frame, end_frame, i; | ||||
|  | ||||
|   start_frame = gdk_frame_history_get_start (history); | ||||
|   end_frame = gdk_frame_history_get_frame_counter (history); | ||||
|   for (i = end_frame; i >= start_frame; i--) | ||||
|     { | ||||
|       GdkFrameTimings *timings = gdk_frame_history_get_timings (history, i); | ||||
|  | ||||
|       if (gdk_frame_timings_get_cookie (timings) == serial) | ||||
|         return timings; | ||||
|     } | ||||
|  | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| GdkFilterReturn | ||||
| _gdk_wm_protocols_filter (GdkXEvent *xev, | ||||
| 			  GdkEvent  *event, | ||||
| @ -1074,6 +1094,71 @@ _gdk_wm_protocols_filter (GdkXEvent *xev, | ||||
|  | ||||
|   display = GDK_WINDOW_DISPLAY (win); | ||||
|  | ||||
|   /* This isn't actually WM_PROTOCOLS because that wouldn't leave enough space | ||||
|    * in the message for everything that gets stuffed in */ | ||||
|   if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_DRAWN")) | ||||
|     { | ||||
|       GdkWindowImplX11 *window_impl; | ||||
|       window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl); | ||||
|       if (window_impl->toplevel) | ||||
|         { | ||||
|           guint32 d0 = xevent->xclient.data.l[0]; | ||||
|           guint32 d1 = xevent->xclient.data.l[1]; | ||||
|           guint32 d2 = xevent->xclient.data.l[2]; | ||||
|           guint32 d3 = xevent->xclient.data.l[3]; | ||||
|  | ||||
|           guint64 serial = ((guint64)d0 << 32) | d1; | ||||
|  | ||||
|           GdkFrameClock *clock = gdk_window_get_frame_clock (event->any.window); | ||||
|           GdkFrameTimings *timings = find_frame_timings (clock, serial); | ||||
|  | ||||
|           if (timings) | ||||
|             gdk_frame_timings_set_drawn_time (timings, ((guint64)d2 << 32) | d3); | ||||
|  | ||||
|           if (window_impl->toplevel->frame_pending) | ||||
|             { | ||||
|               window_impl->toplevel->frame_pending = FALSE; | ||||
|               gdk_frame_clock_thaw (clock); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|       return GDK_FILTER_REMOVE; | ||||
|     } | ||||
|  | ||||
|   if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_TIMINGS")) | ||||
|     { | ||||
|       GdkWindowImplX11 *window_impl; | ||||
|       window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl); | ||||
|       if (window_impl->toplevel) | ||||
|         { | ||||
|           guint32 d0 = xevent->xclient.data.l[0]; | ||||
|           guint32 d1 = xevent->xclient.data.l[1]; | ||||
|           guint32 d2 = xevent->xclient.data.l[2]; | ||||
|           guint32 d3 = xevent->xclient.data.l[3]; | ||||
|  | ||||
|           guint64 serial = ((guint64)d0 << 32) | d1; | ||||
|  | ||||
|           GdkFrameClock *clock = gdk_window_get_frame_clock (event->any.window); | ||||
|           GdkFrameTimings *timings = find_frame_timings (clock, serial); | ||||
|  | ||||
|           if (timings) | ||||
|             { | ||||
|               gint64 drawn_time = gdk_frame_timings_get_drawn_time (timings); | ||||
|               gint32 presentation_time_offset = (gint32)d2; | ||||
|               gint32 refresh_interval = d3; | ||||
|  | ||||
|               if (drawn_time && presentation_time_offset) | ||||
|                 gdk_frame_timings_set_presentation_time (timings, | ||||
|                                                          drawn_time + presentation_time_offset); | ||||
|  | ||||
|               if (refresh_interval) | ||||
|                 gdk_frame_timings_set_refresh_interval (timings, refresh_interval); | ||||
|  | ||||
|               gdk_frame_timings_set_complete (timings, TRUE); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   if (xevent->xclient.message_type != gdk_x11_get_xatom_by_name_for_display (display, "WM_PROTOCOLS")) | ||||
|     return GDK_FILTER_CONTINUE; | ||||
|  | ||||
| @ -1145,21 +1230,6 @@ _gdk_wm_protocols_filter (GdkXEvent *xev, | ||||
|       return GDK_FILTER_REMOVE; | ||||
|     } | ||||
|  | ||||
|   else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_DRAWN")) | ||||
|     { | ||||
|       GdkWindowImplX11 *window_impl; | ||||
|  | ||||
|       window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl); | ||||
|       if (window_impl->toplevel && | ||||
|           window_impl->toplevel->frame_pending) | ||||
|         { | ||||
|           window_impl->toplevel->frame_pending = FALSE; | ||||
|           gdk_frame_clock_thaw (gdk_window_get_frame_clock (event->any.window)); | ||||
|         } | ||||
|  | ||||
|       return GDK_FILTER_REMOVE; | ||||
|     } | ||||
|  | ||||
|   return GDK_FILTER_CONTINUE; | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -853,7 +853,17 @@ static void | ||||
| on_frame_clock_after_paint (GdkFrameClock *clock, | ||||
|                             GdkWindow     *window) | ||||
| { | ||||
|   GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window); | ||||
|   GdkFrameHistory *history = gdk_frame_clock_get_history (clock); | ||||
|   gint64 frame_counter = gdk_frame_history_get_frame_counter (history); | ||||
|   GdkFrameTimings *timings = gdk_frame_history_get_timings (history, frame_counter); | ||||
|  | ||||
|   gdk_x11_window_end_frame (window); | ||||
|  | ||||
|   if (toplevel->frame_pending) | ||||
|     gdk_frame_timings_set_cookie (timings, toplevel->current_counter_value); | ||||
|   else | ||||
|     gdk_frame_timings_set_complete (timings, TRUE); | ||||
| } | ||||
|  | ||||
| void | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Owen W. Taylor
					Owen W. Taylor