Bug 478476 - Output removal ("remove screen") of non-physical screens does not work on Wayland
Summary: Output removal ("remove screen") of non-physical screens does not work on Way...
Status: RESOLVED FIXED
Alias: None
Product: kwin
Classification: Plasma
Component: platform-drm (other bugs)
Version First Reported In: git master
Platform: Other Linux
: NOR normal
Target Milestone: ---
Assignee: KWin default assignee
URL:
Keywords: multiscreen, qt6
Depends on:
Blocks:
 
Reported: 2023-12-13 14:29 UTC by Stefan Hoffmeister
Modified: 2024-02-16 11:52 UTC (History)
3 users (show)

See Also:
Latest Commit:
Version Fixed/Implemented In:
Sentry Crash Report:


Attachments
Immediately after login (before adding screen) ... (49.99 KB, text/plain)
2023-12-13 17:16 UTC, Stefan Hoffmeister
Details
After adding screen (50.25 KB, text/plain)
2023-12-13 17:16 UTC, Stefan Hoffmeister
Details
After removing screen (50.16 KB, text/plain)
2023-12-13 17:16 UTC, Stefan Hoffmeister
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Stefan Hoffmeister 2023-12-13 14:29:56 UTC
SUMMARY

When removing a previously added (virtual) screen from the system, the udev change event is received, but is not processed correctly. The result is that kwin retains the removed output, operates on it, which causes all sorts of (not very) funny behaviour.

I cannot tell whether this is specific to VMware Workstation in legacy mode (i.e. not atomic mode-setting); right now, and from the code, it seems as if this may be generally applicable. I do not have a setup which allows me to conveniently test that, though.

STEPS TO REPRODUCE
0. have hardware with at least two physical screens attached
1. install Fedora Rawhide (40) + KDE Plasma 6 git master into VMware Workstation
2. switch VMware Workstation into fullscreen mode (that will _later_ allow adding additional screens)
3. boot
4. log into (fullscreen) Plasma 6 Wayland session
// cool
5. in VMware Workstation "Cycle multiple monitors" - this adds a new virtual monitor, new output, new window on host
// cool - this works fine
6. in VMware Workstation "Cycle multiple monitors" - this _removes_ the previously added virtual monitor/output

OBSERVED RESULT

* kscreen-doctor and vmwgfx agree that only one monitor/output remains connected
* host window for _second_ monitor/output remains on host screen
* journalctl shows logs with errors (note that this is from a local build with richer logging)
```
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Received udev event KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?|QSocketNotifier::activated|QSocketNotifier::event|QApplicationPrivate::notify_helper
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: udev event: "change" "/dev/dri/card0" KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?|QSocketNotifier::activated|QSocketNotifier::event|QApplicationPrivate::notify_helper
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Received change event for monitored drm device "/dev/dri/card0" KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?|QSocketNotifier::activated|QSocketNotifier::event|QApplicationPrivate::notify_helper
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Adding outputs ?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?|QSocketNotifier::activated
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Could not find edid for connector DrmConnector(id=38, gpu=KWin::DrmGpu(0x6fd1a0), name="Virtual-1-unknown", connection="Connected", countMode=25) ?libkwin.so.6?|?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Connection on "Virtual-1-unknown" is in state 1 ?libkwin.so.6?|?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: updateProperties: modes equal is true ?libkwin.so.6?|?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Connection on "Virtual-2-unknown" is in state 2 ?libkwin.so.6?|?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: updateProperties: mode change detected on "Virtual-2-unknown" for mode index 0 towards 1280 800 ?libkwin.so.6?|?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: updateProperties: modes equal is false ?libkwin.so.6?|?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: DrmPipeline::legacyModeset ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: DrmLegacyCommit::doModeset on "/dev/dri/card0" "Virtual-1" connected true ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Setting legacy dpms failed! Invalid argument ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: DrmPipeline::legacyModeset ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: DrmLegacyCommit::doModeset on "/dev/dri/card0" "Virtual-1" connected true ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: DrmPipeline::legacyModeset ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: DrmLegacyCommit::doModeset on "/dev/dri/card0" "Virtual-2" connected false ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: drmModeSetCrtc failed: Invalid argument ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Modeset failed! Invalid argument ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Failed to revert pipeline: (2) ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Failed to commit pipelines: (2) ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Setting changed mode failed! ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent
Dec 13 15:12:30 fedora kwin_wayland[8451]: kwin_wayland_drm: Connection on "Virtual-3-unknown" is in state 2 ?libkwin.so.6?|?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?
```

