Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Underlying Desktop flashes for split second when dpms is turned off #99

Closed
MichaelAquilina opened this issue Aug 10, 2019 · 5 comments
Closed

Comments

@MichaelAquilina
Copy link

MichaelAquilina commented Aug 10, 2019

I have two laptops and cant reproduce this issue on both my laptops, but on a dell xps 9380 I've noticed the following strange behaviour.

I lock the screen with:

# Auto lock the screen after being idle
exec swayidle -w \
    timeout 300 'swaylock' \
    timeout 300 'swaymsg "output * dpms off"' \
         resume 'swaymsg "output * dpms on"' \
    before-sleep 'swaylock'

combined with:

bindsym --release {
    # Lock screen by entering the idle state
    # Important that this is executed under bindsym --release AND sleep 0.2
    # This workaround gives a few milliseconds for the keys on the keyboard to release (alt and L)
    # before swayidle can detect them as activity and enter the active state again
    Mod1+l exec sleep 0.2 && killall -SIGUSR1 swayidle
}

When I lock the screen with alt+L, it turns off the screen as expected. However when I start typing, for a split second you can see the underlying desktop before swaylock is rendered over it.

NOTE: Running swaylock in a terminal on its own does not show this behaviour. It's the combination of dpms off and swaylock at the same time that causes this.

My suspicion is that the screen on this laptop is quicker to turn back on than my other laptop which is why I cannot reproduce this behaviour there.

@QasimK
Copy link

QasimK commented Oct 25, 2019

I have encountered this problem on my laptop as well:

  1. Using this sway config
set $lock_command swaylock --daemonize --ignore-empty-password --show-failed-attempts
exec swayidle -w \
    timeout 300 'swaymsg "output * dpms off"' \
    timeout 305 "$lock_command" \
    timeout 5 'if pgrep -x swaylock; then swaymsg "output * dpms off"; fi' \
    resume 'swaymsg "output * dpms on"' \
    before-sleep "$lock_command"
  1. Close laptop lid and wait for it to go to sleep

  2. Open laptop and see the desktop for a full second before swaylock hides it with a white screen.

(This is on the Lenovo Thinkpad X1 Carbon 6th Gen (2018))

@Thra11
Copy link

Thra11 commented Dec 15, 2019

I've been noticing this too. I have a config similar to @QasimK, in that it turns the display off, then waits a few seconds before locking. I wondered if perhaps turning the screen off effectively froze the contents of the framebuffer, which is then not updated until after the screen has been turned back on, meaning swaylock can't hide the screen contents until it's too late. I wouldn't be surprised if having both set to occur at the same time means that it isn't entirely deterministic which occurs first.

@michaelweiser
Copy link

I also suspect that it has to do with buffering in sway/wlroots. I hacked around in both to flush the buffers before dpms off or right after dpms on. But the way wlroots does its rendering turned out to be beyond me (for now :).

I worked around it with this swayidle config:

set $lockcmd swaylock -f
exec swayidle -w \
        timeout 300 'imv-wayland -x -t 1 -f /usr/share/backgrounds/blue.png & sleep 0.25 ; swaymsg "output * dpms off"' \
                resume 'swaymsg "output * dpms on"' \
        timeout 315 '$lockcmd' \
        before-sleep '$lockcmd ; sleep 1'

It does two distinct things for the two cases where the desktop would be visible on my laptop:

  1. On inactivity timeout it uses imv to render a defined image filling the whole screen for a second (-x -t 1 -f), giving it quarter of a second to propagate through the buffers and then turning the output off while it's still visible. This way the desktop does not flash briefly when resuming into the lockscreen that was started by the second timeout while the output was off. This also works with a forced lock and dpms off using killall -USR1 swayidle because both timeout actions will be triggered simultaneously and swaylock's lock screen will propagate through the buffers while the sleep of the other action is still delaying the dpms off.
  2. Before system sleep it adds a sleep of a second after starting swaylock to give its fully rendered lockscreen time to be visible for a couple of page flips (hopefully). This reliably prevents brief flashing of the desktop on resume.

My operating theory is that adding a couple of page flips rendering an empty screen somewhere around https://github.com/swaywm/sway/blob/master/sway/config/output.c#L440 (or in the code path leading up to it) would work around the issue. Ideally, the whole renderer would keep going for a couple of page flips leading up to a dpms off to render the lock screen into all buffers. As a PoC I've tried all the variations and locations for a

	struct wlr_renderer *renderer =
		wlr_backend_get_renderer(wlr_output->backend);
	wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
	wlr_renderer_clear(renderer, (float[]){0, 0, 0, 1});
	wlr_renderer_end(renderer);
	wlr_output_commit(wlr_output);

I could think of but couldn't get it to do this for multiple page flips to clear all buffers. Any guidance on whether I'm even looking in the right direction and how to go about it would be welcome.

@travankor
Copy link

This also seems to affect logind's lid switch feature HandleLideSwitch if you have it suspend. The previous workarounds that were mentioned don't really work for me.

@emersion
Copy link
Member

This should be fixed with the new lockscreen protocol.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

6 participants