This is the cause of the spurious "drmHandleEvent failed" messages
at exit. restore_drm_outputs calls handle_drm_event in a loop without
checking whether the FD is readable, so drmHandleEvent ends up with a
short read (0 bytes) and returns an error.
The loop's goal is to wait for all queued page-flip events to complete,
to allow drmModeSetCrtc calls to succeed without EBUSY. The
drmModeSetCrtc calls are supposed to restore whatever KMS state we were
started with. But it's not clear from my PoV that restoring the KMS
state on exit is desirable.
KMS clients are supposed to save and restore the (full) KMS state on VT
switch, but not on exit. Leaving our KMS state on exit avoids unnecessary
modesets and allows flicker-free transitions between clients. See [1]
for more details, and note that with Pekka we've concluded that a new
flag to reset some KMS props to their default value on compositor
start-up is the best way forward. As a side note, Weston doesn't restore
the CRTC by does disable the cursor plane on exit (see
drm_output_deinit_planes, I still think disabling the cursor plane
shouldn't be necessary on exit).
Additionally, restore_drm_outputs only a subset of the KMS state.
Gamma and other atomic properties aren't accounted for. If the previous
KMS client had some outputs disabled, restore_drm_outputs would restore
a garbage mode.
[1]: https://blog.ffwll.ch/2016/01/vt-switching-with-atomic-modeset.html
wl_event_loop_add_fd was called with a NULL data argument, but the
function expects the data argument to be set to the wlr_drm_backend.
Fixes: 053ebe7c27 ("backend/drm: terminate display on drmHandleEvent failure")
Right now callers of drm_crtc_commit need to check whether the
interface is legacy or atomic before passing the TEST_ONLY flag.
Additionally, the fallbacks for legacy are in-place in the common
code.
Add a test_only arg to the crtc_commit hook. This way, there's no
risk to pass atomic-only flags to the legacy function (add an assert
to ensure this) and all of the legacy-specific logic can be put back
into legacy.c (done in next commit).
drm_surface_make_current and drm_surface_unset_current set implicit
state and are an unnecessary mid-layer. Prefer to use directly
wlr_renderer_begin_with_buffer, which automatically unsets the back
buffer on wlr_renderer_end.
I'd like to get rid of drm_surface_make_current once we stop using
it for the primary swapchain.
Some buffers need to be copied across GPUs. Such buffers need to be
allocated with a format and modifier suitable for both the source
and the destination.
When explicit modifiers aren't supported, we were forcing the buffers
to be allocated with a linear layout, because implicit modifiers
aren't portable across GPUs. All is well with this case.
When explicit modifiers are supported, we were advertising the whole
list of destination modifiers, in the hope that the source might
have some in common and might be able to allocate a buffer with a
more optimized layout. This works well if the source supports explicit
modifiers. However, if the source doesn't, then wlr_drm_format_intersect
will fallback to implicit modifiers, and everything goes boom: the
source uses a GPU-specific tiling and the destination interprets it
as linear.
To avoid this, just force linear unconditionally. We'll be able to
revert this once we have a good way to indicate that an implicit modifier
isn't supported in wlr_drm_format_set, see [1].
[1]: https://github.com/swaywm/wlroots/pull/2815
Closes: https://github.com/swaywm/wlroots/issues/3030
[1] and [2] have introduced new wl_array usage in wlroots, but
contains a mistake: wl_array_for_each iterates over pointers to
the wl_array entries, not over entries themselves.
Fix all wl_array_for_each call sites. Name the variables "ptr"
to avoid confusion.
Found via ASan:
==148752==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x602000214111 in thread T0
#0 0x7f6ff2235f19 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:127
#1 0x7f6ff1c04004 in wlr_tablet_destroy ../subprojects/wlroots/types/wlr_tablet_tool.c:24
#2 0x7f6ff1b8463c in wlr_input_device_destroy ../subprojects/wlroots/types/wlr_input_device.c:51
#3 0x7f6ff1ab9941 in backend_destroy ../subprojects/wlroots/backend/wayland/backend.c:306
#4 0x7f6ff1a68323 in wlr_backend_destroy ../subprojects/wlroots/backend/backend.c:57
#5 0x7f6ff1ab36b4 in multi_backend_destroy ../subprojects/wlroots/backend/multi/backend.c:57
#6 0x7f6ff1ab417c in handle_display_destroy ../subprojects/wlroots/backend/multi/backend.c:124
#7 0x7f6ff106184e in wl_display_destroy (/usr/lib/libwayland-server.so.0+0x884e)
#8 0x55cd1a77c9e5 in server_fini ../sway/server.c:218
#9 0x55cd1a77893f in main ../sway/main.c:400
#10 0x7f6ff04bdb24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
#11 0x55cd1a73a7ad in _start (/home/simon/src/sway/build/sway/sway+0x33a7ad)
0x602000214111 is located 1 bytes inside of 16-byte region [0x602000214110,0x602000214120)
freed by thread T0 here:
#0 0x7f6ff2235f19 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:127
#1 0x7f6ff1c04004 in wlr_tablet_destroy ../subprojects/wlroots/types/wlr_tablet_tool.c:24
#2 0x7f6ff1b8463c in wlr_input_device_destroy ../subprojects/wlroots/types/wlr_input_device.c:51
#3 0x7f6ff1ab9941 in backend_destroy ../subprojects/wlroots/backend/wayland/backend.c:306
#4 0x7f6ff1a68323 in wlr_backend_destroy ../subprojects/wlroots/backend/backend.c:57
#5 0x7f6ff1ab36b4 in multi_backend_destroy ../subprojects/wlroots/backend/multi/backend.c:57
#6 0x7f6ff1ab417c in handle_display_destroy ../subprojects/wlroots/backend/multi/backend.c:124
#7 0x7f6ff106184e in wl_display_destroy (/usr/lib/libwayland-server.so.0+0x884e)
previously allocated by thread T0 here:
#0 0x7f6ff2236279 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:145
#1 0x7f6ff1066d03 in wl_array_add (/usr/lib/libwayland-server.so.0+0xdd03)
[1]: https://github.com/swaywm/wlroots/pull/3002
[2]: https://github.com/swaywm/wlroots/pull/3004
The previous fix tried to side-step cursor->pending_fb completely.
However that messes up our buffer locking mechanism.
Instead, stop clearing the pending cursor FB on a failed commit. The
pending cursor FB will remain for the next commit.
Fixes: 6c3d080e25 ("backend/drm: populate cursor plane's current_fb")
This reverts commit 6c3d080e25.
Populating wlr_drm_plane.current_fb messes up the buffer's locking.
The previous buffer is released while it's still being displayed
on-screen.
Custom backends and renderers need to implement
wlr_backend_impl.get_buffer_caps and
wlr_renderer_impl.get_render_buffer_caps. They can't if enum
wlr_buffer_cap isn't made public.
Right now, when a new output state field is added, all backends by
default won't reject it. This means we need to add new checks to
each and every backend when we introduce a new state field.
Instead, introduce a bitmask of supported output state fields in
each backend, and error out if the user has submitted an unknown
field.
Some fields don't need any backend involvment to work. These are
listed in WLR_OUTPUT_STATE_BACKEND_OPTIONAL as a convenience.
This moves the magic incantation into libdrm and is clearer. See
[1] for details.
While at it, fixup the doc comment and improve logging.
[1]: 523b3658aa
The set_cursor() hook is a little bit special: it's not really
synchronized to commit() or test(). Once set_cursor() returns true,
the new cursor is part of the current state.
This fixes a state where wlr_drm_connector.cursor_enabled is true
but there is no FB available. This is triggered by set_cursor()
followed by a failed commit(), which resets pending_fb.
We should definitely fix the output interface to make the cursor part
of the pending state, but that's a more involved change.
Instead of trying to perform a real modeset in init_renderer,
perform an atomic test-only commit to find out whether disabling
modifiers is necessary because of bandwidth limitations.
This decouples init_renderer from the actual commit, making it
possible to modeset an output with a user-supplied buffer instead
of a black frame.
We loose the ability to make sure the buffers coming from the
swapchain will work fine when using the legacy interface. This
can break i915 when atomic is disabled and modifiers enabled.
But i915 always has atomic (so the user must explicitly disable it
to run into potential bandwidth limitations) and is the only known
problematic driver.
Rely on wlr_output's generic swapchain support instead of creating our
own. The headless output now simply keeps a reference to the front buffer
and does nothing else.
Instead of passing a wlr_texture to the backend, directly pass a
wlr_buffer. Use get_cursor_size and get_cursor_formats to create
a wlr_buffer that can be used as a cursor.
We don't want to pass a wlr_texture because we want to remove as
many rendering bits from the backend as possible.
When picking a format, the backend needs to know whether the
buffers allocated by the allocator will be DMA-BUFs or shared
memory. So far, the backend used the renderer's supported
buffer types to guess this information.
This is pretty fragile: renderers in general don't care about the
SHM cap (they only care about the DATA_PTR one). Additionally,
nothing stops a renderer from supporting both DMA-BUFs and shared
memory, but this would break the backend's guess.
Instead, use wlr_allocator.buffer_caps. This is more reliable since
the buffers created with the allocator are guaranteed to have these
caps.
Instead of managing our own renderer and allocator, let the common
code do it.
Because wlr_headless_backend_create_with_renderer needs to re-use
the parent renderer, we have to hand-roll some of the renderer
initialization.
This new functions cleans up the common backend state. While this
currently only emits the destroy signal, this will also clean up
the renderer and allocator in upcoming patches.
Backend-initiated mode changes can use this function instead of
going through drm_connector_set_mode. drm_connector_set_mode becomes
a mere drm_connector_commit_state helper.
Replace it with a new drm_connector_state_is_modeset function that
decides whether a modeset is necessary directly from the
wlr_output_state which is going to be applied.
Populate the wlr_output_state when setting a mode. This will allow
drm_connector_set_mode to stop relying on ephemeral fields in
wlr_drm_crtc. Also drm_connector_set_mode will be able to apply
both a new buffer and a new mode atomically.
Stop assuming that the state to be applied is in output->pending in
crtc_commit. This will allow us to remove ephemeral fields in
wlr_drm_crtc, which are used scratch fields to stash temporary
per-commit data.
On multi-GPU setups, there is a primary DRM backend and secondary
DRM backends. wlr_backend_get_drm_fd will always return the parent
DRM FD even on secondary backends, so that users always use the
primary device for rendering.
However, for our internal rendering we want to use the secondary
device. Use allocator_autocreate_with_drm_fd to make sure the
allocator will create buffers on the secondary device.
We do something similar to ensure our internal rendering will
happen on the secondary device with renderer_autocreate_with_drm_fd.
Fixes: cc1b66364c ("backend: use wlr_allocator_autocreate")
This function is only required because the DRM backend still needs
to perform multi-GPU magic under-the-hood. Remove the wlr_ prefix
to make it clear it's not a candidate for being made public.
This reverts commit f9f90b4173.
gbm_bo_get_modifier may return a modifier in these cases:
- The kernel doesn't support modifiers but Mesa does
- WLR_DRM_NO_MODIFIERS=1 is set
However, in both of these cases, the gbm_bo has been allocated
without modifiers.
There is already a check in drm_fb_create for modifiers:
wlr_drm_format_set_has will make sure buffers with an explicit
modifier will be rejected if the DRM backend doesn't support them.
So no need for an additional check in get_fb_for_bo.
Closes: https://github.com/swaywm/wlroots/issues/2896
The previous code would always print "falling back to legacy method",
even if the format wasn't ARGB8888.
Drop get_fb_for_bo_legacy, since the code can just be inlined without
hurting readability.
Ideally we should only fallback to drmModeAddFB if the error code
indicates the BE failure, but the original PR [1] doesn't say what
error code is returned by the kernel.
[1]: https://github.com/swaywm/wlroots/pull/2569
We shouldn't strip a modifiers from buffers, because the will make
the kernel re-interpret the data as LINEAR on most drivers,
resulting in an incorrect output on screen.
libseat provides all session functionality, so there is no longer need
for a session backend abstraction. The libseat device ID, seat handle
and event loop handle are moved to the main wlr_session and wlr_device
structs.
The get_drm_fd was made available in an internal header with a53ab146f. Move it
now to the public header so consumers opting in to the unstable interfaces can
make use of it.