Difference between revisions of "Oculus Rift DK2 on Linux"

From Sudo Room
Jump to navigation Jump to search
(page made and details added)
 
(No difference)

Latest revision as of 15:33, 29 August 2026

Project page by Raelyn — started August 2026. Status: working (orientation tracking); positional tracking open.

5/13/26 discord user thedesperad0 asked in #free-stuff if anyone wanted a oculus dev kit. user z4ppho took the offer. Nothing official has supported it in years, but every piece needed to run it on a modern Linux desktop exists in the open — it just isn't written down in one place. This page is that place: what the DK2 is, why it looks dead on a modern desktop, and the exact stack that brings it back at its native 75 Hz.

This was done on Fedora 44 / GNOME 50 (Wayland) with an NVIDIA GTX 1060. The same approach should work on any compositor that supports DRM leasing (GNOME 46+, KDE Plasma 6, wlroots-based compositors).

What's in a DK2

Per the iFixit teardown:

  • Display: literally the front panel of a Samsung Galaxy Note 3 — a 5.7" 1080×1920 Super AMOLED, driven through a Toshiba TC358779XBG HDMI→MIPI-DSI bridge and an STM32L100 microcontroller. The MCU's firmware overclocks the panel from 60 to 75 Hz and pulses it for low persistence. (The touchscreen controller is still in there, unused.)
  • Tracking: an InvenSense MPU-6500 IMU (gyro + accelerometer) over USB for orientation, plus an array of IR LEDs read by an external USB camera (Etron eSP570) for position.
  • USB: a Cypress CY7C65632 hub — the headset shows up as 2833:2021 (hub) and 2833:0021 (headset); the camera is 2833:0201.
  • Connections: one HDMI, one USB for the headset, one USB for the camera. It needs a real HDMI port (or a DisplayPort→HDMI adapter that carries a proper EDID).

Because the display path and the tracking path are separate (HDMI vs USB), each can be debugged on its own.

Why the screen stays black

Plug it in and nothing happens: the desktop never lights the panel, and it doesn't appear in display settings. This is deliberate. The Linux kernel carries a quirk list (drivers/gpu/drm/drm_edid.c) that marks the Oculus DK1, DK2 and CV1 EDIDs as non-desktop — a hint that the display is a head-mounted device, so the compositor should not put a desktop on it. Instead, a VR runtime is expected to lease the connector from the compositor and drive it directly.

So the job is: get a VR runtime to ask the compositor for a lease.

The stack

Layer What we used Notes
VR runtime (OpenXR) Monado Packaged in Fedora (monado). Has a native DK2 path through OpenHMD.
Headset driver OpenHMD 0.3.0 Not the current git snapshot — see gotchas.
Display handoff wp_drm_lease_v1 (Wayland DRM lease) Mutter 50 implements it; Monado's "Wayland direct" mode requests the lease.
GPU NVIDIA GTX 1060, Vulkan Monado uses VK_EXT_acquire_drm_display on the leased connector.
Application Python, pyopenxr + OpenGL Anything OpenXR works; ours is a "virtual monitors around the room" app.

Step by step

1. Let your user touch the device

A udev rule so the HID and USB nodes are readable by the video group:

# /etc/udev/rules.d/70-oculus-dk2.rules
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2833", MODE="0660", GROUP="video"
SUBSYSTEM=="usb",    ATTRS{idVendor}=="2833", MODE="0660", GROUP="video"

Then sudo udevadm control --reload && sudo udevadm trigger, and make sure your user is in video.

Gotcha: group membership only applies to processes started after you were added. A terminal, tmux server or user systemd instance that was already running will still lack the group and Monado will report a "Simulated HMD" instead of the real one. Log out and back in, or wrap the launch in sg video -c "...".

2. Install Monado

sudo dnf install monado openhmd hidapi

