My Linux adventure - almost 3 months later
If I'm gonna be honest, I completely forgot I had Windows on this computer. I've been daily-driving this thing for a couple of months now, and I'm quite happy.
The first post was chronological, going over each day and what I did, but it is definitely not the complete picture. Here I wanna present some things in a more structured manner, categorically. I'll go over my usecases, workflows and some entertainment too.
I'll also rank each aspect in "jank before, effort required, jank after" from 0 to 10. 1-2 is truly a minor inconvenience, 5-6 is annoying, 9-10 is a dealbreaker. So, in either case, the lower the number, the better.
This is not exactly a guide, but more like an assessment of Linux and NixOS for my personal use cases, which I believe may also intersect with some of y'all. Since NixOS is so config-based, you don't even have to go through the troubles I did, you can just copy my config!
TODO: put up my config on GitHub. In the meantime you can just contact me or whatever.
Installation
This was remarkably simple. NixOS's installation ISO boots into a live USB environment with a nice GUI (KDE Plasma) and a couple utilities (GParted for partition management). I needed the latter so I could dual-boot Windows and Linux.
But if I hadn't been concerned with that, then this would've been even simpler. Just launch the installer, next, next, allow unfree software, next, fill out your username and password, done. No Microslop rubbish, no online account garbage.
Configuring the system (GPU drivers etc.)
Mm. I did say I'd order this from least jank to most jank, but I kinda have to make one exception and that is this. It's an important first step with NixOS.
This procedure differs slightly between all distros. With some, there may be extra options in the installer, e.g. GPU drivers. Then, as you use your distro, you'll install things through the terminal or some GUI. In NixOS, everything is handled in /etc/nixos/configuration.nix, and when you just start out, it will be very minimal, containing your username, permissions, and a couple of pre-installed packages like Firefox and, say, Kate the text editor.
I gotta mention NixOS has two branches: stable (25.05) and unstable. Unstable really just means "give me the very latest stuff". I chose stable because, well, I do prefer some more peace of mind, knowing it's got a higher chance of working. I don't mind waiting a couple months until stuff is tested and made sure it works.
GPU drivers
I regret to inform you that I'm an nVidia user. (planning to go full-AMD on my next build though)
For the first few days, it took me a while to realise I did not actually have nVidia drivers installed, so I had to enable them like so, fully:
# Allow hardware acceleration
hardware.graphics.enable = true;
hardware.graphics.enable32Bit = true; # lots of 32-bit games
# Get as much firmware as possible
hardware.enableAllFirmware = true;
# Use open-source nVidia kernel modules, they are the best for VR
# Also use the beta version for more features
services.xserver.videoDrivers = [ "nvidia" ];
hardware.nvidia.open = true;
hardware.nvidia.package = config.boot.kernelPackages.nvidiaPackages.beta;
# Enable power management so my monitor doesn't
# randomly turn on while I'm sleeping
hardware.nvidia.powerManagement.enable = true;
hardware.nvidia.modesetting.enable = true;
# Enable CUDA for Blender, OBS and others
nixpkgs.config.cudaSupport = true;
Yes. I had an actual issue with my monitor randomly turning on after the PC was shut down, but it just took one line. I'm also using the "beta" nVidia driver which is really just a slightly newer stable release, 575 as of now, as opposed to 570.
If you're using NixOS unstable, you may even get access to 580, which fixes a long-standing issue for wired VR. As for me, I'll have to wait for that one...
I also gotta note I have a little issue where the GPU driver may sometimes fail to load on startup, giving me a 1024x768 login screen, but a restart from there solves it. I really have no idea why this happens, but it doesn't bother me that much.
Lastly, pay attention to CUDA support. It is crucial for content creation & VR. Man. It's almost like with Windows you have to fight to disable all the bad stuff, and on Linux you gotta actively enable all the good stuff.
Jank before: 9/10.
Effort: 1/10.
Jank after: 3/10.
Automatically mounting my other drives
If you have just one storage device and one partition on it, then this is basically a non-issue and you can skip this.
So I have a couple SSDs and one HDD with a few partitions on it. By default, this stuff is not mounted. In order to open them for the first time, I gotta type in my password. So I figured I'd auto-mount one them (Windows auto-mounts by default once you've format your thing):
# Automatically mount ExpansionUnit (A:). We'll be transferring
# that one to the new PC anyway, so it's whatever.
fileSystems."/expansion-unit" =
{
device = "/dev/disk/by-uuid/562619AC26198DDD";
fsType = "ntfs";
options =
[
"users"
"nofail"
];
};
I managed to obtain the UUID by going into /dev/disk/by-uuid and /dev/disk/by-label and running ls -la. It then gave me these:
[admer456@nixos:/dev/disk/by-label]$ ls -la
total 0
drwxr-xr-x 2 root root 240 Okt 15 17:58 .
drwxr-xr-x 9 root root 180 Okt 15 17:58 ..
lrwxrwxrwx 1 root root 10 Okt 15 17:58 ExpansionUnit -> ../../sdc2
lrwxrwxrwx 1 root root 15 Okt 15 17:58 GamingUnit -> ../../nvme0n1p2
lrwxrwxrwx 1 root root 10 Okt 15 17:58 GeneralStorage -> ../../sdb4
lrwxrwxrwx 1 root root 10 Okt 15 17:58 MediaUnit -> ../../sdb3
lrwxrwxrwx 1 root root 10 Okt 15 17:58 NIXBOOT -> ../../sda5
lrwxrwxrwx 1 root root 10 Okt 15 17:58 OperatingUnit -> ../../sdb2
lrwxrwxrwx 1 root root 10 Okt 15 17:58 Recovery -> ../../sda1
lrwxrwxrwx 1 root root 10 Okt 15 17:58 'Samsung\x20860EVO' -> ../../sda4
lrwxrwxrwx 1 root root 15 Okt 15 17:58 XROOT -> ../../nvme0n1p3
lrwxrwxrwx 1 root root 15 Okt 15 17:58 XSWAP -> ../../nvme0n1p4
Okay. So that means my A: drive was sdc2.
[admer456@nixos:/dev/disk/by-uuid]$ ls -la
total 0
drwxr-xr-x 2 root root 280 Okt 15 17:58 .
drwxr-xr-x 9 root root 180 Okt 15 17:58 ..
lrwxrwxrwx 1 root root 10 Okt 15 17:58 0C7E40657E404A22 -> ../../sdb2
lrwxrwxrwx 1 root root 10 Okt 15 17:58 26946D54946D278F -> ../../sdb3
lrwxrwxrwx 1 root root 10 Okt 15 17:58 3E20A79C20A759A3 -> ../../sda6
lrwxrwxrwx 1 root root 10 Okt 15 17:58 562619AC26198DDD -> ../../sdc2
lrwxrwxrwx 1 root root 15 Okt 15 17:58 74b3edf9-f40f-4e11-bd38-f555f1ef326f -> ../../nvme0n1p4
lrwxrwxrwx 1 root root 10 Okt 15 17:58 78E2D372E2D3335C -> ../../sda4
lrwxrwxrwx 1 root root 15 Okt 15 17:58 9C8E26498E261BF0 -> ../../nvme0n1p2
lrwxrwxrwx 1 root root 10 Okt 15 17:58 AC2EBDE52EBDA92A -> ../../sdb4
lrwxrwxrwx 1 root root 10 Okt 15 17:58 CE60-7FB4 -> ../../sda5
lrwxrwxrwx 1 root root 15 Okt 15 17:58 e0e54b74-146a-47e4-9d67-9694ff88a593 -> ../../nvme0n1p3
lrwxrwxrwx 1 root root 10 Okt 15 17:58 F0CF-C5FC -> ../../sda2
lrwxrwxrwx 1 root root 10 Okt 15 17:58 F428CF7428CF3480 -> ../../sda1
Okay. So sdc2 maps to that particular UUID. Great!
Jank before effort: 3/10.
Effort: 2/10.
Jank after: 0/10.
2D and 3D art
I'll jumble these two together because honestly I've found basically no issues so far. GIMP 3 is neat coming from 2.10.x, Inkscape 1.4 is Inkscape as I remember it, and Krita is as good as ever.
environment.systemPackages = with pkgs; [
blender
krita
gimp3-with-plugins
inkscape
];
Blender also just works.
I must say though, KDE Plasma came with a weird default behaviour for the middle mouse button, and it was interfering with Blender's controls w.r.t. orbiting, panning and zooming in, so I had to disable it.
Jank before effort: 8/10. (Blender barely usable)
Effort: 1/10.
Jank after: 0/10.
Browsing
Pretty standard browsing experience, I can't say much here.
programs.firefox.enable = true;
But, I do gotta say I couldn't see emojis on GitHub, and for that I had to enable this:
fonts.fontconfig.useEmbeddedBitmaps = true;
Other than that, everything else works. I haven't tried playing any games in the browser and especially not WebXR stuff, so I can't comment on that.
Jank before: 3/10.
Effort: 1/10.
Jank after: 0/10.
Gaming
I use Steam for most of my games and Lutris for GoG games. Very simple stuff:
# Steam
programs.steam.enable = true;
programs.steam.protontricks.enable = true;
programs.steam.localNetworkGameTransfers.openFirewall = true;
environment.systemPackages = with pkgs; [
...
lutris
wineWowPackages.waylandFull # 32-bit and 64-bit WINE
winetricks # For Assetto Corsa etc.
protonup-ng # CLI Proton installer
];
Assetto Corsa needed some tweaks to get up and running. But it was just a matter of following a few steps and running a few commands. Obviously you'll also need WINE.
Everything else was a piece of cake. I decided to install Gloomwood one day and it had a light flickering bug, but a Proton update happened the very next day and fixed it, which was pretty funny.
I've been able to enjoy some games natively, like Half-Life, Half-Life 2, Left 4 Dead 2 and BeamNG.drive. Through Proton I could enjoy Assetto Corsa, Far Cry 1 (Lutris), Voices of the Void, Motortown: Behind the Wheel, PEAK, Gloomwood, Abiotic Factor, Quake 2's remaster, The Long Drive and a fair amount of VR games (Bonelab, VRChat, Resonite, HL Alyx, we'll talk about that later).
I don't play any anticheat games like Battlefield 6, EA's Skate or whatever, so I've dodged a bullet in that regard. If you play those, you'll have to dualboot.
Source Engine games had a weird audio issue, but I solved it by clicking the speaker icon, going to "Applications" and changing e.g. L4D2's output device to my monitor, then back to my USB audio interface. I gotta do it every time I launch a Source game, but not HL2VR for some reason. I'm sure this has to do with my Focusrite Scarlett 2i2 Gen4 interface and my PipeWire setup, but we'll talk about that later.
Jank before: 6.5/10. (AC not working)
Effort: 4/10. (using winetricks for Assetto Corsa, getting alternative Proton versions etc.)
Jank after: 3/10. (only the Source audio bug remains)
Sim racing
I gotta say I'm pleased. There was no tweaking required, I just had to install a driver, plug my Logitech G29 in, check it out in Oversteer (a GUI app for managing steering wheels) and head into the game. No Logitech G-Hub required.
# Logitech steering wheel support
hardware.new-lg4ff.enable = true;
environment.systemPackages = with pkgs; [
...
oversteer
];
Jank before: 7/10. (steering wheel worked but no FFB)
Effort: 2/10.
Jank after: 0/10.
Video production
Installing OBS with the needed plugins, pretty easy:
programs.obs-studio.plugins = with pkgs.obs-studio-plugins; [
wlrobs
obs-backgroundremoval
obs-pipewire-audio-capture
obs-vaapi
obs-gstreamer
obs-vkcapture
];
Make sure cudaSupport is also enabled.
Now, there's a little bit of an issue. On my RTX 3060, I can only encode x264 and x265. On Windows, I use DaVinci Resolve to edit my videos, and guess what program does not support x264 on Linux. :>
That's right. I gotta use ffmpeg or Handbrake to convert my footage into AV1 or something similar! Awesome. Until I can buy a copy of DaVinci Resolve Studio, this will have to do. Well, it's either that or Kdenlive, which I'm also kinda fine with, but it is definitely less polished compared to Resolve.
Jank before: 9/10. (basically couldn't edit any videos)
Effort: 4/10. (it took a little bit to figure out which formats were available)
Jank after: 2.5/10. (longer footage can take a while to convert to AV1)
Mind you, this is all because of nVidia. On an RTX 4xxx+ card, you'd have AV1 encoding, and on AMD I think this wouldn't have been an issue.
Programming
Linux is known as an OS for programmers, so you'd think it'd be far easier to get into here, no? On most distros, yes. On NixOS, you need to do a bit of preparation.
NixOS has a non-standard filesystem, meaning there is no /bin or /lib structure where your C/C++ compiler (and other tools!!) would expect tools, libraries and headers and stuff. This means, if you just installed gcc and Qt packages and tried building an app, you'd run into trouble. It couldn't find Qt, it couldn't find this, that, stuff just wouldn't work.
This is fixed by making shells. In some cases, you may need a per-project environment, in other cases you can use a "generic" environment, in my case I have three: one for C++ and Qt programming, one for .NET and another one for doing some light web work, such as updating this website!
In short, you make a .nix file (example below) and run nix-shell example.nix.
In order to build TrenchBroom, I just copied the TrenchBroom package from nixpkgs and used nix-shell on it locally. To build Half-Life Asset Manager, Half-Life SDK etc., I used my generic C++ shell which worked well enough. It's a bit too big to paste here.
To work on my game engine and generally all C# stuff, I use the .NET shell.
{ pkgs ? import <nixpkgs> {} }:
(pkgs.buildFHSEnv {
name = "shell-elegy";
runScript = "bash";
targetPkgs = pkgs: with pkgs; [
bash
coreutils
xdg-utils
dotnet-sdk
unzip
];
multiPkgs = pkgs: with pkgs; [
glibc
udev
libdrm
libgbm
libGL
SDL2
dotnet-sdk
vulkan-loader
fontconfig
cairo
freetype
];
}).env
Other than that, it is your usual game of "look at CMake's log and hunt down the dependencies".
Jank before: 10/10. (completely unworkable)
Effort: 4.5/10. (for some new projects, you may have to add additional packages to your shell)
Jank after: 1/10. (gotta step into a shell each time)
Virtual reality
As we get into more niche things, the levels of jank start to increase.
Basic wireless VR
I have a Pico 4 headset, and it is quite lovely. On Windows I used Virtual Desktop to connect my headset to my PC via Wi-Fi, then gradually got used to ALVR, which performed about the same, it just had more configuration options and hand tracking for the Pico 4, so I could use my fingers and all.
On NixOS, the official ALVR package was broken for me, and it seemed to be nVidia-specific. However, some people said they were able to just run the downloadable binary from GitHub, which is what I ended up doing too. Basically, I'd navigate to alvr/bin/ and do steam-run ./alvr-dashboard. Simple as that.
Oh yeah. Make sure cudaSupport is enabled. Also make sure you open a few ports in your firewall:
networking.firewall = {
allowedTCPPorts = [
9943 9944 # ALVR TCP ports
];
allowedUDPPorts = [
9943 9944 # ALVR UDP ports
];
};
I also tried WiVRn but it seemed to perform a lot worse in Bonelab, I'm not sure if it was due to OpenComposite or something else. ALVR works perfectly fine for me so I likely won't check it out again for a little while. I wrote more in my first post.
Jank before: 10/10. (unusable)
Effort: 3/10.
Jank after: 0/10. (can play SteamVR games perfectly fine)
Desktop overlays
SteamVR's desktop overlay does not seem to work under Wayland. Yay. However, installing wlx-overlay-s from nixpkgs works just fine, just make sure to run it like so: steam-run wlx-overlay-s.
KDE Plasma will then pop up and ask you what you wish to screenshare, and I tend to pick the entire monitor. In my case though, this also disables SteamVR audio, and prevents me from hearing in-game audio.
So, the procedure I have to follow is: launch ALVR, launch game, then launch the overlay. I'm sure it's my jank PipeWire setup.
Jank before: 6/10. (no desktop overlay, gotta use passthrough on VR headset)
Effort: 3/10.
Jank after: 2/10. (gotta remember to launch it after I launch a game)
SlimeVR
I recently got SlimeVR full body trackers, and the setup was a lot smoother than I thought.
I had to install the slimevr package, but also:
- Open ports (21110 TCP; 6969, 35903 and 8266 UDP).
- Add
platformioandopenocdpackages toservices.udev.packagesand to system packages. Without them, SlimeVR will fail to connect to the tracker hardware via USB. The dashboard also refused to open unless I set this environment variable before launching:
export WEBKIT_DISABLE_DMABUF_RENDERER=1
I was able to configure this in the application launcher via GUI, so at least that's nice, don't have to do it every time in the terminal.
Other than that though, I was able to easily calibrate and set everything up.
ALVR has an issue with SlimeVR where your chest tracker will affect your VR view, that is, if you were to launch SlimeVR before ALVR. So, my procedure is now:
- Launch ALVR and SteamVR, connect the headset
- Launch SlimeVR
- Launch a game
steam-run wlx-overlay-sIt should be possible to automate some of this, though! I may just write myself a tool to ease all of that. I've also yet to try alternative desktop overlays.
Jank before: 10/10. (cannot start)
Effort: 4.5/10. (took some scouring over SlimeVR documentation, NixOS Arduino pages etc.)
Jank after: 3/10. (gotta put on the trackers, gotta remember this 4-step procedure)
Music production
Okay. This right here was my final boss.
On Windows I used FL Studio and a load of VST plugins, some 32-bit, some 64-bit. On Linux, it is possible to run FL Studio via WINE, but I instead decided to try Ardour and Reaper, and see what other plugin formats there are.
I learned about CLAP, LADSPA, LV2 and all that. Okay. I learned where Linux DAWs look for plugins and whatnot, and I found out about a vast collection of plugins called LSP. They have compressors, EQs, reverbs, all that stuff. Okay. Standard stuff. I installed Ardour and... 2048 SAMPLES?! Ain't no WAY I'm gonna play my guitar on that. I gotta figure out how this works.
Low-latency audio and DAWs
And so I dug deep and scoured the Internet for everything regarding PipeWire, my audio interface, the Arch Wiki on audio stuff, ALSA properties and I finally got something. I got it down to 128 samples, but it was popping all the time. Mmm. Not good.
And so I discovered Musnix, which enables realtime priority stuff for NixOS. This lets the CPU focus on processing audio ASAP. I'll spare you the details:
# Audio
security.rtkit.enable = true;
services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
wireplumber.enable = true;
pulse.enable = true;
jack.enable = true;
};
# Support low-latency profiles for Ardour etc.
musnix.enable = true;
musnix.rtcqs.enable = true;
Also make sure to add your user to the realtime group:
users.users.admer456.extraGroups = [ "realtime" ];
Here's an excerpt from my audio config(s):
# Low-latency profile (256 samples at 48 kHz)
services.pipewire.extraConfig.pipewire."92-low-latency" = {
"context.properties" = {
"default.clock.rate" = 48000;
# We can go very fast :)
"default.clock.allowed-rates" = [ 44100 48000 82000 96000 ];
"default.clock.quantum" = 256;
"default.clock.min-quantum" = 32;
"default.clock.max-quantum" = 8192;
"clock.power-of-two-quantum" = true;
};
};
Another important detail is using the S24_3LE format here. For PulseAudio applications, I'm fine with a quantum of 512 if not 1024, so I can voice chat on Discord without issues.
This, however, still did not fix popping and crackling in Ardour. Nothing could. But it did fix popping in Firefox, games and Discord. So I switched to Reaper. All of a sudden, no popping. However, the LSP plugins there may sometimes freeze the UI, so I'm looking for alternatives for now.
Still, despite all that, I've managed to record some bits of guitar and voiced an entire video I'm gonna produce this month! And also, Audacity works just fine. No issues there.
Jank before: 10/10. (full of pops, can't play guitar with filters in real time)
Effort: 6.5/10. (this one definitely took me the longest and it took the most tweaks and research)
Jank after: 3/10. (some plugins can freeze the UI a bit, but otherwise aren't an issue, and Reaper is pretty stable)
Linux plugins
Remember all the stuff I said about shells up there? Well, they're useful here too, actually. NixOS has a non-standard filesystem, meaning VST/LV2 plugins normally won't be able to find their needed .so files to function. So, you gotta make a shell to be able to actually launch Reaper in an environment which does have the needed libraries and stuff.
This doesn't apply to some plugins that are available on nixpkgs though! LSP, Guitarix and all, they're available there and easy to install.
I only figured this out because I had to figure it out for programming, too.
{ pkgs ? import <nixpkgs> {} }:
(pkgs.buildFHSEnv {
name = "shell-music";
runScript = "bash";
targetPkgs = pkgs: with pkgs; [
bash
coreutils
xdg-utils
dotnet-sdk
];
multiPkgs = pkgs: with pkgs; [
glibc udev
libdrm libgbm
dotnet-sdk
# X11
xorg.libXcomposite xorg.libXtst
xorg.libXrandr xorg.libXext
xorg.libXi xorg.libX11
xorg.libXfixes xorg.libXcursor
xorg.libSM xorg.libXft
xorg.libICE xorg.libXcursor
xorg.libXrender xorg.libXt
xorg.xcbutil xorg.xcbutilkeysyms
xorg.xcbutilwm xorg.libxcb
libz freetype
fontconfig cairo
# Misc
libGL
vulkan-loader
SDL2
juce # for VSTs
];
}).env
My current VSTs (TyrellN6 mainly) need this. In order to find out which VST needs what dependency, you can use ldd on the .so file of the plugin, and work your way from there, adding packages to the shell as you find them on nixpkgs or cross-referencing the AUR maybe.
Jank before: 8/10. (can't load 90% of plugins)
Effort: 3.5/10.
Jank after: 1/10. (gotta step into a shell each time)
Windows VSTs
For this, I use yabridge. It bridges over DR-84, MONSTER Synth and a few other of my beloved plugins. It just works. You place the VSTs somewhere, run yabridgectl to generate bridged VSTs from them, and ta-da. I bridged TyrellN6 this way before I learned about shells.
TODO: Finish this section
Making it a little easier
Okay so, I have all these shells for C++ and C# development, music production and all. Is it possible to avoid using the terminal every time you wanna launch them? Could we, perhaps, make shortcuts to launch them like normal?
Yes. I'm going to take Reaper as an example.
Preparing the shells
So basically you'll need 2 things:
- A
.nixshell containing the needed FHS environment config and the dependencies for the VST3 plugins. - A
.shscript to wrap around this.
{ pkgs ? import <nixpkgs> {} }:
(pkgs.buildFHSEnv {
name = "shell-reaper";
runScript = "reaper";
targetPkgs = pkgs: with pkgs; [
bash
coreutils
xdg-utils
];
multiPkgs = pkgs: with pkgs; [
glib
udev
librdm
libgbm
... # Everything else you may need, X11, JUCE etc.
];
}).env
I want you to notice the runScript value. Normally this would be bash or whatever you have. Here, however, you want to run Reaper directly.
Next up, the shell script:
nix-shell ~/shell-reaper.nix
Adding it to the start menu
I have found a way to simply add this as a shortcut in the start menu (or in KDE terminology, add a launcher to the application launcher menu?). Here is how:
- Right-click the start menu button
- Click "Edit Applications"
- Right-click a category of applications and click "New Item"
- Fill it in as follows:
Name: The name of the wrapped application, e.g. "Reaper (shell)"
Program: /bin/sh
Commandline arguments: /home/<your-username>/shell-reaper.sh
Also, to read logs and all, you may go to Advanced and enable the terminal option.
Doing this stuff reduces a good deal of jank for not a lot of effort. I'll have to do this for Rider, CLion and a few others.
My thoughts
Honestly I think this is almost it. I just need to work out some kinks, like the video production pipeline and the remaining audio issues. And once I do, I basically don't have to do it again until maybe I get new hardware, like a different audio interface brand or when I switch to AMD.
My biggest gripe with this distro in particular is that everything is kinda disabled by default and I have to enable it. But, that is kinda good in a way. It forces me to be conscious, explicit about it. But I don't really care. I just want my computer to work and the OS to do the tedium for me, which it now mostly does.
My main surprise is how little effort it all actually took. For someone, setting up VR alone could turn into a 3-month project, or music production alone. Instead, I've been able to completely transfer my workflow from Windows within the first 3 weeks, going from almost zero.
But anyway! I am now fully resuming my work. A couple of websites, my game engine, Half-Life modding related projects, and YouTube videos. It is honestly no big deal.
