Introduce a per-page-flip tracking struct passed to the kernel
when we request a page-flip event for an atomic commit. The kernel
will pass us back this pointer when delivering the event.
This eliminates any risk of mixing up events together. In particular,
if two events are pending, or if the CRTC of a connector is swapped,
we no longer blow up in the page-flip event handler.
Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3753
We can just assume CLOCK_MONOTONIC everywhere.
Simplifies the backend API, and fixes clock mismatches when multiple
backends are used together with different clocks.
The kernel complains when the damage exceeds the FB bounds:
[73850.448326] i915 0000:00:02.0: [drm:drm_atomic_check_only] [PLANE:31:plane 1A] invalid damage clip 0 0 2147483647 2147483647
Make the DRM backend behave like the Wayland one and allow compositors
to damage (0, 0, INT32_MAX, INT32_MAX) to repaint everything without
needing to know the exact buffer size.
Closes: https://github.com/swaywm/sway/issues/7632
Since 1d581656c7 ("backend/drm: set "max bpc" to the max") we
set the "max bpc" property to the maximum value. The kernel driver
is supposed to clamp this value depending on hardware capabilities.
All kernel drivers lower the value depending on the GPU capabilities.
However, none of the drivers lower the value depending on the DP-MST
link capabilities. Thus, enabling a 4k@60Hz mode can fail on some
DP-MST setups due to the "max bpc" property.
Additionally, it's not a good idea to unconditionally set "max bpc"
to the max. A high bpc consumes more lanes and more clock speed,
which means higher power consumption and the busy lanes cannot be
used for something else (e.g. other data transfers on a USB-C cable).
For now, let's tie the "max bpc" to the pixel format of the buffer.
Introduce a heuristic to make "high bit-depth buffer" a synonym of
"I want the best quality".
This is not perfect: a "max bpc" higher than 8 might be desirable
for pixel formats with a color depth of 8 bits, for instance when
the color management KMS properties are used. But we don't really
support that yet, so let's leave this for later.
Closes: https://github.com/swaywm/sway/issues/7367
We only need it for one thing: gamma size. Moreover, some bits in
the drmModeCrtc will become out-of-date, for instance the current
mode, so let's avoid caching the whole struct and only keep what
we know won't change.
Instead of having a pending_fb field on the struct wlr_drm_plane,
move it to struct wlr_drm_connector_state. That way, there's no
risk having a stale pending FB around: the state doesn't survive
across tests and commits.
The cursor is a special case because it's disconnected from the
atomic state: the wlr_backend_impl.set_cursor hook sets the cursor
for the next commit. Move the field to
wlr_drm_connector.cursor_pending_fb.
We'll move the pending primary FB into the connector state in the
next commit, dropping wlr_drm_plane.pending_fb in the process.
Introduce a dedicated field for the cursor, which has to be managed
in a special way due to our set_cursor API.
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.
"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
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.
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
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
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
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
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
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.