RiftLinux 0.1.3: Put the Rift On and SteamVR Starts

· 14 min read

A week ago I put out the first release of RiftLinux, my driver for the Oculus Rift CV1 on Linux. Since then people have tried it on their own machines and told me what went wrong: Steam games opening on the monitor instead of in the headset, a picture that went black with a face shield, GNOME logging someone out when they took the headset off. 0.1.1 and a 0.1.2 pre-release fixed the face shield and the GNOME problems. RiftLinux 0.1.3 fixes the Steam games, and the problems my own long unattended test runs turned up.

What’s new in 0.1.3

  • Put the headset on (or pick it up) and SteamVR starts, the way the Oculus app starts on Windows. A game you then start from Steam goes into the headset.
  • SteamVR recovers by itself when its compositor stops, and a SteamVR shutdown that hangs is ended.
  • A headset you take off shows black, instead of switching its display off and leaving HDMI every time.
  • SteamVR’s standby ends only when you put the headset on, not when it gets bumped on a bed.
  • Games added to Steam as a Windows program (Beat Saber bought elsewhere, for example) start from SteamVR Home’s library.
  • Menus out of the way: SteamVR’s menu no longer opens behind you, and Steam’s menu closes once a game shows.
  • A setting for every new behaviour, one riftlinux-setup command each. Which ones fit your setup is below.
  • riftlinux-setup check and riftlinux-setup fix find and clean up what other VR setups left behind.

Why Steam games opened on the monitor

This was the most common report, and the most confusing one, because it worked fine for me: I always started SteamVR first.

A Windows VR game under Proton needs SteamVR to be running before the game starts. Proton checks for it when the game launches, and if SteamVR isn’t there, it switches VR off for that game: VRChat opens in desktop mode, and Beat Saber says OpenXR isn’t installed. On Windows the Oculus app is always running and starts things for you. On Linux, Steam doesn’t start SteamVR for a VR launch, so nothing did.

SteamVR has a way for drivers to do this. A driver can include a small “watchdog” part that Steam’s own client loads while SteamVR is not running, and that part may ask for SteamVR to be started when the hardware says so. RiftLinux 0.1.3 ships one. It watches the headset’s wear sensor and motion while Steam runs, and when you put the Rift on or pick it up it asks Steam to start SteamVR, the same way a click on SteamVR in your library does. If you only picked the headset up to move it, the SteamVR it started quits again after two minutes. Put on only, picked up too, or off altogether: the settings for it are below.

Stability fixes

The rest of the work went into SteamVR sessions that froze or would not end. Until now, both needed a terminal to fix.

When SteamVR’s compositor stops

On NVIDIA I saw SteamVR’s compositor hit a GPU fault four times, as a game quit or as SteamVR came out of standby. After that the headset showed a frozen picture, and SteamVR never recovered: it kept running without a compositor until you killed it.

Now the driver notices when the compositor stops showing frames outside standby. It closes SteamVR, and with Steam running, SteamVR is started again by itself. To test it I froze the compositor on purpose: the driver noticed, closed SteamVR, and Steam started a new one with the headset back in Home.

It doesn’t stop the fault, but when it happens you no longer need a terminal.

Shutdowns that never finished

Sometimes SteamVR’s shutdown waits forever for a process that already ended: its monitor after the compositor crashed on the way out, or Steam’s web helper after it aborted when a game quit. Until that SteamVR is killed by hand, no new one can start.

My first guess was that this was my fault. To check, I ran the same unattended test against the 0.1.0 driver: it hung too, two quits out of four, as soon as the headset was put on and taken off repeatedly. So it’s SteamVR’s, but it still happens to RiftLinux users. Now, when a shutdown is still stuck after 30 seconds, the driver darkens the headset’s display, ends SteamVR’s server and also its monitor, so that Steam sees SteamVR as closed and can start it again.

Handing frames over without blocking

In direct mode SteamVR hands each finished frame to RiftLinux’s own compositor. The driver used to take the frame and wait for the headset’s next refresh in the same call, so SteamVR’s compositor waited too, and logged a timeout on almost every frame. Now the frame is taken at once and handed over after SteamVR’s own work, so SteamVR’s compositor never waits on the driver, and the timeouts are gone in normal running.

Testing without me in the headset

All of this was tested by a script: ten SteamVR sessions in a row, the headset counted as put on and taken off every minute, and in every session SteamVR Home, Beat Saber started from Home’s library and VTOL VR. Every game started, every quit was clean, and there were no GPU errors.

The technical problems behind it

Is the headset on someone’s head?

The CV1 has an infrared sensor between the lenses that sees your face. With a face shield or a thick face pad it doesn’t, and the picture went black while you wore the headset. 0.1.1 added a second rule: a headset that moves like a head counts as worn.

That worked for face shields, but it also counted a headset held in the hands, and one lying on a bed while someone moved on it. So I recorded the headset’s gyro on the bed, in my hands and on my head. The amount of movement didn’t tell them apart: a shaking mattress rotates the headset as fast as a head does. How far it turns does:

How far the headset turned within 10 seconds, one dot per second it moved: on a bed someone moves on it stays under 8 degrees, worn it turns more than 8 degrees in 95 percent of the seconds, held in the hands it turns far more

On the bed the headset wobbles in place and never turned more than 7.6 degrees within 10 seconds. Worn, it turned more than 8 degrees in 95 % of the seconds, because you look around. So 0.1.3 counts a second as head-like only when the headset moved and turned more than 8 degrees, and it needs 20 seconds of that, which is longer than you hold a headset to put it on. Once it counts as worn, a head that holds still keeps the picture.

SteamVR also came out of standby whenever the headset moved, even with the driver telling it “not worn”. That’s SteamVR’s own rule: movement counts as activity. A driver can tell SteamVR to ignore movement for standby, and RiftLinux now does, so only putting the headset on wakes it. If you want the Windows behaviour, where picking the headset up wakes SteamVR, it’s riftlinux-setup standby pick-up.

I tested all four combinations of the standby setting and the head-movement rule, with the same steps each time: moving on the bed, holding the headset and looking into it, then putting it on. Every one did what it should.

Black instead of off

When you took the headset off, RiftLinux switched its display off to protect the OLED panels. The CV1 then leaves HDMI, and for the desktop that’s a monitor being unplugged. GNOME 48 on NVIDIA keeps about 210 MiB of GPU memory every time that happens:

GNOME Shell's GPU memory went from 566 to 2658 MiB over ten times the headset's display was switched off and on: about 210 MiB each time

During a long test, GNOME Shell grew to 23 GB and the kernel killed my desktop session.

USB captures of the Oculus runtime on Windows showed that it never switches the CV1’s display off when you take the headset off: the picture just goes black. RiftLinux now does the same. The display stays connected and shows pure black, which on an OLED panel means no light at all, and it switches off only after 10 minutes. In a test of ten SteamVR sessions with the headset taken off every minute, GNOME’s memory grew only when SteamVR itself quit (a quit still disconnects the headset). Switching the display off right away, as before, is riftlinux-setup not-worn off.

Games added to Steam as a Windows program

If you add a game to Steam yourself and run it with Proton, Steam tells SteamVR to start the game’s .exe directly. That works on Windows. On Linux SteamVR can’t run a Windows program, so the game died at once and SteamVR Home was left waiting. RiftLinux now gives SteamVR’s library an entry that has Steam start the game, the same as the Play button in Steam does.

A bug that wasn’t mine

Sometimes SteamVR’s compositor doesn’t start on the first try, and SteamVR Home shows up later than usual. I tracked it down to the moment SteamVR starts its compositor: a copy of SteamVR’s server gets stuck on a lock that SteamVR’s own main thread was holding at that instant. Since my driver writes to SteamVR’s log right around then, I moved those log lines out and counted 30 starts with each build: 2 of 30 got stuck both ways. So it’s SteamVR’s own. It’s in the known issues, and RiftLinux cleans up the stuck copy when SteamVR quits, so the next start isn’t blocked.

A desktop full of leaked handles

Once, SteamVR started from the headset and SteamVR Home crashed straight away: it could not open any more files. It had inherited about 120,000 open handles. GNOME Shell held 125,239 GPU sync handles without marking them to be closed for new programs (most likely from screen recordings with OBS), and every program started from the dock got a copy: Steam, and through Steam, SteamVR. RiftLinux now starts SteamVR from a clean process that inherits nothing, and riftlinux-setup check warns when the desktop holds thousands of these handles. Logging out and in clears them.

Pick the settings for your setup

Most of the reports came from setups that differ from mine: a face shield, a thick face pad, a headset that lives on the bed, someone who only uses RiftLinux’s own runtime. 0.1.3 fixes the default for each of these and gives each one a setting. Every setting is one riftlinux-setup command, with no files to edit and no launch options, and every old behaviour is still there if you want it back. The Settings page lists all of them with their defaults.

Heavy face pads, face shields, a covered sensor

The wear sensor between the lenses has to see your face. With a thick pad or a shield it may read low or not at all, and then the picture can go black and SteamVR to standby while you’re wearing the headset. In this order:

  1. riftlinux-setup wear-sensor test shows what the sensor reads, live. Put the headset on, then take it off again.
  2. If it still reads clearly more on your head than off it, riftlinux-setup wear-sensor levels <worn above> <not worn below> sets the levels for your headset (30 and 15 by default). For example, if it reads 22 worn and 4 off, wear-sensor levels 15 8 fits.
  3. If it reads about the same either way, leave head movement on (it is by default): the headset counts as worn once it has moved and turned like a head. riftlinux-setup wear-sensor motion high makes that 8 seconds instead of 20.
  4. As a last resort, riftlinux-setup wear-sensor off counts the headset as worn whenever SteamVR runs. The picture then stays on when you take the headset off, so close SteamVR when you put it down.

