Xwayland: after disabling crtc with Xrandr, cannot enable it again
SDL 2.0.16 has a regression for fullscreen apps/games when running on Xwayland, which I've been able to reproduce with a small Xrandr program. I think this might be a bug in Xwayland: it certainly doesn't seem like ideal behaviour.
Version
Xwayland 1.20.13, part of the xorg-server
Debian source package, version 2:1.20.13-1
Steps to reproduce
For a minimal reproducer, build this program:
source code
/*
* Simplified from SDL 2.0.16 SDL_x11modes.c
* Copyright 1997-2021 Sam Lantinga
* Copyright 2021 Collabora Ltd.
* SPDX-License-Identifier: Zlib
*/
#include <err.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xrandr.h>
int main (void)
{
Display *display = NULL;
XRRScreenResources *res = NULL;
XRROutputInfo *output_info = NULL;
XRRCrtcInfo *crtc = NULL;
Status status = Success;
RROutput an_output = None;
int screen = -1;
display = XOpenDisplay (NULL);
if (!display) {
errx (1, "Couldn't open display");
}
screen = DefaultScreen (display);
res = XRRGetScreenResources (display, RootWindow (display, screen));
if (!res) {
errx (1, "Couldn't get XRandR screen resources");
}
if (res->noutput < 1) {
errx (1, "XRandR screen resources have no outputs");
}
an_output = res->outputs[0];
output_info = XRRGetOutputInfo (display, res, an_output);
if (!output_info) {
errx (1, "Couldn't get XRandR output info");
}
if (output_info->connection == RR_Disconnected) {
errx (1, "XRandR output info says it's disconnected");
}
crtc = XRRGetCrtcInfo (display, res, output_info->crtc);
if (!crtc) {
errx (1, "Couldn't get XRandR crtc info");
}
XGrabServer (display);
status = XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
0, 0, None, crtc->rotation, NULL, 0);
if (status != Success) {
XUngrabServer(display);
errx (1, "Failed to disable crtc: %d", status);
}
status = XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
crtc->x, crtc->y, crtc->mode, crtc->rotation,
&an_output, 1);
if (status != Success) {
XUngrabServer(display);
errx (1, "Failed to re-enable crtc: %d", status);
}
return 0;
}
# Copyright 2021 Collabora Ltd.
# SPDX-License-Identifier: Zlib
toggle-crtc: toggle-crtc.c Makefile
$(CC) -o$@ $< $(shell pkg-config --cflags --libs x11 xrandr)
Or, for a more realistic reproducer, use testgl2 --fullscreen
from SDL's test suite, or any SDL2 game configured to run in full-screen at the current resolution (such as OpenArena with +set r_fullscreen 1 +set r_mode -2
), and run it with SDL 2.0.16.
Either way, log in to a Wayland session with Xwayland (I'm mostly using GNOME 3.38 in Wayland mode on Debian 11, but KDE Plasma in Wayland mode also suffers from this). For simplicity, use a machine with one display.
Run xrandr --verbose
. You should see that XWAYLAND0
is connected to crtc 0, with one mode matching the setup of your Wayland display, which is *current
and +preferred
.
Run the reproducer.
Run xrandr --verbose
again.
Expected result
The reproducer has no practical effect on the screen configuration. The second xrandr --verbose
has the same output as the first.
Actual result
The second call to XRRSetCrtcConfig()
fails with status 3 (I think that's BadWindow?). This leaves my Xwayland in a broken state: the XWAYLAND0
output is disabled, and I haven't been able to find a way to re-enable it other than logging out from my GUI session and back in.
xrandr --verbose
says XWAYLAND0
is no longer using a CRTC, and its single mode is still +preferred
but is no longer *current
.
Subsequent attempts to run SDL programs fail.
More context
The regression was triggered by a change in which the call sequence used by SDL to change the video mode was altered. Previously, SDL just called XRRSetCrtcConfig()
to reconfigure the crtc that is already responsible for the desired output. The change is to disable the crtc, then call XRRSetScreenSize()
to change the screen size, and finally re-enable the crtc, in order to behave as the spec says:
This request sets the CRTC to the specified position, mode, rotation and reflection. The entire area of the CRTC must fit within the screen size, else a Match error results. As an example, rotating the screen so that a single CRTC fills the entire screen before and after may necessitate disabling the CRTC, resizing the screen, then re-enabling the CRTC at the new configuration to avoid an invalid intermediate configuration.
In my simplified reproducer, I don't actually call XRRSetScreenSize()
: it's enough to disable the crtc and immediately re-enable it.
I can also reproduce this with xrandr(1)
:
$ xrandr --output XWAYLAND0 --mode 1920x1080
(ok)
$ xrandr --output XWAYLAND0 --pos 0x0 --mode 1920x1080
(ok)
$ xrandr --output XWAYLAND0 --crtc 0 --pos 0x0 --mode 1920x1080
(ok)
$ xrandr --output XWAYLAND0 --crtc 0 --pos 0x0 --mode 1920x1080 --rotate inverted
xrandr: Configure crtc 0 failed
Cross-references
- SDL change that triggered this: https://github.com/libsdl-org/SDL/pull/4494
- SDL regression report: https://github.com/libsdl-org/SDL/issues/4630
- Various attempts to work around this:
- https://github.com/libsdl-org/SDL/pull/4631 (straightforward revert)
- https://github.com/libsdl-org/SDL/pull/4632 (don't disable the crtc)
- https://github.com/libsdl-org/SDL/pull/4638 (skip no-op mode changes to bypass this)