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
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.
"max bpc" is a maximum value, the driver is free to choose a
smaller value depending on the bandwidth available.
Some faulty monitors misbehave with higher bpc values. We'll add
a workaround if users get hit by these in practice.
References: https://gitlab.freedesktop.org/wayland/weston/-/issues/612
The EDID 1.4 spec says that the serial number is optional:
> If this field is not used, then enter “00h, 00h, 00h, 00h”.
Leave the wlr_output.serial field NULL in that case, and hide it
from the output description.
CTA-861-G says that "graphics" is used to indicate non-analog (ie,
digital) content. With that bit set, the sink should turn off analog
reconstruction and other related filtering.
Some output commits (changing e.g. the output scale or transform)
don't require any change in the KMS state. Instead of going through
a KMS commit, return early. Blocking KMS commits can be expensive.
The wlr_output API requires compositors to wait for wlr_output.frame
before submitting a new buffer. However, compositors can perform a
commit which doesn't involve a buffer anytime.
If the commit is a modeset, we set DRM_MODE_ATOMIC_ALLOW_MODESET and
block until the commit is done. If it isn't, we currently always
perform a non-blocking commit. This is an issue because a previous
page-flip might still be in flight kernel-side, returning EBUSY.
Fix this by using blocking commits when a buffer isn't submitted by
the compositor.
Closes: https://github.com/swaywm/sway/issues/6962
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/2239
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.
Prior to [1], if an entry in a DRM format set was different than a
single LINEAR modifier, implicit modifiers were always allowed. This
has changed and now implicit modifiers are only allowed if INVALID
is in the list of modifiers.
So now we can safely enable explicit modifiers for cross-GPU imports,
without risking receiving buffers with an implicit modifier. This
should improve perf a bit on setups where two GPUs from the same vendor
are used.
This fixes the first bullet point from [2].
[1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3231
[2]: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3331
Maintaining our internal table up-to-date is tedious: one needs to
manually go through the PnP ID registry [1] and check whether we're
missing any entry.
udev_hwdb already has an API to fetch a manufacturer name from its
PnP ID. Use that instead.
[1]: https://uefi.org/pnp_id_list
wlroots picks names for all outputs, but it might be desirable for
compositor to override it.
For instance, Sway will use a headless output as a fallback in
case no outputs are connected. Sway wants to clearly label the
fallback output as such and label "real" headless outputs starting
from HEADLESS-1.
drmModeAddFB2 doesn't support explicit modifiers. Only accept INVALID
which indicates an implicit modifier and LINEAR which may indicate
that GBM_BO_USE_LINEAR has been used.
They are never used in practice, which makes all of our flag
handling effectively dead code. Also, APIs such as KMS don't
provide a good way to deal with the flags. Let's just fail the
DMA-BUF import when clients provide flags.
The BO handle table exists to avoid double-closing a BO handle,
which aren't reference-counted by the kernel. But if we can
guarantee that there is only ever a single ref for each BO handle,
then we don't need the BO handle table anymore.
This is possible if we create the handle right before the ADDFB2
IOCTL, and close the handle right after. The handles are very
short-lived and we don't need to track their lifetime.
Because of multi-planar FBs, we need to be a bit careful: some
FB planes might share the same handle. But with a small check, it's
easy to avoid double-closing the same handle (which wouldn't be a
big deal anyways).
There's one gotcha though: drmModeSetCursor2 takes a BO handle as
input. Saving the handles until drmModeSetCursor2 time would require
us to track BO handle lifetimes, so we wouldn't be able to get rid
of the BO handle table. As a workaround, use drmModeGetFB to turn the
FB ID back to a BO handle, call drmModeSetCursor2 and then immediately
close the BO handle. The overhead should be minimal since these IOCTLs
are pretty cheap.
Closes: https://github.com/swaywm/wlroots/issues/3164
drmModeAddFB2 doesn't support explicit modifiers. Only accept INVALID
which indicates an implicit modifier and LINEAR which may indicate
that GBM_BO_USE_LINEAR has been used.
Instead of ensuring the renderer and allocator are initialized in each
backend, do it in wlr_backend_autocreate. This allows compositors to
create backends without any renderer/allocator if they side-step
wlr_backend_autocreate.
Since the wlr_backend_get_renderer and backend_get_allocator end up
calling wlr_renderer_autocreate and wlr_allocator_autocreate, it sounds
like a good idea to centralize all of the opimionated bits in one place.
Expose the panel orientation with wlr_drm_connector_get_panel_orientation.
Leave it to the compositor to consume this information and configure the
output accordingly.
Closes: https://github.com/swaywm/wlroots/issues/1581
Modesets require a buffer. The DRM backend tried to auto-enable
outputs when a CRTC becomes available in the past, but now that
fails because no buffer is available.
Instead of having this magic inside the DRM backend, a better
approach is to do it in the compositor or in an optional helper.
Previously, we were copying wlr_output_state on the stack and
patching it up to be guaranteed to have a proper drmModeModeInfo
stored in it (and not a custom mode). Also, we had a bunch of
helpers deriving DRM-specific information from the generic
wlr_output_state.
Copying the wlr_output_state worked fine so far, but with output
layers we'll be getting a wl_list in there. An empty wl_list stores
two pointers to itself, copying it on the stack blindly results in
infinite loops in wl_list_for_each.
To fix this, rework our DRM backend to stop copying wlr_output_state,
instead add a new struct wlr_drm_connector_state which holds both
the wlr_output_state and additional DRM-specific information.
Using GBM to import DRM dumb buffers tends to not work well. By
using GBM we're calling some driver-specific functions in Mesa.
These functions check whether Mesa can work with the buffer.
Sometimes Mesa has requirements which differ from DRM dumb buffers
and the GBM import will fail (e.g. on amdgpu).
Instead, drop GBM and use drmPrimeFDToHandle directly. But there's
a twist: BO handles are not ref'counted by the kernel and need to
be ref'counted in user-space [1]. libdrm usually performs this
bookkeeping and is used under-the-hood by Mesa.
We can't re-use libdrm for this task without using driver-specific
APIs. So let's just re-implement the ref'counting logic in wlroots.
The wlroots implementation is inspired from amdgpu's in libdrm [2].
Closes: https://github.com/swaywm/wlroots/issues/2916
[1]: https://gitlab.freedesktop.org/mesa/drm/-/merge_requests/110
[2]: 1a4c0ec9ae/amdgpu/handle_table.c
The Coordinated Video Timings (CVT) spec [1] defines two types of
timings: the "CVT standard CRT" timings and the "CVT reduced blanking"
timings (see section 3.6).
The standard CRT timings include pauses in the video stream to allow
CRT displays to reposition their electron beam at the end of each
horizontal scan line [2]. While this was desirable a few decades ago,
nowadays we can just generate a CVT reduced blanking timing by default.
wlroots users can still set full custom DRM modes via
wlr_drm_connector_add_mode.
[1]: https://glenwing.github.io/docs/VESA-CVT-1.2.pdf
[2]: https://en.wikipedia.org/wiki/Coordinated_Video_Timings#Reduced_blanking
To retrieve the formats, an allocated crtc is required. If there is no
currently no crtc available, try to allocate it. This reproducable by
having a disabled output and going through a suspend cycle with amdgpu.
On start CRTCs look like this:
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1099] Reallocating CRTCs
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1110] State before reallocation:
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1116] 'DP-1' crtc=0 state=1 desired_enabled=1
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1116] 'DP-2' crtc=1 state=1 desired_enabled=1
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1116] 'HDMI-A-1' crtc=-1 state=0 desired_enabled=0
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1116] 'HDMI-A-2' crtc=-1 state=0 desired_enabled=0
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1116] 'DVI-D-1' crtc=-1 state=0 desired_enabled=0
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1167] State after reallocation:
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1174] 'DP-1' crtc=0 state=1 desired_enabled=1
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1174] 'DP-2' crtc=1 state=1 desired_enabled=1
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1174] 'HDMI-A-1' crtc=-1 state=0 desired_enabled=0
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1174] 'HDMI-A-2' crtc=-1 state=0 desired_enabled=0
00:00:00.588 [DEBUG] [wlr] [backend/drm/drm.c:1174] 'DVI-D-1' crtc=-1 state=0 desired_enabled=0
where DP-1 is than disabled. After suspend/resume, allocation turns into:
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1099] Reallocating CRTCs
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1110] State before reallocation:
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1116] 'DP-1' crtc=-1 state=1 desired_enabled=0
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1116] 'DP-2' crtc=1 state=3 desired_enabled=1
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1116] 'HDMI-A-1' crtc=-1 state=0 desired_enabled=0
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1116] 'HDMI-A-2' crtc=-1 state=0 desired_enabled=0
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1116] 'DVI-D-1' crtc=-1 state=0 desired_enabled=0
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1167] State after reallocation:
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1174] 'DP-1' crtc=-1 state=1 desired_enabled=0
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1174] 'DP-2' crtc=1 state=3 desired_enabled=1
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1174] 'HDMI-A-1' crtc=-1 state=0 desired_enabled=0
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1174] 'HDMI-A-2' crtc=-1 state=0 desired_enabled=0
00:30:22.680 [DEBUG] [wlr] [backend/drm/drm.c:1174] 'DVI-D-1' crtc=-1 state=0 desired_enabled=0
where the crtc for DP-1 is now NULL. Trying to enable the output results
in:
10:43:36.906 [DEBUG] [sway/config/output.c:351] Turning on output DP-1
10:43:36.906 [DEBUG] [sway/config/output.c:360] Set preferred mode
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [sway/config/output.c:366] Preferred mode rejected, falling back to another mode
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.906 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.906 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.906 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [DEBUG] [sway/config/output.c:400] Auto-detected output scale: 1.000000
10:43:36.907 [DEBUG] [sway/config/output.c:430] Committing output DP-1
10:43:36.907 [DEBUG] [wlr] [backend/drm/drm.c:464] connector DP-1: Can't enable an output without a buffer
10:43:36.907 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
10:43:36.907 [ERROR] [wlr] [types/wlr_output.c:512] Failed to get primary display formats
10:43:36.907 [ERROR] [sway/config/output.c:435] Failed to commit output DP-1
where the primary format can't be queried since there is no crtc
allocated for the connector. Allocating the connector inside
drm_connector_get_primary_formats() fixes this issue. This is possible
since the only user of get_primary_formats() is the swapchain allocation
function, which is only called on output enable. Do the same thing for
the cursor formats in case the user queries them before the output is
enabled.
This allows the kernel to access our buffer damage. Some drivers
can take advantage of this, e.g. for PSR2 panels (Panel Self
Refresh) or for transfer over USB.
Closes: https://github.com/swaywm/wlroots/issues/1267
This reverts commit 85757665e6.
We now check if the output is enabled within wlr_output_send_frame, no
need to handle this explicitly in the DRM backend. This also fixes a
race which was introduced with this commit: if we schedule the flip,
disable and commit the output before the flip happens,
output.frame_pending will not be reset to false. We than always fail to
enable the output subsequently:
00:07:13.276 [INFO] [sway/commands.c:257] Handling command 'output DP-2 enable'
00:07:13.276 [DEBUG] [sway/commands.c:428] Subcommand: enable
00:07:13.276 [DEBUG] [sway/config/output.c:204] Merging on top of existing output config
00:07:13.276 [DEBUG] [sway/config/output.c:227] Config stored for output DP-2 (enabled: 1) (-1x-1@-1.000000Hz position 0,0 scale -1.000000 subpixel unknown transform -1) (bg /home/phoenix/Pictures/Wallpapers/mine/oper.jpg fill) (dpms 1) (max render time: -1)
00:07:13.276 [DEBUG] [sway/config/output.c:351] Turning on output DP-2
00:07:13.276 [DEBUG] [sway/config/output.c:360] Set preferred mode
00:07:13.276 [DEBUG] [wlr] [backend/drm/drm.c:465] connector DP-2: Can't enable an output without a buffer
00:07:13.276 [DEBUG] [wlr] [types/wlr_output.c:689] Attaching empty buffer to output for modeset
00:07:13.277 [DEBUG] [sway/config/output.c:329] Output DPI: 162.560000x161.364706
00:07:13.277 [DEBUG] [sway/config/output.c:400] Auto-detected output scale: 1.000000
00:07:13.277 [DEBUG] [sway/config/output.c:430] Committing output DP-2
00:07:13.277 [DEBUG] [wlr] [types/wlr_output.c:729] Tried to commit a buffer while a frame is pending
since the basic_output_test will always fail.
Reset frame_pending to false even if the output has been disabled in the
meantime.
Fixes https://github.com/swaywm/wlroots/issues/3109
When testing a modeset, make sure the caller has also provided a
buffer. This allows df0e75ba05 ("output: try skipping buffer
allocation if the backend allows it") to work as expected with the
DRM backend.
Closes: https://github.com/swaywm/wlroots/issues/3086
Unless we're dealing with a multi-GPU setup and the backend being
initialized is secondary, we don't need a renderer nor an allocator.
Stop initializing these.
Historically we haven't allowed direct scan-out for legacy KMS,
because legacy misses the functionality to make sure a buffer can
be scanned out. However with renderer v6 the backend can't figure
out anymore whether the buffer comes from its internal swap-chain,
because the backend doesn't have an internal swap-chain.
The legacy KMS API guarantees that the driver won't reject a buffer
as long as it's been allocated with the same parameters as the
previous one. Let's check this in legacy_crtc_test.
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
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.
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.
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.
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.
PRIME support for buffer sharing has become mandatory since the renderer
rewrite. Make sure we check for the appropriate capabilities in backend,
allocator and renderer.
See also #2819.
Downgrade errors to DEBUG level, because drm_fb_create is used in
test_buffer, so errors aren't always fatal. Add ERROR logs at call
sites where a failure is fatal, to make it clear something wrong
happened.
If the import to KMS succeeds, we have a better chance to be able to
scan it out.
Importing is also necessary for test-only commits, which we want to
add in the future.
Compute only the transform matrix in the output. The projection matrix
will be calculated inside the gles2 renderer when we start rendering.
The goal is to help the pixman rendering process.
In 93cd3a79b2 ("backend/drm: stop using GBM flags"), we stopped
using the GBM_BO_USE_LINEAR flag in favor of a modifier list set
to { DRM_FORMAT_MOD_LINEAR }. However, the last argument of
drm_plane_init_surface disables modifiers -- so the buffer will just
get allocated with an implicit modifier, without necessarily being
LINEAR.
To fix this, allow modifiers when allocating the cursor buffers.
wlr_drm_plane.formats should already have the necessary LINEAR
restrictions.
Fixes: 93cd3a79b2 ("backend/drm: stop using GBM flags")
This allows a compositor to get a KMS connector object ID from a
wlr_output. The compositor can then query more information about
the connector via libdrm.
This gives more freedom to compositors and allows them to read
KMS properties that wlroots doesn't know about. For instance,
they could read the EDID or the suggested_{X,Y} properties and
change their output configuration based on that.
The subconnector property indicates the connector sub-type. This is
useful because that usually indicates what kind of connector the user
has plugged in to their monitor, e.g. a DisplayPort-to-DVI cable will
indicate a DVI subconnector. Also some laptops have non-DP connectors
that are internally linked to a DP port on the GPU.
Set the output description accordingly.
See https://drmdb.emersion.fr/properties/3233857728/subconnector
The new wlr_renderer_autocreate API is great for compositors, however
it causes some issues with DRM multi-GPU support.
A DRM child backend wants the compositor to use the parent GPU, so it
exposes the parent's DRM FD in get_drm_fd. However, in order to be able
to perform multi-GPU buffer copies, the child DRM backend still needs to
create a local renderer.
Use the new private wlr_renderer_autocreate_with_drm_fd function to
avoid creating a renderer for the parent GPU.
Fixes: e128e6c08d ("render: drop egl parameters from wlr_renderer_autocreate")
Instead of requiring callers to manually make the EGL context current
before binding a buffer and unsetting it after unbinding a buffer, do
it inside wlr_renderer_bind_buffer.
This hides renderer-specific implementation details inside the
wlr_renderer interface. Non-GLES2 renderers may not use EGL.
This removes all EGL dependencies from the backends.
References: https://github.com/swaywm/wlroots/issues/2618
References: https://github.com/swaywm/wlroots/pull/2615#issuecomment-756687006
Since 5b1b43c68c ("backend/drm: make wlr_drm_plane.{pending,queued,current}_fb
pointers"), current_fb can be NULL if there's no buffer. If current_fb
is not NULL, current_fb->wlr_buf is guaranteed to not be NULL.
Closes: https://github.com/swaywm/wlroots/issues/2634