backend/session: Add rapid hotplug detection
From the commit message: When applied, this patch adds the option to wait after a DRM device change uevent for another identical one in order to avoid monitor rearrangement due to a monitor disconnecting and reconnecting from the implementation of DisplayPort's deep sleep "feature". This is locked behind a new environment variable due to the 1 second delay that occurs to wait for a second event, but can be enable by setting WLR_RAPID_HOTPLUG_PREVENT to 1.
This patch took inspiration from what Windows calls "Rapid Hot Plug Detect" (well in name anyway) and was made after reading drm/amd#2462 (closed) and deciding that the final response in #3494 was not satisfactory, there is most certainly something that can be done about it with a little bit of patience. My system has two GPUs for unrelated (VFIO) purposes, a Radeon RX 550 and a GeForce RTX 3080, and as such this was leveraged to test this change so I'm unsure how difficult or not it will be to follow the test plans with only one. It's also worth noting this issue only seems to occur on the RX 550 and reports suggest other AMD GPUs (though the RTX 3080 never sent a single hotplug event ever, but that's another problem).
Anyway in order to test this commit,
Normal Use Case
- Obtain 2 monitors, at least 1 of which implements DisplayPort deep sleep.
- Open your favorite wlroots compositor, configure them as desired, and place a client on each.
- (Before patch). Power cycle the deep sleep supporting monitor, and observe as every client is shoved onto the other monitor because 2 change events occur in rapid succession, removing and readding the monitor.
- (After patch): Power cycle the deep sleep supporting monitor, and smile as the clients remain in position.
Extreme Simulated Use Case
- Open your favorite wlroots compositor with debug messages turned on, for example labwc -d
- Via udevadm trigger any combination of DRM change messages, alternating between minors 0 and 1 at random (see attached script)
- Wait for however many seconds as events were sent (this is also why an environment variable was implemented, while normal usage will only have this occuring once or twice the compositor outright locks up for 10+ seconds while doing that many)
- Check the compositor log, and any pair of matching events will have been ignored, while non-matching will proceed.