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.
connect_drm_connector() may be called long after create_drm_connector().
During that time the DRM mode might have changed. Avoid working with
stale information.
match_obj() might return a configuration where the CRTC for an
enabled connector is switched to another one.
We don't support this correctly: the wlr_output common code would
need to query again the supported formats, re-allocate the
swapchain, etc.
What's more, the kernel doesn't even support this [1]: it
requires planes to be disabled to change their CRTC, it rejects
commits directly switching the CRTC used by a plane.
[1]: https://cgit.freedesktop.org/drm/drm-misc/tree/drivers/gpu/drm/drm_atomic.c?h=6e90293618ed476d6b11f82ce724efbb9e9a071b#n697
If the commit fails, then our local state becomes out-of-sync with
the kernel's. Additionally, when disabling a connector without going
through dealloc_crtc(), conn->crtc would still be set.
Fix this by updating conn->crtc in drm_connector_commit_state().
The raw enum value wasn't informative enough. It's not trivial to
tell whether 0 means connected or disconnected.
Drop the status from the state after realloc, since the exact same
information is printed right above.
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.
We were calling drm_connector_supports_vrr() before
drm_connector_alloc_crtc(). Thus, when an output is currently off,
the VRR test would always fail, because it checks that the
vrr_enabled CRTC prop exists.
destroy_wl_buffer() is called from backend_destroy(). We need to
ensure the wlr_buffer is unlocked when we're waiting for a
wl_buffer.release event from the parent compositor.
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.