EXPECTED RESULT

* kscreen-doctor and vmwgfx agree that only one monitor/output remains connected
* host window for _second_ monitor/output disappears from host screen
* no warnings in journalctl output

ADDITIONAL INFORMATION

In the logs, note the warnings from trying to modeset on the disappeared output. I have also logging around which should trigger on proper removal of the output inside kwin, but those logs don't appear - so the removed (disconnected) output is still retained by kwin.

Try cycling through multiple monitors often enough and additional funny effects appear: the mouse cursor gets fenced in very strange ways, but drawing remains stable.
Comment 1 Zamundaaa 2023-12-13 14:33:56 UTC
Please attach the output of drm_info for before adding the second output, for when it's added, and for when it's removed again
Comment 2 Stefan Hoffmeister 2023-12-13 17:16:05 UTC
Created attachment 164144 [details]
Immediately after login (before adding screen) ...
Comment 3 Stefan Hoffmeister 2023-12-13 17:16:28 UTC
Created attachment 164145 [details]
After adding screen
Comment 4 Stefan Hoffmeister 2023-12-13 17:16:51 UTC
Created attachment 164146 [details]
After removing screen
Comment 5 Stefan Hoffmeister 2023-12-13 17:19:41 UTC
drm_info output attached as requested; running system was Fedora Rawhide (40), fresh up-to-date + COPR KDE Plasma 6 beta 1.

I also have a local build environment (with some fixes) where I can see the same behaviour from logs.
Comment 6 Stefan Hoffmeister 2023-12-13 17:29:25 UTC
From the implementation, I cannot tell how the framebuffer(?) backing the ouput(?) ever gets removed.

Basically, as part of the change sequence, the second screen goes into !isConnected with resolution 1280x800, and the current implementation still tries to talk to "it" (connector/output). This fails on various DRM calls:
```
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: Connection on "Virtual-2-unknown" is in state 2 ?libkwin.so.6?|?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: updateProperties: mode change detected on "Virtual-2-unknown" for mode index 0 towards 1280 800 ?libkwin.so.6?|?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: updateProperties: modes equal is false ?libkwin.so.6?|?libkwin.so.6?|KWin::DrmBackend::updateOutputs|KWin::DrmBackend::handleUdevEvent|?libQt6Core.so.6?
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: DrmPipeline::legacyModeset ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: DrmLegacyCommit::doModeset on "/dev/dri/card0" "Virtual-1" connected true ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: Failed to set legacy property: Invalid argument ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: Setting legacy dpms failed! Invalid argument ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: DrmPipeline::legacyModeset ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: DrmLegacyCommit::doModeset on "/dev/dri/card0" "Virtual-1" connected true ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: DrmPipeline::legacyModeset ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: DrmLegacyCommit::doModeset on "/dev/dri/card0" "Virtual-2" connected false ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
Dec 13 18:24:43 fedora kwin_wayland[3945]: kwin_wayland_drm: drmModeSetCrtc failed: Invalid argument ?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?|?libkwin.so.6?
```
Comment 7 Stefan Hoffmeister 2023-12-13 22:07:42 UTC
There are two ways to get a virtual screen removed

a) the way described earlier - basically this retains the configuration of the primary screen
b) un-maximizing the whole setup, which cause VMware Workstation to collapse everything into a "simple window", causing the primary screen to also resize

In the case of a), the second virtual screen does not disappear (as described below). In the case of b), the second virtual screen _does_ in fact disappear. That's a bit of an odd situation, to be honest.

I suspect that to have b) working my hack from https://bugs.kde.org/show_bug.cgi?id=477985 needs to be in place, otherwise the resize on the primary screen will not end up well.
Comment 8 Stefan Hoffmeister 2023-12-19 07:50:54 UTC
Tested the "cycle multiple monitors" feature of VMware Workstation on Fedora Workstation Rawhide F40 - it works there.
Comment 9 Stefan Hoffmeister 2023-12-20 01:08:08 UTC
The root cause of this defect is a design challenge in the atomic commit code.

Whenever an output is changed ("DrmGpu::updateOutputs"), among other things, the 1:1 matched up internal processing pipeline of kwin gets "managed", too. The GPU _instance_ retains a list of those pipelines in m_pipelines. When a new pipeline is added, it is added immediately to m_pipelines. When a pipeline is removed, it is immediately removed from m_pipelines.

