Steam Link + Generic Gamepad + Linux Host

Posted by Jack on 2016-11-26 at 12:56
Tagged: software , gaming , hardware , linux

Like a lot of people this week, I picked up a Steam Link for $20 from Amazon and it arrived yesterday.

Previously, I've used Steam home streaming to and from Linux hosts and I've been very pleased with its performance, especially over a wired connection. I streamed Skyrim from a Windows partition elsewhere to my media box running Arch and it even worked on the nouveau driver, so it seemed like a safe bet to invest $20 in a Steam Link to function as a sort of bluetooth KVM switch, so I could stream games and movies from any of the hosts in the house. This post isn't to review the Link, however, it's to clear up exactly how generic controllers (i.e. not the Steam Controller) work in Big Picture Mode (BPM) and how to resolve a couple of Linux configuration snafus.

A note on generic controllers

When I bought the Steam Link, I read that it supports the Wii U Pro Controller. I've got a couple of those laying around since we have a Wii U and they're pretty nice controllers. Supported, in this case though, just means that the Link will properly pair with the controller and it has a good mapping between the Wii U Pro Controller's buttons and the X-Box 360 controller it's emulating. That's it. It's enough to get the Link interface and the BPM interface to work well, and nothing else.

What that means is that you should ignore Big Picture Mode's controller mapping config. Seriously, the most confusing part of this whole experience was discovering that all the neat mapping functionality is Steam Controller only. I mean, I knew I couldn't do all the cool stuff a Steam controller can like profiles and mode shifting etc. but I thought I could at least change simple button presses. I guess I should have taken the hint that the mapping controller is a picture of a Steam Controller and the descriptions all mention "Steam Controller" by name, but it convincingly allowed me to mess with settings it knew would never take.

Despite that, the bindings are still active and will still change on context. Even though you can't actually change the bindings yourself in the interface, BPM will still alter the bindings based on whether you're in Desktop Mode (normal Steam), BPM, or a game. This means it's crucial when you setup bindings in a game that it was launched via Steam and not any other way.

This threw me off quite a bit because I thought it'd either be "Steam can configure this device" or "Steam won't touch this device", not "Steam will pretend to configure this device, fail, but then configure it implicitly when you do something anyway." The latest Steam betas will warn you that you're configuring a different controller, but will still frustratingly pretend that it's actually going to try to make it work. It'd be nice if Valve made this more explicit by forbidding you to change the mapping, instead of it silently reverting to defaults.

Fix constant display/video flickering on NVIDIA cards

The first real problem I faced was that connecting the Link to my Arch Linux system worked, but Steam in BPM would incessantly flicker. Not occasional frame tearing, but headache inducing strobe flickering. [UPDATE: Now that I've tested on better hardware, I've found that this option is necessary to fix the more subtle flickering of full motion video too. ] I'm not sure how to fix this on nouveau, but I switched to the proprietary driver and after invoking this command:

nvidia-settings --assign CurrentMetaMode="HDMI-0:1920x1080\_60 +0+0 { ForceFullCompositionPipeline = On }"

the flickering stopped. Note that you'll need to customize the mode definition. HDMI-0 is the adapter, 1920x1080_60 is the mode (resolution and refresh rate) and screen offset. All of this information you can query from "xrandr -q" if you're unsure. For example, here's the xrandr output on this computer:

HDMI-0 connected 1920x1080+0+0 (normal left inverted right x axis y axis) 698mm x 392mm
   1920x1080     60.00*+  59.94    23.97    60.05    60.00  
   1440x480      60.05  
   1280x720      60.00    59.94  
   720x480       59.94  
   640x480       59.93  

You can see the adapter name, the resolution, the offset (+0+0), and the refresh rate is listed in the current mode (60.00*).

You could automate this either by using nvidia-settings to write your Xorg conf, or you can just invoke this command once before you start steam on the host. Personally, using an XDG autostart compatible WM (like Cinnamon, or Openbox), I just have it in an autostart script so my xorg.conf is still (mostly) auto-generated.

[Desktop Entry]
Exec=nvidia-settings --assign CurrentMetaMode="HDMI-0:1920x1080\_60 +0+0 { ForceFullCompositionPipeline = On }"

Fix Big Picture Mode cursor confusion

The next problem that I faced was that Big Picture Mode had a big blue mouse cursor on it, a Linux desktop cursor, in addition to it's highlight cursor and all of them were out of sync. It made it very hard to tell just what exactly you're doing in the interface. Initially, I thought it was Steam's bindings getting confused but it's actually Xorg trying to be helpful. When you connect a generic controller to the Steam Link, it forwards the traffic over the network as a virtual X-Box 360 controller. Xorg sees that device and says "oh hey, a joystick device, I know what to do with that!" and attaches the mouse.

If we were plugging a controller into a standard Linux desktop, this would be a lifesaver, but since our interface is specialized to use the controller it's just confusing. So, the solution here is to tell Xorg to stop.

Section "InputClass"
        Identifier "joystick catchall"
        MatchIsJoystick "on"
        MatchDevicePath "/dev/input/event*"
        Driver "joystick"
        Option "StartKeysEnabled" "False"       #Disable mouse
        Option "StartMouseEnabled" "False"      #support

After restarting X, this will keep Xorg from automatically connecting the mouse cursor to your gamepad stick and leave Steam alone.

That's pretty much all I had to do to get basic Link functionality up and running when connecting to a Linux host.