1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
# Running the desktop app on WSL/Arch-Razer
> Tribal knowledge (P6): the non-inferable facts for running the native Linux
> `build/study-player` on this dev machine — Arch Linux in WSL2 with WSLg, on a
> Razer laptop with an NVIDIA dGPU passthrough. A fresh model cannot derive
> these from the source; they were found by crashing and then bisecting env.
## Environment
- Arch Linux (`ID=arch`) inside WSL2; graphics via **WSLg** (X11 socket at
`/tmp/.X11-unix/X0`, Wayland socket at `/mnt/wslg/runtime-dir/wayland-0`).
- Mesa GL stack present: `d3d12_dri.so`, `zink_dri.so`, `swrast_dri.so`,
`virtio_gpu_dri.so` under `/usr/lib/dri/`. NVIDIA passthrough libs under
`/usr/lib/wsl/lib/` (`libcuda.so`, `libd3d12.so`, …).
- Audio: WSLg PulseAudio at `unix:/mnt/wslg/PulseServer`.
- The WSLg env vars are set by `/etc/profile.d/wslg.sh` — but **only in a login
shell**. A non-login shell (the default for tool/agent invocations) has
`DISPLAY` and `WAYLAND_DISPLAY` empty, so the app can't find the display at
all unless you export them yourself.
## The segfault trap (root cause)
`/etc/profile.d/wslg.sh` exports **`LIBGL_ALWAYS_INDIRECT=1`** ("Helpful for
some GL apps"). For this app + this GPU stack it is the opposite of helpful:
raylib initializes, then `InitWindow` **segfaults (exit 139, core dumped)**
during GLX/GL context creation — log stops right after the module-load banner,
before "DISPLAY: Device initialized".
**Fix: `unset LIBGL_ALWAYS_INDIRECT`.** With it unset, direct rendering works
and the window comes up cleanly (renderer resolves to Mesa `llvmpipe`, the
software rasterizer — fine for this app).
## Required env vars to run
```sh
export XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir
export DISPLAY=:0
export WAYLAND_DISPLAY=wayland-0
export PULSE_SERVER=unix:/mnt/wslg/PulseServer
unset LIBGL_ALWAYS_INDIRECT # critical — the default wslg.sh sets it and it crashes us
```
## Launching (background, detached)
The app is a raylib event loop that runs until the window is closed, so launch
it detached so it doesn't block the caller:
```sh
cd /home/tradam/projects/study-player
setsid nohup ./build/study-player > /tmp/study-player.log 2>&1 < /dev/null &
disown 2>/dev/null || true
```
## Verifying it came up
- Process stays alive (not exit 139). `kill -0 $!` succeeds after ~2–3 s.
- Log contains, in order: `DISPLAY: Device initialized successfully` →
`PLATFORM: DESKTOP (GLFW - X11): Initialized successfully` →
`AUDIO: Device initialized successfully` → font-load lines.
If the log stops at the module banner and the process is dead → you hit the
`LIBGL_ALWAYS_INDIRECT` trap (see above).
- Harmless warnings in the log: `FONT: [0x007b/0x007d] Glyph height is bigger
than requested font size` (the `{`/`}` braces in the embedded font). Cosmetic
only.
## GPU driver options
- **Default (unset everything except the required vars above):** resolves to
`llvmpipe` (software). Works, slightly more CPU. **This is the recommended
path.**
- **Force the d3d12 GPU driver:** `export MESA_LOADER_DRIVER_OVERRIDE=d3d12`.
Also reaches `PLATFORM: Initialized successfully`. Hardware-accel path if you
want it; not required.
- **Do NOT force Zink:** `MESA_LOADER_DRIVER_OVERRIDE=zink` fails with
`GLX: No GLXFBConfigs returned` / `DRI3 not available` — window never opens.
## Loading media
No CLI file argument. Drag and drop an `.mp3` onto the window (desktop path in
`main.c`'s `IsFileDropped` handler). Silence detection runs on load.
## Stopping
Close the window, or `pkill -x study-player`.
|