Up until now, wlr_backend_autocreate() created the wlr_session and
then stuffed it into struct wlr_multi_backend so that compositors
can grab it later.
This is an abuse of wlr_multi_backend and the wlr_backend API:
wlr_backend_get_session() and wlr_multi_backend.session only exist
to accomodate the needs of wlr_backend_autocreate(). What's more,
the DRM and libinput backends don't implement
wlr_backend_impl.get_session.
Instead, return the struct wlr_session to the compositor in the
wlr_backend_autocreate() call. wlr_backend_get_session() will be
removed in the next commit.
The following situation can be dangerous:
- Output DP-1 is plugged in, compositor enables it.
- User VT switches away.
- User unplugs DP-1.
- User VT switches back.
- scan_drm_connectors() figures out the output is now disconnected,
uninitializes the struct wlr_output.
- The loop restoring previous output state in handle_session_active()
accesses the struct wlr_output to figure out what to restore.
By chance, we zero out the struct wlr_output after uninitializing it,
so enabled and current_mode will always be zero. But let's make sure
we handle this case explicitly, to remind future readers that it exists
and make the code less fragile.
The old drm_connector_set_mode() function did that by calling
drm_crtc_page_flip(). We lost this in the refactoring.
Fixes: f216e97983 ("backend/drm: drop drm_connector_set_mode()")
Once we are DRM master, the CRTC cannot be changed behind our back
except during a VT switch.
After a VT switch, we try to restore whatever KMS state we had last
programmed. Reloading the current CRTC from KMS breaks this and
can result in a modeset without a FB.
Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3432
The drm_connector_commit_state() call in handle_session_active()
was not resulting in any atomic commit, because it didn't match any
of the if branches: active = true, no new buffer was committed,
and adaptive sync/gamma LUT were unchanged. Thus the commit was a
no-op.
Later on, when the compositor performs regular page-flips, the
kernel would return EINVAL indicating that a modeset was needed.
Rework the logic to use a non-blocking page-flip commit if a buffer
was committed, and use a blocking commit if the connector is on or
is being disabled. The only case where we should skip the atomic
commit is when disabling (active = false) an already-disabled
connector (conn->crtc == NULL).
Note, 6936e163b5 ("backend/drm: short-circuit no-op commits")
has introduced early returns for other situations where we don't
need to perform an atomic commit (e.g. updating scale or transform
of an output).
Fixes: f216e97983 ("backend/drm: drop drm_connector_set_mode()")
Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3432
Extract the logic to fetch the current mode to a separate function
to make it more readable. Stop dying in an assert when
get_drm_prop_blob() fails. Always make it so the drmModeModeInfo
pointer is allocated so that we can free() it unconditionally.
We already have disconnect_drm_connector() to handle the
CONNECTED → DISCONNECTED transition. Let's add
connect_drm_connector() to handle DISCONNECTED → CONNECTED. This
makes scan_drm_connectors() shorter and easier to follow.
No functional change, literally just moving code around.
We were using the legacy API (with a detour through drmModeEncoder)
to find out the current CRTC for a connector. Use the atomic API
when available.
Also extract the whole logic into a separate function for better
readability, and better handle errors.
Instead of special-casing modesets, we can just cut the wrapper
and directly call drm_crtc_page_flip(). drm_connector_test() should
already have the checks previously done in drm_connector_set_mode(),
all we need to do is update enabled/mode after a successful atomic
commit.
This field becomes stale too easily: for instance, see 6adca4089c
("backend/drm: don't unconditionally set desired_enabled").
Additionally, drm_connector_alloc_crtc() needs to do some weird
dance, restoring its previous value.
Instead, add a connector arg to realloc_crtcs() to indicate a new
connector we want to enable.
We were unconditonally setting desired_enabled = true for all
connected connectors. This makes realloc_crtcs() always keep a CRTC
active for these, even if the user doesn't want to enable them.
When starting up, the compositor might call wlr_output_set_mode()
with a mode which is already the current one. wlroots will detect
this and make the wlr_output_set_mode() call a no-op. During the
next wlr_output_commit() call, wlroots will perform an atomic
commit without the ALLOW_MODESET flag.
This is an issue, because some drivers need ALLOW_MODESET even if
the mode is the same. For instance, if the FB stride or modifier
changed, some drivers require a modeset.
Add a new flag "allow_artifacts" which is set when the compositor
calls mode-setting functions. Use this flag to figure out whether
we want to perform atomic commits with ALLOW_MODESET.
(The name "allow_artifacts" is picked because ALLOW_MODESET is a
misnomer, see [1].)
[1]: https://patchwork.freedesktop.org/patch/505107/
Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3499
Stack trace:
#0 0x00007f17081f5b99 in wl_list_insert (list=list@entry=0x2d8, elm=elm@entry=0x7ffe7f7e85d0)
at ../wayland-1.21.0/src/wayland-util.c:48
#1 0x00007f17081f5f2e in wl_signal_emit_mutable (signal=signal@entry=0x2d8, data=data@entry=0x7ffe7f7e8660)
at ../wayland-1.21.0/src/wayland-server.c:2167
#2 0x00007f170815a971 in handle_switch_toggle (wlr_switch=0x2a0, event=0x55d5ba13dc00)
at ../backend/libinput/switch.c:50
#3 handle_libinput_event (event=0x55d5ba13dc00, backend=0x55d5b975d740) at ../backend/libinput/events.c:234
#4 handle_libinput_readable (fd=<optimized out>, mask=<optimized out>, _backend=<optimized out>)
at ../backend/libinput/backend.c:58
#5 handle_libinput_readable (fd=fd@entry=34, mask=mask@entry=1, _backend=_backend@entry=0x55d5b975d740)
at ../backend/libinput/backend.c:48
#6 0x00007f170815c110 in backend_start (wlr_backend=0x55d5b975d740) at ../backend/libinput/backend.c:109
#7 0x00007f1708160996 in multi_backend_start (wlr_backend=0x55d5b97583d0) at ../backend/multi/backend.c:32
All we can do to influence adaptive sync on the X11 backend is set the
_VARIABLE_REFRESH window property like mesa automatically does. We don't
have any control beyond that, so we set the state to enabled on creating
the output and never allow changing it (just like the Wayland backend).
Adaptive sync is effectively always enabled when using the Wayland
backend. This is not something we have control over, so we set the
state to enabled on creating the output and never allow changing it.
Previously, adaptive sync was just a hint and wouldn't make any
atomic commit fail if the backend didn't support it. The main reason
is wlr_output_test wasn't supported at the time.
Now that we have a way for compositors to test whether a change can
work, let's remove the exception for adaptive sync and convert it to
a regular output state field.