Improving Xwayland window resizing
One of the quickest ways to determine whether particular application runs using Xwayland is to resize one of its windows and see how it behaves, for example
While it can be handy for the debugging purposes, overall, it makes the Plasma Wayland session look less polished. So, one of the goals for 6.3 was to fix this visual glitch.
This article will provide some background behind what caused the glitch and how we addressed it. Just in case, here’s the same application, which was shown in a screen cast above, but with the corresponding resizing fixes in:
X11 frame synchronization protocol(s)
On X11, all window changes typically take place immediately, including resizing. This can lead to some issues. For example, if a window is resized, it can take a while until the application repaints the window with the new size. What if the compositing manager decides to compose the screen in meanwhile? You’re likely going to see some sort of visual glitches, e.g. the window contents getting cropped or seeing parts of the window that have not been repainted yet.
In order to address this issue, there exists an X11 protocol to synchronize window repaints during interactive resize. An application/client wishing to participate in this protocol needs to list _NET_WM_SYNC_REQUEST
in the WM_PROTOCOLS
property of the client window and also set the XID
of the XSync counter in the _NET_WM_SYNC_REQUEST_COUNTER
property. When the WM wants to resize the window, the following will happen:
- The window manager sends a
_NET_WM_SYNC_REQUEST
client message containing a serial that the client will need to put in the XSync counter after processing aConfigureNotify
event that will be generated after the window is resized. The compositing manager and the window manager will block window updates until the XSync request acknowledgement is received; - The WM resizes the client window, for example by calling the
xcb_configure_window()
function; - The client would then repaint the window with the new size and update the XSync counter with the serial that it had received in step 1;
- The window manager and the compositing manager unblock window updates after receiving receiving the XSync request acknowledgement. For example, now, the window can be repainted by the compositing manager and there shouldn’t be glitches as long as the client behaves well.
Note that the window manager and the compositing manager are often the same. For example, both KWin and Mutter are compositing managers and window managers.
The frame synchronization protocol described above is called basic frame synchronization protocol. There is also an extended frame synchronization protocol, but it is not standardized and it is implemented only by a few compositing managers.
_NET_WM_SYNC_REQUEST
and Xwayland
KWin supports the basic frame synchronization protocol, so there should be no visual glitches when resizing X11 windows in the Plasma Wayland session, right? At quick glance, yes, but we forget about the most important detail: Wayland compositors don’t use XCompositeNameWindowPixmap()
or xcb_composite_name_window_pixmap()
to grab the contents of X11 windows, instead they rely on Xwayland attaching graphics buffers to wl_surface
objects, so there is no strict order between the Wayland compositor receiving an XSync request acknowledgement and graphics buffers for the new window size.
In order to help better understand the issue, let’s consider a concrete example. Assume that a window with geometry 0,0 100x100
is being resized by dragging its left edge. If the left edge is dragged 10
px to the right, the following will happen:
- A
_NET_WM_SYNC_REQUEST
client message will be sent to the client containing the XSync counter serial that must be set after processing theConfigureNotify
event that will be generated after the Wayland compositor callsxcb_configure_window()
with the new window size; - The Wayland compositor calls
xcb_configure_window()
to actually resize the window; - The client receives the sync request client message and the ConfigureNotify event, repaints the window, and acknowledges the sync request;
- The Wayland compositor receives the sync request acknowledgement and updates the window position to
10,0
.
But here is the problem, when the window position is updated to 10,0, it’s not guaranteed that the wl_surface
associated with the X11 window has a buffer with the new window size, i.e. 90x100
. It can take a while until Xwayland commits a graphics buffer with the right size. In meanwhile, the compositor could compose the next frame with the new window position, i.e. 10,0
, but old surface size, i.e. 100x100
. It would look as if the right window edge sticks out of the window decoration. After Xwayland attaches a buffer with the right size, the right window edge will correct itself.
So, ideally, the Wayland compositor should update the window position after receiving the XSync request acknowledgement and Xwayland attaching a new graphics buffer to the wl_surface
.
With that in mind, the frame synchronization procedure looks as follows:
- The compositor blocks
wl_surface
commits by setting the_XWAYLAND_ALLOW_COMMITS
property to0
for the toplevel X11 window. This is needed to ensure the consistent order between XSync request acknowledgements andwl_surface
commits. As long as the_XWAYLAND_ALLOW_COMMITS
property is set to0
, Xwayland will not attempt to commit the wayland surface, for example attach a new graphics buffer after the client repaints the window; - The compositor sends a
_NET_WM_SYNC_REQUEST
client message as before; - The compositor resizes the client window as before;
- The client repaints the window and acknowledges the XSync request as before;
- After receiving the XSync acknowledgement, the compositor unblocks surface commits by setting the
_XWAYLAND_ALLOW_COMMITS
property to1
. Note that the window updates are still blocked, i.e. the window position is not updated yet; - After Xwayland commits the
wl_surface
with a new graphics buffer, the window updates are unblocked, e.g. the window position is updated.
The frame synchronization process looks more involved with Xwayland, but it is still manageable.
_NET_WM_SYNC_REQUEST
support in applications
Most applications that use GTK and Qt support _NET_WM_SYNC_REQUEST
, but there are applications that don’t participate in the frame synchronization protocol. If you use one of those apps, you will observe visual glitches during interactive resize.
Closing words
Frame synchronization is a difficult problem, and requires some very intricate code both on the compositor and the client side. But with the changes that we’ve made, I’m proud to say that KWin is one of the few compositors that properly handles frame synchronization for X11 windows on Wayland.
I would also like to express many thanks to the Xwayland developers (Michel Dänzer and Olivier Fourdan) for helping and assisting us with fixing the glitch.