Nvidia and Sway - black screen fix
Getting Sway to run on Nvidia GPU's has historically been quite troublesome. I ran dual GPU for many years because I could not get my Sway instance up and running on my Nvidia 3080 GPU. I gave it a shot again recently and finally got it to work.
The following setup is working well now for me using nvidia-open or nvidia-open-dkms (610.43 at the time of writing) drivers.
Many guides tell you to set kernel boot arguments nvidia-modeset and nvidia-fbdev but these are now enabled by default (on Arch at least) so it does not seem necessary to do this explicitly anymore.
Set the following environment variables before you launch your sway session:
GBM_BACKEND=nvidia-drm
GDK_BACKEND=wayland
WLR_NO_HARDWARE_CURSOR=1
__GLX_VENDOR_LIBRARY_NAME=nvidia
You still need to launch with sway --unsupported-gpu to not get the warning on start.
After setting these I was still getting a black screen after launching Sway. In the Sway debug logs I saw it tried different display modes and giving up after a while with messages like this for each attempt:
Preparing test commit for 1 outputs with explicit modifiers
Allocating new swapchain buffer
Allocated 3440c1440 GBM buffer with format XR24 (Ox34325258), modifier INVALID (0X00fff...)
drmModeAddFB2 failed: Invalid argument
Poisoning buffer
connector DP-1: Failed to import buffer for scan-out
Test commit for 1 outputs failed
Which seems to mean wlroots can allocate the GBM buffer but the KMS driver rejects turning that buffer into a scanout framebuffer. This seems to mean that the wrong DRM master / wrong KMS driver is picked up so wlroots ends up with a KMS device that can modeset but can't import the GBM buffer. On my setup simpledrm grabs the console early which is then incorrectly being picked up by wlroots.
I was able to fix this by modifying my /etc/mkinitcpio.conf by adding:
MODULES=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)
Then rebuild using sudo mkinitcpio -P
And to avoid simpledrm grabbing the console add this to your kernel arguments in your bootloader configuration:
initcall_blacklist=simpledrm_platform_driver_init
This way simpledrm is not initialized and wlroots is able to correctly pick up the Nvidia KMS driver.
After this, Sway is working correctly on my Nvidia 3080.
I did have some flickering in some Electron apps at times. The following modprobe to force the GPU into performance mode seems to mostly fix it for me:
modprobe nvidia NVreg_RegistryDwords="PowerMizerEnable=0x1; PerfLevelSrc=0x2222; PowerMizerLevel=0x3; PowerMizerDefault=0x3; PowerMizerDefaultAC=0x3"
(thanks to tyqualters)
You can persist this across reboots by creating a file /etc/modprobe.d/nvidia-powermizer.conf with following contents:
options nvidia NVreg_RegistryDwords="PowerMizerEnable=0x1; PerfLevelSrc=0x2222; PowerMizerLevel=0x3; PowerMizerDefault=0x3; PowerMizerDefaultAC=0x3"