glxsync - explicit frame synchronization sample implementation

Michael Clark michaeljclark at mac.com
Sun Jan 2 02:45:30 UTC 2022


On 31/12/21 1:31 pm, Michael Clark wrote:
> I would like to add these implementation notes to the README because 
> this is information one cannot easily find. It occurs to me that XFlush 
> before frames makes a lot more sense than after frames if one thinks 
> about Nagle and flow control combined with frame pacing. If we have 
> capacity to render at a constant frame rate with accurate scheduling for 
> the start of frames, then an XFlush(dpy) marker placed at the start of 
> the frame will occur at a constant rate, subject to variable render 
> times, whereas an XFlush(dpy) marker placed at the end of the frame 
> would have irregular timings needing stats for recovery. I am guessing 
> these are conversations that folks have already had because it seems to 
> work on my machine. An XSync(dpy, False) marker for congestion control 
> also seems to make sense to me because if we get frame drops we want to 
> resynchronize input and output. I am not sure under which conditions one 
> may wish to do XSync(dpy, True). Possibly some sort of watchdog or hang 
> check for IO when recovering from flooding.
> 
> Anyway I don't know where to go for this information so I am verbalizing 
> it to see if anyone can acknowledge it as being reasonable protocol.

I wrote up the sample implementation notes here:

- https://github.com/michaeljclark/glxsync/blob/trunk/README.md

I made one minor change after reasoning about when the frame buffer is 
volatile. It seemed safe to move the start of the lock from just before 
draw_frame to just before swap_buffers. The notes on buffer safety and 
waiting until present timing has been received before starting a new 
frame are from observations with the Mesa Intel driver in Ubuntu 21.04.

My account of events for a synchronized window update look like this:

- _ClientMessage_
   - _synchronize_ (`_e.xclient.data.l[0] == _NET_WM_SYNC_REQUEST`)
     - store synchronizatized rendering serial number:
       - `sync_serial = _e.xclient.data.l[2]`
- _ConfigureNotify_
   - _resize_
     - signal synchronizatized rendering initiated:
       - `sync_counter(dpy, extended_counter, sync_serial + 0)`
- _Expose_
   - _XFlush_
     - make sure last frame has been flushed.
   - _draw_frame_
     - run user code to draw the frame.
   - _begin_frame_
     - signal buffer contents for serial number are rendering (urgent):
       - `sync_counter(dpy, extended_counter, sync_serial + 3)`
   - _swap_buffers_
     - the frame buffer contents are volatile at this point.
   - _end_frame_
     - signal buffer contents for serial number are now complete:
       - `sync_counter(dpy, extended_counter, sync_serial + 4)`
- _ClientMessage_
   - _frame_drawn_ (`e.xclient.message_type == _NET_WM_FRAME_DRAWN`)
     - drawing at this point is *not safe* because present has
       not been scheduled (buffer has not been copied).
- _ClientMessage_
   - _frame_timings_ (`e.xclient.message_type == _NET_WM_FRAME_TIMINGS`)
     - drawing at this point is *safe* frame because present has
       been scheduled (buffer has been copied).


More information about the mesa-dev mailing list