The DRM backend is a little special when it comes to wlr_outputs: the
wlr_drm_connectors are long-lived and are created even when no screen is
connected.
A wlr_drm_connector only advertises a wlr_output to the compositor when
a screen is connected. As such, most of wlr_output's state is invalid
when the connector is disconnected.
We want to stop using wlr_output state on disconnected connectors.
Introduce wlr_drm_connector.name which is always valid regardless of the
connector status to avoid reading wlr_output.name when disconnected.
Simplify and unify connector-specific logging with a new
wlr_drm_conn_log macro. This makes it easier to understand which
connector a failure is about, without having to explicitly integrate the
connector name in each log message.
The workaround is broken because drm_fb_acquire doesn't leave the EGL
context current anymore. We'll need to re-introduce it.
References: https://github.com/swaywm/wlroots/issues/2525
gbm_bo_create_with_modifiers doesn't take GBM flags, so our
wlr_gbm_allocator interface doesn't either. We were still internally
using GBM flags in the DRM backend, leading to awkward back-and-forth
conversions.
The only flag passed to drm_plane_init_surface was GBM_BO_USE_LINEAR, so
turn that into a bool to make sure other flags can't be passed in.
Move the "force linear" logic out of init_drm_surface, because the
supplied wlr_drm_format should already contain that information.
drm_fb_import_wlr may need to change the current EGL context. For
instance by calling drm_fb_clear, which calls wlr_buffer_unlock, which
may destroy a buffer if the cursor swapchain size has changed, which
calls gles2's destroy_buffer, which calls glDeleteFramebuffers.
Closes: https://github.com/swaywm/wlroots/issues/2479
This is just the vendor-agnostic define for the GBM platform. It has the
same value as EGL_PLATFORM_GBM_MESA, so should work with old drivers
that only offer the Mesa-vendored extension too.
On some platforms it's possible that the display engine supports
modifiers not supported by the render engine.
Query render formats and intersect them with plane formats to accommodate
for this.
After discussing with Pekka and Daniel on #dri-devel, we concluded [1]
that user-space shouldn't need to force-probe connectors. Force-probing
can take some time, so using drmModeGetConnectorCurrent can result in
faster start-up.
Users can manually trigger a force-probe if necessary:
echo detect | sudo tee /sys/class/drm/card0-DP-1/status
Or just by running a tool like drm_info.
A similar change has been submitted to Weston [2].
[1]: https://lists.freedesktop.org/archives/dri-devel/2020-November/287728.html
[2]: https://gitlab.freedesktop.org/wayland/weston/-/issues/437
Instead of operating on FDs in {open,close}_device, operate on
wlr_devices. This avoids the device lookup in wlr_session and allows
callers to have access to wlr_device fields.
For now, we use it to remove wlr_session_signal_add and replace it with
a more idiomatic wlr_session.events.change field. In the future, other
events will be added.
We would always return the GAMMA_LUT_SIZE property if available, and
only fall back to legacy gamma size otherwise. This leads to issues if
both are available in differs in size while we use the legacy backend.
Ensure that we only return the legacy size if we're using the legacy
backend.
Closes: https://github.com/swaywm/wlroots/issues/2429
When performing a modeset, the DRM backend will request a page-flip
event. However frame_pending wasn't set to true, so any subsequent
wlr_output_schedule_frame calls would imemdiately trigger a synthetic
frame event, asking the compositor to submit a new frame. Committing the
new frame fails with "a page-flip is already pending" error in the DRM
backend.
When an output is disabled one last pageflip will happen to disable it.
Currently this pageflip causes a frame event.
Since the output is disabled we don't want to send this frame event.
get_drm_prop_blob does not set path_len if it returns NULL. Check the
return value before path_len to avoid reading uninitialized memory.
(Granted, this doesn't change the logic at all, but it does make
Valgrind a bit happier.)
drm_connector_set_cursor wasn't checking the return value of the
drm_surface_make_current call. On failure, this results in a failed
assertion in wlr_renderer_begin (because no rendering context is
current).
The output backend API is now mostly state-less thanks to the atomic
hooks (commit and test). There is one exception though: attach_render.
This function makes the rendering context current. However sometimes the
compositor might decide not to render after attach_render (e.g. when
there's nothing new to render to the back buffer). Thus
wlr_output_rollback has been introduced to revert the pending state.
Because the output backend API is mostly state-less, the only thing
wlr_output_impl.rollback needs to do is revert the current rendering
context. Rename the function to rollback_render to make this clear. Add
a check in the common wlr_output code to only call rollback_render when
attach_buffer has been previously called.
On the long term, we'll be able to remove attach_render and
rollback_render together.
This patch fixes this failure:
01:57:16.642 [ERROR] [backend/drm/drm.c:360] Failed to page-flip output 'eDP-1': a page-flip is already pending
01:57:16.684 [ERROR] [backend/drm/drm.c:360] Failed to page-flip output 'eDP-1': a page-flip is already pending
01:57:16.684 [ERROR] [backend/drm/drm.c:732] Failed to initialize renderer on connector 'eDP-1': initial page-flip failed
01:57:16.684 [ERROR] [backend/drm/drm.c:805] Failed to initialize renderer for plane
01:57:16.684 [sway/config/output.c:423] Failed to commit output eDP-1
References: https://github.com/swaywm/sway/issues/5101
When the mode, status or buffer hasn't changed, drm_connector_commit was
a no-op. Because of this individual changes to the gamma LUT or adaptive
sync status were ignored (if committed without a buffer).
Instead, perform a commit to apply the changes.
A test commit doesn't apply the pending state.
The CRTC state will be populated again if the compositor decides to
perform a regular commit afterwards.
Previously, we only had the pending state (crtc->pending, crtc->mode and
crtc->active). This causes issues when a commit fails: the pending state
is left as-is, and the next commit may read stale data from it.
This will also cause issues when implementing test-only commits: we need
to rollback the pending CRTC state after a test-only commit.
Introduce separate pending and current CRTC states. Properly update the
current state after a commit.
retry_pageflip is now dead code, since drm_connector_start_renderer
isn't called anymore. It was previously called when enabling an output.
The name "retry_pageflip" was a little confusing because the function
retried a modeset and the timer wasn't set up while performing a simple
page-flip.
Let's just remove this altogether for now. We can discuss whether it's
worth it to bring it back. Should we only do it on failed page-flips?
Should we only do it on EBUSY?
If the atomic commit fails or is test-only, rollback
wlr_drm_crtc.{mode_id,gamma_lut} blob IDs to their previous value. This
prevents the next commits from failing or applying test-only state.
After swapping buffers, it doesn't make sense to perform more rendering
operations. Unset the context to reflect this.
This commit makes it so the context is always only current between
wlr_egl_make_current and wlr_egl_swap_buffers.
This is an alternative to [1].
[1]: https://github.com/swaywm/wlroots/pull/2212
This function can be called after wlr_egl_make_current to cleanup the
EGL context. This avoids having lingering EGL contexts that make things
work by chance.
Closes: https://github.com/swaywm/wlroots/issues/2197
We already have the logic to fallback to the legacy interface above. We
just need to avoid calling atomic_add with a zero prop ID.
Closes: https://github.com/swaywm/wlroots/issues/2187
dealloc_crtc was destroying GBM surfaces, but the cursor_enabled flag
was left as-is. When re-enabling the output, atomic_crtc_pageflip would
try enabling the cursor plane, but would fail because no framebuffer is
available.
Closes: https://github.com/swaywm/wlroots/issues/2150
When an output is enabled and modeset at the same time,
drm_connector_commit would first try to modeset then try to commit. This
won't work because both will trigger a page-flip. KMS will reject that.
Change the logic to only enable an output if no modeset has been
requested. The logic in wlr_output already checks that the user isn't
doing a modeset and disabling the output at the same time.
We have a workaround for legacy drivers that support drmModeSetCursor
without exposing a cursor plane. It doesn't work anymore now that we've
moved to a more atomic interface.
Let's just remove this workaround and fallback to software cursors.
Closes: https://github.com/swaywm/wlroots/issues/2166
conn->crtc is NULL in case the output is disabled.
However, the DRM backend will set the GAMMA_LUT property anyway. On each
commit the whole state is sent to KMS. Adding WLR_DRM_CRTC_GAMMA_LUT to
the pending state would just make the backend re-create the blob
containing the gamma LUT.
We don't need a per-CRTC atomic request anymore. Let's make the request
per-commit so that it's easier to debug.
This is also groundwork for supporting wlr_output_test properly.
GAMMA_LUT_SIZE isn't an atomic property. It can be used with the legacy
interface too. So we can unify both codepaths and remove
wlr_drm_interface.crtc_get_gamma_size.
It's no guaranteed to exist though, so we still need to keep the
fallback.
The logs don't currently display the importance of a line. It's easy to
read "skipping page-flip" as a debug message instead of an error
message.
Change the error message to make it more explicit.
References: https://github.com/swaywm/wlroots/pull/2147
Reconnecting an external display fails on initial
page-flip. This occurs when the pageflip_pending flag
has been set on the connector at the time the monitor
is removed. Once the connector's CRTC has been deallocated,
page_flip_handler cannot find the connector by its crtc_id,
so pageflip_pending will remain set. This causes
initialization to fail when the monitor is reconnected
with the error messages:
Skipping pageflip on output 'X'
Failed to initialize renderer on connector 'X': initial page-flip failed
To fix this problem, clear the pageflip_pending flag
when cleaning up the connector.
Some primary planes don't support ARGB8888, they only support XRGB8888
(for instance on older Intel hardware). The DRM backend would fail to
initialize.
When that's the case, try to allocate buffers without an alpha channel.
This is a type which manages gbm_surfaces and imported dmabufs in the
same place, and makes the lifetime management between the two shared. It
should lead to easier to understand code, and fewer special cases.
This also contains a fair bit of refactoring to start using this new
type.
Co-authored-by: Simon Ser <contact@emersion.fr>
Most of the pending output state is not forwarded to the backend prior
to an output commit. For instance, wlr_output_set_mode just stashes the
mode without calling any wlr_output_impl function.
wlr_output_impl.commit is responsible for applying the pending mode.
However, there are exceptions to this rule. The first one is
wlr_output_attach_render. It won't go away before renderer v6 is
complete, because it needs to set the current EGL surface.
The second one is wlr_output_attach_buffer.
wlr_output_impl.attach_buffer is removed in [1].
When wlr_output_rollback is called, all pending state is supposed to be
cleared. This works for all the state except the two exceptions
mentionned above. To fix this, introduce wlr_output_impl.rollback.
Right now, the backend resets the current EGL surface. This prevents GL
commands from affecting the output after wlr_output_rollback.
This patch is required for FBO-based outputs to work properly. The
compositor might be using FBOs for its own purposes [2], having leftover
FBO state can have bad consequences.
[1]: https://github.com/swaywm/wlroots/pull/2097
[2]: https://github.com/swaywm/wlroots/pull/2063#issuecomment-597614312
Check that buffer can be scanned out in wlr_output_test instead of
wlr_output_attach_buffer. This allows the backend to have access to the
whole pending state when performing the check.
This brings the wlr_output API more in line with the KMS API.
This removes the need for wlr_output_attach_buffer to return a value,
and for wlr_output_impl.attach_buffer.
Consumers call wlr_buffer_lock. Once all consumers are done with the
buffer, only the producer should have a reference to the buffer. In this
case, we can release the buffer (and let the producer re-use it).
This function allowed backends to provide a custom function for frame
scheduling. Before resuming the rendering loop, the DRM and Wayland
backends would wait for vsync.
There isn't a clear benefit of doing this. The only upside is that we
get more stable timings: the delay between two repaints doesn't change too
much and is close to a mutliple of the refresh rate.
However this introduces latency, especially when a client misses a
frame. For instance a fullscreen game missing vblank will need to wait
more than a whole frame before being able to display new content. This
worst case scenario happens as follows:
- Client is still rendering its frame and cannot submit it in time
- Deadline is reached
- Compositor decides to stop the rendering loop since nothing changed on
screen
- Client finally manages to render its frame, submits it
- Compositor calls wlr_output_schedule_frame
- DRM backend waits for next vblank
- The wlr_output frame event is fired, compositor draws new content on screen
- On the second next vblank, the new content reaches the screen
With this patch, the wlr_output frame event is fired immediately when
the client submits its late frame.
This change also makes it easier to support variable refresh rate, since
VRR is all about being able to present too-late frames earlier.
References: https://github.com/swaywm/wlroots/issues/1925