In output_ensure_buffer() we create a swapchain and attach an empty
buffer to the output if necessary. We do that during the first commit.
This is fine when the first commit enables the output, however this breaks
when the first commit disables the output. A commit which disables an
output and has a buffer attached is invalid (see output_basic_test()), and
makes the DRM backend crash:
00:00:00.780 [wlr] [backend/drm/drm.c:622] connector eDP-1: Turning off
../subprojects/wlroots/backend/drm/drm.c:652:44: runtime error: member access within null pointer of type 'struct wlr_drm_crtc'
AddressSanitizer:DEADLYSIGNAL
=================================================================
==2524==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7f22e894afc1 bp 0x7ffe1d57c550 sp 0x7ffe1d57c420 T0)
==2524==The signal is caused by a READ memory access.
==2524==Hint: address points to the zero page.
#0 0x7f22e894afc1 in drm_connector_commit_state ../subprojects/wlroots/backend/drm/drm.c:652
#1 0x7f22e894b1f5 in drm_connector_commit ../subprojects/wlroots/backend/drm/drm.c:674
#2 0x7f22e89e8da9 in wlr_output_commit_state ../subprojects/wlroots/types/output/output.c:756
#3 0x555ab325624d in apply_output_config ../sway/config/output.c:517
#4 0x555ab31a1aa1 in handle_new_output ../sway/desktop/output.c:974
#5 0x7f22e9272f6d in wl_signal_emit_mutable (/usr/lib/libwayland-server.so.0+0x9f6d)
#6 0x7f22e899b012 in new_output_reemit ../subprojects/wlroots/backend/multi/backend.c:161
#7 0x7f22e9272f6d in wl_signal_emit_mutable (/usr/lib/libwayland-server.so.0+0x9f6d)
#8 0x7f22e895a153 in scan_drm_connectors ../subprojects/wlroots/backend/drm/drm.c:1488
#9 0x7f22e893c2e4 in backend_start ../subprojects/wlroots/backend/drm/backend.c:24
#10 0x7f22e892ed00 in wlr_backend_start ../subprojects/wlroots/backend/backend.c:56
#11 0x7f22e8999b83 in multi_backend_start ../subprojects/wlroots/backend/multi/backend.c:31
#12 0x7f22e892ed00 in wlr_backend_start ../subprojects/wlroots/backend/backend.c:56
#13 0x555ab317d5cc in server_start ../sway/server.c:316
#14 0x555ab317748d in main ../sway/main.c:400
#15 0x7f22e783c28f (/usr/lib/libc.so.6+0x2328f)
#16 0x7f22e783c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
#17 0x555ab3134c84 in _start (/home/simon/src/sway/build/sway/sway+0x377c84)
Fixes: 3be6658ee7 ("output: allocate swapchain on first commit")
Closes: https://github.com/swaywm/sway/issues/7373
The backend no longer changes the output state behind the
compositor's back. Instead, compositors can listen to the "commit"
event and check for WLR_OUTPUT_STATE_ENABLED/WLR_OUTPUT_STATE_MODE.
Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/2300
If a fixed mode matching the user requirements is available, use
that. This avoids generating the mode with GTF or CVT in the DRM
backend, and instead uses mode timings advertised by the output.
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3514
On first commit, require a new buffer if the compositor called a
mode-setting function, even if the mode won't change. This makes it
so the swapchain is created now.
Stop trying to check whether the backend supports buffer-less modesets
because that makes everything more complicated. For instance, the
DRM backend doesn't need a new buffer if the previous DRM master left
the output enabled.
Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3499
Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3502
Some compositors want to have full control over the buffers attached
to the output, and don't want to use the internal swapchain. Such
compositors include KWinFT (allocates its buffers on its own) and
gamescope (uses a headless output without any buffers).
Let's just make output_ensure_buffer() a no-op in that case.
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
In wlr_output_attach_render(), stop setting
wlr_output.pending.buffer. This removes one footgun: using the
wlr_buffer at that stage is invalid, because rendering operations
haven't been flushed to the GPU yet. We need to wait until
output_clear_back_buffer() for the wlr_buffer to be used safely.
Instead, set wlr_output.pending.buffer in wlr_output_test() and
wlr_output_commit().
Additionally, move the output_clear_back_buffer() from
wlr_output_commit_state() to wlr_output_commit(). This reduces the
number of calls in the failure path.
We can just use pending.buffer instead. It's completely fine to
call wlr_swapchain_set_buffer_submitted() with a buffer which
doesn't come from the swapchain, in which case it's a no-op.
This is documented to reset the gamma LUT, but we don't handle this
properly.
While at it, make sure we leave wlr_output.pending in a good state
on allocation failure.
If the first test in output_ensure_buffer() fails with modifiers we
replace the swapchain with a modifierless swapchain and try again.
However if that fails as well the output is currently stuck without
modifiers until the next modeset.
To fix this, destroy the modifierless swapchain if the test using it
fails. The next output_attach_back_buffer() call will create a swapchain
that allows modifiers when needed.
When using direct scanout back_buffer is NULL. We'd emit a commit
event with WLR_OUTPUT_STATE_BUFFER set but with a NULL buffer field,
which is non-sensical.
The previous wlr_output_cursor_set_image() allows setting a NULL buffer for the
cursor to hide it. This functionality was used by sway to hide the cursor,
restore the original semantics by allowing NULL buffers again by avoiding the
wlr_buffer allocation in case we have NULL pixels and handing a NULL wlr_buffer
to wlr_output_cursor_set_buffer().
Before calling wlr_output_impl.{test,commit}, perform a cheap
comparison between the current and candidate state. Unset any
fields which didn't change.
This refactors output_ensure_buffer() to not mutate the state passed,
making the previous subtle behavior much more explicit.
Fixes: d483dd2f ("output: add wlr_output_commit_state")
Closes: #3442
This allows the make/model/serial to be NULL when unset, and allows
them to be longer than the hardcoded array length.
This is a breaking change: compositors need to handle the new NULL
case, and we stop setting make/model to useless "headless" or
"wayland" strings.