wsi/x11: Rewrite implementation to always use threads.
What does this MR do and why?
The current implementation has many different code paths which get very messy to reason about and maintain.
- FIFO mode worked well enough.
- IMMEDIATE did not need a thread at all, but present wait implementation complicated a lot of things since we had to handle concurrent special event reads.
- MAILBOX (and Xwayland) adds even more jank on top of this where have present thread, but no acquire thread, so there are tons of forward progress issues to consider.
In the new model, we have two threads:
- Queue thread is only responsible for receiving presents, waiting for them if necessary, and submitting them to X.
- Event thread pumps the special event queue alone and notifies other threads about frame completions.
Two threads are required to implement IMMEDIATE and MAILBOX well. IDLE events can come back at any time and the queue thread might be waiting for a new presentation request to come through.
This new model has the advantage that we will be able to implement VK_EXT_swapchain_maintenance1 in a more reasonable way, since we can just toggle the present mode per present request as all presentation go through the same system.
Another improvement while moving to threads was to allow multiple presentation requests to remain pending per image. In IMMEDIATE mode and MAILBOX, if the application is using present ID, we would not have been able to queue up a new present until a COMPLETE was observed, but these events may be deferred to V-blank. When rendering at very high frame rates, we would have to block, which is not great. To resolve this, each image now gets an array of pending serial / presentIDs. We only need to block when that array is exhausted, which should only happen if we're rendering at truly ridiculous frame rates.
The old code was questionable, since we overwrote the signal_present_id while there were pending presentations in flight.