With a pad the sensor can’t see through, keep SteamVR starting on pick-up (the default): a put-on the sensor doesn’t notice won’t start SteamVR.

The headset lives on a bed or a couch

The defaults are made for this: moving around on the bed no longer wakes SteamVR, and a headset lying on a shaking mattress doesn’t count as worn. If the picture still comes on there, riftlinux-setup wear-sensor motion low asks for 30 seconds of head-like movement instead of 20.

You want it to behave as on Windows

riftlinux-setup standby pick-up lets SteamVR wake from standby as soon as the headset moves, as it does with the Oculus software. The picture still waits until the headset is on. On a bed, anyone moving wakes it too, which is why it isn’t the default.

You pick the headset up a lot without wanting to play

With Steam running, picking the Rift up starts SteamVR, and a SteamVR started that way quits again when nobody puts the headset on within two minutes and no game starts. riftlinux-setup autostart trigger put-on starts it only when you put the headset on; riftlinux-setup autostart quit-unused off keeps a SteamVR running that a pick-up started.

You don’t use SteamVR

riftlinux-setup autostart off, for example if you only use RiftLinux’s own runtime for OpenXR applications.

When you take the headset off

By default the display shows pure black 5 seconds after you take the headset off, and switches off after 10 minutes of black. riftlinux-setup not-worn black <minutes> changes the 10 minutes (never keeps it black), riftlinux-setup display-off <seconds> changes the 5 seconds, and riftlinux-setup not-worn off switches the display off instead, as earlier versions did. On GNOME 48 with NVIDIA that costs GPU memory at every take-off (see above).

Controllers and Steam’s menu

  • riftlinux-setup controller-sleep 3|5|7|off sets the minutes after you take the headset off before the Touch controllers may sleep (5 by default); a button wakes them. off keeps them awake while SteamVR runs.
  • riftlinux-setup game-menu keep: Steam opens its menu as a game starts, and RiftLinux now closes it once the game shows. This keeps it open instead. A menu you open yourself during a game always stays.

When something doesn’t work

  • riftlinux-setup check looks for everything that kept games out of the headset on other people’s machines (the full list is below).
  • riftlinux-setup fix puts the configuration RiftLinux is tested with in place, in one go. It lists every change, asks once, and keeps a backup of every file it changes.
  • If you broke the settings file editing it by hand, RiftLinux keeps using the last settings it could read and writes nothing into the broken file. riftlinux-setup check shows where it’s broken, and riftlinux-setup fix last-known puts the last good settings back.

What riftlinux-setup check looks for

Another headset driver still registered with SteamVR or forced in its settings (SteamVR-OpenHMD, ALVR); an OpenVR runtime other than SteamVR (xrizer, OpenComposite) or another OpenXR runtime; variables or launch options that point games at another runtime (XR_RUNTIME_JSON, VR_OVERRIDE); SteamVR settings games depend on, changed from their defaults; USB power saving on the Rift’s devices; other VR services (Monado, WiVRn, ouvrt) or a camera app holding the Rift’s devices; a headset left in pairing mode; a desktop holding thousands of leaked handles; Steam still running the part of an older RiftLinux that starts SteamVR (restart Steam); and the lsusb command.

That last one surprised me. Before SteamVR runs, Steam asks SteamVR’s client library whether a headset is connected, and on Linux that library runs lsusb to look for each driver’s headset. Without the usbutils package Steam never sees the Rift. The packages now depend on it.

Smaller fixes

  • SteamVR’s menu no longer opens behind you at the start. SteamVR opens it before RiftLinux places the room around you, and placing the room turned it away from you. It now shows once the room is placed, in front of you.
  • The Touch controllers go to sleep when the headset isn’t in use. RiftLinux used to keep them awake as long as SteamVR ran, also with the headset on the desk for hours, and the batteries ran flat overnight.
  • A worn thumbstick that stops short of its range now counts as fully pushed. My left stick pushed right reached only 82 to 95 percent of its range, and snap turns missed some pushes.
  • If a session crashed while the headset’s headphones and microphone were your default sound devices, the next session puts your own back.
  • The headset’s display is switched off when nothing is running it. A SteamVR that crashed or was ended by hand used to leave it lit.
  • USB power saving stays off for the Rift’s devices, also after the kernel’s camera driver takes the sensors back and turns it on again.
  • Programs SteamVR starts no longer get copies of the driver’s handles to the headset. One that kept running after SteamVR quit kept the headset open.

0.1.3 also carries everything from 0.1.1 and the 0.1.2 pre-release: steadier tracking with the rear headband LEDs, the headset held in place when no sensor can see it, as the Oculus runtime does, thumbsticks that read zero at rest, and the GNOME 50 fix.

Try it

If you’re upgrading, install the new package and restart Steam once: Steam loads the part that starts SteamVR when Steam starts.

Everything here was tested on NVIDIA. AMD and Intel should work through Vulkan, but I don’t have the hardware, so if you try either, please tell me how it goes. And thanks to everyone who sent a report: a good part of this release started with one.