wezterm
wezterm copied to clipboard
x11: fix window contents jumping on async resize
We can't hope to keep the renderer's idea of the window size consistent with the actual window size when the user can asynchronously change its size at any possible moment. Therefore, we create a child window which we render to instead and which we synchronously resize in response to user-generated, asynchronous resize events. Since by default the contents of X11 windows are undefined on resize, we take the additional steps of setting our windows' X11 background color and bit gravity as appropriate as well. These changes are intended to address the contents of the window jumping around in response to user-generated, asynchronous resizes.
I'm currently marking this as a draft because I am aware of one outstanding issue where we should probably be calling eglWaitClient()
before resizes to the child window, and I am unsure how to idiomatically do that in this code! In practice, not doing so doesn't seem to cause any issue in my testing, but I believe that there may be some race condition where the GPU is still rendering when we synchronously resize the child window where we could still end up seeing the window contents jumping around. I believe that calling eglWaitClient()
since the last OpenGL operations were performed would address this race condition unless there is something I'm failing to account for (like, I'm hoping that nothing is ever rendering to the window concurrently in a separate thread). In the meantime, I've marked the two places where I believe eglWaitClient()
calls should go in code comments so that it is hopefully clearer what I think is necessary to get this completely right.
I've managed to convince myself that eglWaitClient()
or some analog is not required before resizing. For one thing, I can't reproduce any race without that synchronization. Furthermore, there are many authoritative sources which only synchronize after the resize but not before. The original GLUT3 library appears to only call glXWaitX()
after resizing but not glXWaitGL()
before resizing (glXWaitGL()
is the GLX equivalent of eglWaitClient()
and glXWaitX()
is at worst an XSync()
). Moreover, the "OpenGL® on Silicon Graphics Systems" guide states:
Note: The X and OpenGL command streams are asynchronous, meaning that the order in which OpenGL and X commands complete is not strictly defined. In a few cases, it is important to explicitly synchronize X and OpenGL command completion. For example, if an X call is used to resize a window within a widget program, call glXWaitX() before calling glViewport() to ensure that the window resize operation is complete.
The guide makes no mention of glXWaitGL()
, and a later code sample in the guide only calls glXWaitX()
.
As such, I think I am happy with the current level of synchronization, and so I will mark this merge request ready for review. :)
Of course, I haven't mentioned webgpu at all, but I cannot reproduce any race using webgpu either, and I suspect (hope?) that a similar reasoning would apply for why this merge request's current level of synchronization is sufficient for webgpu as well.
I just realized that this approach breaks transparent backgrounds. But perhaps if I set the parent window to be fully transparent...
I just realized that this approach breaks transparent backgrounds. But perhaps if I set the parent window to be fully transparent...
Yes this appears to work.
Thanks!