Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

wivrn: init at 0.16 #316975

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2405.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m

- [watchdogd](https://troglobit.com/projects/watchdogd/), a system and process supervisor using watchdog timers. Available as [services.watchdogd](#opt-services.watchdogd.enable).

- [WiVRn](https://github.com/Meumeu/WiVRn), an OpenXR streaming application. Available as [services.wivrn](#opt-services.wivrn.enable).

- [Workout-tracker](https://github.com/jovandeginste/workout-tracker), a workout tracking web application for personal use.

- [wyoming-satellite](https://github.com/rhasspy/wyoming-satellite), a voice assistant satellite for Home Assistant using the Wyoming protocol. Available as [services.wyoming.satellite](#opt-services.wyoming.satellite.enable).
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,7 @@
./services/video/mediamtx.nix
./services/video/unifi-video.nix
./services/video/v4l2-relayd.nix
./services/video/wivrn.nix
./services/wayland/cage.nix
./services/wayland/hypridle.nix
./services/web-apps/akkoma.nix
Expand Down
170 changes: 170 additions & 0 deletions nixos/modules/services/video/wivrn.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
{ config, pkgs, lib, ... }:
let
inherit (lib) mkAliasOptionModule mkIf mkEnableOption mkPackageOption mkOption mkDefault optional optionalString optionalAttrs isDerivation getExe literalExpression maintainers;
cfg = config.services.wivrn;
configFormat = pkgs.formats.json { };

# For the application option to work with systemd PATH, we find the store binary path of
# the package, concat all of the following strings, and then update the application attribute.
# Application can either be a package or a list that has a package as the first element.
applicationExists = builtins.hasAttr "application" cfg.config.json;
applicationListNotEmpty = (
if builtins.isList cfg.config.json.application
then if builtins.length cfg.config.json.application == 0
then false
else true
else true
);
PassiveLemon marked this conversation as resolved.
Show resolved Hide resolved
applicationCheck = applicationExists && applicationListNotEmpty;

applicationBinary = (
if builtins.isList cfg.config.json.application
then (builtins.head cfg.config.json.application)
else cfg.config.json.application
);
applicationStrings = builtins.tail cfg.config.json.application;

applicationPath = mkIf applicationCheck applicationBinary;

applicationConcat = (
if builtins.isList cfg.config.json.application
then builtins.concatStringsSep " " ([ (getExe applicationBinary) ] ++ applicationStrings)
else (getExe applicationBinary)
);
applicationUpdate = cfg.config.json // optionalAttrs applicationCheck { application = applicationConcat; };
configFile = configFormat.generate "config.json" applicationUpdate;
in
{
options = {
services.wivrn = {
enable = mkEnableOption "WiVRn, an OpenXR streaming application";

package = mkPackageOption pkgs "wivrn" { };

openFirewall = mkEnableOption "the default ports in the firewall for the WiVRn server";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be true by default?


defaultRuntime = mkEnableOption ''
WiVRn Monado as the default OpenXR runtime on the system.
The config can be found at `/etc/xdg/openxr/1/active_runtime.json`.

Note that applications can bypass this option by setting an active
runtime in a writable XDG_CONFIG_DIRS location like `~/.config`
'' // { default = true; };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this not be true by default?


highPriority = mkEnableOption "high priority capability for asynchronous reprojection" // { default = true; };

config = {
enable = mkEnableOption "configuration for WiVRn";
json = mkOption {
type = configFormat.type;
description = ''
Configuration for WiVRn. The attributes are serialized to JSON in config.json.

Note that the application option must be either a package or a
list with package as the first element.

See https://github.com/Meumeu/WiVRn/blob/master/docs/configuration.md
'';
default = { };
example = literalExpression ''
PassiveLemon marked this conversation as resolved.
Show resolved Hide resolved
{
scale = 0.8;
bitrate = 100000000;
encoders = [
{
encoder = "nvenc";
codec = "h264";
width = 1.0;
height = 1.0;
offset_x = 0.0;
offset_y = 0.0;
}
];
application = [ pkgs.wlx-overlay-s ];
tcp_only = true;
}
'';
PassiveLemon marked this conversation as resolved.
Show resolved Hide resolved
};
};
};
};

imports = [
(mkAliasOptionModule [ "services" "wivrn" "monadoEnvironment" ] [ "systemd" "user" "services" "wivrn" "environment" ])
];

config = mkIf cfg.enable {
assertions = [
(mkIf applicationCheck {
assertion = isDerivation applicationBinary;
message = "The application in WiVRn configuration is not a package. Please ensure that the application is a package or that a package is the first element in the list.";
})
];

security.wrappers."wivrn-server" = mkIf cfg.highPriority {
setuid = false;
owner = "root";
group = "root";
# We need cap_sys_nice for asynchronous reprojection
capabilities = "cap_sys_nice+eip";
source = getExe cfg.package;
};

systemd.user = {
services.wivrn = {
description = "WiVRn XR runtime service module";
PassiveLemon marked this conversation as resolved.
Show resolved Hide resolved
unitConfig.ConditionUser = "!root";
serviceConfig = {
ExecStart = (
if cfg.highPriority
then "${config.security.wrapperDir}/wivrn-server"
else getExe cfg.package
) + optionalString cfg.config.enable " -f ${configFile}";
Restart = "no";
};
# We need to add the application to PATH so WiVRn can find it
path = [ applicationPath ];
restartTriggers = [
cfg.package
configFile
];
};
};

services = {
wivrn.monadoEnvironment = {
# Default options
# https://gitlab.freedesktop.org/monado/monado/-/blob/598080453545c6bf313829e5780ffb7dde9b79dc/src/xrt/targets/service/monado.in.service#L12
XRT_COMPOSITOR_LOG = mkDefault "debug";
XRT_PRINT_OPTIONS = mkDefault "on";
IPC_EXIT_ON_DISCONNECT = mkDefault "off";
};
# WiVRn can be used with some wired headsets so we include xr-hardware
udev.packages = with pkgs; [
android-udev-rules
xr-hardware
];
avahi = {
enable = true;
publish = {
enable = true;
userServices = true;
};
};
};

networking.firewall = mkIf cfg.openFirewall {
allowedTCPPorts = [ 9757 ];
allowedUDPPorts = [ 9757 ];
};

environment = {
systemPackages = [ cfg.package ];
pathsToLink = [ "/share/openxr" ];
etc."xdg/openxr/1/active_runtime.json" = mkIf cfg.defaultRuntime {
source = "${cfg.package}/share/openxr/1/openxr_wivrn.json";
};
};
};
meta.maintainers = with maintainers; [ passivelemon ];
}
145 changes: 145 additions & 0 deletions pkgs/by-name/wi/wivrn/package.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
{ config
, lib
, stdenv
, fetchFromGitHub
, fetchFromGitLab
, applyPatches
, autoAddDriverRunpath
, avahi
, boost
, cmake
, cudaPackages ? { }
, cudaSupport ? config.cudaSupport
, eigen
, ffmpeg
, freetype
, git
, glm
, glslang
, harfbuzz
, libdrm
, libGL
, libva
, libpulseaudio
, libX11
, libXrandr
, nix-update-script
, nlohmann_json
, onnxruntime
, openxr-loader
, pipewire
, pkg-config
, python3
, shaderc
, spdlog
, systemd
, udev
, vulkan-headers
, vulkan-loader
, vulkan-tools
, x264
}:
stdenv.mkDerivation (finalAttrs: {
pname = "wivrn";
version = "0.16";

src = fetchFromGitHub {
owner = "meumeu";
repo = "wivrn";
rev = "v${finalAttrs.version}";
hash = "sha256-6qBx/DwzEU4f4JiyfOH7aaBwM4tP93TekgFqpgoQHMI=";
};

monado = applyPatches {
src = fetchFromGitLab {
domain = "gitlab.freedesktop.org";
owner = "monado";
repo = "monado";
rev = "598080453545c6bf313829e5780ffb7dde9b79dc";
hash = "sha256-9LsKvIXAQpr+rpv8gDr4YfoNN+MSkXfccbIwLrWcIXg=";
};

patches = [
("${finalAttrs.src}/patches/monado/0001-c-multi-disable-dropping-of-old-frames.patch")
("${finalAttrs.src}/patches/monado/0002-ipc-server-Always-listen-to-stdin.patch")
("${finalAttrs.src}/patches/monado/0003-c-multi-Don-t-log-frame-time-diff.patch")
];
};

postUnpack = ''
# Let's make sure our monado source revision matches what is used by WiVRn upstream
ourMonadoRev="${finalAttrs.monado.src.rev}"
theirMonadoRev=$(grep -A1 "https://gitlab.freedesktop.org/monado/monado" ${finalAttrs.src.name}/CMakeLists.txt | tail -n1 | sed 's/.*GIT_TAG\s*//')
if [ ! "$theirMonadoRev" == "$ourMonadoRev" ]; then
echo "Our Monado source revision doesn't match CMakeLists.txt." >&2
echo " theirs: $theirMonadoRev" >&2
echo " ours: $ourMonadoRev" >&2
return 1
fi
'';

PassiveLemon marked this conversation as resolved.
Show resolved Hide resolved
nativeBuildInputs = [
cmake
git
pkg-config
python3
] ++ lib.optionals cudaSupport [
autoAddDriverRunpath
];

buildInputs = [
avahi
boost
eigen
ffmpeg
freetype
glm
glslang
harfbuzz
libdrm
libGL
libva
libX11
libXrandr
libpulseaudio
nlohmann_json
onnxruntime
openxr-loader
pipewire
shaderc
spdlog
systemd
udev
vulkan-headers
vulkan-loader
vulkan-tools
x264
] ++ lib.optionals cudaSupport [
cudaPackages.cudatoolkit
];

cmakeFlags = [
(lib.cmakeBool "WIVRN_USE_VAAPI" true)
(lib.cmakeBool "WIVRN_USE_X264" true)
(lib.cmakeBool "WIVRN_USE_NVENC" cudaSupport)
(lib.cmakeBool "WIVRN_USE_SYSTEMD" true)
(lib.cmakeBool "WIVRN_USE_PIPEWIRE" true)
(lib.cmakeBool "WIVRN_USE_PULSEAUDIO" true)
(lib.cmakeBool "WIVRN_BUILD_CLIENT" false)
(lib.cmakeBool "WIVRN_OPENXR_INSTALL_ABSOLUTE_RUNTIME_PATH" true)
(lib.cmakeBool "FETCHCONTENT_FULLY_DISCONNECTED" true)
(lib.cmakeFeature "FETCHCONTENT_SOURCE_DIR_MONADO" "${finalAttrs.monado}")
];

passthru.updateScript = nix-update-script { };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail to update the hardcoded monado version.


meta = with lib; {
description = "An OpenXR streaming application to a standalone headset";
homepage = "https://github.com/Meumeu/WiVRn/";
changelog = "https://github.com/Meumeu/WiVRn/releases/tag/v${finalAttrs.version}";
PassiveLemon marked this conversation as resolved.
Show resolved Hide resolved
license = licenses.gpl3Only;
maintainers = with maintainers; [ passivelemon ];
platforms = platforms.linux;
mainProgram = "wivrn-server";
};
})