After the GPU instance state for pipelines has been altered, all this gets tested and ends up in DrmGpu::testPipelines(). This then does commitPipelines(m_pipelines, DrmPipeline::CommitMode::TestAllowModeset. This will pass, and all is good - new configuration is accepted.

Alas, what is missing is a successful atomic commit to clean up any _removed_ pipeline(s) all the way into the _kernel_. This has the effect that the _DRM plane_ that was connected to the removed pipeline still has a framebuffer object attached to it that is now frozen in time, because nothing ever updates it. And because there is still that framebuffer object around, the VMware Workstation host will faithfully show that forever.

This behaviour is best illustrated by adding one single log statement to the implementation:

```
  DrmPipeline::Error DrmPipeline::commitPipelinesAtomic(const QList<DrmPipeline *> &pipelines, CommitMode mode, const QList<DrmObject *> &unusedObjects)
{
+      qCDebug(KWIN_DRM) << "commitPipelinesAtomic is applied to" << pipelines.size() << "pipelines";
```

Notice how this will print the number(a) as explained above - numbers that are not good ;). Also inspect the output of drm_info gathered in attachement "After removing screen" and notice how plane 2 (which is the removed screen) still has a non-zero framebuffer buffer ID (FB_ID) value (96)
Comment 10 Stefan Hoffmeister 2023-12-20 01:21:33 UTC
As far as I can see, this defect only hits systems where an output does not _physically_ disappear. Or, in other words, if you plug the cable, well, there is nothing coming down that wire any more, right?

So, this will most likely only detrimentally _affect_ systems with non-physical screens which allow multi-screen configurations. Such as (confirmed) VMware Workstation (and most likely all desktop hypervisor products created by VMware, for instance VMware Fusion). Perhaps GNOME Boxes / qemu / kvm (with virtio-gpu)? Perhaps VirtualBox? Perhaps whatever is using the qxl driver? Whatever does virtualization and software abstraction tricks.

It will also only _affect_ users of said systems who turn on and _off_ one more screens in addition to the primary screen.

So while the defect is universal, after triage, its impact (most likely) is rather limited.
Comment 11 Nate Graham 2023-12-20 20:41:44 UTC
Interesting, I wonder if the issue would affect KVM users as well.
Comment 12 Zamundaaa 2023-12-21 01:19:05 UTC
No, normal drivers turn off the CRTC used on a given connector when the connector goes away. The VM drivers should imo do the same, but as it's probably unspecified (like with all drm things), we should probably work around it.
Comment 13 Bug Janitor Service 2023-12-21 02:24:00 UTC
A possibly relevant merge request was started @ https://invent.kde.org/plasma/kwin/-/merge_requests/4822
Comment 14 Zamundaaa 2024-02-16 11:35:43 UTC
Git commit 9ea6f311ead4566feb4d94db23a815230302e5c9 by Xaver Hugl.
Committed on 16/02/2024 at 11:20.
Pushed by zamundaaa into branch 'master'.

backends/drm: force a modeset when connectors are unplugged

And turn off unused CRTCs with legacy

M  +6    -6    src/backends/drm/drm_gpu.cpp
M  +1    -0    src/backends/drm/drm_gpu.h
M  +1    -1    src/backends/drm/drm_pipeline.cpp
M  +1    -1    src/backends/drm/drm_pipeline.h
M  +6    -1    src/backends/drm/drm_pipeline_legacy.cpp

https://invent.kde.org/plasma/kwin/-/commit/9ea6f311ead4566feb4d94db23a815230302e5c9
Comment 15 Zamundaaa 2024-02-16 11:52:09 UTC
Git commit c84739d51e97356d38778ff143d181ae14462877 by Xaver Hugl.
Committed on 16/02/2024 at 11:41.
Pushed by zamundaaa into branch 'Plasma/6.0'.

backends/drm: force a modeset when connectors are unplugged

And turn off unused CRTCs with legacy


(cherry picked from commit 9ea6f311ead4566feb4d94db23a815230302e5c9)

M  +6    -6    src/backends/drm/drm_gpu.cpp
M  +1    -0    src/backends/drm/drm_gpu.h
M  +1    -1    src/backends/drm/drm_pipeline.cpp
M  +1    -1    src/backends/drm/drm_pipeline.h
M  +6    -1    src/backends/drm/drm_pipeline_legacy.cpp

https://invent.kde.org/plasma/kwin/-/commit/c84739d51e97356d38778ff143d181ae14462877