(Fedora's openhmd package gets replaced in step 3, but it pulls in the right dependencies.)

3. Build OpenHMD 0.3.0 by hand

The OpenHMD in Fedora (and current git master) uses a new Kalman-filter fusion for positional tracking. With a DK2 it aborts within a minute — Cholesky decomposition failed on P_rootwith or without the camera plugged in. The last release, 0.3.0, uses the older orientation-only fusion and is rock solid.

Monado links against two symbols newer than 0.3.0 (ohmd_device_set_haptics_on/off), so add a tiny stub file and compile the library directly — no cmake needed:

git clone --branch 0.3.0 https://github.com/OpenHMD/OpenHMD.git && cd OpenHMD
cat > src/stubs_compat.c <<'C'
#include "openhmdi.h"
int ohmd_device_set_haptics_on(ohmd_device* d, float f, float a, float t)  { (void)d;(void)f;(void)a;(void)t; return OHMD_S_UNSUPPORTED; }
int ohmd_device_set_haptics_off(ohmd_device* d) { (void)d; return OHMD_S_UNSUPPORTED; }
C
mkdir -p ~/vr/lib
gcc -O2 -fPIC -shared -Wl,-soname,libopenhmd.so.0 \
  -DDRIVER_OCULUS_RIFT -DDRIVER_DUMMY -DDRIVER_EXTERNAL \
  -Iinclude -Isrc -I/usr/include/hidapi \
  src/openhmd.c src/fusion.c src/omath.c src/shaders.c src/platform-posix.c src/stubs_compat.c \
  src/drv_dummy/dummy.c src/drv_external/external.c \
  src/drv_oculus_rift/rift.c src/drv_oculus_rift/packet.c \
  -lhidapi-libusb -lm -lpthread -o ~/vr/lib/libopenhmd.so.0

Point Monado at it with LD_LIBRARY_PATH=$HOME/vr/lib.

4. Start Monado in Wayland direct mode

XRT_COMPOSITOR_FORCE_WAYLAND_DIRECT=1 XRT_NO_STDIN=1 XRT_LOG=info \
  sg video -c "LD_LIBRARY_PATH=$HOME/vr/lib monado-service"

Watch the log for two lines. The lease:

connector HDMI-A-1 (OVR Rift DK2) id: 96

and the tracker:

head: Rift (DK2) (OpenHMD)

If it says Simulated HMD, go back to the group gotcha in step 1. If no connector is offered, your compositor isn't handing out leases (check its version).

Gotcha: sg is setuid and strips LD_LIBRARY_PATH from its own environment — put the variable inside the quoted command, as above.

5. Run something

Any OpenXR app will now render to the headset at 75 Hz. The smallest test is pyopenxr's hello_xr-style sample: a blank scene that spins as you turn your head. Ours draws textured quads at (yaw, pitch, distance) around the wearer and refreshes them from log files, a webcam, a video stream and a real Firefox window — a poor person's command center. A single Python process with an EGL offscreen context holds 75 fps with ~3 ms of frame work on a GTX 1060.

Results

  • First light and orientation tracking: about one hour from "plugged in" to "I CAN LOOK AROUND."
  • Steady 75 fps (the panel's native rate) at 1920×2160 per eye (Monado's maximum, 2× the physical resolution), downsampled for cleaner text.
  • The panel is still a 2014 pentile 1080p: roughly 10 pixels per degree. Text has to be about 1° tall to read. Plan your UI around big, close, few-lined panels — no amount of supersampling adds pixels.

Open problems

  • Positional tracking. The IR camera opens fine (Opened 1 Rift Sensor cameras), but the only OpenHMD fusion that uses it is the one that aborts. Fixing the UKF, or porting position-only from the newer code onto the 0.3.0 base, is the next real project.
  • Panel upgrade? The Note 3 panel can't be swapped on the original board — the STM32 firmware initialises that exact Samsung driver IC. A 5.5" 2560×1440 module with its own HDMI driver board (~$40–90) would fit and keeps tracking intact (separate USB path), but trades 75 Hz low-persistence OLED for 60 Hz full-persistence LCD and needs its own distortion profile. A trade, not an upgrade; not attempted.
  • Persistence. The units above were started with systemd-run; write proper unit files so they survive a reboot.

See also

This project is ongoing and will continue to be updated.

Written by Raelyn with Riley. from the working notes of the project. (August 28–29, 2026).