From eb8c9435728bf85b9091614765252fdec75e9398 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sat, 8 Aug 2026 15:36:19 +0200 Subject: [PATCH] feat(packaging): ship punktfunk-gamescope on RPM and apt too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now the patched gamescope reached exactly four kinds of box: the Bazzite/Fedora-Atomic sysext, the Arch package, the SteamOS installer and a NixOS option. Everyone else was told to build gamescope from source. A traditional Fedora-family box — Nobara, plain Fedora, the HTPCs people actually stream from — therefore ran stock gamescope by default, which streams SDR, cursorless, and tells every game its display is 60 Hz. That is not a user error; there was no package to install. Both new packages REPACK the binary CI already builds rather than building gamescope again: it is a ~10-minute meson compile of an unrelated tree, cached per distro base because the binary is soname-coupled to it. The Arch PKGBUILD stays the one recipe that builds from source, because that is what makepkg is for. - packaging/gamescope/punktfunk-gamescope.spec + build-gamescope-rpm.sh. Version is derived from the binary's own banner (3.16.25.pfhdr4) — the only source that cannot drift from what is in the package. rpmbuild's automatic ELF Requires are what stop an f43 build installing on f44. - packaging/debian/build-gamescope-deb.sh, same shape, with dpkg-shlibdeps for Depends. - rpm.yml packages and publishes it beside the host RPMs; deb.yml gains a cached gamescope build (keyed on packaging/gamescope/** alone) and packages it into the existing publish loop. Both legs are best-effort, matching the sysext's existing rule: no binary, no package, and the host stays on its current SDR path. Neither package Provides or Conflicts with gamescope — it installs as /usr/bin/punktfunk-gamescope and only the sessions the host starts itself resolve it, so a box's own Game Mode keeps using the distro binary. Both refuse to package a binary without the +pfhdr marker. That marker is the host's entire capability probe, so a build that lost the patches would install fine and then silently stream SDR with no cursor. Verified: build-gamescope-deb.sh produces an installable .deb from a stand-in binary (correct version derived from the banner, 0755 tree, control fields) and exits 1 on an unmarked one. The .spec is not yet exercised — no rpm tooling on the box I had; CI's Fedora leg is its first run. --- .gitea/workflows/deb.yml | 40 +++++++ .gitea/workflows/rpm.yml | 34 ++++++ docs-site/content/docs/gamescope.md | 19 ++++ packaging/debian/build-gamescope-deb.sh | 113 +++++++++++++++++++ packaging/gamescope/build-gamescope-rpm.sh | 78 +++++++++++++ packaging/gamescope/punktfunk-gamescope.spec | 78 +++++++++++++ 6 files changed, 362 insertions(+) create mode 100755 packaging/debian/build-gamescope-deb.sh create mode 100755 packaging/gamescope/build-gamescope-rpm.sh create mode 100644 packaging/gamescope/punktfunk-gamescope.spec diff --git a/.gitea/workflows/deb.yml b/.gitea/workflows/deb.yml index bcf7c1b8..2e95f73c 100644 --- a/.gitea/workflows/deb.yml +++ b/.gitea/workflows/deb.yml @@ -320,6 +320,46 @@ jobs: run: | VERSION="$VERSION" BUNDLE_FFMPEG=1 bash packaging/debian/build-deb.sh + # punktfunk-gamescope for apt. Same reasoning as the RPM leg in rpm.yml: without a packaged + # build, a Debian/Ubuntu box has no route to the patched gamescope except compiling it, and a + # stock gamescope streams SDR, cursorless, and tells every game its display is 60 Hz. + # + # CACHED on packaging/gamescope/** alone — it depends on nothing else in this repo, so a + # normal push restores a binary instead of spending ~10 minutes on someone else's tree. + - uses: actions/cache@v4 + id: gamescope + with: + path: gs-cache + key: punktfunk-gamescope-noble-${{ hashFiles('packaging/gamescope/**') }} + + - name: Build the patched gamescope + if: steps.gamescope.outputs.cache-hit != 'true' + # Best-effort, exactly like rpm.yml: the host packages above are the primary delivery and + # work without this binary, so a hiccup building an unrelated tree must not fail the job. + # `build-dep gamescope` resolves the distro's much older packaged version, so it can come up + # short — that is what the `|| true`s absorb, and the marker check downstream is what makes + # a half-built result impossible to ship. + run: | + set -x + apt-get update + apt-get install -y --no-install-recommends meson ninja-build glslc git || true + apt-get build-dep -y gamescope || true + if bash packaging/gamescope/build-punktfunk-gamescope.sh \ + --destdir "$PWD/gs-stage" --prefix /usr --jobs "$(nproc)"; then + install -Dm0755 gs-stage/usr/bin/punktfunk-gamescope gs-cache/punktfunk-gamescope + else + echo "::warning::punktfunk-gamescope failed to build on noble — no .deb this run (gamescope sessions stay SDR)" + fi + + - name: Build punktfunk-gamescope .deb + # Picked up by the publish loop below, which globs dist/*.deb. + run: | + if [ -x gs-cache/punktfunk-gamescope ] && gs-cache/punktfunk-gamescope --version >/dev/null 2>&1; then + bash packaging/debian/build-gamescope-deb.sh --binary gs-cache/punktfunk-gamescope + else + echo "::warning::no usable punktfunk-gamescope — skipping its .deb" + fi + - name: Publish to the Gitea apt registry env: TOKEN: ${{ secrets.REGISTRY_TOKEN }} diff --git a/.gitea/workflows/rpm.yml b/.gitea/workflows/rpm.yml index 1769e661..675395c6 100644 --- a/.gitea/workflows/rpm.yml +++ b/.gitea/workflows/rpm.yml @@ -213,6 +213,40 @@ jobs: echo "::warning::punktfunk-gamescope failed to build for f${{ matrix.fedver }} — the sysext ships without it (gamescope sessions stay SDR)" fi + # The same binary, as an ordinary RPM. The sysext below is the Atomic/Bazzite delivery; this + # is the one a traditional Fedora-family box (Nobara, plain Fedora) can actually install — + # until it existed those users had no packaged route to the patched build at all, and a stock + # gamescope tells every game its display is 60 Hz whatever the client negotiated. + # + # Same best-effort rule as the build above: no binary, no package, and the host stays on its + # existing SDR/host-composited path. The spec re-checks the +pfhdr marker itself. + - name: Package punktfunk-gamescope as an RPM + run: | + if [ -x gs-cache/punktfunk-gamescope ] && gs-cache/punktfunk-gamescope --version >/dev/null 2>&1; then + bash packaging/gamescope/build-gamescope-rpm.sh \ + --binary gs-cache/punktfunk-gamescope \ + --release "$PF_RELEASE" + else + echo "::warning::no usable punktfunk-gamescope for f${{ matrix.fedver }} — skipping its RPM" + fi + + - name: Publish punktfunk-gamescope to the Gitea RPM registry + env: + TOKEN: ${{ secrets.REGISTRY_TOKEN }} + run: | + shopt -s nullglob + for rpm in dist/punktfunk-gamescope-*.rpm; do + case "$rpm" in *debuginfo*|*debugsource*) continue;; esac + NAME=$(rpm -qp --qf '%{NAME}' "$rpm" 2>/dev/null) + VR=$(rpm -qp --qf '%{VERSION}-%{RELEASE}' "$rpm" 2>/dev/null) + ARCH=$(rpm -qp --qf '%{ARCH}' "$rpm" 2>/dev/null) + echo "uploading $rpm" + curl -fsS -o /dev/null --user "enricobuehler:$TOKEN" -X DELETE \ + "https://$REGISTRY/api/packages/$OWNER/rpm/$GROUP/package/$NAME/$VR/$ARCH" || true + curl -fsS --user "enricobuehler:$TOKEN" --upload-file "$rpm" \ + "https://$REGISTRY/api/packages/$OWNER/rpm/$GROUP/upload" + done + # The no-layering Bazzite path: wrap the just-built host + web RPMs into a systemd-sysext # image and publish it to the per-Fedora-major feed (punktfunk-sysext/f43[-canary], …) that # `punktfunk-sysext install|update` reads. Same RPMs, same channels — just no rpm-ostree. diff --git a/docs-site/content/docs/gamescope.md b/docs-site/content/docs/gamescope.md index d23ba2d9..2bcd7c9e 100644 --- a/docs-site/content/docs/gamescope.md +++ b/docs-site/content/docs/gamescope.md @@ -161,6 +161,9 @@ To stream real HDR you need `punktfunk-gamescope`: gamescope plus a small patch own name and does **not** replace your system gamescope — your Gaming Mode keeps using that one. - **Bazzite / Fedora Atomic** — included in the Punktfunk sysext; `punktfunk-sysext update` gets it. +- **Fedora, Nobara and other RPM boxes** — `sudo dnf install punktfunk-gamescope` from the same + Punktfunk repo the host comes from. +- **Debian / Ubuntu** — `sudo apt install punktfunk-gamescope` from the Punktfunk apt repo. - **Arch** — the `punktfunk-gamescope` package. - **SteamOS (Steam Deck installer)** — built and wired automatically by `scripts/steamdeck/install.sh` / `update.sh`. @@ -200,6 +203,22 @@ These apply to the **Gaming Mode (gamescope)** path only; the desktop path is un capture node, so the overlay is missing from an otherwise perfect picture. Either case is logged at startup with the version found. Bazzite's and SteamOS's current gamescope is past both; this only bites if you've pinned an old one. +- **On a stock gamescope, Gaming Mode reports the wrong refresh rate — and offers no resolutions.** + A headless gamescope has no EDID, and upstream's headless connector advertises no display modes + and no refresh rates at all. Steam's in-session display settings then show a single refresh entry + and an empty resolution list, and that one entry is whatever the session was launched with — or + **60 Hz** if the launch flag went missing. Games that pace themselves to the display will hold + themselves there, even though the stream is running at your client's full rate (the client's own + fps counter keeps reading correctly, because the encoder repeats held frames — so the counter is + not the thing to trust here; an in-game fps readout is). `punktfunk-gamescope` publishes the real + mode and rate, and `PUNKTFUNK_GAMESCOPE_REFRESH_RATES=60,90,120` puts more than one entry in that + menu. If the host log says *"the session did not start at the mode we asked for"*, a file in + `/etc/gamescope-session-plus/sessions.d/` is overriding `GAMESCOPE_BIN` or setting `GAMESCOPECMD`. +- **The performance overlay (fps / frametime / stats) needs the patched build.** It is mangoapp, + which gamescope draws as an *external overlay* — a layer upstream's capture composite has never + included on any version, so on a stock gamescope you can turn the overlay on and it simply will + not appear in the stream. There is no host-side substitute: the host cannot reconstruct another + process's overlay window. `punktfunk-gamescope` paints it into the capture stream. - **The cursor comes from the compositor when it can, and from the host otherwise.** A stock gamescope leaves the pointer out of its captured image, so the host reads it separately and draws it into every frame — a full pass over the picture, and the fastest encode source cannot blend at diff --git a/packaging/debian/build-gamescope-deb.sh b/packaging/debian/build-gamescope-deb.sh new file mode 100755 index 00000000..2c02b285 --- /dev/null +++ b/packaging/debian/build-gamescope-deb.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash +# Package an already-built punktfunk-gamescope binary as a .deb, for the Gitea apt registry. +# +# Counterpart to ../gamescope/build-gamescope-rpm.sh, and the same argument: the binary is a +# ~10-minute meson build of an unrelated tree that CI does once and caches, so this repacks rather +# than rebuilds. The Arch package (../gamescope/PKGBUILD) is the one recipe that builds from source, +# because that is what makepkg is for. +# +# Installed as /usr/bin/punktfunk-gamescope — it does NOT replace the distro's gamescope, and does +# not Provide/Conflict with it. Only the sessions punktfunk-host starts itself resolve this binary +# (PUNKTFUNK_GAMESCOPE_BIN > punktfunk-gamescope > gamescope). +# +# Usage: +# VERSION=3.16.25.pfhdr4~ci42.gdeadbee bash packaging/debian/build-gamescope-deb.sh \ +# --binary gs-cache/punktfunk-gamescope [--arch amd64] +# Output: dist/punktfunk-gamescope__.deb +set -euo pipefail + +BINARY="" +DEB_ARCH="" +while [ $# -gt 0 ]; do + case "$1" in + --binary) BINARY="${2:?--binary needs a path}"; shift 2 ;; + --arch) DEB_ARCH="${2:?--arch needs a value}"; shift 2 ;; + *) echo "unknown argument: $1" >&2; exit 2 ;; + esac +done + +[ -n "$BINARY" ] || { echo "ERROR: --binary is required" >&2; exit 2; } +[ -x "$BINARY" ] || { echo "ERROR: $BINARY is not an executable file" >&2; exit 1; } + +PKG="punktfunk-gamescope" +ROOTDIR="$(cd "$(dirname "$0")/../.." && pwd)" +cd "$ROOTDIR" + +DEB_ARCH="${DEB_ARCH:-$(dpkg --print-architecture)}" + +# The marker is the host's whole capability probe: a binary that lost the patches installs fine and +# then silently streams SDR, cursorless, at a 60 Hz-advertising session. Refuse to package it. +BANNER="$("$BINARY" --version 2>&1 | head -1)" +case "$BANNER" in + *'+pfhdr'*) ;; + *) echo "ERROR: $BINARY has no +pfhdr marker — it is not a punktfunk gamescope build" >&2 + echo " banner: $BANNER" >&2 + exit 1 ;; +esac + +# Derive the version from the binary when the caller did not pass one — it is the only source that +# cannot drift from what is actually in the package. +if [ -z "${VERSION:-}" ]; then + UPSTREAM="$(printf '%s\n' "$BANNER" | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1)" + PFHDR="$(printf '%s\n' "$BANNER" | grep -o '+pfhdr[0-9]\+' | head -1 | tr -d '+')" + [ -n "$UPSTREAM" ] || { echo "ERROR: no X.Y.Z version in banner: $BANNER" >&2; exit 1; } + VERSION="${UPSTREAM}.${PFHDR}" +fi + +STAGE="$(mktemp -d)" +trap 'rm -rf "$STAGE"' EXIT +# mktemp gives 0700; the package root has to be world-readable or `dpkg-deb -c` shows the tree as +# root-only and some tooling refuses it. +chmod 0755 "$STAGE" +install -Dm0755 "$BINARY" "$STAGE/usr/bin/punktfunk-gamescope" +mkdir -p "$STAGE/DEBIAN" + +# Shared-library dependencies straight from the binary's own ELF NEEDED entries. That is what makes +# the package honest about the Ubuntu release it was compiled on: gamescope links a broad set +# (wlroots, SDL, libliftoff, vulkan, xwayland's libs), and hand-listing them would rot. +DEPS="" +if command -v dpkg-shlibdeps >/dev/null 2>&1; then + # dpkg-shlibdeps insists on running from a package root with a debian/ dir. + mkdir -p "$STAGE/debian" + : > "$STAGE/debian/control" + ( cd "$STAGE" && dpkg-shlibdeps -O --ignore-missing-info usr/bin/punktfunk-gamescope 2>/dev/null ) \ + > "$STAGE/.shlibdeps" || true + DEPS="$(sed -n 's/^shlibs:Depends=//p' "$STAGE/.shlibdeps" | head -1)" + rm -rf "$STAGE/debian" "$STAGE/.shlibdeps" +fi +[ -n "$DEPS" ] || echo "WARNING: dpkg-shlibdeps produced no Depends — packaging without them" >&2 + +{ + echo "Package: $PKG" + echo "Version: $VERSION" + echo "Architecture: $DEB_ARCH" + echo "Maintainer: unom " + echo "Section: utils" + echo "Priority: optional" + [ -n "$DEPS" ] && echo "Depends: $DEPS" + # Not a hard dependency in either direction: the host works without this binary (SDR, + # host-composited cursor), and someone may want the binary for their own capture consumer. + echo "Recommends: punktfunk-host" + echo "Homepage: https://git.unom.io/unom/punktfunk" + echo "Description: gamescope with punktfunk's PipeWire capture patches" + echo " gamescope built from the upstream revision punktfunk pins, plus the patches in" + echo " packaging/gamescope/patches:" + echo " ." + echo " * 10-bit BT.2020/PQ capture formats, so an HDR game reaches a capture consumer as HDR" + echo " instead of pre-tonemapped SDR." + echo " * --pipewire-composite-cursor: the pointer is painted into the capture stream, so a" + echo " consumer with no cursor of its own gets one and the host stops blending one in." + echo " * A headless session advertises its real mode and refresh rates (and" + echo " --custom-refresh-rates), so Steam and games see the resolution and refresh the stream" + echo " actually runs at instead of an unnamed 60 Hz panel." + echo " * --pipewire-composite-external-overlay: the mangoapp performance overlay is painted" + echo " into the capture stream, so the fps/stats readout is visible remotely." + echo " ." + echo " Installed as /usr/bin/punktfunk-gamescope; your system gamescope is untouched." +} > "$STAGE/DEBIAN/control" + +mkdir -p dist +OUT="dist/${PKG}_${VERSION}_${DEB_ARCH}.deb" +dpkg-deb --build --root-owner-group "$STAGE" "$OUT" +echo "==> wrote $OUT" +echo " banner: $BANNER" diff --git a/packaging/gamescope/build-gamescope-rpm.sh b/packaging/gamescope/build-gamescope-rpm.sh new file mode 100755 index 00000000..6d7f4df5 --- /dev/null +++ b/packaging/gamescope/build-gamescope-rpm.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +# Package an already-built punktfunk-gamescope binary as an RPM, for the Gitea RPM registry. +# +# WHY this exists: before it, the only ways to get punktfunk-gamescope were the Bazzite/Atomic +# sysext, the Arch package, the SteamOS installer, a NixOS option — or building gamescope from +# source yourself. A traditional Fedora-family box (Nobara, plain Fedora, Nobara-derived HTPCs) +# had no packaged route at all, which is how a field report ended up on a stock gamescope streaming +# a session that told every game the display was 60 Hz. +# +# The binary is NOT built here; CI builds it once per Fedora major and caches it +# (.gitea/workflows/rpm.yml). See punktfunk-gamescope.spec's header for why repacking beats +# rebuilding. +# +# Usage: +# bash packaging/gamescope/build-gamescope-rpm.sh \ +# --binary gs-cache/punktfunk-gamescope \ +# [--version 3.16.25] [--release 1] [--outdir dist] +# +# Output: /punktfunk-gamescope--..rpm +set -euo pipefail + +BINARY="" +# Default the version to the upstream gamescope the pinned revision describes as, suffixed with the +# patch-set revision — same shape as the Arch package's `pkgver`, so the two channels read alike. +VERSION="" +RELEASE="1" +OUTDIR="dist" + +while [ $# -gt 0 ]; do + case "$1" in + --binary) BINARY="${2:?--binary needs a path}"; shift 2 ;; + --version) VERSION="${2:?--version needs a value}"; shift 2 ;; + --release) RELEASE="${2:?--release needs a value}"; shift 2 ;; + --outdir) OUTDIR="${2:?--outdir needs a value}"; shift 2 ;; + *) echo "unknown argument: $1" >&2; exit 2 ;; + esac +done + +[ -n "$BINARY" ] || { echo "ERROR: --binary is required" >&2; exit 2; } +[ -x "$BINARY" ] || { echo "ERROR: $BINARY is not an executable file" >&2; exit 1; } + +ROOTDIR="$(cd "$(dirname "$0")/../.." && pwd)" +cd "$ROOTDIR" + +# Derive the version from the binary itself when not told: it is the only source that cannot drift +# from what is actually being packaged. `gamescope version 3.16.25-1-g8c676c3+pfhdr4 (gcc …)` → +# `3.16.25` + the marker. RPM versions may not contain `-`, hence the trailing `.pfhdrN` form. +BANNER="$("$BINARY" --version 2>&1 | head -1)" +case "$BANNER" in + *'+pfhdr'*) ;; + *) echo "ERROR: $BINARY has no +pfhdr marker — it is not a punktfunk gamescope build" >&2 + echo " banner: $BANNER" >&2 + exit 1 ;; +esac +PFHDR="$(printf '%s\n' "$BANNER" | grep -o '+pfhdr[0-9]\+' | head -1 | tr -d '+')" +if [ -z "$VERSION" ]; then + UPSTREAM="$(printf '%s\n' "$BANNER" | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1)" + [ -n "$UPSTREAM" ] || { echo "ERROR: no X.Y.Z version in banner: $BANNER" >&2; exit 1; } + VERSION="${UPSTREAM}.${PFHDR}" +fi + +echo "==> packaging $BINARY as punktfunk-gamescope-${VERSION}-${RELEASE}" +echo " banner: $BANNER" + +TOP="$(mktemp -d)" +trap 'rm -rf "$TOP"' EXIT +mkdir -p "$TOP"/{SOURCES,SPECS,BUILD,BUILDROOT,RPMS,SRPMS} +install -m0755 "$BINARY" "$TOP/SOURCES/punktfunk-gamescope" + +mkdir -p "$OUTDIR" +rpmbuild \ + --define "_topdir $TOP" \ + --define "pf_version $VERSION" \ + --define "pf_release $RELEASE" \ + -bb packaging/gamescope/punktfunk-gamescope.spec + +find "$TOP/RPMS" -name '*.rpm' -exec cp -v {} "$OUTDIR/" \; +echo "==> wrote $(find "$OUTDIR" -name 'punktfunk-gamescope-*.rpm' -newer "$TOP" -print -quit 2>/dev/null || echo "$OUTDIR"/punktfunk-gamescope-*.rpm)" diff --git a/packaging/gamescope/punktfunk-gamescope.spec b/packaging/gamescope/punktfunk-gamescope.spec new file mode 100644 index 00000000..bfbe163d --- /dev/null +++ b/packaging/gamescope/punktfunk-gamescope.spec @@ -0,0 +1,78 @@ +# punktfunk-gamescope — gamescope carrying punktfunk's capture patches, installed under its own +# name so it sits BESIDE the distro's gamescope (Game Mode keeps using that one). +# +# This spec REPACKS a binary that was already built, rather than building gamescope itself: the +# build is a ~10-minute meson compile of an unrelated tree that CI already does once per Fedora +# major and caches (.gitea/workflows/rpm.yml). Rebuilding it inside rpmbuild would double that for +# no gain, and would need network access in the build root to fetch the upstream tree. +# +# The counterpart for Arch is packaging/gamescope/PKGBUILD, which DOES build from source, because +# makepkg fetches sources by design and the AUR-style recipe is what an Arch user expects. +# +# Usage: bash packaging/gamescope/build-gamescope-rpm.sh --binary +Name: punktfunk-gamescope +Version: %{pf_version} +Release: %{pf_release}%{?dist} +Summary: gamescope with punktfunk's PipeWire capture patches (HDR, cursor, overlay, virtual-display modes) + +# gamescope is BSD-2-Clause; our patches are contributed under the same terms. +License: BSD-2-Clause +URL: https://git.unom.io/unom/punktfunk +Source0: punktfunk-gamescope + +# Not `Provides: gamescope` and not `Conflicts:` either — this ships a differently-named binary and +# is designed to coexist. A box's Game Mode session keeps running the distro's gamescope; only the +# sessions punktfunk-host starts itself resolve this one (PUNKTFUNK_GAMESCOPE_BIN > +# punktfunk-gamescope > gamescope). +# +# The runtime library Requires are auto-generated by rpmbuild from the binary's ELF NEEDED entries, +# which is exactly right here: this binary is soname-coupled to the Fedora major it was compiled +# on, and the generated Requires are what stop it installing on the wrong one. +Recommends: punktfunk-host + +# Nothing is compiled here, so there is no debuginfo to extract; without this rpmbuild fails +# looking for sources it was never given. +%global debug_package %{nil} + +%description +gamescope built from the upstream revision punktfunk pins, plus the patches in +packaging/gamescope/patches: + + * 10-bit BT.2020/PQ capture formats on the PipeWire node, so an HDR game reaches a capture + consumer as HDR instead of pre-tonemapped SDR. + * --pipewire-composite-cursor: paint the pointer into the capture stream, so a consumer with no + cursor of its own gets one — and the host stops blending one in, which frees the encoder's + fastest zero-copy source. + * A headless session advertises its real mode and refresh rates (and --custom-refresh-rates), so + Steam and games see the resolution and refresh the stream actually runs at instead of an + unnamed 60 Hz panel. + * --pipewire-composite-external-overlay: paint the mangoapp performance overlay into the capture + stream, so the fps/stats readout is visible to someone watching remotely. + +Installed as /usr/bin/punktfunk-gamescope. Your system gamescope is untouched. + +%prep +# Nothing to unpack: Source0 IS the binary. + +%build +# Nothing to build — see the header. + +%install +install -Dm0755 %{SOURCE0} %{buildroot}%{_bindir}/punktfunk-gamescope + +%check +# The marker is the host's entire capability probe (`gamescope_patch_level()`): a binary that lost +# the patches would install fine and then silently stream SDR with no cursor. Refuse to package it. +# +# Executed in the build root, which is the same container the binary was compiled in — if that ever +# stops being true this check is the thing that notices. +%{buildroot}%{_bindir}/punktfunk-gamescope --version 2>&1 | grep -q '+pfhdr' || { + echo "punktfunk-gamescope: the +pfhdr marker is missing — the patches did not take" >&2 + exit 1 +} + +%files +%{_bindir}/punktfunk-gamescope + +%changelog +# Generated per build; see the git history for the patch set's own changes.