Files
punktfunk/flake.nix
T
enricobuehler d6818263ce feat(gamescope): a build of gamescope whose capture output can be HDR
gamescope's built-in PipeWire node has always been SDR-only: it offers BGRx
and NV12, and `paint_pipewire()` hardcodes a Gamma-2.2 composite with the SDR
screenshot LUT set. So an HDR game reaches punktfunk already tone-mapped down,
and the whole gamescope backend streams 8-bit no matter what the client can
decode. Games CAN render HDR on a headless gamescope today — only the capture
half is missing.

Carry the two patches that close it (packaging/gamescope/patches): the node
additionally offers `xRGB_210LE`/`xBGR_210LE` with MANDATORY SMPTE ST.2084 +
BT.2020 props, mapped to the same 10-bit capture texture the HDR AVIF
screenshot path already allocates, and `paint_pipewire()` composites into them
with the HDR screenshot LUTs + `EOTF_PQ` — which is exactly the in-tree
`bHDRScreenshot` branch. The new formats are listed LAST, so every existing
consumer keeps negotiating the 8-bit stream bit-for-bit. Offered upstream
against ValveSoftware/gamescope#2126.

Ship it as `punktfunk-gamescope`, beside the distro's own binary rather than
replacing it: a Bazzite sysext payload (`build-sysext.sh --gamescope`, which
refuses a binary without the marker), an Arch package, a nix derivation +
`services.punktfunk.host.gamescopeHdr`, and one distro-agnostic build script
the rest call.

The second patch stamps `+pfhdr1` into the `--version` banner. That is not
cosmetic: punktfunk fixes a session's bit depth in the Welcome, before the
display exists and with no way to take it back, so its capability answer has to
be a static property of the binary it will spawn.
2026-07-28 18:01:20 +02:00

205 lines
6.9 KiB
Nix

