ci / web (pull_request) Successful in 1m0s
ci / bun-nix (pull_request) Successful in 2m6s
ci / rust-arm64 (pull_request) Successful in 3m29s
ci / docs-site (pull_request) Successful in 3m53s
android / android (pull_request) Successful in 5m4s
ci / rust (pull_request) Successful in 5m9s
apple / swift (pull_request) Successful in 2m0s
apple / distribute (pull_request) Skipped
apple / screenshots (pull_request) Skipped
nix / flake (pull_request) Failing after 6m17s
The previous commit built the layer and taught the host to use it, but only the
Arch PKGBUILD carried the files, so every other channel still landed on the
no-game-HDR fallback. This finishes the job.
The packaging scripts now take `--stage`, the DESTDIR the gamescope build script
wrote, instead of a path to one binary. That is the part worth keeping: the next
file this package needs will not require a new flag in four scripts and two
workflows. CI caches the whole staged tree for the same reason. The gs-cache key
already hashes packaging/gamescope/**, which this commit changes, so stale caches
in the old single-file shape cannot be restored into the new layout.
Channels, all of them:
rpm spec gains Source1/Source2 and %files entries
deb build-gamescope-deb.sh copies the layer into the package root
Arch PKGBUILD (previous commit); the sysext extracts the whole usr tree
sysext bazzite takes --gamescope-stage; arch asserts the layer arrived
nix the derivation keeps, renames and rewrites the layer rather than
deleting it with everything else
A missing layer is fatal in every one of them, not best-effort. A package that
carries the compositor without it looks completely healthy and then silently
denies every game an HDR10 swapchain -- the exact failure this whole change
exists to end, so it must not be possible to ship it again by accident.
Two things needed care:
The layer manifest carries an ABSOLUTE library_path baked in at build time, so
every channel has to install the .so at exactly that path. That means literal
/usr/lib/punktfunk, not %{_libdir} (which is /usr/lib64 on Fedora) and not a
Debian multiarch triplet. Nothing links the .so by soname -- the loader dlopens
it by that path -- so multilib has no claim here. The rpm and nix install checks
now read the path back out of the manifest and fail if it names a file the
package does not install, because a manifest pointing at nothing is the silent
shape of this bug.
NixOS has no /usr, so the layer lives inside the gamescope derivation and the
host's path is overridable via PUNKTFUNK_GAMESCOPE_WSI_LAYER_DIR, which the
module sets -- the same posture as PUNKTFUNK_GAMESCOPE_BIN, and documented.
The manifest rewrite moved out of a heredoc into
packaging/gamescope/rewrite-wsi-layer-manifest.py because the FHS builds and the
Nix store both need it and must rename the layer identically; two copies would
drift into a host looking for a name only one of them produces.
Verified: 214 pf-vdisplay tests pass in a linux container, clippy -D warnings and
rustfmt clean, bash -n on all five changed shell scripts, both workflow YAMLs
parse, and the rewrite script was run against a synthetic FROG manifest to
confirm it renames/repoints/regates while preserving the `functions` block --
which is the field that decides whether the layer loads at all.
NOT verified: no nix on this machine, so gamescope.nix, flake.nix and the module
are unevaluated; no gamescope build, no package build of any kind, and no game
has taken an HDR swapchain on glass.
137 lines
6.8 KiB
Bash
Executable File
137 lines
6.8 KiB
Bash
Executable File
#!/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).
|
|
#
|
|
# `--stage` is the DESTDIR build-punktfunk-gamescope.sh wrote, not a single binary: that tree carries
|
|
# the compositor AND the Vulkan WSI layer built beside it, and a game nested under gamescope gets its
|
|
# HDR10 swapchain from that layer or from nowhere. Taking the whole tree is what stops the next file
|
|
# in the package needing a new flag in every packaging script.
|
|
#
|
|
# Usage:
|
|
# VERSION=3.16.25.pfhdr4~ci42.gdeadbee bash packaging/debian/build-gamescope-deb.sh \
|
|
# --stage gs-cache [--arch amd64]
|
|
# Output: dist/punktfunk-gamescope_<version>_<arch>.deb
|
|
set -euo pipefail
|
|
|
|
SRC_STAGE=""
|
|
DEB_ARCH=""
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--stage) SRC_STAGE="${2:?--stage 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 "$SRC_STAGE" ] || { echo "ERROR: --stage is required" >&2; exit 2; }
|
|
# The layout build-punktfunk-gamescope.sh writes under its --destdir/--prefix.
|
|
BINARY="$SRC_STAGE/usr/bin/punktfunk-gamescope"
|
|
LAYER_SO="$SRC_STAGE/usr/lib/punktfunk/libVkLayer_PUNKTFUNK_gamescope_wsi.so"
|
|
LAYER_JSON="$SRC_STAGE/usr/lib/punktfunk/vulkan/implicit_layer.d/punktfunk_gamescope_wsi.json"
|
|
[ -x "$BINARY" ] || { echo "ERROR: $BINARY is not an executable file" >&2; exit 1; }
|
|
# Hard, not best-effort: a package carrying the compositor without its layer looks perfectly healthy
|
|
# and then silently denies every game an HDR10 swapchain.
|
|
for f in "$LAYER_SO" "$LAYER_JSON"; do
|
|
[ -f "$f" ] || { echo "ERROR: $f missing from the stage — no game HDR without it" >&2; exit 1; }
|
|
done
|
|
|
|
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"
|
|
# /usr/lib/punktfunk, not a multiarch triplet dir: the layer manifest carries that absolute path
|
|
# baked in at build time, so the two have to agree. Nothing links the .so by soname — the Vulkan
|
|
# loader dlopens it by exactly that path — so multiarch has no say here.
|
|
install -Dm0755 "$LAYER_SO" "$STAGE/usr/lib/punktfunk/libVkLayer_PUNKTFUNK_gamescope_wsi.so"
|
|
install -Dm0644 "$LAYER_JSON" \
|
|
"$STAGE/usr/lib/punktfunk/vulkan/implicit_layer.d/punktfunk_gamescope_wsi.json"
|
|
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 <packages@unom.io>"
|
|
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, with its matching Vulkan WSI layer under"
|
|
echo " /usr/lib/punktfunk. The layer has its own name and its own enable variable, so it sits"
|
|
echo " beside your gamescope package's rather than replacing it; your system gamescope is"
|
|
echo " 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"
|