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