{
description = "punktfunk — low-latency desktop/game streaming host + native Linux client";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
crane.url = "github:ipetkov/crane";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
# The bun packages' node_modules (punktfunk-web, punktfunk-scripting): one fetchurl per package,
# straight out of `bun.lock`'s integrity hashes — no hand-maintained aggregate deps hash to bump.
# PIN THE TAG. `bun.nix` has no schema stability guarantee across bun2nix versions, so this ref
# must move together with the `bun2nix` devDependency in web/package.json + sdk/package.json
# (which regenerates the file on every `bun install`). See packaging/nix/README.md.
bun2nix = {
url = "github:nix-community/bun2nix?ref=2.1.2";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{
self,
nixpkgs,
crane,
rust-overlay,
bun2nix,
}:
let
# Linux/x86_64 only — the host encodes with desktop NVENC and CI publishes no aarch64 leg
# (mirrors the RPM's `ExclusiveArch: x86_64`). Add a system here once there's an arm64 build.
systems = [ "x86_64-linux" ];
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
# The workspace version is the single source of truth (crates/*/Cargo.toml inherit it).
version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).workspace.package.version;
pkgsFor =
system:
import nixpkgs {
inherit system;
overlays = [ (import rust-overlay) ];
};
# Pin cargo/rustc EXACTLY to rust-toolchain.toml (channel 1.96.0 + rustfmt/clippy) so a Nix
# build, a dev shell and CI all use the identical toolchain — the repo is deliberate about
# this (see rust-toolchain.toml's header on rustfmt format-drift).
toolchainFor = pkgs: pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
craneLibFor = pkgs: (crane.mkLib pkgs).overrideToolchain toolchainFor;
packagesFor =
system:
let
pkgs = pkgsFor system;
in
pkgs.callPackage ./packaging/nix/packages.nix {
craneLib = craneLibFor pkgs;
src = self;
inherit version;
# `.hook` + `.fetchBunDeps` (bun2nix v2 API) — see packages.nix.
bun2nix = bun2nix.packages.${system}.default;
}
// {
# gamescope + our `pipewire-hdr` patches, so the gamescope backend can stream HDR.
# Kept OUT of packages.nix (a Rust/crane file) — it is a C++ meson override with a
# disjoint dependency set — and out of `checks` below, because it rebuilds gamescope
# from source and would make `nix flake check` an hour long.
punktfunk-gamescope = pkgs.callPackage ./packaging/nix/gamescope.nix {
patchDir = ./packaging/gamescope/patches;
};
};
in
{
packages = forAllSystems (
system:
let
pf = packagesFor system;
in
{
inherit (pf)
punktfunk-host
punktfunk-client
punktfunk-web
punktfunk-scripting
punktfunk-tray
punktfunk-gamescope
;
default = pf.punktfunk-host;
}
);
# `nix run .#punktfunk-host -- serve` / `nix run .#punktfunk-client`.
apps = forAllSystems (
system:
let
pf = packagesFor system;
in
{
punktfunk-host = {
type = "app";
program = "${pf.punktfunk-host}/bin/punktfunk-host";
};
punktfunk-client = {
type = "app";
program = "${pf.punktfunk-client}/bin/punktfunk-client";
};
# `nix run .#punktfunk-web` — the console (auto-wire the mgmt token / cert via env or the
# NixOS module; see packaging/nix/README.md).
punktfunk-web = {
type = "app";
program = "${pf.punktfunk-web}/bin/punktfunk-web-server";
};
# `nix run .#punktfunk-scripting -- --list` — the plugin/script runner.
punktfunk-scripting = {
type = "app";
program = "${pf.punktfunk-scripting}/bin/punktfunk-scripting";
};
default = self.apps.${system}.punktfunk-host;
}
);
# `nix flake check` builds every package.
checks = forAllSystems (
system:
let
pf = packagesFor system;
in
{
inherit (pf)
punktfunk-host
punktfunk-client
punktfunk-web
punktfunk-scripting
;
}
);
# `nix develop` — the pinned toolchain plus every system lib the workspace links, wired so
# `cargo build` (all crates, host + client) works out of the box.
devShells = forAllSystems (
system:
let
pkgs = pkgsFor system;
toolchain = toolchainFor pkgs;
gbm = pkgs.libgbm or pkgs.mesa;
in
{
default = pkgs.mkShell {
strictDeps = false;
nativeBuildInputs = [
toolchain
pkgs.rust-analyzer
pkgs.pkg-config
pkgs.cmake
pkgs.nasm
pkgs.perl
pkgs.rustPlatform.bindgenHook
];
buildInputs = [
# host
pkgs.ffmpeg
pkgs.pipewire
pkgs.libopus
pkgs.wayland
pkgs.libxkbcommon
pkgs.libGL
gbm
pkgs.vulkan-loader
# client
pkgs.sdl3
pkgs.gtk4
pkgs.libadwaita
pkgs.glib
pkgs.librsvg
pkgs.gsettings-desktop-schemas
pkgs.adwaita-icon-theme
pkgs.vulkan-headers
];
# pf-ffvk bindgen (no /usr/include on NixOS); GPU driver libs at runtime for `cargo run`.
PF_FFVK_VULKAN_INCLUDE = "${pkgs.vulkan-headers}/include";
# CMake ≥ 4 rejects the pre-3.5 minimums some vendored C libs (libopus) still declare.
CMAKE_POLICY_VERSION_MINIMUM = "3.5";
LD_LIBRARY_PATH = "/run/opengl-driver/lib:${
pkgs.lib.makeLibraryPath [
pkgs.vulkan-loader
pkgs.libGL
gbm
]
}";
};
}
);
formatter = forAllSystems (system: (pkgsFor system).nixfmt-rfc-style);
# NixOS integration — see packaging/nix/nixos-module.nix and packaging/nix/README.md.
# imports = [ punktfunk.nixosModules.default ];
# services.punktfunk.host.enable = true;
nixosModules.default = import ./packaging/nix/nixos-module.nix self;
nixosModules.punktfunk = self.nixosModules.default;
};
}