When I try to screen record with OBS, the gnome portal selection pops up, sees all my windows and reports back a size to OBS, but only a black screen is actually shown once selected.
I've tried some different things like environment variables, different portals (kde, cosmic, and hyprland). I've seen some similar things on previous issues, but none of the configs match mine and none of the solutions work.
Current /etc/environment
EDITOR=nvim
VISUAL=nvim
LC_COLLATE=en_US.UTF-8
XCURSOR_SIZE=16
GTK_CURSOR_THEME=Breeze_Default
GTK_ICON_THEME=Papirus-Dark
GTK_THEME=Arc-Dark
ELECTRON_TRASH=trash-cli
ELECTRON_OZONE_PLATFORM_HINT=wayland
QT_QPA_PLATFORM=wayland
QT_QPA_PLATFORMTHEME=qt6ct
LIBVA_DRIVER_NAME=nvidia
__GL_GSYNC_ALLOWED=1
__NV_PRIME_RENDER_OFFLOAD=1
__GLX_VENDOR_LIBRARY_NAME=nvidia
__VK_LAYER_NV_optimus=NVIDIA_only
XDG_SESSION_TYPE=wayland
GBM_BACKEND=nvidia
WLR_NO_HARDWARE_CURSORS=1
NVD_BACKEND=direct
QML_DISABLE_DISK_CACHE=1
I'd also like to note that this affects Sunshine (a game streaming app) and WebRTC stuff in the browser.
However, it doesn't affect screen shots and it doesn't affect the alternative OBS capture option "Wayland output (scpy)" based on wlr-screencopy.
I think it's not communicating with OBS about formats correctly. Here's the OBS output when I select a screen:
OBS Log
info: PipeWire initialized
info: User added source 'Screen Capture (PipeWire)' (pipewire-screen-capture-source) to scene 'Screen Recording'
info: [pipewire] Screencast session created
info: [pipewire] Asking for monitor and window
info: [pipewire] source selected, setting up screencast
info: [pipewire] Server version: 1.4.7
info: [pipewire] Library version: 1.4.7
info: [pipewire] Header version: 1.4.7
info: [pipewire] Created stream 0x55f08b3e3c40
info: [pipewire] Stream 0x55f08b3e3c40 state: "connecting" (error: none)
info: [pipewire] Playing stream 0x55f08b3e3c40
info: [pipewire] Stream 0x55f08b3e3c40 state: "paused" (error: none)
info: [pipewire] Negotiated format:
info: [pipewire] Format: 8 (Spa:Enum:VideoFormat:BGRx)
info: [pipewire] Modifier: 0x0
info: [pipewire] Size: 1920x1080
info: [pipewire] Framerate: 0/1
info: [pipewire] Negotiated format:
info: [pipewire] Format: 8 (Spa:Enum:VideoFormat:BGRx)
info: [pipewire] Modifier: 0x0
info: [pipewire] Size: 1920x1080
info: [pipewire] Framerate: 0/1
info: [pipewire] Stream 0x55f08b3e3c40 state: "streaming" (error: none)
error: glEGLImageTargetTexture2DOES failed, glGetError returned GL_INVALID_OPERATION(0x502)
info: [pipewire] Renegotiating stream
info: [pipewire] Stream 0x55f08b3e3c40 state: "paused" (error: none)
info: [pipewire] Negotiated format:
info: [pipewire] Format: 8 (Spa:Enum:VideoFormat:BGRx)
info: [pipewire] Modifier: 0x0
info: [pipewire] Size: 1920x1080
info: [pipewire] Framerate: 0/1
info: [pipewire] Negotiated format:
info: [pipewire] Format: 8 (Spa:Enum:VideoFormat:BGRx)
info: [pipewire] Modifier: 0xffffffffffffff
info: [pipewire] Size: 1920x1080
info: [pipewire] Framerate: 0/1
info: [pipewire] Stream 0x55f08b3e3c40 state: "streaming" (error: none)
error: glEGLImageTargetTexture2DOES failed, glGetError returned GL_INVALID_OPERATION(0x502)
info: [pipewire] Renegotiating stream
info: [pipewire] Stream 0x55f08b3e3c40 state: "paused" (error: none)
info: [pipewire] Stream 0x55f08b3e3c40 state: "error" (error: no more input formats)
error: [pipewire] Error id:2 seq:42 res:-32 (Broken pipe): no more input formats
info: adding 85 milliseconds of audio buffering, total audio buffering is now 106 milliseconds (source: Mic/Aux)
Here's my niri config:
Niri Config
// This config is in the KDL format: https://kdl.dev
// "/-" comments out the following node.
// Check the wiki for a full description of the configuration:
// https://github.com/YaLTeR/niri/wiki/Configuration:-Introduction
environment {
DISPLAY ":0"
}
spawn-at-startup "wl-clipboard"
spawn-at-startup "dunst" "-conf" "~/.config/dunst/dunstsrc"
spawn-at-startup "/home/dylan/.config/niri/startup.sh"
// Input device configuration.
input {
keyboard {
xkb {
options "compose:ralt"
}
numlock
}
// Next sections include libinput settings.
// Omitting settings disables them, or leaves them at their default values.
touchpad {
tap
natural-scroll
accel-speed 0.2
}
// Uncomment this to make the mouse warp to the center of newly focused windows.
warp-mouse-to-focus
// Focus windows and outputs automatically when moving the mouse into them.
// Setting max-scroll-amount="0%" makes it work only on windows already fully on screen.
focus-follows-mouse
workspace-auto-back-and-forth
}
output "eDP-2" {
mode "1920x1080@360"
scale 1
transform "normal"
position x=1723 y=1440
}
output "DP-1" {
mode "3440x1400@60"
scale 1
transform "normal"
position x=0 y=0
}
// Settings that influence how windows are positioned and sized.
layout {
// Set gaps around windows in logical pixels.
gaps 16
// When to center a column when changing focus
center-focused-column "never"
// You can customize the widths that "switch-preset-column-width" (Mod+R) toggles between.
preset-column-widths {
proportion 0.33333
proportion 0.5
proportion 0.66667
}
// You can change the default width of the new windows.
default-column-width { proportion 0.5; }
// You can change how the focus ring looks.
focus-ring {
// How many logical pixels the ring extends out from the windows.
width 4
// Color of the ring on the active monitor.
active-color "#03BB85"
// Color of the ring on inactive monitors.
inactive-color "#505050"
}
// You can also add a border. It's similar to the focus ring, but always visible.
border {
off
}
// You can enable drop shadows for windows.
shadow {
// Uncomment the next line to enable shadows.
on
// Softness controls the shadow blur radius.
softness 5
// Spread expands the shadow.
spread 3
// Offset moves the shadow relative to the window.
offset x=-2 y=2
// You can also change the shadow color and opacity.
color "#0007"
}
// Struts shrink the area occupied by windows, similarly to layer-shell panels.
// You can think of them as a kind of outer gaps. They are set in logical pixels.
// Left and right struts will cause the next window to the side to always be visible.
// Top and bottom struts will simply add outer gaps in addition to the area occupied by
// layer-shell panels and regular gaps.
struts {
left 16
right 16
// top 64
// bottom 64
}
}
// You can change the path where screenshots are saved.
// A ~ at the front will be expanded to the home directory.
// The path is formatted with strftime(3) to give you the screenshot date and time.
screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png"
// Work around WezTerm's initial configure bug
// by setting an empty default-column-width.
window-rule {
// This regular expression is intentionally made as specific as possible,
// since this is the default config, and we want no false positives.
// You can get away with just app-id="wezterm" if you want.
match app-id=r#"^org\.wezfurlong\.wezterm$"#
default-column-width {}
}
// Example: enable rounded corners for all windows.
// (This example rule is commented out with a "/-" in front.)
window-rule {
geometry-corner-radius 12
clip-to-geometry true
}
binds {
// Mod-Shift-/, which is usually the same as Mod-?,
// shows a list of important hotkeys.
Mod+Shift+Slash { show-hotkey-overlay; }
// Suggested binds for running programs: terminal, app launcher, screen locker.
Mod+Return hotkey-overlay-title="Open a Terminal: alacritty" { spawn "alacritty"; }
Mod+S hotkey-overlay-title="Run an Application: wofi" { spawn "wofi" "--location" "0" "--show=drun,run" "--allow-images" "--insensitive"; }
Mod+L hotkey-overlay-title="Lock the Screen: swaylock" { spawn "swaylock" "-F" "-i" "~/Pictures/Wallpapers/linux-supremecy-3.png" "-k" "--ring-color" "03bb85ff" "--inside-color" "00000000" "--line-color=03bb85" "--line-color=03bb85" "--separator-color=00000000" "--ring-ver-color=0385bb" "--inside-ver-color=00000000" "--inside-wrong-color=00000000"; }
// Example volume keys mappings for PipeWire & WirePlumber.
// The allow-when-locked=true property makes them work even when the session is locked.
XF86AudioRaiseVolume allow-when-locked=true { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.05+"; }
XF86AudioLowerVolume allow-when-locked=true { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.05-"; }
XF86AudioMute allow-when-locked=true { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; }
XF86AudioMicMute allow-when-locked=true { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SOURCE@" "toggle"; }
// Open/close the Overview: a zoomed-out view of workspaces and windows.
Mod+O repeat=false { toggle-overview; }
Mod+X { close-window; }
Mod+Left { focus-column-left; }
Mod+Down { focus-window-down; }
Mod+Up { focus-window-up; }
Mod+Right { focus-column-right; }
Mod+Shift+Left { move-column-left; }
Mod+Shift+Down { move-window-down; }
Mod+Shift+Up { move-window-up; }
Mod+Shift+Right { move-column-right; }
Mod+Home { focus-column-first; }
Mod+End { focus-column-last; }
Mod+Ctrl+Home { move-column-to-first; }
Mod+Ctrl+End { move-column-to-last; }
Mod+Ctrl+Down { focus-workspace-down; }
Mod+Ctrl+Up { focus-workspace-up; }
Mod+Ctrl+Shift+Down { move-column-to-workspace-down; }
Mod+Ctrl+Shift+Up { move-column-to-workspace-up; }
Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; }
Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; }
Mod+Shift+WheelScrollDown { focus-column-right; }
Mod+Shift+WheelScrollUp { focus-column-left; }
Mod+BracketLeft { consume-or-expel-window-left; }
Mod+BracketRight { consume-or-expel-window-right; }
Mod+Comma { consume-window-into-column; }
Mod+Period { expel-window-from-column; }
Mod+R { switch-preset-column-width; }
Mod+Shift+R { switch-preset-window-height; }
Mod+Ctrl+R { reset-window-height; }
Mod+F { maximize-column; }
Mod+Shift+F { fullscreen-window; }
Mod+Ctrl+F { expand-column-to-available-width; }
Mod+C { center-column; }
Mod+Ctrl+C { center-visible-columns; }
Mod+Minus { set-column-width "-10%"; }
Mod+Equal { set-column-width "+10%"; }
Mod+Shift+Minus { set-window-height "-10%"; }
Mod+Shift+Equal { set-window-height "+10%"; }
// Move the focused window between the floating and the tiling layout.
Mod+Shift+Space { toggle-window-floating; }
Mod+Ctrl+Space { switch-focus-between-floating-and-tiling; }
// Toggle tabbed column display mode.
Mod+W { toggle-column-tabbed-display; }
// Screenshot
Print { screenshot; }
Win+Shift+S { screenshot; }
Ctrl+Print { screenshot-screen; }
Alt+Print { screenshot-window; }
// Applications such as remote-desktop clients and software KVM switches may
// request that niri stops processing the keyboard shortcuts defined here
// so they may, for example, forward the key presses as-is to a remote machine.
// It's a good idea to bind an escape hatch to toggle the inhibitor,
// so a buggy application can't hold your session hostage.
//
// The allow-inhibiting=false property can be applied to other binds as well,
// which ensures niri always processes them, even when an inhibitor is active.
Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; }
// The quit action will show a confirmation dialog to avoid accidental exits.
Mod+Shift+E { quit; }
Ctrl+Alt+Delete { quit; }
// Powers off the monitors. To turn them back on, do any input like
// moving the mouse or pressing any other key.
Mod+Shift+P { power-off-monitors; }
}
And here's my niri log from when starting streaming:
journalctl --user -xeu niri
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.146090Z DEBUG niri::dbus::mutter_screen_cast: record_monitor connector="eDP-2" properties=RecordMonitorProperties { cursor_mode: Some(Metadata), _is_recording: None }
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.146352Z DEBUG niri::dbus::mutter_screen_cast: start
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.146364Z DEBUG niri::niri: StartCast session_id=6 stream_id=6
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.146413Z DEBUG niri::pw_utils: pw stream: state changed: Unconnected -> Connecting
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.148162Z DEBUG niri::pw_utils: pw stream: state changed: Connecting -> Paused
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.148169Z DEBUG niri::pw_utils: pw stream: sending signal with 164
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.167960Z DEBUG niri::pw_utils: pw stream: got format = VideoInfoRaw { format: VideoFormat::BGRx, flags: VideoFlags(0xc), modifier: 0, size: spa_rectangle { width: 1920, height: 1080 }, framerate: spa_fract>
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.167976Z DEBUG niri::pw_utils: pw stream: fixating the modifier
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.167979Z DEBUG niri::pw_utils: find_preferred_modifier: size=Size<smithay::utils::geometry::Physical> { w: 1920, h: 1080 }, fourcc=XR24, modifiers=[0, 72057594037927935]
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.169147Z DEBUG niri::pw_utils: pw stream: allocation successful (modifier=Linear, plane_count=1), moving to confirmation pending
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.169260Z DEBUG niri::pw_utils: pw stream: got format = VideoInfoRaw { format: VideoFormat::BGRx, flags: VideoFlags(0x4), modifier: 0, size: spa_rectangle { width: 1920, height: 1080 }, framerate: spa_fract>
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.169266Z DEBUG niri::pw_utils: pw stream: moving to ready state
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.237612Z DEBUG niri::pw_utils: pw stream: state changed: Paused -> Streaming
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.249593Z DEBUG niri::pw_utils: pw stream: state changed: Streaming -> Paused
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.249704Z DEBUG niri::pw_utils: pw stream: got format = VideoInfoRaw { format: VideoFormat::BGRx, flags: VideoFlags(0xc), modifier: 0, size: spa_rectangle { width: 1920, height: 1080 }, framerate: spa_fract>
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.249712Z DEBUG niri::pw_utils: pw stream: fixating the modifier
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.249715Z DEBUG niri::pw_utils: find_preferred_modifier: size=Size<smithay::utils::geometry::Physical> { w: 1920, h: 1080 }, fourcc=XR24, modifiers=[72057594037927935]
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.253423Z DEBUG niri::pw_utils: pw stream: allocation successful (modifier=Invalid, plane_count=1), moving to confirmation pending
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.253629Z DEBUG niri::pw_utils: pw stream: got format = VideoInfoRaw { format: VideoFormat::BGRx, flags: VideoFlags(0x4), modifier: 72057594037927935, size: spa_rectangle { width: 1920, height: 1080 }, fram>
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.253638Z DEBUG niri::pw_utils: pw stream: moving to ready state
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.272278Z DEBUG niri::pw_utils: pw stream: state changed: Paused -> Streaming
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.278460Z DEBUG niri::pw_utils: pw stream: state changed: Streaming -> Paused
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.279138Z DEBUG niri::pw_utils: pw stream: state changed: Paused -> Error("no more input formats")
Aug 12 20:45:07 msi-raider niri[44560]: 2025-08-13T01:45:07.279146Z WARN niri::pw_utils: pw error id=2 seq=286 res=-32 no more input formats
Aug 12 20:45:12 msi-raider niri[44560]: 2025-08-13T01:45:12.214036Z DEBUG niri::dbus::mutter_screen_cast: stop
Aug 12 20:45:12 msi-raider niri[44560]: 2025-08-13T01:45:12.214097Z DEBUG niri::niri: StopCast session_id=6
Aug 12 20:45:12 msi-raider niri[44560]: 2025-08-13T01:45:12.214145Z DEBUG niri::pw_utils: pw stream: state changed: Paused -> Unconnected
Something about Niri/Wayland + Nvidia + Pipewire + gnome portal is just not clicking.
It might just be my config, but at this point I feel like I've tried everything I know that could be causing an issue. Like, you'll notice I'm on the latest commit. I was previously on the released version, but saw a commit that might help nvidia, so I'm on the latest now, but still it didn't help.
Any help would be appreciated!
System Information
- niri version: niri 25.05.1 (v25.05.1-95-g00445786)
- GPU: Nvidia RTX 3080 Mobile
When I try to screen record with OBS, the gnome portal selection pops up, sees all my windows and reports back a size to OBS, but only a black screen is actually shown once selected.
I've tried some different things like environment variables, different portals (kde, cosmic, and hyprland). I've seen some similar things on previous issues, but none of the configs match mine and none of the solutions work.
Current /etc/environment
I'd also like to note that this affects Sunshine (a game streaming app) and WebRTC stuff in the browser.
However, it doesn't affect screen shots and it doesn't affect the alternative OBS capture option "Wayland output (scpy)" based on wlr-screencopy.
I think it's not communicating with OBS about formats correctly. Here's the OBS output when I select a screen:
OBS Log
Here's my niri config:
Niri Config
And here's my niri log from when starting streaming:
journalctl --user -xeu niri
Something about Niri/Wayland + Nvidia + Pipewire + gnome portal is just not clicking.
It might just be my config, but at this point I feel like I've tried everything I know that could be causing an issue. Like, you'll notice I'm on the latest commit. I was previously on the released version, but saw a commit that might help nvidia, so I'm on the latest now, but still it didn't help.
Any help would be appreciated!
System Information